sql_show.cc 321 KB
Newer Older
Sergei Golubchik's avatar
Sergei Golubchik committed
1
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
2
   Copyright (c) 2009, 2013, Monty Program Ab
3

unknown's avatar
unknown committed
4 5
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
6
   the Free Software Foundation; version 2 of the License.
7

unknown's avatar
unknown committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
12

unknown's avatar
unknown committed
13 14
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
15
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
unknown's avatar
unknown committed
16 17 18 19


/* Function with list databases, tables or fields */

Mats Kindahl's avatar
Mats Kindahl committed
20
#include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
21 22 23
#include "sql_priv.h"
#include "unireg.h"
#include "sql_acl.h"                        // fill_schema_*_privileges
24
#include "sql_select.h"                         // For select_describe
25
#include "sql_base.h"                       // close_tables_for_reopen
26
#include "create_options.h"
27
#include "sql_show.h"
28 29 30
#include "sql_table.h"                        // filename_to_tablename,
                                              // primary_key_name,
                                              // build_table_filename
31
#include "repl_failsafe.h"
32 33
#include "sql_parse.h"             // check_access, check_table_access
#include "sql_partition.h"         // partition_element
34 35
#include "sql_derived.h"           // mysql_derived_prepare,
                                   // mysql_handle_derived,
36 37 38 39 40 41
#include "sql_db.h"     // check_db_dir_existence, load_db_opt_by_name
#include "sql_time.h"   // interval_type_to_name
#include "tztime.h"                             // struct Time_zone
#include "sql_acl.h"     // TABLE_ACLS, check_grant, DB_ACLS, acl_get,
                         // check_grant_db
#include "filesort.h"    // filesort_free_buffers
42
#include "sp.h"
43
#include "sp_head.h"
Sergey Glukhov's avatar
Sergey Glukhov committed
44
#include "sp_pcontext.h"
45
#include "set_var.h"
46
#include "sql_trigger.h"
Sergei Golubchik's avatar
Sergei Golubchik committed
47
#include "sql_derived.h"
48
#include "sql_statistics.h"
Sergei Golubchik's avatar
Sergei Golubchik committed
49
#include "sql_connect.h"
unknown's avatar
unknown committed
50
#include "authors.h"
51
#include "contributors.h"
52
#include "sql_partition.h"
53
#ifdef HAVE_EVENT_SCHEDULER
54
#include "events.h"
55
#include "event_data_objects.h"
56
#endif
unknown's avatar
unknown committed
57
#include <my_dir.h>
58
#include "lock.h"                           // MYSQL_OPEN_IGNORE_FLUSH
59
#include "debug_sync.h"
Sergei Golubchik's avatar
Sergei Golubchik committed
60
#include "keycaches.h"
unknown's avatar
unknown committed
61

62 63 64
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
65 66 67 68 69 70
enum enum_i_s_events_fields
{
  ISE_EVENT_CATALOG= 0,
  ISE_EVENT_SCHEMA,
  ISE_EVENT_NAME,
  ISE_DEFINER,
71
  ISE_TIME_ZONE,
72 73 74 75 76 77 78 79 80 81 82 83 84 85
  ISE_EVENT_BODY,
  ISE_EVENT_DEFINITION,
  ISE_EVENT_TYPE,
  ISE_EXECUTE_AT,
  ISE_INTERVAL_VALUE,
  ISE_INTERVAL_FIELD,
  ISE_SQL_MODE,
  ISE_STARTS,
  ISE_ENDS,
  ISE_STATUS,
  ISE_ON_COMPLETION,
  ISE_CREATED,
  ISE_LAST_ALTERED,
  ISE_LAST_EXECUTED,
86
  ISE_EVENT_COMMENT,
unknown's avatar
unknown committed
87 88 89 90
  ISE_ORIGINATOR,
  ISE_CLIENT_CS,
  ISE_CONNECTION_CL,
  ISE_DB_CL
91 92
};

93
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
94 95 96 97 98
static const char *grant_names[]={
  "select","insert","update","delete","create","drop","reload","shutdown",
  "process","file","grant","references","index","alter"};

static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
99
                               "grant_types",
100
                               grant_names, NULL};
unknown's avatar
unknown committed
101
#endif
unknown's avatar
unknown committed
102

103 104 105
/* Match the values of enum ha_choice */
static const char *ha_choice_values[] = {"", "0", "1"};

106 107 108
static void store_key_options(THD *thd, String *packet, TABLE *table,
                              KEY *key_info);

Georgi Kodinov's avatar
merge  
Georgi Kodinov committed
109
#ifdef WITH_PARTITION_STORAGE_ENGINE
110 111 112 113 114
static void get_cs_converted_string_value(THD *thd,
                                          String *input_str,
                                          String *output_str,
                                          CHARSET_INFO *cs,
                                          bool use_hex);
Georgi Kodinov's avatar
merge  
Georgi Kodinov committed
115
#endif
116

117 118
static void
append_algorithm(TABLE_LIST *table, String *buff);
119

120
static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table);
unknown's avatar
unknown committed
121

122 123 124 125 126 127 128 129
typedef struct st_lookup_field_values
{
  LEX_STRING db_value, table_value;
  bool wild_db_value, wild_table_value;
} LOOKUP_FIELD_VALUES;

bool get_lookup_field_values(THD *, COND *, TABLE_LIST *, LOOKUP_FIELD_VALUES *);

unknown's avatar
unknown committed
130
/***************************************************************************
unknown's avatar
unknown committed
131
** List all table types supported
unknown's avatar
unknown committed
132 133
***************************************************************************/

unknown's avatar
unknown committed
134 135
static int make_version_string(char *buf, int buf_length, uint version)
{
unknown's avatar
unknown committed
136
  return my_snprintf(buf, buf_length, "%d.%d", version>>8,version&0xff);
unknown's avatar
unknown committed
137 138
}

unknown's avatar
unknown committed
139 140 141 142 143 144 145 146 147 148

static const LEX_STRING maturity_name[]={
  { C_STRING_WITH_LEN("Unknown") },
  { C_STRING_WITH_LEN("Experimental") },
  { C_STRING_WITH_LEN("Alpha") },
  { C_STRING_WITH_LEN("Beta") },
  { C_STRING_WITH_LEN("Gamma") },
  { C_STRING_WITH_LEN("Stable") }};


unknown's avatar
WL#2936  
unknown committed
149
static my_bool show_plugins(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
150 151 152
                            void *arg)
{
  TABLE *table= (TABLE*) arg;
unknown's avatar
unknown committed
153
  struct st_maria_plugin *plug= plugin_decl(plugin);
unknown's avatar
WL#2936  
unknown committed
154
  struct st_plugin_dl *plugin_dl= plugin_dlib(plugin);
unknown's avatar
unknown committed
155 156 157 158 159
  CHARSET_INFO *cs= system_charset_info;
  char version_buf[20];

  restore_record(table, s->default_values);

unknown's avatar
WL#2936  
unknown committed
160 161
  table->field[0]->store(plugin_name(plugin)->str,
                         plugin_name(plugin)->length, cs);
unknown's avatar
unknown committed
162 163 164 165 166

  table->field[1]->store(version_buf,
        make_version_string(version_buf, sizeof(version_buf), plug->version),
        cs);

unknown's avatar
WL#2936  
unknown committed
167
  switch (plugin_state(plugin)) {
unknown's avatar
unknown committed
168
  case PLUGIN_IS_DELETED:
unknown's avatar
unknown committed
169
    table->field[2]->store(STRING_WITH_LEN("DELETED"), cs);
unknown's avatar
unknown committed
170 171
    break;
  case PLUGIN_IS_UNINITIALIZED:
unknown's avatar
unknown committed
172
    table->field[2]->store(STRING_WITH_LEN("INACTIVE"), cs);
unknown's avatar
unknown committed
173 174
    break;
  case PLUGIN_IS_READY:
unknown's avatar
unknown committed
175
    table->field[2]->store(STRING_WITH_LEN("ACTIVE"), cs);
unknown's avatar
unknown committed
176
    break;
177 178 179
  case PLUGIN_IS_DISABLED:
    table->field[2]->store(STRING_WITH_LEN("DISABLED"), cs);
    break;
180 181 182
  case PLUGIN_IS_FREED: // filtered in fill_plugins, used in fill_all_plugins
    table->field[2]->store(STRING_WITH_LEN("NOT INSTALLED"), cs);
    break;
unknown's avatar
unknown committed
183 184 185 186
  default:
    DBUG_ASSERT(0);
  }

unknown's avatar
unknown committed
187 188 189
  table->field[3]->store(plugin_type_names[plug->type].str,
                         plugin_type_names[plug->type].length,
                         cs);
unknown's avatar
unknown committed
190
  table->field[4]->store(version_buf,
unknown's avatar
unknown committed
191
        make_version_string(version_buf, sizeof(version_buf),
unknown's avatar
unknown committed
192
                            *(uint *)plug->info), cs);
unknown's avatar
unknown committed
193

unknown's avatar
WL#2936  
unknown committed
194
  if (plugin_dl)
unknown's avatar
unknown committed
195
  {
unknown's avatar
WL#2936  
unknown committed
196
    table->field[5]->store(plugin_dl->dl.str, plugin_dl->dl.length, cs);
unknown's avatar
unknown committed
197
    table->field[5]->set_notnull();
unknown's avatar
unknown committed
198
    table->field[6]->store(version_buf,
unknown's avatar
unknown committed
199
          make_version_string(version_buf, sizeof(version_buf),
unknown's avatar
unknown committed
200
                              plugin_dl->mariaversion),
unknown's avatar
unknown committed
201 202
          cs);
    table->field[6]->set_notnull();
unknown's avatar
unknown committed
203 204
  }
  else
unknown's avatar
unknown committed
205
  {
unknown's avatar
unknown committed
206
    table->field[5]->set_null();
unknown's avatar
unknown committed
207 208 209 210
    table->field[6]->set_null();
  }


unknown's avatar
unknown committed
211 212
  if (plug->author)
  {
unknown's avatar
unknown committed
213 214
    table->field[7]->store(plug->author, strlen(plug->author), cs);
    table->field[7]->set_notnull();
unknown's avatar
unknown committed
215 216
  }
  else
unknown's avatar
unknown committed
217
    table->field[7]->set_null();
unknown's avatar
unknown committed
218 219 220

  if (plug->descr)
  {
unknown's avatar
unknown committed
221 222
    table->field[8]->store(plug->descr, strlen(plug->descr), cs);
    table->field[8]->set_notnull();
unknown's avatar
unknown committed
223 224
  }
  else
unknown's avatar
unknown committed
225
    table->field[8]->set_null();
unknown's avatar
unknown committed
226

227 228
  switch (plug->license) {
  case PLUGIN_LICENSE_GPL:
229
    table->field[9]->store(PLUGIN_LICENSE_GPL_STRING,
230 231 232
                           strlen(PLUGIN_LICENSE_GPL_STRING), cs);
    break;
  case PLUGIN_LICENSE_BSD:
233
    table->field[9]->store(PLUGIN_LICENSE_BSD_STRING,
234 235 236
                           strlen(PLUGIN_LICENSE_BSD_STRING), cs);
    break;
  default:
237
    table->field[9]->store(PLUGIN_LICENSE_PROPRIETARY_STRING,
238 239 240 241
                           strlen(PLUGIN_LICENSE_PROPRIETARY_STRING), cs);
    break;
  }

242 243 244 245 246
  table->field[10]->store(
    global_plugin_typelib_names[plugin_load_option(plugin)],
    strlen(global_plugin_typelib_names[plugin_load_option(plugin)]),
    cs);

Sergei Golubchik's avatar
Sergei Golubchik committed
247 248
  if (plug->maturity <= MariaDB_PLUGIN_MATURITY_STABLE)
     table->field[11]->store(maturity_name[plug->maturity].str,
unknown's avatar
unknown committed
249 250 251
                             maturity_name[plug->maturity].length,
                             cs);
   else
Sergei Golubchik's avatar
Sergei Golubchik committed
252
     table->field[11]->store("Unknown", 7, cs);
unknown's avatar
unknown committed
253 254 255

  if (plug->version_info)
  {
Sergei Golubchik's avatar
Sergei Golubchik committed
256
    table->field[12]->store(plug->version_info,
unknown's avatar
unknown committed
257
                            strlen(plug->version_info), cs);
Sergei Golubchik's avatar
Sergei Golubchik committed
258
    table->field[12]->set_notnull();
unknown's avatar
unknown committed
259 260
  }
  else
Sergei Golubchik's avatar
Sergei Golubchik committed
261
    table->field[12]->set_null();
unknown's avatar
unknown committed
262

unknown's avatar
unknown committed
263 264 265 266 267 268 269 270 271
  return schema_table_store_record(thd, table);
}


int fill_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
{
  DBUG_ENTER("fill_plugins");
  TABLE *table= tables->table;

272 273
  if (plugin_foreach_with_mask(thd, show_plugins, MYSQL_ANY_PLUGIN,
                               ~PLUGIN_IS_FREED, table))
unknown's avatar
unknown committed
274
    DBUG_RETURN(1);
275

unknown's avatar
unknown committed
276 277 278 279
  DBUG_RETURN(0);
}


280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
int fill_all_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
{
  DBUG_ENTER("fill_all_plugins");
  TABLE *table= tables->table;
  LOOKUP_FIELD_VALUES lookup;

  if (get_lookup_field_values(thd, cond, tables, &lookup))
    DBUG_RETURN(0);

  if (lookup.db_value.str && !lookup.db_value.str[0])
    DBUG_RETURN(0); // empty string never matches a valid SONAME

  MY_DIR *dirp= my_dir(opt_plugin_dir, MY_THREAD_SPECIFIC);
  if (!dirp)
  {
    my_error(ER_CANT_READ_DIR, MYF(0), opt_plugin_dir, my_errno);
    DBUG_RETURN(1);
  }

  if (!lookup.db_value.str)
    plugin_dl_foreach(thd, 0, show_plugins, table);

  const char *wstr= lookup.db_value.str, *wend= wstr + lookup.db_value.length;
  for (uint i=0; i < (uint) dirp->number_of_files; i++)
  {
    FILEINFO *file= dirp->dir_entry+i;
    LEX_STRING dl= { file->name, strlen(file->name) };
    const char *dlend= dl.str + dl.length;
    const size_t so_ext_len= sizeof(SO_EXT) - 1;

    if (strcasecmp(dlend - so_ext_len, SO_EXT))
      continue;

    if (lookup.db_value.str)
    {
      if (lookup.wild_db_value)
      {
        if (my_wildcmp(files_charset_info, dl.str, dlend, wstr, wend,
                       wild_prefix, wild_one, wild_many))
          continue;
      }
      else
      {
        if (my_strnncoll(files_charset_info,
                         (uchar*)dl.str, dl.length,
                         (uchar*)lookup.db_value.str, lookup.db_value.length))
          continue;
      }
    }

    plugin_dl_foreach(thd, &dl, show_plugins, table);
    thd->clear_error();
  }

  my_dirend(dirp);
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
/***************************************************************************
** List all Authors.
** If you can update it, you get to be in it :)
***************************************************************************/

bool mysqld_show_authors(THD *thd)
{
  List<Item> field_list;
  Protocol *protocol= thd->protocol;
  DBUG_ENTER("mysqld_show_authors");

  field_list.push_back(new Item_empty_string("Name",40));
  field_list.push_back(new Item_empty_string("Location",40));
  field_list.push_back(new Item_empty_string("Comment",80));

354
  if (protocol->send_result_set_metadata(&field_list,
unknown's avatar
unknown committed
355 356 357 358 359 360 361 362 363 364 365 366 367
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
    DBUG_RETURN(TRUE);

  show_table_authors_st *authors;
  for (authors= show_table_authors; authors->name; authors++)
  {
    protocol->prepare_for_resend();
    protocol->store(authors->name, system_charset_info);
    protocol->store(authors->location, system_charset_info);
    protocol->store(authors->comment, system_charset_info);
    if (protocol->write())
      DBUG_RETURN(TRUE);
  }
368
  my_eof(thd);
unknown's avatar
unknown committed
369 370
  DBUG_RETURN(FALSE);
}
371

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387

/***************************************************************************
** List all Contributors.
** Please get permission before updating
***************************************************************************/

bool mysqld_show_contributors(THD *thd)
{
  List<Item> field_list;
  Protocol *protocol= thd->protocol;
  DBUG_ENTER("mysqld_show_contributors");

  field_list.push_back(new Item_empty_string("Name",40));
  field_list.push_back(new Item_empty_string("Location",40));
  field_list.push_back(new Item_empty_string("Comment",80));

388
  if (protocol->send_result_set_metadata(&field_list,
389 390 391 392 393 394 395 396 397 398 399 400 401
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
    DBUG_RETURN(TRUE);

  show_table_contributors_st *contributors;
  for (contributors= show_table_contributors; contributors->name; contributors++)
  {
    protocol->prepare_for_resend();
    protocol->store(contributors->name, system_charset_info);
    protocol->store(contributors->location, system_charset_info);
    protocol->store(contributors->comment, system_charset_info);
    if (protocol->write())
      DBUG_RETURN(TRUE);
  }
402
  my_eof(thd);
403 404 405 406
  DBUG_RETURN(FALSE);
}


unknown's avatar
unknown committed
407
/***************************************************************************
408
 List all privileges supported
unknown's avatar
unknown committed
409 410
***************************************************************************/

411 412 413 414
struct show_privileges_st {
  const char *privilege;
  const char *context;
  const char *comment;
unknown's avatar
unknown committed
415 416
};

417 418
static struct show_privileges_st sys_privileges[]=
{
unknown's avatar
unknown committed
419
  {"Alter", "Tables",  "To alter the table"},
420
  {"Alter routine", "Functions,Procedures",  "To alter or drop stored functions/procedures"},
421
  {"Create", "Databases,Tables,Indexes",  "To create new databases and tables"},
422
  {"Create routine","Databases","To use CREATE FUNCTION/PROCEDURE"},
unknown's avatar
unknown committed
423 424
  {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
  {"Create view", "Tables",  "To create new views"},
unknown's avatar
unknown committed
425
  {"Create user", "Server Admin",  "To create new users"},
unknown's avatar
unknown committed
426
  {"Delete", "Tables",  "To delete existing rows"},
unknown's avatar
unknown committed
427
  {"Drop", "Databases,Tables", "To drop databases, tables, and views"},
428
#ifdef HAVE_EVENT_SCHEDULER
429
  {"Event","Server Admin","To create, alter, drop and execute events"},
430
#endif
431
  {"Execute", "Functions,Procedures", "To execute stored routines"},
unknown's avatar
unknown committed
432
  {"File", "File access on server",   "To read and write files on the server"},
433
  {"Grant option",  "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"},
unknown's avatar
unknown committed
434 435 436 437
  {"Index", "Tables",  "To create or drop indexes"},
  {"Insert", "Tables",  "To insert data into tables"},
  {"Lock tables","Databases","To use LOCK TABLES (together with SELECT privilege)"},
  {"Process", "Server Admin", "To view the plain text of currently executing queries"},
438
  {"Proxy", "Server Admin", "To make proxy user possible"},
439
  {"References", "Databases,Tables", "To have references on tables"},
unknown's avatar
unknown committed
440 441 442 443 444
  {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
  {"Replication client","Server Admin","To ask where the slave or master servers are"},
  {"Replication slave","Server Admin","To read binary log events from the master"},
  {"Select", "Tables",  "To retrieve rows from table"},
  {"Show databases","Server Admin","To see all databases with SHOW DATABASES"},
unknown's avatar
unknown committed
445 446
  {"Show view","Tables","To see views with SHOW CREATE VIEW"},
  {"Shutdown","Server Admin", "To shut down the server"},
unknown's avatar
unknown committed
447
  {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
448
  {"Trigger","Tables", "To use triggers"},
449
  {"Create tablespace", "Server Admin", "To create/alter/drop tablespaces"},
unknown's avatar
unknown committed
450 451
  {"Update", "Tables",  "To update existing rows"},
  {"Usage","Server Admin","No privileges - allow connect only"},
452 453 454
  {NullS, NullS, NullS}
};

unknown's avatar
unknown committed
455
bool mysqld_show_privileges(THD *thd)
unknown's avatar
unknown committed
456 457
{
  List<Item> field_list;
unknown's avatar
unknown committed
458
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
459 460 461 462
  DBUG_ENTER("mysqld_show_privileges");

  field_list.push_back(new Item_empty_string("Privilege",10));
  field_list.push_back(new Item_empty_string("Context",15));
463
  field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
unknown's avatar
unknown committed
464

465
  if (protocol->send_result_set_metadata(&field_list,
466
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
467
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
468

469 470
  show_privileges_st *privilege= sys_privileges;
  for (privilege= sys_privileges; privilege->privilege ; privilege++)
unknown's avatar
unknown committed
471
  {
unknown's avatar
unknown committed
472
    protocol->prepare_for_resend();
473 474 475
    protocol->store(privilege->privilege, system_charset_info);
    protocol->store(privilege->context, system_charset_info);
    protocol->store(privilege->comment, system_charset_info);
unknown's avatar
unknown committed
476
    if (protocol->write())
unknown's avatar
unknown committed
477
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
478
  }
479
  my_eof(thd);
unknown's avatar
unknown committed
480
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
481 482 483
}


484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
/** Hash of LEX_STRINGs used to search for ignored db directories. */
static HASH ignore_db_dirs_hash;

/** 
  An array of LEX_STRING pointers to collect the options at 
  option parsing time.
*/
static DYNAMIC_ARRAY ignore_db_dirs_array;

/**
  A value for the read only system variable to show a list of
  ignored directories.
*/
char *opt_ignore_db_dirs= NULL;

/**
  This flag is ON if:
        - the list of ignored directories is not empty

        - and some of the ignored directory names
        need no tablename-to-filename conversion.
        Otherwise, if the name of the directory contains
        unconditional characters like '+' or '.', they
        never can match the database directory name. So the
        db_name_is_in_ignore_db_dirs_list() can just return at once.
*/
static bool skip_ignored_dir_check= TRUE;

/**
  Sets up the data structures for collection of directories at option
  processing time.
  We need to collect the directories in an array first, because
  we need the character sets initialized before setting up the hash.

  @return state
  @retval TRUE  failed
  @retval FALSE success
*/

bool
ignore_db_dirs_init()
{
  return my_init_dynamic_array(&ignore_db_dirs_array, sizeof(LEX_STRING *),
527
                               0, 0, MYF(0));
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
}


/**
  Retrieves the key (the string itself) from the LEX_STRING hash members.

  Needed by hash_init().

  @param     data         the data element from the hash
  @param out len_ret      Placeholder to return the length of the key
  @param                  unused
  @return                 a pointer to the key
*/

static uchar *
db_dirs_hash_get_key(const uchar *data, size_t *len_ret,
                     my_bool __attribute__((unused)))
{
  LEX_STRING *e= (LEX_STRING *) data;

  *len_ret= e->length;
  return (uchar *) e->str;
}


/**
  Wrap a directory name into a LEX_STRING and push it to the array.

  Called at option processing time for each --ignore-db-dir option.

  @param    path  the name of the directory to push
  @return state
  @retval TRUE  failed
  @retval FALSE success
*/

bool
push_ignored_db_dir(char *path)
{
  LEX_STRING *new_elt;
  char *new_elt_buffer;
  size_t path_len= strlen(path);

  if (!path_len || path_len >= FN_REFLEN)
    return true;

  // No need to normalize, it's only a directory name, not a path.
  if (!my_multi_malloc(0,
                       &new_elt, sizeof(LEX_STRING),
                       &new_elt_buffer, path_len + 1,
                       NullS))
    return true;
  new_elt->str= new_elt_buffer;
  memcpy(new_elt_buffer, path, path_len);
  new_elt_buffer[path_len]= 0;
  new_elt->length= path_len;
  return insert_dynamic(&ignore_db_dirs_array, (uchar*) &new_elt);
}


/**
  Clean up the directory ignore options accumulated so far.

  Called at option processing time for each --ignore-db-dir option
  with an empty argument.
*/

void
ignore_db_dirs_reset()
{
  LEX_STRING **elt;
  while (NULL!= (elt= (LEX_STRING **) pop_dynamic(&ignore_db_dirs_array)))
    if (elt && *elt)
Sergei Golubchik's avatar
Sergei Golubchik committed
601
      my_free(*elt);
602 603 604 605 606 607 608 609 610 611 612 613 614 615
}


/**
  Free the directory ignore option variables.

  Called at server shutdown.
*/

void
ignore_db_dirs_free()
{
  if (opt_ignore_db_dirs)
  {
Sergei Golubchik's avatar
Sergei Golubchik committed
616
    my_free(opt_ignore_db_dirs);
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
    opt_ignore_db_dirs= NULL;
  }
  ignore_db_dirs_reset();
  delete_dynamic(&ignore_db_dirs_array);
  my_hash_free(&ignore_db_dirs_hash);
}


/**
  Initialize the ignore db directories hash and status variable from
  the options collected in the array.

  Called when option processing is over and the server's in-memory 
  structures are fully initialized.

  @return state
  @retval TRUE  failed
  @retval FALSE success
*/

static void dispose_db_dir(void *ptr)
{
Sergei Golubchik's avatar
Sergei Golubchik committed
639
  my_free(ptr);
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
}


bool
ignore_db_dirs_process_additions()
{
  ulong i;
  size_t len;
  char *ptr;
  LEX_STRING *dir;


  skip_ignored_dir_check= TRUE;

  if (my_hash_init(&ignore_db_dirs_hash, 
                   lower_case_table_names ?
                     character_set_filesystem : &my_charset_bin,
                   0, 0, 0, db_dirs_hash_get_key,
                   dispose_db_dir,
                   HASH_UNIQUE))
    return true;

  /* len starts from 1 because of the terminating zero. */
  len= 1;
  for (i= 0; i < ignore_db_dirs_array.elements; i++)
  {
    get_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i);
    len+= dir->length + 1;                      // +1 for the comma
    if (skip_ignored_dir_check)
    {
      char buff[FN_REFLEN];
671
      (void) tablename_to_filename(dir->str, buff, sizeof(buff));
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
      skip_ignored_dir_check= strcmp(dir->str, buff) != 0;
    }
  }

  /* No delimiter for the last directory. */
  if (len > 1)
    len--;

  /* +1 the terminating zero */
  ptr= opt_ignore_db_dirs= (char *) my_malloc(len + 1, MYF(0));
  if (!ptr)
    return true;

  /* Make sure we have an empty string to start with. */
  *ptr= 0;

  for (i= 0; i < ignore_db_dirs_array.elements; i++)
  {
    get_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i);
    if (my_hash_insert(&ignore_db_dirs_hash, (uchar *) dir))
      return true;
    ptr= strnmov(ptr, dir->str, dir->length);
    if (i + 1 < ignore_db_dirs_array.elements)
      ptr= strmov(ptr, ",");

    /*
      Set the transferred array element to NULL to avoid double free
      in case of error.
    */
    dir= NULL;
    set_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i);
  }

  /* make sure the string is terminated */
  DBUG_ASSERT(ptr - opt_ignore_db_dirs <= (ptrdiff_t) len);
  *ptr= 0;

  /* 
    It's OK to empty the array here as the allocated elements are
    referenced through the hash now.
  */
  reset_dynamic(&ignore_db_dirs_array);

  return false;
}


/**
  Check if a directory name is in the hash of ignored directories.

  @return search result
  @retval TRUE  found
  @retval FALSE not found
*/

static inline bool
is_in_ignore_db_dirs_list(const char *directory)
{
  return ignore_db_dirs_hash.records &&
    NULL != my_hash_search(&ignore_db_dirs_hash, (const uchar *) directory, 
                           strlen(directory));
}


/**
  Check if a database name is in the hash of ignored directories.

  @return search result
  @retval TRUE  found
  @retval FALSE not found
*/

bool
db_name_is_in_ignore_db_dirs_list(const char *directory)
{
  char buff[FN_REFLEN];
  uint buff_len;

  if (skip_ignored_dir_check)
    return 0;

  buff_len= tablename_to_filename(directory, buff, sizeof(buff));

  return my_hash_search(&ignore_db_dirs_hash, (uchar *) buff, buff_len)!=NULL;
}

758 759 760 761 762
enum find_files_result {
  FIND_FILES_OK,
  FIND_FILES_OOM,
  FIND_FILES_DIR
};
763

764 765 766 767 768 769 770
/*
  find_files() - find files in a given directory.

  SYNOPSIS
    find_files()
    thd                 thread handler
    files               put found files in this list
771 772
    db                  database name to search tables in
                        or NULL to search for databases
773 774 775 776 777 778 779 780 781 782
    path                path to database
    wild                filter for found files

  RETURN
    FIND_FILES_OK       success
    FIND_FILES_OOM      out of memory error
    FIND_FILES_DIR      no such directory, or directory can't be read
*/


783
static find_files_result
784
find_files(THD *thd, Dynamic_array<LEX_STRING*> *files, LEX_STRING *db,
785
           const char *path, const LEX_STRING *wild)
unknown's avatar
unknown committed
786 787
{
  MY_DIR *dirp;
788
  Discovered_table_list tl(thd, files, wild);
789
  DBUG_ENTER("find_files");
unknown's avatar
unknown committed
790

791
  if (!(dirp = my_dir(path, MY_THREAD_SPECIFIC | (db ? 0 : MY_WANT_STAT))))
792 793
  {
    if (my_errno == ENOENT)
794
      my_error(ER_BAD_DB_ERROR, MYF(ME_BELL | ME_WAITTANG), db->str);
795
    else
796
      my_error(ER_CANT_READ_DIR, MYF(ME_BELL | ME_WAITTANG), path, my_errno);
797
    DBUG_RETURN(FIND_FILES_DIR);
798
  }
unknown's avatar
unknown committed
799

800
  if (!db)                                           /* Return databases */
unknown's avatar
unknown committed
801
  {
802 803 804
    for (uint i=0; i < (uint) dirp->number_of_files; i++)
    {
      FILEINFO *file= dirp->dir_entry+i;
unknown's avatar
unknown committed
805 806
#ifdef USE_SYMDIR
      char *ext;
807
      char buff[FN_REFLEN];
unknown's avatar
unknown committed
808
      if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
809
      {
810 811
        /* Only show the sym file if it points to a directory */
        char *end;
812
        *ext=0;                                 /* Remove extension */
813 814 815 816
        unpack_dirname(buff, file->name);
        end= strend(buff);
        if (end != buff && end[-1] == FN_LIBCHAR)
          end[-1]= 0;				// Remove end FN_LIBCHAR
Marc Alff's avatar
Marc Alff committed
817
        if (!mysql_file_stat(key_file_misc, buff, file->mystat, MYF(0)))
818 819
               continue;
       }
unknown's avatar
unknown committed
820
#endif
821 822
      if (!MY_S_ISDIR(file->mystat->st_mode))
        continue;
823

824 825 826
      if (is_in_ignore_db_dirs_list(file->name))
        continue;

827 828
      if (tl.add_file(file->name))
        goto err;
unknown's avatar
unknown committed
829
    }
830
    tl.sort();
unknown's avatar
unknown committed
831
  }
832 833
  else
  {
834
    if (ha_discover_table_names(thd, db, dirp, &tl, false))
835 836 837
      goto err;
  }

838
  DBUG_PRINT("info",("found: %zu files", files->elements()));
unknown's avatar
unknown committed
839
  my_dirend(dirp);
unknown's avatar
unknown committed
840

841
  DBUG_RETURN(FIND_FILES_OK);
842 843 844 845

err:
  my_dirend(dirp);
  DBUG_RETURN(FIND_FILES_OOM);
unknown's avatar
unknown committed
846 847
}

848

Martin Hansson's avatar
 
Martin Hansson committed
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
/**
   An Internal_error_handler that suppresses errors regarding views'
   underlying tables that occur during privilege checking within SHOW CREATE
   VIEW commands. This happens in the cases when

   - A view's underlying table (e.g. referenced in its SELECT list) does not
     exist. There should not be an error as no attempt was made to access it
     per se.

   - Access is denied for some table, column, function or stored procedure
     such as mentioned above. This error gets raised automatically, since we
     can't untangle its access checking from that of the view itself.
 */
class Show_create_error_handler : public Internal_error_handler {
  
  TABLE_LIST *m_top_view;
  bool m_handling;
  Security_context *m_sctx;

  char m_view_access_denied_message[MYSQL_ERRMSG_SIZE];
  char *m_view_access_denied_message_ptr;

public:

  /**
     Creates a new Show_create_error_handler for the particular security
     context and view. 

     @thd Thread context, used for security context information if needed.
     @top_view The view. We do not verify at this point that top_view is in
     fact a view since, alas, these things do not stay constant.
  */
  explicit Show_create_error_handler(THD *thd, TABLE_LIST *top_view) : 
    m_top_view(top_view), m_handling(FALSE),
    m_view_access_denied_message_ptr(NULL) 
  {
    
    m_sctx = test(m_top_view->security_ctx) ?
      m_top_view->security_ctx : thd->security_ctx;
  }

  /**
     Lazy instantiation of 'view access denied' message. The purpose of the
     Show_create_error_handler is to hide details of underlying tables for
     which we have no privileges behind ER_VIEW_INVALID messages. But this
     obviously does not apply if we lack privileges on the view itself.
     Unfortunately the information about for which table privilege checking
     failed is not available at this point. The only way for us to check is by
     reconstructing the actual error message and see if it's the same.
  */
  char* get_view_access_denied_message() 
  {
    if (!m_view_access_denied_message_ptr)
    {
      m_view_access_denied_message_ptr= m_view_access_denied_message;
      my_snprintf(m_view_access_denied_message, MYSQL_ERRMSG_SIZE,
                  ER(ER_TABLEACCESS_DENIED_ERROR), "SHOW VIEW",
                  m_sctx->priv_user,
                  m_sctx->host_or_ip, m_top_view->get_table_name());
    }
    return m_view_access_denied_message_ptr;
  }

912
  bool handle_condition(THD *thd, uint sql_errno, const char * /* sqlstate */,
913
                        MYSQL_ERROR::enum_warning_level level,
914
                        const char *message, MYSQL_ERROR ** /* cond_hdl */)
915
  {
916
    /*
Martin Hansson's avatar
 
Martin Hansson committed
917 918 919 920 921 922 923 924 925
       The handler does not handle the errors raised by itself.
       At this point we know if top_view is really a view.
    */
    if (m_handling || !m_top_view->view)
      return FALSE;

    m_handling= TRUE;

    bool is_handled;
926

Martin Hansson's avatar
 
Martin Hansson committed
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
    switch (sql_errno)
    {
    case ER_TABLEACCESS_DENIED_ERROR:
      if (!strcmp(get_view_access_denied_message(), message))
      {
        /* Access to top view is not granted, don't interfere. */
        is_handled= FALSE;
        break;
      }
    case ER_COLUMNACCESS_DENIED_ERROR:
    case ER_VIEW_NO_EXPLAIN: /* Error was anonymized, ignore all the same. */
    case ER_PROCACCESS_DENIED_ERROR:
      is_handled= TRUE;
      break;

    case ER_NO_SUCH_TABLE:
943
    case ER_NO_SUCH_TABLE_IN_ENGINE:
Martin Hansson's avatar
 
Martin Hansson committed
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
      /* Established behavior: warn if underlying tables are missing. */
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                          ER_VIEW_INVALID,
                          ER(ER_VIEW_INVALID),
                          m_top_view->get_db_name(),
                          m_top_view->get_table_name());
      is_handled= TRUE;
      break;

    case ER_SP_DOES_NOT_EXIST:
      /* Established behavior: warn if underlying functions are missing. */
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                          ER_VIEW_INVALID,
                          ER(ER_VIEW_INVALID),
                          m_top_view->get_db_name(),
                          m_top_view->get_table_name());
      is_handled= TRUE;
      break;
    default:
      is_handled= FALSE;
    }

    m_handling= FALSE;
    return is_handled;
  }
};


972 973 974 975 976 977 978 979 980 981 982 983 984 985 986
/*
  Return CREATE command for table or view

  @param thd	     Thread handler
  @param table_list  Table / view

  @return
  @retval 0      OK
  @retval 1      Error

  @notes
  table_list->db and table_list->table_name are kept unchanged to
  not cause problems with SP.
*/

unknown's avatar
unknown committed
987
bool
unknown's avatar
unknown committed
988 989
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
unknown's avatar
unknown committed
990 991 992
  Protocol *protocol= thd->protocol;
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
993 994
  List<Item> field_list;
  bool error= TRUE;
unknown's avatar
unknown committed
995 996
  DBUG_ENTER("mysqld_show_create");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
997
                      table_list->table_name));
unknown's avatar
unknown committed
998

999 1000 1001 1002
  /*
    Metadata locks taken during SHOW CREATE should be released when
    the statmement completes as it is an information statement.
  */
1003
  MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
1004

1005
  /* We want to preserve the tree for views. */
Sergey Glukhov's avatar
Sergey Glukhov committed
1006
  thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
1007

1008
  {
1009 1010 1011 1012 1013 1014
    /*
      Use open_tables() directly rather than open_normal_and_derived_tables().
      This ensures that close_thread_tables() is not called if open tables fails
      and the error is ignored. This allows us to handle broken views nicely.
    */
    uint counter;
Martin Hansson's avatar
 
Martin Hansson committed
1015 1016
    Show_create_error_handler view_error_suppressor(thd, table_list);
    thd->push_internal_handler(&view_error_suppressor);
1017
    bool open_error=
1018 1019
      open_tables(thd, &table_list, &counter,
                  MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) ||
Sergei Golubchik's avatar
Sergei Golubchik committed
1020
                  mysql_handle_derived(thd->lex, DT_PREPARE);
Martin Hansson's avatar
 
Martin Hansson committed
1021
    thd->pop_internal_handler();
1022 1023
    if (open_error && (thd->killed || thd->is_error()))
      goto exit;
1024
  }
1025

unknown's avatar
VIEW  
unknown committed
1026 1027 1028
  /* TODO: add environment variables show when it become possible */
  if (thd->lex->only_view && !table_list->view)
  {
1029
    my_error(ER_WRONG_OBJECT, MYF(0),
1030
             table_list->db, table_list->table_name, "VIEW");
1031
    goto exit;
unknown's avatar
VIEW  
unknown committed
1032
  }
unknown's avatar
unknown committed
1033

1034
  buffer.length(0);
unknown's avatar
unknown committed
1035 1036 1037 1038

  if (table_list->view)
    buffer.set_charset(table_list->view_creation_ctx->get_client_cs());

unknown's avatar
VIEW  
unknown committed
1039 1040
  if ((table_list->view ?
       view_store_create_info(thd, table_list, &buffer) :
1041 1042
       store_create_info(thd, table_list, &buffer, NULL,
                         FALSE /* show_database */)))
1043
    goto exit;
1044

unknown's avatar
unknown committed
1045 1046
  if (table_list->view)
  {
1047
    field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN));
unknown's avatar
unknown committed
1048 1049
    field_list.push_back(new Item_empty_string("Create View",
                                               max(buffer.length(),1024)));
unknown's avatar
unknown committed
1050 1051 1052 1053
    field_list.push_back(new Item_empty_string("character_set_client",
                                               MY_CS_NAME_SIZE));
    field_list.push_back(new Item_empty_string("collation_connection",
                                               MY_CS_NAME_SIZE));
unknown's avatar
unknown committed
1054 1055 1056
  }
  else
  {
1057
    field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
unknown's avatar
unknown committed
1058 1059 1060 1061
    // 1024 is for not to confuse old clients
    field_list.push_back(new Item_empty_string("Create Table",
                                               max(buffer.length(),1024)));
  }
unknown's avatar
unknown committed
1062

1063
  if (protocol->send_result_set_metadata(&field_list,
1064
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
1065 1066
    goto exit;

unknown's avatar
unknown committed
1067
  protocol->prepare_for_resend();
unknown's avatar
VIEW  
unknown committed
1068 1069 1070 1071
  if (table_list->view)
    protocol->store(table_list->view_name.str, system_charset_info);
  else
  {
unknown's avatar
unknown committed
1072
    if (table_list->schema_table)
1073 1074
      protocol->store(table_list->schema_table->table_name,
                      system_charset_info);
unknown's avatar
unknown committed
1075
    else
1076
      protocol->store(table_list->table->alias.c_ptr(), system_charset_info);
unknown's avatar
VIEW  
unknown committed
1077
  }
unknown's avatar
unknown committed
1078 1079 1080

  if (table_list->view)
  {
1081 1082
    protocol->store(buffer.ptr(), buffer.length(),
                    table_list->view_creation_ctx->get_client_cs());
unknown's avatar
unknown committed
1083 1084 1085 1086 1087 1088 1089 1090 1091

    protocol->store(table_list->view_creation_ctx->get_client_cs()->csname,
                    system_charset_info);

    protocol->store(table_list->view_creation_ctx->get_connection_cl()->name,
                    system_charset_info);
  }
  else
    protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
unknown's avatar
VIEW  
unknown committed
1092

unknown's avatar
unknown committed
1093
  if (protocol->write())
1094
    goto exit;
unknown's avatar
unknown committed
1095

1096
  error= FALSE;
1097
  my_eof(thd);
1098 1099 1100 1101 1102 1103

exit:
  close_thread_tables(thd);
  /* Release any metadata locks taken during SHOW CREATE. */
  thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
  DBUG_RETURN(error);
unknown's avatar
unknown committed
1104 1105
}

unknown's avatar
unknown committed
1106 1107
bool mysqld_show_create_db(THD *thd, char *dbname,
                           HA_CREATE_INFO *create_info)
1108 1109 1110
{
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
unknown's avatar
unknown committed
1111
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1112
  Security_context *sctx= thd->security_ctx;
1113
  uint db_access;
unknown's avatar
unknown committed
1114
#endif
1115 1116 1117 1118 1119 1120
  HA_CREATE_INFO create;
  uint create_options = create_info ? create_info->options : 0;
  Protocol *protocol=thd->protocol;
  DBUG_ENTER("mysql_show_create_db");

#ifndef NO_EMBEDDED_ACCESS_CHECKS
1121
  if (test_all_bits(sctx->master_access, DB_ACLS))
1122 1123
    db_access=DB_ACLS;
  else
1124 1125
    db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
		sctx->master_access);
1126
  if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname))
1127
  {
1128
    status_var_increment(thd->status_var.access_denied_errors);
1129
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
1130
             sctx->priv_user, sctx->host_or_ip, dbname);
1131 1132
    general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
                      sctx->priv_user, sctx->host_or_ip, dbname);
unknown's avatar
unknown committed
1133
    DBUG_RETURN(TRUE);
1134 1135
  }
#endif
1136
  if (is_infoschema_db(dbname))
1137
  {
1138
    dbname= INFORMATION_SCHEMA_NAME.str;
1139
    create.default_table_charset= system_charset_info;
1140
  }
1141
  else
1142
  {
1143
    if (check_db_dir_existence(dbname))
1144 1145 1146 1147
    {
      my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
      DBUG_RETURN(TRUE);
    }
1148 1149

    load_db_opt_by_name(thd, dbname, &create);
1150 1151
  }
  List<Item> field_list;
1152
  field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
1153 1154
  field_list.push_back(new Item_empty_string("Create Database",1024));

1155
  if (protocol->send_result_set_metadata(&field_list,
1156
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
1157
    DBUG_RETURN(TRUE);
1158 1159 1160 1161

  protocol->prepare_for_resend();
  protocol->store(dbname, strlen(dbname), system_charset_info);
  buffer.length(0);
1162
  buffer.append(STRING_WITH_LEN("CREATE DATABASE "));
1163
  if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
1164
    buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ "));
1165 1166 1167 1168
  append_identifier(thd, &buffer, dbname, strlen(dbname));

  if (create.default_table_charset)
  {
1169 1170
    buffer.append(STRING_WITH_LEN(" /*!40100"));
    buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET "));
1171 1172 1173
    buffer.append(create.default_table_charset->csname);
    if (!(create.default_table_charset->state & MY_CS_PRIMARY))
    {
1174
      buffer.append(STRING_WITH_LEN(" COLLATE "));
1175 1176
      buffer.append(create.default_table_charset->name);
    }
1177
    buffer.append(STRING_WITH_LEN(" */"));
1178 1179 1180 1181
  }
  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());

  if (protocol->write())
unknown's avatar
unknown committed
1182
    DBUG_RETURN(TRUE);
1183
  my_eof(thd);
unknown's avatar
unknown committed
1184
  DBUG_RETURN(FALSE);
1185
}
unknown's avatar
unknown committed
1186

unknown's avatar
unknown committed
1187 1188


unknown's avatar
unknown committed
1189
/****************************************************************************
1190 1191
  Return only fields for API mysql_list_fields
  Use "show table wildcard" in mysql instead of this
unknown's avatar
unknown committed
1192 1193 1194 1195 1196 1197 1198
****************************************************************************/

void
mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
{
  TABLE *table;
  DBUG_ENTER("mysqld_list_fields");
1199
  DBUG_PRINT("enter",("table: %s",table_list->table_name));
unknown's avatar
unknown committed
1200

1201
  if (open_normal_and_derived_tables(thd, table_list,
Sergei Golubchik's avatar
Sergei Golubchik committed
1202
                                     MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL,
1203
                                     DT_PREPARE | DT_CREATE))
unknown's avatar
unknown committed
1204
    DBUG_VOID_RETURN;
1205 1206
  table= table_list->table;

unknown's avatar
unknown committed
1207 1208 1209 1210 1211
  List<Item> field_list;

  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1212
    if (!wild || !wild[0] ||
1213
        !wild_case_compare(system_charset_info, field->field_name,wild))
1214 1215 1216 1217 1218 1219 1220 1221
    {
      if (table_list->view)
        field_list.push_back(new Item_ident_for_show(field,
                                                     table_list->view_db.str,
                                                     table_list->view_name.str));
      else
        field_list.push_back(new Item_field(field));
    }
unknown's avatar
unknown committed
1222
  }
1223
  restore_record(table, s->default_values);              // Get empty record
1224
  table->use_all_columns();
1225
  if (thd->protocol->send_result_set_metadata(&field_list, Protocol::SEND_DEFAULTS))
unknown's avatar
unknown committed
1226
    DBUG_VOID_RETURN;
1227
  my_eof(thd);
unknown's avatar
unknown committed
1228 1229 1230
  DBUG_VOID_RETURN;
}

1231
/*
1232
  Go through all character combinations and ensure that sql_lex.cc can
1233
  parse it as an identifier.
1234 1235

  SYNOPSIS
1236 1237 1238 1239 1240 1241 1242
  require_quotes()
  name			attribute name
  name_length		length of name

  RETURN
    #	Pointer to conflicting character
    0	No conflicting character
1243 1244
*/

1245
static const char *require_quotes(const char *name, uint name_length)
1246
{
1247
  uint length;
1248
  bool pure_digit= TRUE;
1249 1250
  const char *end= name + name_length;

1251
  for (; name < end ; name++)
1252
  {
1253 1254 1255 1256
    uchar chr= (uchar) *name;
    length= my_mbcharlen(system_charset_info, chr);
    if (length == 1 && !system_charset_info->ident_map[chr])
      return name;
1257 1258
    if (length == 1 && (chr < '0' || chr > '9'))
      pure_digit= FALSE;
1259
  }
1260 1261
  if (pure_digit)
    return name;
1262 1263
  return 0;
}
1264

1265

1266 1267 1268 1269 1270 1271 1272 1273 1274 1275
/*
  Quote the given identifier if needed and append it to the target string.
  If the given identifier is empty, it will be quoted.

  SYNOPSIS
  append_identifier()
  thd                   thread handler
  packet                target string
  name                  the identifier to be appended
  name_length           length of the appending identifier
unknown's avatar
unknown committed
1276 1277 1278 1279

  RETURN VALUES
    true                Error
    false               Ok
1280 1281
*/

unknown's avatar
unknown committed
1282
bool
1283
append_identifier(THD *thd, String *packet, const char *name, uint length)
1284
{
1285 1286
  const char *name_end;
  char quote_char;
1287
  int q= get_quote_char_for_identifier(thd, name, length);
1288

1289
  if (q == EOF)
unknown's avatar
unknown committed
1290
    return packet->append(name, length, packet->charset());
1291

1292 1293
  /*
    The identifier must be quoted as it includes a quote character or
1294
    it's a keyword
1295
  */
1296

Konstantin Osipov's avatar
Konstantin Osipov committed
1297
  (void) packet->reserve(length*2 + 2);
1298
  quote_char= (char) q;
unknown's avatar
unknown committed
1299 1300
  if (packet->append(&quote_char, 1, system_charset_info))
    return true;
1301 1302 1303

  for (name_end= name+length ; name < name_end ; name+= length)
  {
1304
    uchar chr= (uchar) *name;
1305
    length= my_mbcharlen(system_charset_info, chr);
1306
    /*
unknown's avatar
unknown committed
1307
      my_mbcharlen can return 0 on a wrong multibyte
1308 1309 1310 1311 1312 1313 1314
      sequence. It is possible when upgrading from 4.0,
      and identifier contains some accented characters.
      The manual says it does not work. So we'll just
      change length to 1 not to hang in the endless loop.
    */
    if (!length)
      length= 1;
unknown's avatar
unknown committed
1315 1316 1317 1318 1319
    if (length == 1 && chr == (uchar) quote_char &&
        packet->append(&quote_char, 1, system_charset_info))
      return true;
    if (packet->append(name, length, system_charset_info))
      return true;
1320
  }
unknown's avatar
unknown committed
1321
  return packet->append(&quote_char, 1, system_charset_info);
1322 1323
}

1324

1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
/*
  Get the quote character for displaying an identifier.

  SYNOPSIS
    get_quote_char_for_identifier()
    thd		Thread handler
    name	name to quote
    length	length of name

  IMPLEMENTATION
1335 1336 1337 1338 1339
    Force quoting in the following cases:
      - name is empty (for one, it is possible when we use this function for
        quoting user and host names for DEFINER clause);
      - name is a keyword;
      - name includes a special character;
1340 1341 1342 1343 1344 1345 1346
    Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE
    is set.

  RETURN
    EOF	  No quote character is needed
    #	  Quote character
*/
1347 1348 1349

int get_quote_char_for_identifier(THD *thd, const char *name, uint length)
{
unknown's avatar
unknown committed
1350
  if (length &&
1351
      !is_keyword(name,length) &&
1352
      !require_quotes(name, length) &&
1353
      !(thd->variables.option_bits & OPTION_QUOTE_SHOW_CREATE))
1354
    return EOF;
1355
  if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
1356
    return '"';
1357
  return '`';
1358 1359 1360
}


1361 1362 1363 1364 1365
/* Append directory name (if exists) to CREATE INFO */

static void append_directory(THD *thd, String *packet, const char *dir_type,
			     const char *filename)
{
unknown's avatar
unknown committed
1366
  if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
1367
  {
1368
    uint length= dirname_length(filename);
1369 1370
    packet->append(' ');
    packet->append(dir_type);
1371
    packet->append(STRING_WITH_LEN(" DIRECTORY='"));
1372
#ifdef __WIN__
unknown's avatar
unknown committed
1373 1374 1375 1376 1377 1378 1379 1380 1381
    /* Convert \ to / to be able to create table on unix */
    char *winfilename= (char*) thd->memdup(filename, length);
    char *pos, *end;
    for (pos= winfilename, end= pos+length ; pos < end ; pos++)
    {
      if (*pos == '\\')
        *pos = '/';
    }
    filename= winfilename;
1382
#endif
unknown's avatar
unknown committed
1383
    packet->append(filename, length);
1384 1385 1386 1387 1388
    packet->append('\'');
  }
}


unknown's avatar
unknown committed
1389
#define LIST_PROCESS_HOST_LEN 64
1390

1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419

/**
  Print "ON UPDATE" clause of a field into a string.

  @param timestamp_field   Pointer to timestamp field of a table.
  @param field             The field to generate ON UPDATE clause for.
  @bool  lcase             Whether to print in lower case.
  @return                  false on success, true on error.
*/
static bool print_on_update_clause(Field *field, String *val, bool lcase)
{
  DBUG_ASSERT(val->charset()->mbminlen == 1);
  val->length(0);
  if (field->has_update_default_function())
  {
    if (lcase)
      val->append(STRING_WITH_LEN("on update "));
    else
      val->append(STRING_WITH_LEN("ON UPDATE "));
    val->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
    if (field->decimals() > 0)
      val->append_parenthesized(field->decimals());
    return true;
  }
  return false;
}


static bool get_field_default_value(THD *thd, Field *field, String *def_value,
1420 1421 1422 1423
                                    bool quoted)
{
  bool has_default;
  bool has_now_default;
1424
  enum enum_field_types field_type= field->type();
Sergey Glukhov's avatar
Sergey Glukhov committed
1425 1426

  /*
1427 1428 1429
     We are using CURRENT_TIMESTAMP instead of NOW because it is
     more standard
  */
1430
  has_now_default= field->has_insert_default_function();
Sergey Glukhov's avatar
Sergey Glukhov committed
1431

1432
  has_default= (field_type != FIELD_TYPE_BLOB &&
1433 1434 1435 1436 1437 1438 1439 1440 1441
                !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
                field->unireg_check != Field::NEXT_NUMBER &&
                !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
                  && has_now_default));

  def_value->length(0);
  if (has_default)
  {
    if (has_now_default)
1442
    {
1443
      def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
1444 1445 1446
      if (field->decimals() > 0)
        def_value->append_parenthesized(field->decimals());
    }
1447 1448 1449 1450
    else if (!field->is_null())
    {                                             // Not null by default
      char tmp[MAX_FIELD_WIDTH];
      String type(tmp, sizeof(tmp), field->charset());
1451 1452 1453
      if (field_type == MYSQL_TYPE_BIT)
      {
        longlong dec= field->val_int();
Sergei Golubchik's avatar
Sergei Golubchik committed
1454
        char *ptr= longlong2str(dec, tmp + 2, 2);
1455 1456
        uint32 length= (uint32) (ptr - tmp);
        tmp[0]= 'b';
Michael Widenius's avatar
Michael Widenius committed
1457
        tmp[1]= '\'';
1458 1459 1460 1461 1462 1463
        tmp[length]= '\'';
        type.length(length + 1);
        quoted= 0;
      }
      else
        field->val_str(&type);
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
      if (type.length())
      {
        String def_val;
        uint dummy_errors;
        /* convert to system_charset_info == utf8 */
        def_val.copy(type.ptr(), type.length(), field->charset(),
                     system_charset_info, &dummy_errors);
        if (quoted)
          append_unescaped(def_value, def_val.ptr(), def_val.length());
        else
          def_value->append(def_val.ptr(), def_val.length());
      }
      else if (quoted)
        def_value->append(STRING_WITH_LEN("''"));
    }
    else if (field->maybe_null() && quoted)
      def_value->append(STRING_WITH_LEN("NULL"));    // Null as default
    else
      return 0;

  }
  return has_default;
}

Sergey Glukhov's avatar
Sergey Glukhov committed
1488

1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
/**
  Appends list of options to string

  @param thd             thread handler
  @param packet          string to append
  @param opt             list of options
*/

static void append_create_options(THD *thd, String *packet,
				  engine_option_value *opt)
{
  for(; opt; opt= opt->next)
  {
    DBUG_ASSERT(opt->value.str);
    packet->append(' ');
    append_identifier(thd, packet, opt->name.str, opt->name.length);
    packet->append('=');
    if (opt->quoted_value)
      append_unescaped(packet, opt->value.str, opt->value.length);
    else
      packet->append(opt->value.str, opt->value.length);
  }
}

1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
/*
  Build a CREATE TABLE statement for a table.

  SYNOPSIS
    store_create_info()
    thd               The thread
    table_list        A list containing one table to write statement
                      for.
    packet            Pointer to a string where statement will be
                      written.
    create_info_arg   Pointer to create information that can be used
                      to tailor the format of the statement.  Can be
                      NULL, in which case only SQL_MODE is considered
                      when building the statement.
1527

1528 1529 1530
  NOTE
    Currently always return 0, but might return error code in the
    future.
1531

1532 1533 1534
  RETURN
    0       OK
 */
1535 1536

int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
1537
                      HA_CREATE_INFO *create_info_arg, bool show_database)
unknown's avatar
unknown committed
1538
{
1539
  List<Item> field_list;
1540
  char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH];
1541
  const char *alias;
1542
  String type(tmp, sizeof(tmp), system_charset_info);
1543
  String def_value(def_value_buf, sizeof(def_value_buf), system_charset_info);
1544 1545 1546
  Field **ptr,*field;
  uint primary_key;
  KEY *key_info;
unknown's avatar
unknown committed
1547
  TABLE *table= table_list->table;
1548
  handler *file= table->file;
1549
  TABLE_SHARE *share= table->s;
1550
  HA_CREATE_INFO create_info;
1551
#ifdef WITH_PARTITION_STORAGE_ENGINE
1552
  bool show_table_options= FALSE;
1553
#endif /* WITH_PARTITION_STORAGE_ENGINE */
1554 1555 1556 1557 1558 1559
  bool foreign_db_mode=  (thd->variables.sql_mode & (MODE_POSTGRESQL |
                                                     MODE_ORACLE |
                                                     MODE_MSSQL |
                                                     MODE_DB2 |
                                                     MODE_MAXDB |
                                                     MODE_ANSI)) != 0;
unknown's avatar
unknown committed
1560 1561 1562
  bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS |
                                                       MODE_MYSQL323 |
                                                       MODE_MYSQL40)) != 0;
1563
  my_bitmap_map *old_map;
1564
  int error= 0;
unknown's avatar
unknown committed
1565
  DBUG_ENTER("store_create_info");
unknown's avatar
unknown committed
1566
  DBUG_PRINT("enter",("table: %s", table->s->table_name.str));
unknown's avatar
unknown committed
1567

1568
  restore_record(table, s->default_values); // Get empty record
1569

1570
  if (share->tmp_table)
1571
    packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
1572
  else
1573
    packet->append(STRING_WITH_LEN("CREATE TABLE "));
1574 1575 1576
  if (create_info_arg &&
      (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS))
    packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
unknown's avatar
unknown committed
1577
  if (table_list->schema_table)
1578
    alias= table_list->schema_table->table_name;
unknown's avatar
unknown committed
1579
  else
1580 1581
  {
    if (lower_case_table_names == 2)
1582
      alias= table->alias.c_ptr();
1583 1584 1585 1586 1587
    else
    {
      alias= share->table_name.str;
    }
  }
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599

  /*
    Print the database before the table name if told to do that. The
    database name is only printed in the event that it is different
    from the current database.  The main reason for doing this is to
    avoid having to update gazillions of tests and result files, but
    it also saves a few bytes of the binary log.
   */
  if (show_database)
  {
    const LEX_STRING *const db=
      table_list->schema_table ? &INFORMATION_SCHEMA_NAME : &table->s->db;
1600
    if (!thd->db || strcmp(db->str, thd->db))
1601 1602 1603 1604 1605 1606
    {
      append_identifier(thd, packet, db->str, db->length);
      packet->append(STRING_WITH_LEN("."));
    }
  }

unknown's avatar
unknown committed
1607
  append_identifier(thd, packet, alias, strlen(alias));
1608
  packet->append(STRING_WITH_LEN(" (\n"));
1609 1610 1611 1612 1613 1614
  /*
    We need this to get default values from the table
    We have to restore the read_set if we are called from insert in case
    of row based replication.
  */
  old_map= tmp_use_all_columns(table, table->read_set);
1615

unknown's avatar
unknown committed
1616 1617
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1618 1619
    uint flags = field->flags;

1620
    if (ptr != table->field)
1621
      packet->append(STRING_WITH_LEN(",\n"));
1622

1623
    packet->append(STRING_WITH_LEN("  "));
1624
    append_identifier(thd,packet,field->field_name, strlen(field->field_name));
unknown's avatar
unknown committed
1625 1626
    packet->append(' ');
    // check for surprises from the previous call to Field::sql_type()
1627
    if (type.ptr() != tmp)
1628
      type.set(tmp, sizeof(tmp), system_charset_info);
unknown's avatar
unknown committed
1629 1630
    else
      type.set_charset(system_charset_info);
1631

unknown's avatar
unknown committed
1632
    field->sql_type(type);
1633
    packet->append(type.ptr(), type.length(), system_charset_info);
1634

1635
    if (field->has_charset() &&
1636
        !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
1637
    {
1638
      if (field->charset() != share->table_charset)
1639
      {
1640
	packet->append(STRING_WITH_LEN(" CHARACTER SET "));
1641 1642
	packet->append(field->charset()->csname);
      }
1643 1644
      /*
	For string types dump collation name only if
1645 1646 1647 1648
	collation is not primary for the given charset
      */
      if (!(field->charset()->state & MY_CS_PRIMARY))
      {
1649
	packet->append(STRING_WITH_LEN(" COLLATE "));
1650
	packet->append(field->charset()->name);
1651
      }
1652
    }
1653

Igor Babaev's avatar
Igor Babaev committed
1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
    if (field->vcol_info)
    {
      packet->append(STRING_WITH_LEN(" AS ("));
      packet->append(field->vcol_info->expr_str.str,
                     field->vcol_info->expr_str.length,
                     system_charset_info);
      packet->append(STRING_WITH_LEN(")"));
      if (field->stored_in_db)
        packet->append(STRING_WITH_LEN(" PERSISTENT"));
      else
        packet->append(STRING_WITH_LEN(" VIRTUAL"));
    }

unknown's avatar
unknown committed
1667
    if (flags & NOT_NULL_FLAG)
1668
      packet->append(STRING_WITH_LEN(" NOT NULL"));
1669
    else if (field->type() == MYSQL_TYPE_TIMESTAMP)
1670 1671 1672 1673 1674
    {
      /*
        TIMESTAMP field require explicit NULL flag, because unlike
        all other fields they are treated as NOT NULL by default.
      */
1675
      packet->append(STRING_WITH_LEN(" NULL"));
1676
    }
1677

1678
    if (!field->vcol_info &&
1679
        get_field_default_value(thd, field, &def_value, 1))
1680
    {
1681
      packet->append(STRING_WITH_LEN(" DEFAULT "));
1682
      packet->append(def_value.ptr(), def_value.length(), system_charset_info);
1683
    }
1684

1685 1686 1687 1688 1689 1690
    if (!limited_mysql_mode && print_on_update_clause(field, &def_value, false))
    {
      packet->append(STRING_WITH_LEN(" "));
      packet->append(def_value);
    }

1691

1692
    if (field->unireg_check == Field::NEXT_NUMBER &&
1693
        !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
1694
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
1695 1696 1697

    if (field->comment.length)
    {
1698
      packet->append(STRING_WITH_LEN(" COMMENT "));
1699 1700
      append_unescaped(packet, field->comment.str, field->comment.length);
    }
1701
    append_create_options(thd, packet, field->option_list);
unknown's avatar
unknown committed
1702 1703
  }

1704
  key_info= table->key_info;
1705
  bzero((char*) &create_info, sizeof(create_info));
1706
  /* Allow update_create_info to update row type, page checksums and options */
1707
  create_info.row_type= share->row_type;
1708 1709
  create_info.page_checksum= share->page_checksum;
  create_info.options= share->db_create_options;
1710
  file->update_create_info(&create_info);
1711
  primary_key= share->primary_key;
1712

1713
  for (uint i=0 ; i < share->keys ; i++,key_info++)
unknown's avatar
unknown committed
1714
  {
1715 1716
    KEY_PART_INFO *key_part= key_info->key_part;
    bool found_primary=0;
1717
    packet->append(STRING_WITH_LEN(",\n  "));
1718

1719
    if (i == primary_key && !strcmp(key_info->name, primary_key_name))
1720 1721
    {
      found_primary=1;
1722 1723 1724 1725 1726
      /*
        No space at end, because a space will be added after where the
        identifier would go, but that is not added for primary key.
      */
      packet->append(STRING_WITH_LEN("PRIMARY KEY"));
1727
    }
1728
    else if (key_info->flags & HA_NOSAME)
1729
      packet->append(STRING_WITH_LEN("UNIQUE KEY "));
1730
    else if (key_info->flags & HA_FULLTEXT)
1731
      packet->append(STRING_WITH_LEN("FULLTEXT KEY "));
unknown's avatar
unknown committed
1732
    else if (key_info->flags & HA_SPATIAL)
1733 1734 1735
      packet->append(STRING_WITH_LEN("SPATIAL KEY "));
    else
      packet->append(STRING_WITH_LEN("KEY "));
unknown's avatar
unknown committed
1736

1737
    if (!found_primary)
1738
     append_identifier(thd, packet, key_info->name, strlen(key_info->name));
unknown's avatar
unknown committed
1739

1740
    packet->append(STRING_WITH_LEN(" ("));
1741

unknown's avatar
unknown committed
1742 1743
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
1744
      if (j)
1745
        packet->append(',');
1746

1747
      if (key_part->field)
1748 1749
        append_identifier(thd,packet,key_part->field->field_name,
			  strlen(key_part->field->field_name));
1750
      if (key_part->field &&
1751 1752
          (key_part->length !=
           table->field[key_part->fieldnr-1]->key_length() &&
unknown's avatar
unknown committed
1753
           !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))))
unknown's avatar
unknown committed
1754
      {
1755
        char *end;
1756
        buff[0] = '(';
1757 1758 1759
        end= int10_to_str((long) key_part->length /
                          key_part->field->charset()->mbmaxlen,
                          buff + 1,10);
1760 1761
        *end++ = ')';
        packet->append(buff,(uint) (end-buff));
unknown's avatar
unknown committed
1762 1763 1764
      }
    }
    packet->append(')');
unknown's avatar
unknown committed
1765
    store_key_options(thd, packet, table, key_info);
1766 1767
    if (key_info->parser)
    {
unknown's avatar
WL#2936  
unknown committed
1768
      LEX_STRING *parser_name= plugin_name(key_info->parser);
1769
      packet->append(STRING_WITH_LEN(" /*!50100 WITH PARSER "));
unknown's avatar
WL#2936  
unknown committed
1770
      append_identifier(thd, packet, parser_name->str, parser_name->length);
1771
      packet->append(STRING_WITH_LEN(" */ "));
1772
    }
1773
    append_create_options(thd, packet, key_info->option_list);
unknown's avatar
unknown committed
1774
  }
1775

1776 1777 1778 1779
  /*
    Get possible foreign key definitions stored in InnoDB and append them
    to the CREATE TABLE statement
  */
unknown's avatar
unknown committed
1780

1781
  if ((for_str= file->get_foreign_key_create_info()))
1782 1783 1784
  {
    packet->append(for_str, strlen(for_str));
    file->free_foreign_key_create_info(for_str);
unknown's avatar
unknown committed
1785 1786
  }

1787
  packet->append(STRING_WITH_LEN("\n)"));
1788
  if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
1789
  {
1790
#ifdef WITH_PARTITION_STORAGE_ENGINE
1791
    show_table_options= TRUE;
1792
#endif /* WITH_PARTITION_STORAGE_ENGINE */
1793

1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804
    /*
      IF   check_create_info
      THEN add ENGINE only if it was used when creating the table
    */
    if (!create_info_arg ||
        (create_info_arg->used_fields & HA_CREATE_USED_ENGINE))
    {
      if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
        packet->append(STRING_WITH_LEN(" TYPE="));
      else
        packet->append(STRING_WITH_LEN(" ENGINE="));
1805
#ifdef WITH_PARTITION_STORAGE_ENGINE
unknown's avatar
unknown committed
1806
    if (table->part_info)
unknown's avatar
unknown committed
1807 1808
      packet->append(ha_resolve_storage_engine_name(
                        table->part_info->default_engine_type));
1809
    else
1810
      packet->append(file->table_type());
1811
#else
1812
      packet->append(file->table_type());
1813
#endif
1814
    }
1815

1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826
    /*
      Add AUTO_INCREMENT=... if there is an AUTO_INCREMENT column,
      and NEXT_ID > 1 (the default).  We must not print the clause
      for engines that do not support this as it would break the
      import of dumps, but as of this writing, the test for whether
      AUTO_INCREMENT columns are allowed and wether AUTO_INCREMENT=...
      is supported is identical, !(file->table_flags() & HA_NO_AUTO_INCREMENT))
      Because of that, we do not explicitly test for the feature,
      but may extrapolate its existence from that of an AUTO_INCREMENT column.
    */

1827
    if (create_info.auto_increment_value > 1)
1828
    {
1829
      char *end;
1830
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT="));
1831 1832 1833
      end= longlong10_to_str(create_info.auto_increment_value, buff,10);
      packet->append(buff, (uint) (end - buff));
    }
1834
    
1835
    if (share->table_charset &&
1836 1837
	!(thd->variables.sql_mode & MODE_MYSQL323) &&
	!(thd->variables.sql_mode & MODE_MYSQL40))
1838
    {
1839 1840 1841 1842 1843 1844
      /*
        IF   check_create_info
        THEN add DEFAULT CHARSET only if it was used when creating the table
      */
      if (!create_info_arg ||
          (create_info_arg->used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
1845
      {
1846 1847 1848 1849 1850 1851 1852
        packet->append(STRING_WITH_LEN(" DEFAULT CHARSET="));
        packet->append(share->table_charset->csname);
        if (!(share->table_charset->state & MY_CS_PRIMARY))
        {
          packet->append(STRING_WITH_LEN(" COLLATE="));
          packet->append(table->s->table_charset->name);
        }
1853
      }
1854
    }
1855

1856
    if (share->min_rows)
1857
    {
1858
      char *end;
1859
      packet->append(STRING_WITH_LEN(" MIN_ROWS="));
1860
      end= longlong10_to_str(share->min_rows, buff, 10);
unknown's avatar
unknown committed
1861
      packet->append(buff, (uint) (end- buff));
1862
    }
unknown's avatar
unknown committed
1863

1864
    if (share->max_rows && !table_list->schema_table)
1865
    {
1866
      char *end;
1867
      packet->append(STRING_WITH_LEN(" MAX_ROWS="));
1868
      end= longlong10_to_str(share->max_rows, buff, 10);
unknown's avatar
unknown committed
1869
      packet->append(buff, (uint) (end - buff));
1870
    }
unknown's avatar
unknown committed
1871

1872
    if (share->avg_row_length)
1873
    {
1874
      char *end;
1875
      packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
1876
      end= longlong10_to_str(share->avg_row_length, buff,10);
unknown's avatar
unknown committed
1877
      packet->append(buff, (uint) (end - buff));
1878
    }
1879

1880
    if (create_info.options & HA_OPTION_PACK_KEYS)
1881
      packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
1882
    if (create_info.options & HA_OPTION_NO_PACK_KEYS)
1883
      packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
1884
    /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
1885
    if (create_info.options & HA_OPTION_CHECKSUM)
1886
      packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
1887
    if (create_info.page_checksum != HA_CHOICE_UNDEF)
1888 1889
    {
      packet->append(STRING_WITH_LEN(" PAGE_CHECKSUM="));
1890
      packet->append(ha_choice_values[create_info.page_checksum], 1);
1891
    }
1892
    if (create_info.options & HA_OPTION_DELAY_KEY_WRITE)
1893
      packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1"));
1894
    if (create_info.row_type != ROW_TYPE_DEFAULT)
1895
    {
1896
      packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
1897
      packet->append(ha_row_type[(uint) create_info.row_type]);
1898
    }
1899 1900 1901
    if (share->transactional != HA_CHOICE_UNDEF)
    {
      packet->append(STRING_WITH_LEN(" TRANSACTIONAL="));
1902
      packet->append(ha_choice_values[(uint) share->transactional], 1);
1903
    }
1904 1905
    if (table->s->key_block_size)
    {
unknown's avatar
unknown committed
1906
      char *end;
1907 1908 1909 1910
      packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
      end= longlong10_to_str(table->s->key_block_size, buff, 10);
      packet->append(buff, (uint) (end - buff));
    }
1911
    table->file->append_create_info(packet);
1912
    if (share->comment.length)
1913
    {
1914
      packet->append(STRING_WITH_LEN(" COMMENT="));
1915
      append_unescaped(packet, share->comment.str, share->comment.length);
1916
    }
1917 1918
    if (share->connect_string.length)
    {
1919
      packet->append(STRING_WITH_LEN(" CONNECTION="));
1920 1921
      append_unescaped(packet, share->connect_string.str, share->connect_string.length);
    }
1922
    append_create_options(thd, packet, share->option_list);
unknown's avatar
unknown committed
1923 1924
    append_directory(thd, packet, "DATA",  create_info.data_file_name);
    append_directory(thd, packet, "INDEX", create_info.index_file_name);
1925
  }
1926
#ifdef WITH_PARTITION_STORAGE_ENGINE
1927
  {
unknown's avatar
unknown committed
1928
    if (table->part_info &&
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939
        !((table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) &&
          table->part_info->is_auto_partitioned))
    {
      /*
        Partition syntax for CREATE TABLE is at the end of the syntax.
      */
      uint part_syntax_len;
      char *part_syntax;
      String comment_start;
      table->part_info->set_show_version_string(&comment_start);
      if ((part_syntax= generate_partition_syntax(table->part_info,
unknown's avatar
unknown committed
1940
                                                  &part_syntax_len,
1941
                                                  FALSE,
1942
                                                  show_table_options,
1943 1944 1945 1946 1947 1948 1949 1950 1951
                                                  NULL, NULL,
                                                  comment_start.c_ptr())))
      {
         packet->append(comment_start);
         if (packet->append(part_syntax, part_syntax_len) ||
             packet->append(STRING_WITH_LEN(" */")))
          error= 1;
         my_free(part_syntax);
      }
1952 1953 1954
    }
  }
#endif
1955
  tmp_restore_column_map(table->read_set, old_map);
1956
  DBUG_RETURN(error);
unknown's avatar
unknown committed
1957 1958
}

1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995

static void store_key_options(THD *thd, String *packet, TABLE *table,
                              KEY *key_info)
{
  bool limited_mysql_mode= (thd->variables.sql_mode &
                            (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
                             MODE_MYSQL40)) != 0;
  bool foreign_db_mode=  (thd->variables.sql_mode & (MODE_POSTGRESQL |
                                                     MODE_ORACLE |
                                                     MODE_MSSQL |
                                                     MODE_DB2 |
                                                     MODE_MAXDB |
                                                     MODE_ANSI)) != 0;
  char *end, buff[32];

  if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) &&
      !limited_mysql_mode && !foreign_db_mode)
  {

    if (key_info->algorithm == HA_KEY_ALG_BTREE)
      packet->append(STRING_WITH_LEN(" USING BTREE"));

    if (key_info->algorithm == HA_KEY_ALG_HASH)
      packet->append(STRING_WITH_LEN(" USING HASH"));

    /* send USING only in non-default case: non-spatial rtree */
    if ((key_info->algorithm == HA_KEY_ALG_RTREE) &&
        !(key_info->flags & HA_SPATIAL))
      packet->append(STRING_WITH_LEN(" USING RTREE"));

    if ((key_info->flags & HA_USES_BLOCK_SIZE) &&
        table->s->key_block_size != key_info->block_size)
    {
      packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
      end= longlong10_to_str(key_info->block_size, buff, 10);
      packet->append(buff, (uint) (end - buff));
    }
1996 1997 1998 1999 2000 2001 2002 2003
    DBUG_ASSERT(test(key_info->flags & HA_USES_COMMENT) == 
               (key_info->comment.length > 0));
    if (key_info->flags & HA_USES_COMMENT)
    {
      packet->append(STRING_WITH_LEN(" COMMENT "));
      append_unescaped(packet, key_info->comment.str, 
                       key_info->comment.length);
    }
2004 2005 2006 2007
  }
}


2008 2009
void
view_store_options(THD *thd, TABLE_LIST *table, String *buff)
2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021
{
  append_algorithm(table, buff);
  append_definer(thd, buff, &table->definer.user, &table->definer.host);
  if (table->view_suid)
    buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER "));
  else
    buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER "));
}


/*
  Append DEFINER clause to the given buffer.
2022

2023 2024 2025 2026 2027 2028 2029 2030 2031
  SYNOPSIS
    append_definer()
    thd           [in] thread handle
    buffer        [inout] buffer to hold DEFINER clause
    definer_user  [in] user name part of definer
    definer_host  [in] host name part of definer
*/

static void append_algorithm(TABLE_LIST *table, String *buff)
2032
{
2033
  buff->append(STRING_WITH_LEN("ALGORITHM="));
2034
  switch ((int16)table->algorithm) {
2035
  case VIEW_ALGORITHM_UNDEFINED:
2036
    buff->append(STRING_WITH_LEN("UNDEFINED "));
2037 2038
    break;
  case VIEW_ALGORITHM_TMPTABLE:
2039
    buff->append(STRING_WITH_LEN("TEMPTABLE "));
2040 2041
    break;
  case VIEW_ALGORITHM_MERGE:
2042
    buff->append(STRING_WITH_LEN("MERGE "));
2043 2044 2045 2046 2047
    break;
  default:
    DBUG_ASSERT(0); // never should happen
  }
}
unknown's avatar
unknown committed
2048

2049 2050
/*
  Append DEFINER clause to the given buffer.
2051

2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070
  SYNOPSIS
    append_definer()
    thd           [in] thread handle
    buffer        [inout] buffer to hold DEFINER clause
    definer_user  [in] user name part of definer
    definer_host  [in] host name part of definer
*/

void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
                    const LEX_STRING *definer_host)
{
  buffer->append(STRING_WITH_LEN("DEFINER="));
  append_identifier(thd, buffer, definer_user->str, definer_user->length);
  buffer->append('@');
  append_identifier(thd, buffer, definer_host->str, definer_host->length);
  buffer->append(' ');
}


2071
int
unknown's avatar
VIEW  
unknown committed
2072 2073
view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
{
2074
  my_bool compact_view_name= TRUE;
unknown's avatar
VIEW  
unknown committed
2075 2076 2077 2078 2079 2080
  my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
                                                       MODE_ORACLE |
                                                       MODE_MSSQL |
                                                       MODE_DB2 |
                                                       MODE_MAXDB |
                                                       MODE_ANSI)) != 0;
2081

2082
  if (!thd->db || strcmp(thd->db, table->view_db.str))
2083 2084 2085 2086
    /*
      print compact view name if the view belongs to the current database
    */
    compact_view_name= table->compact_view_format= FALSE;
2087 2088
  else
  {
2089 2090 2091 2092
    /*
      Compact output format for view body can be used
      if this view only references table inside it's own db
    */
2093
    TABLE_LIST *tbl;
2094
    table->compact_view_format= TRUE;
2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
    for (tbl= thd->lex->query_tables;
         tbl;
         tbl= tbl->next_global)
    {
      if (strcmp(table->view_db.str, tbl->view ? tbl->view_db.str :tbl->db)!= 0)
      {
        table->compact_view_format= FALSE;
        break;
      }
    }
  }

2107
  buff->append(STRING_WITH_LEN("CREATE "));
2108
  if (!foreign_db_mode)
unknown's avatar
VIEW  
unknown committed
2109
  {
2110
    view_store_options(thd, table, buff);
unknown's avatar
VIEW  
unknown committed
2111
  }
2112
  buff->append(STRING_WITH_LEN("VIEW "));
2113
  if (!compact_view_name)
2114 2115 2116 2117
  {
    append_identifier(thd, buff, table->view_db.str, table->view_db.length);
    buff->append('.');
  }
2118
  append_identifier(thd, buff, table->view_name.str, table->view_name.length);
2119
  buff->append(STRING_WITH_LEN(" AS "));
2120 2121 2122 2123 2124

  /*
    We can't just use table->query, because our SQL_MODE may trigger
    a different syntax, like when ANSI_QUOTES is defined.
  */
2125
  table->view->unit.print(buff, QT_ORDINARY);
2126

2127 2128 2129
  if (table->with_check != VIEW_CHECK_NONE)
  {
    if (table->with_check == VIEW_CHECK_LOCAL)
2130
      buff->append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION"));
2131
    else
2132
      buff->append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION"));
2133
  }
unknown's avatar
VIEW  
unknown committed
2134 2135 2136 2137
  return 0;
}


unknown's avatar
unknown committed
2138
/****************************************************************************
2139 2140
  Return info about all processes
  returns for each thread: thread id, user, host, db, command, info
unknown's avatar
unknown committed
2141 2142 2143 2144
****************************************************************************/

class thread_info :public ilink {
public:
unknown's avatar
unknown committed
2145 2146 2147 2148
  static void *operator new(size_t size)
  {
    return (void*) sql_alloc((uint) size);
  }
unknown's avatar
unknown committed
2149
  static void operator delete(void *ptr __attribute__((unused)),
unknown's avatar
unknown committed
2150 2151
                              size_t size __attribute__((unused)))
  { TRASH(ptr, size); }
unknown's avatar
unknown committed
2152

unknown's avatar
unknown committed
2153 2154
  ulong thread_id;
  time_t start_time;
2155
  uint   command;
unknown's avatar
unknown committed
2156
  const char *user,*host,*db,*proc_info,*state_info;
2157
  CSET_STRING query_string;
2158
  double progress;
unknown's avatar
unknown committed
2159 2160
};

2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184
static const char *thread_state_info(THD *tmp)
{
#ifndef EMBEDDED_LIBRARY
  if (tmp->net.reading_or_writing)
  {
    if (tmp->net.reading_or_writing == 2)
      return "Writing to net";
    else if (tmp->command == COM_SLEEP)
      return "";
    else
      return "Reading from net";
  }
  else
#endif
  {
    if (tmp->proc_info)
      return tmp->proc_info;
    else if (tmp->mysys_var && tmp->mysys_var->current_cond)
      return "Waiting on cond";
    else
      return NULL;
  }
}

unknown's avatar
unknown committed
2185 2186 2187 2188 2189
void mysqld_list_processes(THD *thd,const char *user, bool verbose)
{
  Item *field;
  List<Item> field_list;
  I_List<thread_info> thread_infos;
unknown's avatar
unknown committed
2190 2191
  ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
			   PROCESS_LIST_WIDTH);
unknown's avatar
unknown committed
2192
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
2193 2194
  DBUG_ENTER("mysqld_list_processes");

2195
  field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
2196
  field_list.push_back(new Item_empty_string("User", USERNAME_CHAR_LENGTH));
2197
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
2198
  field_list.push_back(field=new Item_empty_string("db",NAME_CHAR_LEN));
unknown's avatar
unknown committed
2199 2200
  field->maybe_null=1;
  field_list.push_back(new Item_empty_string("Command",16));
2201
  field_list.push_back(field= new Item_return_int("Time",7, MYSQL_TYPE_LONG));
2202
  field->unsigned_flag= 0;
unknown's avatar
unknown committed
2203 2204 2205 2206
  field_list.push_back(field=new Item_empty_string("State",30));
  field->maybe_null=1;
  field_list.push_back(field=new Item_empty_string("Info",max_query_length));
  field->maybe_null=1;
2207 2208 2209 2210 2211
  if (!thd->variables.old_mode)
  {
    field_list.push_back(field= new Item_float("Progress", 0.0, 3, 7));
    field->maybe_null= 0;
  }
2212
  if (protocol->send_result_set_metadata(&field_list,
2213
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
2214 2215
    DBUG_VOID_RETURN;

Marc Alff's avatar
Marc Alff committed
2216
  mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
unknown's avatar
unknown committed
2217 2218 2219 2220 2221 2222
  if (!thd->killed)
  {
    I_List_iterator<THD> it(threads);
    THD *tmp;
    while ((tmp=it++))
    {
2223
      Security_context *tmp_sctx= tmp->security_ctx;
2224
      struct st_my_thread_var *mysys_var;
2225
      if ((tmp->vio_ok() || tmp->system_thread) &&
2226
          (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
unknown's avatar
unknown committed
2227
      {
2228
        thread_info *thd_info= new thread_info;
2229 2230

        thd_info->thread_id=tmp->thread_id;
2231 2232 2233 2234 2235
        thd_info->user= thd->strdup(tmp_sctx->user ? tmp_sctx->user :
                                    (tmp->system_thread ?
                                     "system user" : "unauthenticated user"));
	if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) &&
            thd->security_ctx->host_or_ip[0])
2236
	{
2237
	  if ((thd_info->host= (char*) thd->alloc(LIST_PROCESS_HOST_LEN+1)))
unknown's avatar
unknown committed
2238
	    my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
2239
			"%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
2240 2241
	}
	else
2242 2243
	  thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ?
                                      tmp_sctx->host_or_ip :
2244
                                      tmp_sctx->host ? tmp_sctx->host : "");
2245
        thd_info->command=(int) tmp->command;
2246
        mysql_mutex_lock(&tmp->LOCK_thd_data);
2247 2248
        if ((thd_info->db= tmp->db))             // Safe test
          thd_info->db= thd->strdup(thd_info->db);
2249
        if ((mysys_var= tmp->mysys_var))
Marc Alff's avatar
Marc Alff committed
2250
          mysql_mutex_lock(&mysys_var->mutex);
2251
        thd_info->proc_info= (char*) (tmp->killed >= KILL_QUERY ?
2252
                                      "Killed" : 0);
2253
        thd_info->state_info= thread_state_info(tmp);
2254
        if (mysys_var)
Marc Alff's avatar
Marc Alff committed
2255
          mysql_mutex_unlock(&mysys_var->mutex);
unknown's avatar
unknown committed
2256

2257
        /* Lock THD mutex that protects its data when looking at it. */
2258
        if (tmp->query())
2259
        {
2260
          uint length= min(max_query_length, tmp->query_length());
2261 2262 2263 2264
          char *q= thd->strmake(tmp->query(),length);
          /* Safety: in case strmake failed, we set length to 0. */
          thd_info->query_string=
            CSET_STRING(q, q ? length : 0, tmp->query_charset());
2265
        }
2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279

        /*
          Progress report. We need to do this under a lock to ensure that all
          is from the same stage.
        */
        if (tmp->progress.max_counter)
        {
          uint max_stage= max(tmp->progress.max_stage, 1);
          thd_info->progress= (((tmp->progress.stage / (double) max_stage) +
                                ((tmp->progress.counter /
                                  (double) tmp->progress.max_counter) /
                                 (double) max_stage)) *
                               100.0);
        }
Sergei Golubchik's avatar
Sergei Golubchik committed
2280 2281
        else
          thd_info->progress= 0.0;
2282
        thd_info->start_time= tmp->start_time;
Sergei Golubchik's avatar
Sergei Golubchik committed
2283
        mysql_mutex_unlock(&tmp->LOCK_thd_data);
2284
        thread_infos.append(thd_info);
unknown's avatar
unknown committed
2285 2286 2287
      }
    }
  }
Marc Alff's avatar
Marc Alff committed
2288
  mysql_mutex_unlock(&LOCK_thread_count);
unknown's avatar
unknown committed
2289 2290

  thread_info *thd_info;
2291
  time_t now= my_time(0);
2292 2293 2294
  char buff[20];                                // For progress
  String store_buffer(buff, sizeof(buff), system_charset_info);

unknown's avatar
unknown committed
2295 2296
  while ((thd_info=thread_infos.get()))
  {
unknown's avatar
unknown committed
2297 2298
    protocol->prepare_for_resend();
    protocol->store((ulonglong) thd_info->thread_id);
2299 2300 2301
    protocol->store(thd_info->user, system_charset_info);
    protocol->store(thd_info->host, system_charset_info);
    protocol->store(thd_info->db, system_charset_info);
unknown's avatar
unknown committed
2302
    if (thd_info->proc_info)
2303
      protocol->store(thd_info->proc_info, system_charset_info);
unknown's avatar
unknown committed
2304
    else
2305
      protocol->store(command_name[thd_info->command].str, system_charset_info);
unknown's avatar
unknown committed
2306
    if (thd_info->start_time)
2307
      protocol->store_long ((longlong) (now - thd_info->start_time));
unknown's avatar
unknown committed
2308
    else
unknown's avatar
unknown committed
2309
      protocol->store_null();
2310
    protocol->store(thd_info->state_info, system_charset_info);
2311 2312
    protocol->store(thd_info->query_string.str(),
                    thd_info->query_string.charset());
2313 2314
    if (!thd->variables.old_mode)
      protocol->store(thd_info->progress, 3, &store_buffer);
unknown's avatar
unknown committed
2315
    if (protocol->write())
unknown's avatar
unknown committed
2316 2317
      break; /* purecov: inspected */
  }
2318
  my_eof(thd);
unknown's avatar
unknown committed
2319 2320 2321
  DBUG_VOID_RETURN;
}

2322

2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343
/*
  Produce EXPLAIN data.

  This function is APC-scheduled to be run in the context of the thread that
  we're producing EXPLAIN for.
*/

void Show_explain_request::call_in_target_thread()
{
  Query_arena backup_arena;
  bool printed_anything= FALSE;

  /* 
    Change the arena because JOIN::print_explain and co. are going to allocate
    items. Let them allocate them on our arena.
  */
  target_thd->set_n_backup_active_arena((Query_arena*)request_thd,
                                        &backup_arena);
  
  query_str.copy(target_thd->query(), 
                 target_thd->query_length(),
2344
                 target_thd->query_charset());
2345

2346 2347
  DBUG_ASSERT(current_thd == target_thd);
  set_current_thd(request_thd);
Sergey Petrunya's avatar
Sergey Petrunya committed
2348 2349
  if (target_thd->lex->print_explain(explain_buf, 0 /* explain flags*/,
                                     &printed_anything))
2350 2351 2352
  {
    failed_to_produce= TRUE;
  }
2353
  set_current_thd(target_thd);
2354 2355 2356 2357 2358 2359 2360 2361 2362 2363

  if (!printed_anything)
    failed_to_produce= TRUE;

  target_thd->restore_active_arena((Query_arena*)request_thd, &backup_arena);
}


int select_result_explain_buffer::send_data(List<Item> &items)
{
2364 2365 2366 2367 2368 2369 2370 2371 2372 2373
  int res;
  THD *cur_thd= current_thd;
  DBUG_ENTER("select_result_explain_buffer::send_data");

  /*
    Switch to the recieveing thread, so that we correctly count memory used
    by it. This is needed as it's the receiving thread that will free the
    memory.
  */
  set_current_thd(thd);
2374
  fill_record(thd, dst_table, dst_table->field, items, TRUE, FALSE);
2375 2376 2377
  res= dst_table->file->ha_write_tmp_row(dst_table->record[0]);
  set_current_thd(cur_thd);  
  DBUG_RETURN(test(res));
2378 2379
}

2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444
bool select_result_text_buffer::send_result_set_metadata(List<Item> &fields, uint flag)
{
  n_columns= fields.elements;
  return append_row(fields, true /*send item names */);
  return send_data(fields);
}


int select_result_text_buffer::send_data(List<Item> &items)
{
  return append_row(items, false /*send item values */);
}

int select_result_text_buffer::append_row(List<Item> &items, bool send_names)
{
  List_iterator<Item> it(items);
  Item *item;
  char **row;
  int column= 0;

  if (!(row= (char**) thd->alloc(sizeof(char*) * n_columns)))
    return true;
  rows.push_back(row);

  while ((item= it++))
  {
    DBUG_ASSERT(column < n_columns);
    StringBuffer<32> buf;
    const char *data_ptr; 
    size_t data_len;
    if (send_names)
    {
      data_ptr= item->name;
      data_len= strlen(item->name);
    }
    else
    {
      String *res;
      res= item->val_str(&buf);
      if (item->null_value)
      {
        data_ptr= "NULL";
        data_len=4;
      }
      else
      {
        data_ptr= res->c_ptr_safe();
        data_len= res->length();
      }
    }

    char *ptr= (char*)thd->alloc(data_len + 1);
    memcpy(ptr, data_ptr, data_len + 1);
    row[column]= ptr;

    column++;
  }
  return false;
}


void select_result_text_buffer::save_to(String *res)
{
  List_iterator<char*> it(rows);
  char **row;
2445
  res->append("## <explain>\n");
2446 2447
  while ((row= it++))
  {
2448
    res->append("##   ");
2449 2450 2451 2452 2453 2454 2455 2456
    for (int i=0; i < n_columns; i++)
    {
      if (i)
        res->append('\t');
      res->append(row[i]);
    }
    res->append("\n");
  }
2457
  res->append("## </explain>\n");
2458 2459
}

2460

2461 2462
/*
  Store the SHOW EXPLAIN output in the temporary table.
2463 2464
*/

2465
int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
2466
{
2467
  const char *calling_user;
2468
  THD *tmp;
2469 2470 2471 2472
  my_thread_id  thread_id;
  DBUG_ENTER("fill_show_explain");

  DBUG_ASSERT(cond==NULL);
2473
  thread_id= thd->lex->value_list.head()->val_int();
2474 2475 2476
  calling_user= (thd->security_ctx->master_access & PROCESS_ACL) ?  NullS :
                 thd->security_ctx->priv_user;

2477
  if ((tmp= find_thread_by_id(thread_id)))
2478
  {
2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489
    Security_context *tmp_sctx= tmp->security_ctx;
    /*
      If calling_user==NULL, calling thread has SUPER or PROCESS
      privilege, and so can do SHOW EXPLAIN on any user.
      
      if calling_user!=NULL, he's only allowed to view SHOW EXPLAIN on
      his own threads.
    */
    if (calling_user && (!tmp_sctx->user || strcmp(calling_user, 
                                                   tmp_sctx->user)))
    {
2490
      my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "PROCESS");
2491
      mysql_mutex_unlock(&tmp->LOCK_thd_data);
2492 2493 2494 2495 2496 2497
      DBUG_RETURN(1);
    }

    if (tmp == thd)
    {
      mysql_mutex_unlock(&tmp->LOCK_thd_data);
2498
      my_error(ER_TARGET_NOT_EXPLAINABLE, MYF(0));
2499
      DBUG_RETURN(1);
2500 2501
    }

2502 2503 2504
    bool bres;
    /* 
      Ok we've found the thread of interest and it won't go away because 
Sergey Petrunya's avatar
Sergey Petrunya committed
2505
      we're holding its LOCK_thd data. Post it a SHOW EXPLAIN request.
2506 2507 2508 2509 2510 2511
    */
    bool timed_out;
    int timeout_sec= 30;
    Show_explain_request explain_req;
    select_result_explain_buffer *explain_buf;
    
2512
    explain_buf= new select_result_explain_buffer(thd, table->table);
2513 2514 2515 2516

    explain_req.explain_buf= explain_buf;
    explain_req.target_thd= tmp;
    explain_req.request_thd= thd;
2517
    explain_req.failed_to_produce= FALSE;
2518 2519
    
    /* Ok, we have a lock on target->LOCK_thd_data, can call: */
2520
    bres= tmp->apc_target.make_apc_call(thd, &explain_req, timeout_sec, &timed_out);
2521 2522

    if (bres || explain_req.failed_to_produce)
2523
    {
2524 2525
      if (thd->killed)
        thd->send_kill_message();
2526 2527
      else if (timed_out)
        my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
2528
      else
2529 2530
        my_error(ER_TARGET_NOT_EXPLAINABLE, MYF(0));

2531
      bres= TRUE;
2532
    }
2533 2534
    else
    {
2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561
      /*
        Push the query string as a warning. The query may be in a different
        charset than the charset that's used for error messages, so, convert it
        if needed.
      */
      CHARSET_INFO *fromcs= explain_req.query_str.charset();
      CHARSET_INFO *tocs= error_message_charset_info;
      char *warning_text;
      if (!my_charset_same(fromcs, tocs))
      {
        uint conv_length= 1 + tocs->mbmaxlen * explain_req.query_str.length() / 
                              fromcs->mbminlen;
        uint dummy_errors;
        char *to, *p;
        if (!(to= (char*)thd->alloc(conv_length + 1)))
          DBUG_RETURN(1);
        p= to;
        p+= copy_and_convert(to, conv_length, tocs,
                             explain_req.query_str.c_ptr(), 
                             explain_req.query_str.length(), fromcs,
                             &dummy_errors);
        *p= 0;
        warning_text= to;
      }
      else
        warning_text= explain_req.query_str.c_ptr_safe();

2562
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
2563
                   ER_YES, warning_text);
2564
    }
2565
    DBUG_RETURN(bres);
2566 2567 2568 2569
  }
  else
  {
    my_error(ER_NO_SUCH_THREAD, MYF(0), thread_id);
2570
    DBUG_RETURN(1);
2571 2572 2573 2574
  }
}


2575 2576 2577 2578 2579
int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
{
  TABLE *table= tables->table;
  CHARSET_INFO *cs= system_charset_info;
  char *user;
Michael Widenius's avatar
Michael Widenius committed
2580
  my_hrtime_t unow= my_hrtime();
Sergei Golubchik's avatar
Sergei Golubchik committed
2581
  DBUG_ENTER("fill_schema_processlist");
2582

2583 2584
  DEBUG_SYNC(thd,"fill_schema_processlist_after_unow");

2585 2586 2587
  user= thd->security_ctx->master_access & PROCESS_ACL ?
        NullS : thd->security_ctx->priv_user;

Marc Alff's avatar
Marc Alff committed
2588
  mysql_mutex_lock(&LOCK_thread_count);
2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599

  if (!thd->killed)
  {
    I_List_iterator<THD> it(threads);
    THD* tmp;

    while ((tmp= it++))
    {
      Security_context *tmp_sctx= tmp->security_ctx;
      struct st_my_thread_var *mysys_var;
      const char *val;
2600
      ulonglong max_counter;
2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631

      if ((!tmp->vio_ok() && !tmp->system_thread) ||
          (user && (!tmp_sctx->user || strcmp(tmp_sctx->user, user))))
        continue;

      restore_record(table, s->default_values);
      /* ID */
      table->field[0]->store((longlong) tmp->thread_id, TRUE);
      /* USER */
      val= tmp_sctx->user ? tmp_sctx->user :
            (tmp->system_thread ? "system user" : "unauthenticated user");
      table->field[1]->store(val, strlen(val), cs);
      /* HOST */
      if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) &&
          thd->security_ctx->host_or_ip[0])
      {
        char host[LIST_PROCESS_HOST_LEN + 1];
        my_snprintf(host, LIST_PROCESS_HOST_LEN, "%s:%u",
                    tmp_sctx->host_or_ip, tmp->peer_port);
        table->field[2]->store(host, strlen(host), cs);
      }
      else
        table->field[2]->store(tmp_sctx->host_or_ip,
                               strlen(tmp_sctx->host_or_ip), cs);
      /* DB */
      if (tmp->db)
      {
        table->field[3]->store(tmp->db, strlen(tmp->db), cs);
        table->field[3]->set_notnull();
      }

2632
      mysql_mutex_lock(&tmp->LOCK_thd_data);
2633
      if ((mysys_var= tmp->mysys_var))
Marc Alff's avatar
Marc Alff committed
2634
        mysql_mutex_lock(&mysys_var->mutex);
2635
      /* COMMAND */
2636
      if ((val= (char *) ((tmp->killed >= KILL_QUERY ?
2637
                           "Killed" : 0))))
2638 2639 2640 2641
        table->field[4]->store(val, strlen(val), cs);
      else
        table->field[4]->store(command_name[tmp->command].str,
                               command_name[tmp->command].length, cs);
2642
      /* MYSQL_TIME */
2643 2644
      ulonglong start_utime= tmp->start_time * HRTIME_RESOLUTION + tmp->start_time_sec_part;
      ulonglong utime= start_utime < unow.val ? unow.val - start_utime : 0;
Michael Widenius's avatar
Michael Widenius committed
2645
      table->field[5]->store(utime / HRTIME_RESOLUTION, TRUE);
2646
      /* STATE */
2647
      if ((val= thread_state_info(tmp)))
2648 2649 2650 2651 2652 2653
      {
        table->field[6]->store(val, strlen(val), cs);
        table->field[6]->set_notnull();
      }

      if (mysys_var)
Marc Alff's avatar
Marc Alff committed
2654
        mysql_mutex_unlock(&mysys_var->mutex);
2655
      mysql_mutex_unlock(&tmp->LOCK_thd_data);
2656

2657 2658 2659
      /* TIME_MS */
      table->field[8]->store((double)(utime / (HRTIME_RESOLUTION / 1000.0)));

2660
      /* INFO */
2661
      /* Lock THD mutex that protects its data when looking at it. */
2662
      mysql_mutex_lock(&tmp->LOCK_thd_data);
2663
      if (tmp->query())
2664
      {
2665
        table->field[7]->store(tmp->query(),
2666
                               min(PROCESS_LIST_INFO_WIDTH,
2667
                                   tmp->query_length()), cs);
2668 2669 2670
        table->field[7]->set_notnull();
      }

2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681
      /*
        Progress report. We need to do this under a lock to ensure that all
        is from the same stage.
      */
      if ((max_counter= tmp->progress.max_counter))
      {
        table->field[9]->store((longlong) tmp->progress.stage + 1, 1);
        table->field[10]->store((longlong) tmp->progress.max_stage, 1);
        table->field[11]->store((double) tmp->progress.counter /
                                (double) max_counter*100.0);
      }
Sergei Golubchik's avatar
Sergei Golubchik committed
2682
      mysql_mutex_unlock(&tmp->LOCK_thd_data);
2683

2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695
      /*
        This may become negative if we free a memory allocated by another
        thread in this thread. However it's better that we notice it eventually
        than hide it.
      */
      table->field[12]->store((longlong) (tmp->status_var.memory_used +
                                          sizeof(THD)),
                              FALSE);
      table->field[12]->set_notnull();
      table->field[13]->store((longlong) tmp->examined_row_count, TRUE);
      table->field[13]->set_notnull();

2696 2697 2698
      /* QUERY_ID */
      table->field[14]->store(tmp->query_id, TRUE);

2699 2700
      if (schema_table_store_record(thd, table))
      {
Marc Alff's avatar
Marc Alff committed
2701
        mysql_mutex_unlock(&LOCK_thread_count);
2702 2703 2704 2705 2706
        DBUG_RETURN(1);
      }
    }
  }

Marc Alff's avatar
Marc Alff committed
2707
  mysql_mutex_unlock(&LOCK_thread_count);
2708 2709 2710
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
2711
/*****************************************************************************
unknown's avatar
unknown committed
2712
  Status functions
unknown's avatar
unknown committed
2713 2714
*****************************************************************************/

2715 2716
static DYNAMIC_ARRAY all_status_vars;
static bool status_vars_inited= 0;
2717 2718

C_MODE_START
2719 2720
static int show_var_cmp(const void *var1, const void *var2)
{
2721
  return strcasecmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
2722
}
2723
C_MODE_END
2724 2725 2726 2727 2728 2729 2730

/*
  deletes all the SHOW_UNDEF elements from the array and calls
  delete_dynamic() if it's completely empty.
*/
static void shrink_var_array(DYNAMIC_ARRAY *array)
{
2731
  uint a,b;
2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768
  SHOW_VAR *all= dynamic_element(array, 0, SHOW_VAR *);

  for (a= b= 0; b < array->elements; b++)
    if (all[b].type != SHOW_UNDEF)
      all[a++]= all[b];
  if (a)
  {
    bzero(all+a, sizeof(SHOW_VAR)); // writing NULL-element to the end
    array->elements= a;
  }
  else // array is completely empty - delete it
    delete_dynamic(array);
}

/*
  Adds an array of SHOW_VAR entries to the output of SHOW STATUS

  SYNOPSIS
    add_status_vars(SHOW_VAR *list)
    list - an array of SHOW_VAR entries to add to all_status_vars
           the last entry must be {0,0,SHOW_UNDEF}

  NOTE
    The handling of all_status_vars[] is completely internal, it's allocated
    automatically when something is added to it, and deleted completely when
    the last entry is removed.

    As a special optimization, if add_status_vars() is called before
    init_status_vars(), it assumes "startup mode" - neither concurrent access
    to the array nor SHOW STATUS are possible (thus it skips locks and qsort)

    The last entry of the all_status_vars[] should always be {0,0,SHOW_UNDEF}
*/
int add_status_vars(SHOW_VAR *list)
{
  int res= 0;
  if (status_vars_inited)
Marc Alff's avatar
Marc Alff committed
2769
    mysql_mutex_lock(&LOCK_status);
2770
  if (!all_status_vars.buffer && // array is not allocated yet - do it now
2771
      my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 200, 20, MYF(0)))
2772 2773 2774 2775 2776
  {
    res= 1;
    goto err;
  }
  while (list->name)
2777 2778
    res|= insert_dynamic(&all_status_vars, (uchar*)list++);
  res|= insert_dynamic(&all_status_vars, (uchar*)list); // appending NULL-element
2779 2780 2781 2782 2783
  all_status_vars.elements--; // but next insert_dynamic should overwite it
  if (status_vars_inited)
    sort_dynamic(&all_status_vars, show_var_cmp);
err:
  if (status_vars_inited)
Marc Alff's avatar
Marc Alff committed
2784
    mysql_mutex_unlock(&LOCK_status);
2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801
  return res;
}

/*
  Make all_status_vars[] usable for SHOW STATUS

  NOTE
    See add_status_vars(). Before init_status_vars() call, add_status_vars()
    works in a special fast "startup" mode. Thus init_status_vars()
    should be called as late as possible but before enabling multi-threading.
*/
void init_status_vars()
{
  status_vars_inited=1;
  sort_dynamic(&all_status_vars, show_var_cmp);
}

unknown's avatar
WL#2936  
unknown committed
2802 2803 2804 2805 2806 2807 2808 2809 2810
void reset_status_vars()
{
  SHOW_VAR *ptr= (SHOW_VAR*) all_status_vars.buffer;
  SHOW_VAR *last= ptr + all_status_vars.elements;
  for (; ptr < last; ptr++)
  {
    /* Note that SHOW_LONG_NOFLUSH variables are not reset */
    if (ptr->type == SHOW_LONG)
      *(ulong*) ptr->value= 0;
2811
  }
unknown's avatar
WL#2936  
unknown committed
2812 2813
}

2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840
/*
  catch-all cleanup function, cleans up everything no matter what

  DESCRIPTION
    This function is not strictly required if all add_to_status/
    remove_status_vars are properly paired, but it's a safety measure that
    deletes everything from the all_status_vars[] even if some
    remove_status_vars were forgotten
*/
void free_status_vars()
{
  delete_dynamic(&all_status_vars);
}

/*
  Removes an array of SHOW_VAR entries from the output of SHOW STATUS

  SYNOPSIS
    remove_status_vars(SHOW_VAR *list)
    list - an array of SHOW_VAR entries to remove to all_status_vars
           the last entry must be {0,0,SHOW_UNDEF}

  NOTE
    there's lots of room for optimizing this, especially in non-sorted mode,
    but nobody cares - it may be called only in case of failed plugin
    initialization in the mysqld startup.
*/
unknown's avatar
unknown committed
2841

2842 2843 2844 2845
void remove_status_vars(SHOW_VAR *list)
{
  if (status_vars_inited)
  {
Marc Alff's avatar
Marc Alff committed
2846
    mysql_mutex_lock(&LOCK_status);
2847 2848 2849 2850
    SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);

    for (; list->name; list++)
    {
2851 2852
      int res= 0, a= 0, b= all_status_vars.elements, c= (a+b)/2;
      for (; b-a > 0; c= (a+b)/2)
2853 2854 2855 2856 2857 2858
      {
        res= show_var_cmp(list, all+c);
        if (res < 0)
          b= c;
        else if (res > 0)
          a= c;
unknown's avatar
unknown committed
2859 2860
        else
          break;
2861 2862 2863 2864 2865
      }
      if (res == 0)
        all[c].type= SHOW_UNDEF;
    }
    shrink_var_array(&all_status_vars);
Marc Alff's avatar
Marc Alff committed
2866
    mysql_mutex_unlock(&LOCK_status);
2867 2868 2869 2870
  }
  else
  {
    SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
unknown's avatar
unknown committed
2871
    uint i;
2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885
    for (; list->name; list++)
    {
      for (i= 0; i < all_status_vars.elements; i++)
      {
        if (show_var_cmp(list, all+i))
          continue;
        all[i].type= SHOW_UNDEF;
        break;
      }
    }
    shrink_var_array(&all_status_vars);
  }
}

2886 2887


2888
static bool show_status_array(THD *thd, const char *wild,
2889
                              SHOW_VAR *variables,
2890 2891
                              enum enum_var_type value_type,
                              struct system_status_var *status_var,
2892
                              const char *prefix, TABLE *table,
2893 2894
                              bool ucase_names,
                              COND *cond)
unknown's avatar
unknown committed
2895
{
2896 2897
  my_aligned_storage<SHOW_VAR_FUNC_BUFF_SIZE, MY_ALIGNOF(long)> buffer;
  char * const buff= buffer.data;
2898
  char *prefix_end;
2899 2900
  /* the variable name should not be longer than 64 characters */
  char name_buffer[64];
2901
  int len;
2902
  LEX_STRING null_lex_str;
2903
  SHOW_VAR tmp, *var;
2904 2905
  enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
  bool res= FALSE;
2906
  CHARSET_INFO *charset= system_charset_info;
2907
  DBUG_ENTER("show_status_array");
unknown's avatar
unknown committed
2908

Michael Widenius's avatar
Michael Widenius committed
2909
  thd->count_cuted_fields= CHECK_FIELD_WARN;
2910
  null_lex_str.str= 0;				// For sys_var->value_ptr()
2911
  null_lex_str.length= 0;
unknown's avatar
unknown committed
2912

2913
  prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1);
2914 2915
  if (*prefix)
    *prefix_end++= '_';
2916 2917
  len=name_buffer + sizeof(name_buffer) - prefix_end;

unknown's avatar
unknown committed
2918
  for (; variables->name; variables++)
unknown's avatar
unknown committed
2919
  {
2920
    bool wild_checked;
2921 2922
    strnmov(prefix_end, variables->name, len);
    name_buffer[sizeof(name_buffer)-1]=0;       /* Safety */
2923
    if (ucase_names)
2924
      my_caseup_str(system_charset_info, name_buffer);
2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935
    else
    {
      my_casedn_str(system_charset_info, name_buffer);
      DBUG_ASSERT(name_buffer[0] >= 'a');
      DBUG_ASSERT(name_buffer[0] <= 'z');

      /* traditionally status variables have a first letter uppercased */
      if (status_var)
        name_buffer[0]-= 'a' - 'A';
    }

2936

2937 2938 2939
    restore_record(table, s->default_values);
    table->field[0]->store(name_buffer, strlen(name_buffer),
                           system_charset_info);
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952

    /*
      Compare name for types that can't return arrays. We do this to not
      calculate the value for function variables that we will not access
    */
    if ((variables->type != SHOW_FUNC && variables->type != SHOW_ARRAY))
    {
      if (wild && wild[0] && wild_case_compare(system_charset_info,
                                               name_buffer, wild))
        continue;
      wild_checked= 1;                          // Avoid checking it again
    }

2953
    /*
2954 2955
      if var->type is SHOW_FUNC or SHOW_SIMPLE_FUNC, call the function.
      Repeat as necessary, if new var is again one of the above
2956
    */
2957 2958
    for (var=variables; var->type == SHOW_FUNC ||
           var->type == SHOW_SIMPLE_FUNC; var= &tmp)
2959
      ((mysql_show_var_func)(var->value))(thd, &tmp, buff);
2960 2961 2962

    SHOW_TYPE show_type=var->type;
    if (show_type == SHOW_ARRAY)
2963
    {
2964
      show_status_array(thd, wild, (SHOW_VAR *) var->value, value_type,
2965
                        status_var, name_buffer, table, ucase_names, cond);
2966 2967
    }
    else
unknown's avatar
unknown committed
2968
    {
2969 2970 2971
      if ((wild_checked ||
           (wild && wild[0] && wild_case_compare(system_charset_info,
                                                 name_buffer, wild))) &&
2972
          (!cond || cond->val_int()))
unknown's avatar
unknown committed
2973
      {
2974
        char *value=var->value;
unknown's avatar
unknown committed
2975
        const char *pos, *end;                  // We assign a lot of const's
2976

Marc Alff's avatar
Marc Alff committed
2977
        mysql_mutex_lock(&LOCK_global_system_variables);
unknown's avatar
WL#2936  
unknown committed
2978

2979 2980
        if (show_type == SHOW_SYS)
        {
2981
          sys_var *var= ((sys_var *) value);
2982 2983 2984
          show_type= var->show_type();
          value= (char*) var->value_ptr(thd, value_type, &null_lex_str);
          charset= var->charset(thd);
2985 2986 2987
        }

        pos= end= buff;
2988 2989 2990 2991
        /*
          note that value may be == buff. All SHOW_xxx code below
          should still work in this case
        */
2992
        switch (show_type) {
2993
        case SHOW_DOUBLE_STATUS:
2994
          value= ((char *) status_var + (intptr) value);
2995 2996
          /* fall through */
        case SHOW_DOUBLE:
2997 2998
          /* 6 is the default precision for '%f' in sprintf() */
          end= buff + my_fcvt(*(double *) value, 6, buff, NULL);
2999
          break;
3000
        case SHOW_LONG_STATUS:
3001
          value= ((char *) status_var + (intptr) value);
3002
          /* fall through */
3003
        case SHOW_ULONG:
3004
        case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
3005 3006
          end= int10_to_str(*(long*) value, buff, 10);
          break;
3007
        case SHOW_LONGLONG_STATUS:
3008
          value= ((char *) status_var + (intptr) value);
3009
          /* fall through */
3010
        case SHOW_ULONGLONG:
3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021
          end= longlong10_to_str(*(longlong*) value, buff, 10);
          break;
        case SHOW_HA_ROWS:
          end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
          break;
        case SHOW_BOOL:
          end= strmov(buff, *(bool*) value ? "ON" : "OFF");
          break;
        case SHOW_MY_BOOL:
          end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
          break;
3022
        case SHOW_UINT:
Sergei Golubchik's avatar
Sergei Golubchik committed
3023
          end= int10_to_str((long) *(uint*) value, buff, 10);
3024
          break;
3025 3026 3027 3028 3029 3030 3031 3032 3033
        case SHOW_SINT:
          end= int10_to_str((long) *(uint*) value, buff, -10);
          break;
        case SHOW_SLONG:
          end= int10_to_str(*(long*) value, buff, -10);
          break;
        case SHOW_SLONGLONG:
          end= longlong10_to_str(*(longlong*) value, buff, -10);
          break;
3034
        case SHOW_HAVE:
unknown's avatar
unknown committed
3035 3036 3037 3038 3039 3040
        {
          SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
          pos= show_comp_option_name[(int) tmp];
          end= strend(pos);
          break;
        }
3041
        case SHOW_CHAR:
unknown's avatar
unknown committed
3042 3043 3044 3045 3046 3047
        {
          if (!(pos= value))
            pos= "";
          end= strend(pos);
          break;
        }
unknown's avatar
unknown committed
3048
       case SHOW_CHAR_PTR:
unknown's avatar
unknown committed
3049 3050 3051
        {
          if (!(pos= *(char**) value))
            pos= "";
3052 3053 3054 3055 3056 3057 3058 3059

          DBUG_EXECUTE_IF("alter_server_version_str",
                          if (!my_strcasecmp(system_charset_info,
                                             variables->name,
                                             "version")) {
                            pos= "some-other-version";
                          });

unknown's avatar
unknown committed
3060 3061 3062
          end= strend(pos);
          break;
        }
3063 3064 3065 3066 3067 3068 3069 3070 3071
        case SHOW_LEX_STRING:
        {
          LEX_STRING *ls=(LEX_STRING*)value;
          if (!(pos= ls->str))
            end= pos= "";
          else
            end= pos + ls->length;
          break;
        }
3072
        case SHOW_UNDEF:
3073 3074
          break;                                        // Return empty string
        case SHOW_SYS:                                  // Cannot happen
3075
        default:
3076
          DBUG_ASSERT(0);
3077 3078
          break;
        }
3079
        table->field[1]->store(pos, (uint32) (end - pos), charset);
3080
        thd->count_cuted_fields= CHECK_FIELD_IGNORE;
3081
        table->field[1]->set_notnull();
unknown's avatar
WL#2936  
unknown committed
3082

Marc Alff's avatar
Marc Alff committed
3083
        mysql_mutex_unlock(&LOCK_global_system_variables);
unknown's avatar
WL#2936  
unknown committed
3084

3085
        if (schema_table_store_record(thd, table))
3086 3087 3088 3089
        {
          res= TRUE;
          goto end;
        }
unknown's avatar
unknown committed
3090 3091 3092
      }
    }
  }
3093 3094 3095
end:
  thd->count_cuted_fields= save_count_cuted_fields;
  DBUG_RETURN(res);
3096 3097
}

Sergei Golubchik's avatar
Sergei Golubchik committed
3098
#ifdef COMPLETE_PATCH_NOT_ADDED_YET
3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114
/*
  Aggregate values for mapped_user entries by their role.

  SYNOPSIS
  aggregate_user_stats
  all_user_stats - input to aggregate
  agg_user_stats - returns aggregated values

  RETURN
  0 - OK
  1 - error
*/

static int aggregate_user_stats(HASH *all_user_stats, HASH *agg_user_stats)
{
  DBUG_ENTER("aggregate_user_stats");
Sergei Golubchik's avatar
Sergei Golubchik committed
3115
  if (my_hash_init(agg_user_stats, system_charset_info,
3116
                max(all_user_stats->records, 1),
Sergei Golubchik's avatar
Sergei Golubchik committed
3117 3118
                0, 0, (my_hash_get_key)get_key_user_stats,
                (my_hash_free_key)free_user_stats, 0))
3119 3120 3121 3122 3123 3124 3125
  {
    sql_print_error("Malloc in aggregate_user_stats failed");
    DBUG_RETURN(1);
  }

  for (uint i= 0; i < all_user_stats->records; i++)
  {
Sergei Golubchik's avatar
Sergei Golubchik committed
3126
    USER_STATS *user= (USER_STATS*)my_hash_element(all_user_stats, i);
3127 3128 3129
    USER_STATS *agg_user;
    uint name_length= strlen(user->priv_user);

Sergei Golubchik's avatar
Sergei Golubchik committed
3130
    if (!(agg_user= (USER_STATS*) my_hash_search(agg_user_stats,
3131 3132 3133 3134 3135
                                              (uchar*)user->priv_user,
                                              name_length)))
    {
      // First entry for this role.
      if (!(agg_user= (USER_STATS*) my_malloc(sizeof(USER_STATS),
3136 3137
                                              MYF(MY_WME | MY_ZEROFILL|
                                                  MY_THREAD_SPECIFIC))))
3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209
      {
        sql_print_error("Malloc in aggregate_user_stats failed");
        DBUG_RETURN(1);
      }

      init_user_stats(agg_user, user->priv_user, name_length,
                      user->priv_user,
                      user->total_connections, user->concurrent_connections,
                      user->connected_time, user->busy_time, user->cpu_time,
                      user->bytes_received, user->bytes_sent,
                      user->binlog_bytes_written,
                      user->rows_sent, user->rows_read,
                      user->rows_inserted, user->rows_deleted,
                      user->rows_updated, 
                      user->select_commands, user->update_commands,
                      user->other_commands,
                      user->commit_trans, user->rollback_trans,
                      user->denied_connections, user->lost_connections,
                      user->access_denied_errors, user->empty_queries);

      if (my_hash_insert(agg_user_stats, (uchar*) agg_user))
      {
        /* Out of memory */
        my_free(agg_user, 0);
        sql_print_error("Malloc in aggregate_user_stats failed");
        DBUG_RETURN(1);
      }
    }
    else
    {
      /* Aggregate with existing values for this role. */
      add_user_stats(agg_user,
                     user->total_connections, user->concurrent_connections,
                     user->connected_time, user->busy_time, user->cpu_time,
                     user->bytes_received, user->bytes_sent,
                     user->binlog_bytes_written,
                     user->rows_sent, user->rows_read,
                     user->rows_inserted, user->rows_deleted,
                     user->rows_updated,
                     user->select_commands, user->update_commands,
                     user->other_commands,
                     user->commit_trans, user->rollback_trans,
                     user->denied_connections, user->lost_connections,
                     user->access_denied_errors, user->empty_queries);
    }
  }
  DBUG_PRINT("exit", ("aggregated %lu input into %lu output entries",
                      all_user_stats->records, agg_user_stats->records));
  DBUG_RETURN(0);
}
#endif

/*
  Write result to network for SHOW USER_STATISTICS

  SYNOPSIS
  send_user_stats
  all_user_stats - values to return
  table - I_S table

  RETURN
  0 - OK
  1 - error
*/

int send_user_stats(THD* thd, HASH *all_user_stats, TABLE *table)
{
  DBUG_ENTER("send_user_stats");

  for (uint i= 0; i < all_user_stats->records; i++)
  {
    uint j= 0;
Sergei Golubchik's avatar
Sergei Golubchik committed
3210
    USER_STATS *user_stats= (USER_STATS*) my_hash_element(all_user_stats, i);
3211 3212 3213 3214
    
    table->field[j++]->store(user_stats->user, user_stats->user_name_length,
                             system_charset_info);
    table->field[j++]->store((longlong)user_stats->total_connections,TRUE);
Sergei Golubchik's avatar
Sergei Golubchik committed
3215 3216
    table->field[j++]->store((longlong)user_stats->concurrent_connections, TRUE);
    table->field[j++]->store((longlong)user_stats->connected_time, TRUE);
3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264
    table->field[j++]->store((double)user_stats->busy_time);
    table->field[j++]->store((double)user_stats->cpu_time);
    table->field[j++]->store((longlong)user_stats->bytes_received, TRUE);
    table->field[j++]->store((longlong)user_stats->bytes_sent, TRUE);
    table->field[j++]->store((longlong)user_stats->binlog_bytes_written, TRUE);
    table->field[j++]->store((longlong)user_stats->rows_read, TRUE);
    table->field[j++]->store((longlong)user_stats->rows_sent, TRUE);
    table->field[j++]->store((longlong)user_stats->rows_deleted, TRUE);
    table->field[j++]->store((longlong)user_stats->rows_inserted, TRUE);
    table->field[j++]->store((longlong)user_stats->rows_updated, TRUE);
    table->field[j++]->store((longlong)user_stats->select_commands, TRUE);
    table->field[j++]->store((longlong)user_stats->update_commands, TRUE);
    table->field[j++]->store((longlong)user_stats->other_commands, TRUE);
    table->field[j++]->store((longlong)user_stats->commit_trans, TRUE);
    table->field[j++]->store((longlong)user_stats->rollback_trans, TRUE);
    table->field[j++]->store((longlong)user_stats->denied_connections, TRUE);
    table->field[j++]->store((longlong)user_stats->lost_connections, TRUE);
    table->field[j++]->store((longlong)user_stats->access_denied_errors, TRUE);
    table->field[j++]->store((longlong)user_stats->empty_queries, TRUE);
    if (schema_table_store_record(thd, table))
    {
      DBUG_PRINT("error", ("store record error"));
      DBUG_RETURN(1);
    }
  }
  DBUG_RETURN(0);
}

/*
  Process SHOW USER_STATISTICS

  SYNOPSIS
  mysqld_show_user_stats
  thd - current thread
  wild - limit results to the entry for this user
  with_roles - when true, display role for mapped users

  RETURN
  0 - OK
  1 - error
*/

int fill_schema_user_stats(THD* thd, TABLE_LIST* tables, COND* cond)
{
  TABLE *table= tables->table;
  int result;
  DBUG_ENTER("fill_schema_user_stats");

3265 3266
  if (check_global_access(thd, SUPER_ACL | PROCESS_ACL, true))
    DBUG_RETURN(0);
3267 3268 3269 3270 3271 3272

  /*
    Iterates through all the global stats and sends them to the client.
    Pattern matching on the client IP is supported.
  */

Sergei Golubchik's avatar
Sergei Golubchik committed
3273
  mysql_mutex_lock(&LOCK_global_user_client_stats);
3274
  result= send_user_stats(thd, &global_user_stats, table) != 0;
Sergei Golubchik's avatar
Sergei Golubchik committed
3275
  mysql_mutex_unlock(&LOCK_global_user_client_stats);
3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299

  DBUG_PRINT("exit", ("result: %d", result));
  DBUG_RETURN(result);
}

/*
   Process SHOW CLIENT_STATISTICS

   SYNOPSIS
     mysqld_show_client_stats
       thd - current thread
       wild - limit results to the entry for this client

   RETURN
     0 - OK
     1 - error
*/

int fill_schema_client_stats(THD* thd, TABLE_LIST* tables, COND* cond)
{
  TABLE *table= tables->table;
  int result;
  DBUG_ENTER("fill_schema_client_stats");

3300 3301
  if (check_global_access(thd, SUPER_ACL | PROCESS_ACL, true))
    DBUG_RETURN(0);
3302 3303 3304 3305 3306 3307

  /*
    Iterates through all the global stats and sends them to the client.
    Pattern matching on the client IP is supported.
  */

Sergei Golubchik's avatar
Sergei Golubchik committed
3308
  mysql_mutex_lock(&LOCK_global_user_client_stats);
3309
  result= send_user_stats(thd, &global_client_stats, table) != 0;
Sergei Golubchik's avatar
Sergei Golubchik committed
3310
  mysql_mutex_unlock(&LOCK_global_user_client_stats);
3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323

  DBUG_PRINT("exit", ("result: %d", result));
  DBUG_RETURN(result);
}


/* Fill information schema table with table statistics */

int fill_schema_table_stats(THD *thd, TABLE_LIST *tables, COND *cond)
{
  TABLE *table= tables->table;
  DBUG_ENTER("fill_schema_table_stats");

Sergei Golubchik's avatar
Sergei Golubchik committed
3324
  mysql_mutex_lock(&LOCK_global_table_stats);
3325 3326 3327 3328
  for (uint i= 0; i < global_table_stats.records; i++)
  {
    char *end_of_schema;
    TABLE_STATS *table_stats= 
Sergei Golubchik's avatar
Sergei Golubchik committed
3329
      (TABLE_STATS*)my_hash_element(&global_table_stats, i);
3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340
    TABLE_LIST tmp_table;
    size_t schema_length, table_name_length;

    end_of_schema= strend(table_stats->table);
    schema_length= (size_t) (end_of_schema - table_stats->table);
    table_name_length= strlen(table_stats->table + schema_length + 1);

    bzero((char*) &tmp_table,sizeof(tmp_table));
    tmp_table.db=         table_stats->table;
    tmp_table.table_name= end_of_schema+1;
    tmp_table.grant.privilege= 0;
Sergei Golubchik's avatar
Sergei Golubchik committed
3341 3342
    if (check_access(thd, SELECT_ACL, tmp_table.db,
                     &tmp_table.grant.privilege, NULL, 0, 1) ||
3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356
        check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX,
                    1))
      continue;

    table->field[0]->store(table_stats->table, schema_length,
                           system_charset_info);
    table->field[1]->store(table_stats->table + schema_length+1,
                           table_name_length, system_charset_info);
    table->field[2]->store((longlong)table_stats->rows_read, TRUE);
    table->field[3]->store((longlong)table_stats->rows_changed, TRUE);
    table->field[4]->store((longlong)table_stats->rows_changed_x_indexes,
                           TRUE);
    if (schema_table_store_record(thd, table))
    {
Sergei Golubchik's avatar
Sergei Golubchik committed
3357
      mysql_mutex_unlock(&LOCK_global_table_stats);
3358 3359 3360
      DBUG_RETURN(1);
    }
  }
Sergei Golubchik's avatar
Sergei Golubchik committed
3361
  mysql_mutex_unlock(&LOCK_global_table_stats);
3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372
  DBUG_RETURN(0);
}


/* Fill information schema table with index statistics */

int fill_schema_index_stats(THD *thd, TABLE_LIST *tables, COND *cond)
{
  TABLE *table= tables->table;
  DBUG_ENTER("fill_schema_index_stats");

Sergei Golubchik's avatar
Sergei Golubchik committed
3373
  mysql_mutex_lock(&LOCK_global_index_stats);
3374 3375 3376
  for (uint i= 0; i < global_index_stats.records; i++)
  {
    INDEX_STATS *index_stats =
Sergei Golubchik's avatar
Sergei Golubchik committed
3377
      (INDEX_STATS*) my_hash_element(&global_index_stats, i);
3378 3379 3380 3381 3382 3383 3384 3385
    TABLE_LIST tmp_table;
    char *index_name;
    size_t schema_name_length, table_name_length, index_name_length;

    bzero((char*) &tmp_table,sizeof(tmp_table));
    tmp_table.db=         index_stats->index;
    tmp_table.table_name= strend(index_stats->index)+1;
    tmp_table.grant.privilege= 0;
Sergei Golubchik's avatar
Sergei Golubchik committed
3386 3387
    if (check_access(thd, SELECT_ACL, tmp_table.db,
                      &tmp_table.grant.privilege, NULL, 0, 1) ||
3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405
        check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX, 1))
      continue;

    index_name=         strend(tmp_table.table_name)+1; 
    schema_name_length= (tmp_table.table_name - index_stats->index) -1;
    table_name_length=  (index_name - tmp_table.table_name)-1;
    index_name_length=  (index_stats->index_name_length - schema_name_length -
                         table_name_length - 3);

    table->field[0]->store(tmp_table.db, schema_name_length,
                           system_charset_info);
    table->field[1]->store(tmp_table.table_name, table_name_length,
                           system_charset_info);
    table->field[2]->store(index_name, index_name_length, system_charset_info);
    table->field[3]->store((longlong)index_stats->rows_read, TRUE);

    if (schema_table_store_record(thd, table))
    { 
Sergei Golubchik's avatar
Sergei Golubchik committed
3406
      mysql_mutex_unlock(&LOCK_global_index_stats);
3407 3408 3409
      DBUG_RETURN(1);
    }
  }
Sergei Golubchik's avatar
Sergei Golubchik committed
3410
  mysql_mutex_unlock(&LOCK_global_index_stats);
3411 3412 3413
  DBUG_RETURN(0);
}

3414

3415 3416 3417 3418 3419 3420 3421
/* collect status for all running threads */

void calc_sum_of_all_status(STATUS_VAR *to)
{
  DBUG_ENTER("calc_sum_of_all_status");

  /* Ensure that thread id not killed during loop */
Marc Alff's avatar
Marc Alff committed
3422
  mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
3423 3424 3425

  I_List_iterator<THD> it(threads);
  THD *tmp;
3426

3427 3428
  /* Get global values as base */
  *to= global_status_var;
3429

3430 3431 3432 3433
  /* Add to this status from existing threads */
  while ((tmp= it++))
    add_to_status(to, &tmp->status_var);
  
Marc Alff's avatar
Marc Alff committed
3434
  mysql_mutex_unlock(&LOCK_thread_count);
3435 3436 3437 3438
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
3439
/* This is only used internally, but we need it here as a forward reference */
3440 3441
extern ST_SCHEMA_TABLE schema_tables[];

3442 3443 3444 3445 3446 3447 3448
/*
  Store record to I_S table, convert HEAP table
  to MyISAM if necessary

  SYNOPSIS
    schema_table_store_record()
    thd                   thread handler
3449 3450
    table                 Information schema table to be updated

3451 3452
  RETURN
    0	                  success
3453
    1	                  error
3454 3455
*/

3456
bool schema_table_store_record(THD *thd, TABLE *table)
3457 3458
{
  int error;
3459
  if ((error= table->file->ha_write_tmp_row(table->record[0])))
3460
  {
3461 3462
    TMP_TABLE_PARAM *param= table->pos_in_table_list->schema_table_param;
    if (create_internal_tmp_table_from_heap(thd, table, param->start_recinfo, 
3463
                                            &param->recinfo, error, 0, NULL))
3464

3465 3466 3467 3468 3469 3470
      return 1;
  }
  return 0;
}


3471 3472
static int make_table_list(THD *thd, SELECT_LEX *sel,
                           LEX_STRING *db_name, LEX_STRING *table_name)
3473 3474
{
  Table_ident *table_ident;
3475
  table_ident= new Table_ident(thd, *db_name, *table_name, 1);
3476
  if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ))
3477 3478 3479 3480 3481
    return 1;
  return 0;
}


3482
/**
3483
  @brief    Get lookup value from the part of 'WHERE' condition
3484

3485 3486
  @details This function gets lookup value from
           the part of 'WHERE' condition if it's possible and
3487 3488 3489 3490 3491 3492
           fill appropriate lookup_field_vals struct field
           with this value.

  @param[in]      thd                   thread handler
  @param[in]      item_func             part of WHERE condition
  @param[in]      table                 I_S table
3493
  @param[in, out] lookup_field_vals     Struct which holds lookup values
3494

3495 3496 3497
  @return
    0             success
    1             error, there can be no matching records for the condition
3498 3499
*/

3500
bool get_lookup_value(THD *thd, Item_func *item_func,
3501
                      TABLE_LIST *table,
3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519
                      LOOKUP_FIELD_VALUES *lookup_field_vals)
{
  ST_SCHEMA_TABLE *schema_table= table->schema_table;
  ST_FIELD_INFO *field_info= schema_table->fields_info;
  const char *field_name1= schema_table->idx_field1 >= 0 ?
    field_info[schema_table->idx_field1].field_name : "";
  const char *field_name2= schema_table->idx_field2 >= 0 ?
    field_info[schema_table->idx_field2].field_name : "";

  if (item_func->functype() == Item_func::EQ_FUNC ||
      item_func->functype() == Item_func::EQUAL_FUNC)
  {
    int idx_field, idx_val;
    char tmp[MAX_FIELD_WIDTH];
    String *tmp_str, str_buff(tmp, sizeof(tmp), system_charset_info);
    Item_field *item_field;
    CHARSET_INFO *cs= system_charset_info;

3520
    if (item_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
3521 3522 3523 3524 3525
        item_func->arguments()[1]->const_item())
    {
      idx_field= 0;
      idx_val= 1;
    }
3526
    else if (item_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
3527 3528 3529 3530 3531 3532
             item_func->arguments()[0]->const_item())
    {
      idx_field= 1;
      idx_val= 0;
    }
    else
3533
      return 0;
3534

3535
    item_field= (Item_field*) item_func->arguments()[idx_field]->real_item();
3536
    if (table->table != item_field->field->table)
3537
      return 0;
3538 3539
    tmp_str= item_func->arguments()[idx_val]->val_str(&str_buff);

3540 3541 3542 3543
    /* impossible value */
    if (!tmp_str)
      return 1;

3544 3545 3546 3547 3548
    /* Lookup value is database name */
    if (!cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
                               (uchar *) item_field->field_name,
                               strlen(item_field->field_name), 0))
    {
3549 3550
      thd->make_lex_string(&lookup_field_vals->db_value,
                           tmp_str->ptr(), tmp_str->length());
3551 3552 3553 3554 3555 3556 3557
    }
    /* Lookup value is table name */
    else if (!cs->coll->strnncollsp(cs, (uchar *) field_name2,
                                    strlen(field_name2),
                                    (uchar *) item_field->field_name,
                                    strlen(item_field->field_name), 0))
    {
3558 3559
      thd->make_lex_string(&lookup_field_vals->table_value,
                           tmp_str->ptr(), tmp_str->length());
3560 3561
    }
  }
3562
  return 0;
3563 3564 3565 3566
}


/**
3567
  @brief    Calculates lookup values from 'WHERE' condition
3568 3569

  @details This function calculates lookup value(database name, table name)
3570
           from 'WHERE' condition if it's possible and
3571 3572 3573 3574 3575
           fill lookup_field_vals struct fields with these values.

  @param[in]      thd                   thread handler
  @param[in]      cond                  WHERE condition
  @param[in]      table                 I_S table
3576
  @param[in, out] lookup_field_vals     Struct which holds lookup values
3577

3578 3579 3580
  @return
    0             success
    1             error, there can be no matching records for the condition
3581 3582
*/

3583
bool calc_lookup_values_from_cond(THD *thd, COND *cond, TABLE_LIST *table,
3584 3585 3586
                                  LOOKUP_FIELD_VALUES *lookup_field_vals)
{
  if (!cond)
3587
    return 0;
3588 3589 3590 3591 3592 3593 3594 3595 3596 3597

  if (cond->type() == Item::COND_ITEM)
  {
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
    {
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
      Item *item;
      while ((item= li++))
      {
        if (item->type() == Item::FUNC_ITEM)
3598 3599 3600 3601
        {
          if (get_lookup_value(thd, (Item_func*)item, table, lookup_field_vals))
            return 1;
        }
3602
        else
3603 3604 3605 3606
        {
          if (calc_lookup_values_from_cond(thd, item, table, lookup_field_vals))
            return 1;
        }
3607 3608
      }
    }
3609
    return 0;
3610
  }
3611 3612 3613 3614
  else if (cond->type() == Item::FUNC_ITEM &&
           get_lookup_value(thd, (Item_func*) cond, table, lookup_field_vals))
    return 1;
  return 0;
3615 3616 3617
}


3618 3619 3620 3621 3622
bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
{
  if (item->type() == Item::FUNC_ITEM)
  {
    Item_func *item_func= (Item_func*)item;
3623
    for (uint i=0; i<item_func->argument_count(); i++)
3624
    {
3625
      if (!uses_only_table_name_fields(item_func->arguments()[i], table))
3626
        return 0;
3627
    }
3628 3629 3630 3631 3632 3633 3634
  }
  else if (item->type() == Item::FIELD_ITEM)
  {
    Item_field *item_field= (Item_field*)item;
    CHARSET_INFO *cs= system_charset_info;
    ST_SCHEMA_TABLE *schema_table= table->schema_table;
    ST_FIELD_INFO *field_info= schema_table->fields_info;
3635 3636 3637 3638
    const char *field_name1= schema_table->idx_field1 >= 0 ?
      field_info[schema_table->idx_field1].field_name : "";
    const char *field_name2= schema_table->idx_field2 >= 0 ?
      field_info[schema_table->idx_field2].field_name : "";
3639 3640
    if (table->table != item_field->field->table ||
        (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
3641
                               (uchar *) item_field->field_name,
3642 3643
                               strlen(item_field->field_name), 0) &&
         cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2),
3644
                               (uchar *) item_field->field_name,
3645
                               strlen(item_field->field_name), 0)))
3646 3647
      return 0;
  }
3648 3649
  else if (item->type() == Item::REF_ITEM)
    return uses_only_table_name_fields(item->real_item(), table);
3650

3651
  if (item->real_type() == Item::SUBSELECT_ITEM && !item->const_item())
3652 3653
    return 0;

3654
  return 1;
3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713
}


static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table)
{
  if (!cond)
    return (COND*) 0;
  if (cond->type() == Item::COND_ITEM)
  {
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
    {
      /* Create new top level AND item */
      Item_cond_and *new_cond=new Item_cond_and;
      if (!new_cond)
	return (COND*) 0;
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
      Item *item;
      while ((item=li++))
      {
	Item *fix= make_cond_for_info_schema(item, table);
	if (fix)
	  new_cond->argument_list()->push_back(fix);
      }
      switch (new_cond->argument_list()->elements) {
      case 0:
	return (COND*) 0;
      case 1:
	return new_cond->argument_list()->head();
      default:
	new_cond->quick_fix_field();
	return new_cond;
      }
    }
    else
    {						// Or list
      Item_cond_or *new_cond=new Item_cond_or;
      if (!new_cond)
	return (COND*) 0;
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
      Item *item;
      while ((item=li++))
      {
	Item *fix=make_cond_for_info_schema(item, table);
	if (!fix)
	  return (COND*) 0;
	new_cond->argument_list()->push_back(fix);
      }
      new_cond->quick_fix_field();
      new_cond->top_level_item();
      return new_cond;
    }
  }

  if (!uses_only_table_name_fields(cond, table))
    return (COND*) 0;
  return cond;
}


3714 3715 3716 3717 3718 3719 3720 3721 3722 3723
/**
  @brief   Calculate lookup values(database name, table name)

  @details This function calculates lookup values(database name, table name)
           from 'WHERE' condition or wild values (for 'SHOW' commands only)
           from LEX struct and fill lookup_field_vals struct field
           with these values.

  @param[in]      thd                   thread handler
  @param[in]      cond                  WHERE condition
unknown's avatar
unknown committed
3724
  @param[in]      tables                I_S table
3725
  @param[in, out] lookup_field_values   Struct which holds lookup values
3726

3727 3728 3729
  @return
    0             success
    1             error, there can be no matching records for the condition
3730 3731
*/

3732
bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables,
3733 3734 3735
                             LOOKUP_FIELD_VALUES *lookup_field_values)
{
  LEX *lex= thd->lex;
Sergei Golubchik's avatar
cleanup  
Sergei Golubchik committed
3736
  String *wild= lex->wild;
3737 3738
  bool rc= 0;

3739 3740 3741 3742 3743
  bzero((char*) lookup_field_values, sizeof(LOOKUP_FIELD_VALUES));
  switch (lex->sql_command) {
  case SQLCOM_SHOW_DATABASES:
    if (wild)
    {
Sergei Golubchik's avatar
cleanup  
Sergei Golubchik committed
3744 3745
      thd->make_lex_string(&lookup_field_values->db_value,
                           wild->ptr(), wild->length());
3746 3747
      lookup_field_values->wild_db_value= 1;
    }
3748
    break;
3749 3750 3751 3752
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SHOW_TABLE_STATUS:
  case SQLCOM_SHOW_TRIGGERS:
  case SQLCOM_SHOW_EVENTS:
3753
    thd->make_lex_string(&lookup_field_values->db_value, 
3754
                         lex->select_lex.db, strlen(lex->select_lex.db));
3755 3756
    if (wild)
    {
3757
      thd->make_lex_string(&lookup_field_values->table_value, 
Sergei Golubchik's avatar
cleanup  
Sergei Golubchik committed
3758
                           wild->ptr(), wild->length());
3759 3760
      lookup_field_values->wild_table_value= 1;
    }
3761
    break;
3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772
  case SQLCOM_SHOW_PLUGINS:
    if (lex->ident.str)
      thd->make_lex_string(&lookup_field_values->db_value, 
                           lex->ident.str, lex->ident.length);
    else if (lex->wild)
    {
      thd->make_lex_string(&lookup_field_values->db_value, 
                           lex->wild->ptr(), lex->wild->length());
      lookup_field_values->wild_db_value= 1;
    }
    break;
3773 3774 3775 3776 3777
  default:
    /*
      The "default" is for queries over I_S.
      All previous cases handle SHOW commands.
    */
3778 3779
    rc= calc_lookup_values_from_cond(thd, cond, tables, lookup_field_values);
    break;
3780
  }
3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795

  if (lower_case_table_names && !rc)
  {
    /* 
      We can safely do in-place upgrades here since all of the above cases
      are allocating a new memory buffer for these strings.
    */  
    if (lookup_field_values->db_value.str && lookup_field_values->db_value.str[0])
      my_casedn_str(system_charset_info, lookup_field_values->db_value.str);
    if (lookup_field_values->table_value.str && 
        lookup_field_values->table_value.str[0])
      my_casedn_str(system_charset_info, lookup_field_values->table_value.str);
  }

  return rc;
3796 3797 3798
}


3799 3800 3801 3802 3803 3804
enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
{
  return (enum enum_schema_tables) (schema_table - &schema_tables[0]);
}


unknown's avatar
unknown committed
3805
/*
3806
  Create db names list. Information schema name always is first in list
unknown's avatar
unknown committed
3807 3808

  SYNOPSIS
3809
    make_db_list()
unknown's avatar
unknown committed
3810 3811 3812
    thd                   thread handler
    files                 list of db names
    wild                  wild string
3813 3814
    idx_field_vals        idx_field_vals->db_name contains db name or
                          wild string
unknown's avatar
unknown committed
3815 3816

  RETURN
3817 3818
    zero                  success
    non-zero              error
unknown's avatar
unknown committed
3819 3820
*/

3821
int make_db_list(THD *thd, Dynamic_array<LEX_STRING*> *files,
3822
                 LOOKUP_FIELD_VALUES *lookup_field_vals)
3823
{
3824
  if (lookup_field_vals->wild_db_value)
unknown's avatar
unknown committed
3825
  {
3826 3827 3828 3829 3830
    /*
      This part of code is only for SHOW DATABASES command.
      idx_field_vals->db_value can be 0 when we don't use
      LIKE clause (see also get_index_field_values() function)
    */
3831
    if (!lookup_field_vals->db_value.str ||
3832
        !wild_case_compare(system_charset_info,
3833
                           INFORMATION_SCHEMA_NAME.str,
3834
                           lookup_field_vals->db_value.str))
3835
    {
3836
      if (files->append_val(&INFORMATION_SCHEMA_NAME))
3837 3838
        return 1;
    }
3839
    return find_files(thd, files, 0, mysql_data_home,
3840
                      &lookup_field_vals->db_value);
unknown's avatar
unknown committed
3841
  }
3842

3843

3844
  /*
3845
    If we have db lookup vaule we just add it to list and
3846 3847 3848
    exit from the function.
    We don't do this for database names longer than the maximum
    path length.
3849
  */
3850 3851
  if (lookup_field_vals->db_value.str && 
      lookup_field_vals->db_value.length < FN_REFLEN)
3852
  {
3853 3854
    if (is_infoschema_db(lookup_field_vals->db_value.str,
                         lookup_field_vals->db_value.length))
3855
    {
3856
      if (files->append_val(&INFORMATION_SCHEMA_NAME))
3857 3858
        return 1;
      return 0;
3859
    }
3860
    if (files->append_val(&lookup_field_vals->db_value))
3861 3862
      return 1;
    return 0;
3863 3864
  }

3865 3866 3867 3868
  /*
    Create list of existing databases. It is used in case
    of select from information schema table
  */
3869
  if (files->append_val(&INFORMATION_SCHEMA_NAME))
3870
    return 1;
3871
  return find_files(thd, files, 0, mysql_data_home, &null_lex_str);
3872 3873
}

3874

3875
struct st_add_schema_table
unknown's avatar
unknown committed
3876
{
3877
  Dynamic_array<LEX_STRING*> *files;
unknown's avatar
unknown committed
3878 3879 3880
  const char *wild;
};

3881

unknown's avatar
WL#2936  
unknown committed
3882
static my_bool add_schema_table(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
3883 3884
                                void* p_data)
{
3885
  LEX_STRING *file_name= 0;
unknown's avatar
unknown committed
3886
  st_add_schema_table *data= (st_add_schema_table *)p_data;
3887
  Dynamic_array<LEX_STRING*> *file_list= data->files;
unknown's avatar
unknown committed
3888
  const char *wild= data->wild;
unknown's avatar
WL#2936  
unknown committed
3889
  ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
unknown's avatar
unknown committed
3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906
  DBUG_ENTER("add_schema_table");

  if (schema_table->hidden)
      DBUG_RETURN(0);
  if (wild)
  {
    if (lower_case_table_names)
    {
      if (wild_case_compare(files_charset_info,
                            schema_table->table_name,
                            wild))
        DBUG_RETURN(0);
    }
    else if (wild_compare(schema_table->table_name, wild, 0))
      DBUG_RETURN(0);
  }

3907 3908
  if ((file_name= thd->make_lex_string(schema_table->table_name,
                                       strlen(schema_table->table_name))) &&
3909
      !file_list->append(file_name))
3910 3911
    DBUG_RETURN(0);
  DBUG_RETURN(1);
unknown's avatar
unknown committed
3912
}
3913

3914

3915 3916
int schema_tables_add(THD *thd, Dynamic_array<LEX_STRING*> *files,
                      const char *wild)
3917
{
3918
  LEX_STRING *file_name= 0;
3919
  ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
unknown's avatar
unknown committed
3920 3921 3922
  st_add_schema_table add_data;
  DBUG_ENTER("schema_tables_add");

3923
  for (; tmp_schema_table->table_name; tmp_schema_table++)
3924
  {
3925 3926
    if (tmp_schema_table->hidden)
      continue;
3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938
    if (wild)
    {
      if (lower_case_table_names)
      {
        if (wild_case_compare(files_charset_info,
                              tmp_schema_table->table_name,
                              wild))
          continue;
      }
      else if (wild_compare(tmp_schema_table->table_name, wild, 0))
        continue;
    }
3939
    if ((file_name=
3940 3941
         thd->make_lex_string(tmp_schema_table->table_name,
                              strlen(tmp_schema_table->table_name))) &&
3942
        !files->append(file_name))
3943 3944
      continue;
    DBUG_RETURN(1);
3945
  }
unknown's avatar
unknown committed
3946 3947 3948 3949 3950 3951 3952 3953

  add_data.files= files;
  add_data.wild= wild;
  if (plugin_foreach(thd, add_schema_table,
                     MYSQL_INFORMATION_SCHEMA_PLUGIN, &add_data))
      DBUG_RETURN(1);

  DBUG_RETURN(0);
3954 3955 3956
}


3957 3958
/**
  @brief          Create table names list
3959

3960 3961
  @details        The function creates the list of table names in
                  database
3962

3963 3964 3965 3966 3967
  @param[in]      thd                   thread handler
  @param[in]      table_names           List of table names in database
  @param[in]      lex                   pointer to LEX struct
  @param[in]      lookup_field_vals     pointer to LOOKUP_FIELD_VALUE struct
  @param[in]      db_name               database name
3968

3969 3970 3971 3972 3973
  @return         Operation status
    @retval       0           ok
    @retval       1           fatal error
    @retval       2           Not fatal error; Safe to ignore this file list
*/
3974

3975
static int
3976 3977
make_table_name_list(THD *thd, Dynamic_array<LEX_STRING*> *table_names,
                     LEX *lex, LOOKUP_FIELD_VALUES *lookup_field_vals,
3978
                     LEX_STRING *db_name)
3979
{
3980 3981
  char path[FN_REFLEN + 1];
  build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0);
3982 3983
  if (!lookup_field_vals->wild_table_value &&
      lookup_field_vals->table_value.str)
3984
  {
3985
    if (db_name == &INFORMATION_SCHEMA_NAME)
3986
    {
3987
      LEX_STRING *name;
3988 3989 3990
      ST_SCHEMA_TABLE *schema_table=
        find_schema_table(thd, lookup_field_vals->table_value.str);
      if (schema_table && !schema_table->hidden)
3991
      {
3992 3993
        if (!(name= thd->make_lex_string(schema_table->table_name,
                                         strlen(schema_table->table_name))) ||
3994
            table_names->append(name))
3995 3996 3997 3998
          return 1;
      }
    }
    else
3999
    {
4000
      if (table_names->append_val(&lookup_field_vals->table_value))
4001 4002 4003 4004 4005 4006 4007 4008 4009
        return 1;
    }
    return 0;
  }

  /*
    This call will add all matching the wildcards (if specified) IS tables
    to the list
  */
4010
  if (db_name == &INFORMATION_SCHEMA_NAME)
4011 4012 4013
    return (schema_tables_add(thd, table_names,
                              lookup_field_vals->table_value.str));

4014
  find_files_result res= find_files(thd, table_names, db_name, path,
4015
                                    &lookup_field_vals->table_value);
4016 4017 4018 4019 4020 4021 4022
  if (res != FIND_FILES_OK)
  {
    /*
      Downgrade errors about problems with database directory to
      warnings if this is not a 'SHOW' command.  Another thread
      may have dropped database, and we may still have a name
      for that directory.
4023
    */
4024 4025
    if (res == FIND_FILES_DIR)
    {
4026
      if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)
4027 4028 4029 4030 4031
        return 1;
      thd->clear_error();
      return 2;
    }
    return 1;
4032
  }
4033 4034
  return 0;
}
4035

4036

4037
/**
4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049
  Fill I_S table with data obtained by performing full-blown table open.

  @param  thd                       Thread handler.
  @param  is_show_fields_or_keys    Indicates whether it is a legacy SHOW
                                    COLUMNS or SHOW KEYS statement.
  @param  table                     TABLE object for I_S table to be filled.
  @param  schema_table              I_S table description structure.
  @param  orig_db_name              Database name.
  @param  orig_table_name           Table name.
  @param  open_tables_state_backup  Open_tables_state object which is used
                                    to save/restore original status of
                                    variables related to open tables state.
4050 4051 4052 4053
  @param  can_deadlock              Indicates that deadlocks are possible
                                    due to metadata locks, so to avoid
                                    them we should not wait in case if
                                    conflicting lock is present.
4054 4055 4056

  @retval FALSE - Success.
  @retval TRUE  - Failure.
4057
*/
4058 4059 4060 4061 4062
static bool
fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
                          TABLE *table, ST_SCHEMA_TABLE *schema_table,
                          LEX_STRING *orig_db_name,
                          LEX_STRING *orig_table_name,
4063 4064
                          Open_tables_backup *open_tables_state_backup,
                          bool can_deadlock)
4065
{
4066
  Query_arena i_s_arena(thd->mem_root,
4067
                        Query_arena::STMT_CONVENTIONAL_EXECUTION),
4068 4069 4070 4071 4072
              backup_arena, *old_arena;
  LEX *old_lex= thd->lex, temp_lex, *lex;
  LEX_STRING db_name, table_name;
  TABLE_LIST *table_list;
  bool result= true;
4073
  DBUG_ENTER("fill_schema_table_by_open");
4074 4075

  /*
4076 4077 4078 4079
    When a view is opened its structures are allocated on a permanent
    statement arena and linked into the LEX tree for the current statement
    (this happens even in cases when view is handled through TEMPTABLE
    algorithm).
4080

4081 4082 4083
    To prevent this process from unnecessary hogging of memory in the permanent
    arena of our I_S query and to avoid damaging its LEX we use temporary
    arena and LEX for table/view opening.
4084

4085 4086
    Use temporary arena instead of statement permanent arena. Also make
    it active arena and save original one for successive restoring.
4087
  */
4088 4089 4090
  old_arena= thd->stmt_arena;
  thd->stmt_arena= &i_s_arena;
  thd->set_n_backup_active_arena(&i_s_arena, &backup_arena);
4091

4092 4093 4094 4095 4096 4097
  /* Prepare temporary LEX. */
  thd->lex= lex= &temp_lex;
  lex_start(thd);

  /* Disable constant subquery evaluation as we won't be locking tables. */
  lex->context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW;
4098 4099

  /*
4100 4101
    Some of process_table() functions rely on wildcard being passed from
    old LEX (or at least being initialized).
4102
  */
4103
  lex->wild= old_lex->wild;
4104 4105

  /*
4106 4107 4108 4109
    Since make_table_list() might change database and table name passed
    to it we create copies of orig_db_name and orig_table_name here.
    These copies are used for make_table_list() while unaltered values
    are passed to process_table() functions.
4110
  */
4111 4112 4113 4114
  if (!thd->make_lex_string(&db_name,
                            orig_db_name->str, orig_db_name->length) ||
      !thd->make_lex_string(&table_name,
                            orig_table_name->str, orig_table_name->length))
4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146
    goto end;

  /*
    Create table list element for table to be open. Link it with the
    temporary LEX. The latter is required to correctly open views and
    produce table describing their structure.
  */
  if (make_table_list(thd, &lex->select_lex, &db_name, &table_name))
    goto end;

  table_list= lex->select_lex.table_list.first;

  if (is_show_fields_or_keys)
  {
    /*
      Restore thd->temporary_tables to be able to process
      temporary tables (only for 'show index' & 'show columns').
      This should be changed when processing of temporary tables for
      I_S tables will be done.
    */
    thd->temporary_tables= open_tables_state_backup->temporary_tables;
  }
  else
  {
    /*
      Apply optimization flags for table opening which are relevant for
      this I_S table. We can't do this for SHOW COLUMNS/KEYS because of
      backward compatibility.
    */
    table_list->i_s_requested_object= schema_table->i_s_requested_object;
  }

4147 4148 4149 4150
  /*
    Let us set fake sql_command so views won't try to merge
    themselves into main statement. If we don't do this,
    SELECT * from information_schema.xxxx will cause problems.
4151 4152
    SQLCOM_SHOW_FIELDS is used because it satisfies
    'only_view_structure()'.
4153 4154
  */
  lex->sql_command= SQLCOM_SHOW_FIELDS;
4155
  result= open_normal_and_derived_tables(thd, table_list,
4156 4157 4158
                                         (MYSQL_OPEN_IGNORE_FLUSH |
                                          MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
                                          (can_deadlock ?
Sergei Golubchik's avatar
Sergei Golubchik committed
4159 4160
                                           MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)),
                                         DT_PREPARE | DT_CREATE);
4161 4162 4163 4164 4165
  /*
    Restore old value of sql_command back as it is being looked at in
    process_table() function.
  */
  lex->sql_command= old_lex->sql_command;
4166 4167 4168

  DEBUG_SYNC(thd, "after_open_table_ignore_flush");

4169
  /*
4170 4171 4172 4173 4174 4175 4176 4177 4178
    XXX:  show_table_list has a flag i_is_requested,
    and when it's set, open_normal_and_derived_tables()
    can return an error without setting an error message
    in THD, which is a hack. This is why we have to
    check for res, then for thd->is_error() and only then
    for thd->main_da.sql_errno().

    Again we don't do this for SHOW COLUMNS/KEYS because
    of backward compatibility.
4179
  */
4180
  if (!is_show_fields_or_keys && result && thd->is_error() &&
4181 4182
      (thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE ||
       thd->stmt_da->sql_errno() == ER_WRONG_OBJECT))
4183 4184 4185 4186
  {
    /*
      Hide error for a non-existing table.
      For example, this error can occur when we use a where condition
4187 4188
      with a db name and table, but the table does not exist or
      there is a view with the same name.
4189
    */
4190
    result= false;
4191 4192 4193 4194 4195 4196 4197 4198 4199 4200
    thd->clear_error();
  }
  else
  {
    result= schema_table->process_table(thd, table_list,
                                        table, result,
                                        orig_db_name,
                                        orig_table_name);
  }

4201

4202 4203 4204 4205 4206 4207
end:
  lex->unit.cleanup();

  /* Restore original LEX value, statement's arena and THD arena values. */
  lex_end(thd->lex);

4208 4209 4210
  // Free items, before restoring backup_arena below.
  DBUG_ASSERT(i_s_arena.free_list == NULL);
  thd->free_items();
4211

4212
  /*
4213 4214
    For safety reset list of open temporary tables before closing
    all tables open within this Open_tables_state.
4215
  */
4216 4217
  thd->temporary_tables= NULL;
  close_thread_tables(thd);
4218 4219 4220 4221
  /*
    Release metadata lock we might have acquired.
    See comment in fill_schema_table_from_frm() for details.
  */
4222 4223
  thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);

4224
  thd->lex= old_lex;
4225

4226 4227
  thd->stmt_arena= old_arena;
  thd->restore_active_arena(&i_s_arena, &backup_arena);
4228

4229
  DBUG_RETURN(result);
4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245
}


/**
  @brief          Fill I_S table for SHOW TABLE NAMES commands

  @param[in]      thd                      thread handler
  @param[in]      table                    TABLE struct for I_S table
  @param[in]      db_name                  database name
  @param[in]      table_name               table name

  @return         Operation status
    @retval       0           success
    @retval       1           error
*/

4246
static int fill_schema_table_names(THD *thd, TABLE_LIST *tables,
4247
                                   LEX_STRING *db_name, LEX_STRING *table_name)
4248
{
4249
  TABLE *table= tables->table;
4250
  if (db_name == &INFORMATION_SCHEMA_NAME)
4251 4252 4253 4254
  {
    table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
                           system_charset_info);
  }
4255
  else if (tables->table_open_method != SKIP_OPEN_TABLE)
4256
  {
4257 4258 4259 4260 4261 4262 4263 4264
    CHARSET_INFO *cs= system_charset_info;
    handlerton *hton;
    if (ha_table_exists(thd, db_name->str, table_name->str, &hton))
    {
      if (hton == view_pseudo_hton)
        table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
      else
        table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
4265
    }
4266 4267 4268
    else
      table->field[3]->store(STRING_WITH_LEN("ERROR"), cs);

Marc Alff's avatar
Marc Alff committed
4269
    if (thd->is_error() && thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296
    {
      thd->clear_error();
      return 0;
    }
  }
  if (schema_table_store_record(thd, table))
    return 1;
  return 0;
}


/**
  @brief          Get open table method

  @details        The function calculates the method which will be used
                  for table opening:
                  SKIP_OPEN_TABLE - do not open table
                  OPEN_FRM_ONLY   - open FRM file only
                  OPEN_FULL_TABLE - open FRM, data, index files
  @param[in]      tables               I_S table table_list
  @param[in]      schema_table         I_S table struct
  @param[in]      schema_table_idx     I_S table index

  @return         return a set of flags
    @retval       SKIP_OPEN_TABLE | OPEN_FRM_ONLY | OPEN_FULL_TABLE
*/

4297
uint get_table_open_method(TABLE_LIST *tables,
4298 4299 4300 4301 4302 4303 4304 4305 4306 4307
                                  ST_SCHEMA_TABLE *schema_table,
                                  enum enum_schema_tables schema_table_idx)
{
  /*
    determine which method will be used for table opening
  */
  if (schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
  {
    Field **ptr, *field;
    int table_open_method= 0, field_indx= 0;
4308 4309
    uint star_table_open_method= OPEN_FULL_TABLE;
    bool used_star= true;                  // true if '*' is used in select
4310 4311
    for (ptr=tables->table->field; (field= *ptr) ; ptr++)
    {
4312 4313 4314
      star_table_open_method=
        min(star_table_open_method,
            schema_table->fields_info[field_indx].open_method);
4315
      if (bitmap_is_set(tables->table->read_set, field->field_index))
4316 4317
      {
        used_star= false;
4318
        table_open_method|= schema_table->fields_info[field_indx].open_method;
4319
      }
4320 4321
      field_indx++;
    }
4322 4323
    if (used_star)
      return star_table_open_method;
4324 4325 4326 4327 4328 4329 4330
    return table_open_method;
  }
  /* I_S tables which use get_all_tables but can not be optimized */
  return (uint) OPEN_FULL_TABLE;
}


Konstantin Osipov's avatar
Konstantin Osipov committed
4331
/**
Konstantin Osipov's avatar
Konstantin Osipov committed
4332 4333
   Try acquire high priority share metadata lock on a table (with
   optional wait for conflicting locks to go away).
Konstantin Osipov's avatar
Konstantin Osipov committed
4334 4335

   @param thd            Thread context.
Konstantin Osipov's avatar
Konstantin Osipov committed
4336
   @param mdl_request    Pointer to memory to be used for MDL_request
Konstantin Osipov's avatar
Konstantin Osipov committed
4337 4338
                         object for a lock request.
   @param table          Table list element for the table
Konstantin Osipov's avatar
Konstantin Osipov committed
4339 4340 4341
   @param can_deadlock   Indicates that deadlocks are possible due to
                         metadata locks, so to avoid them we should not
                         wait in case if conflicting lock is present.
Konstantin Osipov's avatar
Konstantin Osipov committed
4342 4343 4344 4345 4346 4347 4348

   @note This is an auxiliary function to be used in cases when we want to
         access table's description by looking up info in TABLE_SHARE without
         going through full-blown table open.
   @note This function assumes that there are no other metadata lock requests
         in the current metadata locking context.

Konstantin Osipov's avatar
Konstantin Osipov committed
4349 4350
   @retval FALSE  No error, if lock was obtained TABLE_LIST::mdl_request::ticket
                  is set to non-NULL value.
Konstantin Osipov's avatar
Konstantin Osipov committed
4351 4352 4353 4354
   @retval TRUE   Some error occured (probably thread was killed).
*/

static bool
Konstantin Osipov's avatar
Konstantin Osipov committed
4355 4356
try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
                                      bool can_deadlock)
Konstantin Osipov's avatar
Konstantin Osipov committed
4357 4358
{
  bool error;
Konstantin Osipov's avatar
Konstantin Osipov committed
4359
  table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
4360
                          MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION);
4361 4362

  if (can_deadlock)
Konstantin Osipov's avatar
Konstantin Osipov committed
4363
  {
4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376
    /*
      When .FRM is being open in order to get data for an I_S table,
      we might have some tables not only open but also locked.
      E.g. this happens when a SHOW or I_S statement is run
      under LOCK TABLES or inside a stored function.
      By waiting for the conflicting metadata lock to go away we
      might create a deadlock which won't entirely belong to the
      MDL subsystem and thus won't be detectable by this subsystem's
      deadlock detector. To avoid such situation, when there are
      other locked tables, we prefer not to wait on a conflicting
      lock.
    */
    error= thd->mdl_context.try_acquire_lock(&table->mdl_request);
Konstantin Osipov's avatar
Konstantin Osipov committed
4377
  }
4378 4379 4380 4381
  else
    error= thd->mdl_context.acquire_lock(&table->mdl_request,
                                         thd->variables.lock_wait_timeout);

Konstantin Osipov's avatar
Konstantin Osipov committed
4382
  return error;
Konstantin Osipov's avatar
Konstantin Osipov committed
4383 4384 4385
}


4386 4387 4388 4389 4390 4391 4392 4393 4394
/**
  @brief          Fill I_S table with data from FRM file only

  @param[in]      thd                      thread handler
  @param[in]      table                    TABLE struct for I_S table
  @param[in]      schema_table             I_S table struct
  @param[in]      db_name                  database name
  @param[in]      table_name               table name
  @param[in]      schema_table_idx         I_S table index
4395 4396 4397
  @param[in]      open_tables_state_backup Open_tables_state object which is used
                                           to save/restore original state of metadata
                                           locks.
Konstantin Osipov's avatar
Konstantin Osipov committed
4398 4399 4400 4401
  @param[in]      can_deadlock             Indicates that deadlocks are possible
                                           due to metadata locks, so to avoid
                                           them we should not wait in case if
                                           conflicting lock is present.
4402 4403 4404 4405 4406 4407 4408 4409

  @return         Operation status
    @retval       0           Table is processed and we can continue
                              with new table
    @retval       1           It's view and we have to use
                              open_tables function for this table
*/

Sergey Glukhov's avatar
Sergey Glukhov committed
4410 4411
static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
                                      ST_SCHEMA_TABLE *schema_table,
4412 4413
                                      LEX_STRING *db_name,
                                      LEX_STRING *table_name,
Konstantin Osipov's avatar
Konstantin Osipov committed
4414
                                      enum enum_schema_tables schema_table_idx,
4415
                                      Open_tables_backup *open_tables_state_backup,
Konstantin Osipov's avatar
Konstantin Osipov committed
4416
                                      bool can_deadlock)
4417
{
Sergey Glukhov's avatar
Sergey Glukhov committed
4418
  TABLE *table= tables->table;
4419
  TABLE_SHARE *share;
4420 4421
  TABLE tbl;
  TABLE_LIST table_list;
4422
  uint res= 0;
4423
  char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1];
4424

4425 4426
  bzero((char*) &table_list, sizeof(TABLE_LIST));
  bzero((char*) &tbl, sizeof(TABLE));
4427

4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447
  if (lower_case_table_names)
  {
    /*
      In lower_case_table_names > 0 metadata locking and table definition
      cache subsystems require normalized (lowercased) database and table
      names as input.
    */
    strmov(db_name_buff, db_name->str);
    strmov(table_name_buff, table_name->str);
    my_casedn_str(files_charset_info, db_name_buff);
    my_casedn_str(files_charset_info, table_name_buff);
    table_list.db= db_name_buff;
    table_list.table_name= table_name_buff;
  }
  else
  {
    table_list.table_name= table_name->str;
    table_list.db= db_name->str;
  }

4448 4449
  /*
    TODO: investigate if in this particular situation we can get by
4450 4451
          simply obtaining internal lock of the data-dictionary
          instead of obtaining full-blown metadata lock.
4452
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
4453
  if (try_acquire_high_prio_shared_mdl_lock(thd, &table_list, can_deadlock))
4454
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
4455 4456 4457 4458 4459 4460
    /*
      Some error occured (most probably we have been killed while
      waiting for conflicting locks to go away), let the caller to
      handle the situation.
    */
    return 1;
4461 4462
  }

Konstantin Osipov's avatar
Konstantin Osipov committed
4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478
  if (! table_list.mdl_request.ticket)
  {
    /*
      We are in situation when we have encountered conflicting metadata
      lock and deadlocks can occur due to waiting for it to go away.
      So instead of waiting skip this table with an appropriate warning.
    */
    DBUG_ASSERT(can_deadlock);

    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                        ER_WARN_I_S_SKIPPED_TABLE,
                        ER(ER_WARN_I_S_SKIPPED_TABLE),
                        table_list.db, table_list.table_name);
    return 0;
  }

Sergey Glukhov's avatar
Sergey Glukhov committed
4479 4480
  if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY)
  {
4481
    init_sql_alloc(&tbl.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
Sergey Glukhov's avatar
Sergey Glukhov committed
4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493
    if (!Table_triggers_list::check_n_load(thd, db_name->str,
                                           table_name->str, &tbl, 1))
    {
      table_list.table= &tbl;
      res= schema_table->process_table(thd, &table_list, table,
                                       res, db_name, table_name);
      delete tbl.triggers;
    }
    free_root(&tbl.mem_root, MYF(0));
    goto end;
  }

4494
  share= get_table_share(thd, table_list.db, table_list.table_name,
4495
                         GTS_TABLE | GTS_VIEW);
4496
  if (!share)
4497
  {
4498
    res= 0;
4499
    goto end;
4500
  }
Sergey Glukhov's avatar
Sergey Glukhov committed
4501

4502 4503 4504
  if (share->is_view)
  {
    if (schema_table->i_s_requested_object & OPEN_TABLE_ONLY)
4505
    {
4506 4507
      /* skip view processing */
      res= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
4508
      goto end_share;
4509
    }
4510 4511 4512
    else if (schema_table->i_s_requested_object & OPEN_VIEW_FULL)
    {
      /*
Sergey Glukhov's avatar
Sergey Glukhov committed
4513
        tell get_all_tables() to fall back to
4514 4515 4516
        open_normal_and_derived_tables()
      */
      res= 1;
Konstantin Osipov's avatar
Konstantin Osipov committed
4517
      goto end_share;
4518
    }
4519

Sergey Glukhov's avatar
Sergey Glukhov committed
4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532
    if (open_new_frm(thd, share, table_name->str,
                     (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
                             HA_GET_INDEX | HA_TRY_READ_ONLY),
                     READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD |
                     OPEN_VIEW_NO_PARSE,
                     thd->open_options, &tbl, &table_list, thd->mem_root))
      goto end_share;
    table_list.view= (LEX*) share->is_view;
    res= schema_table->process_table(thd, &table_list, table,
                                     res, db_name, table_name);
    goto end_share;
  }

4533 4534 4535
  if (!open_table_from_share(thd, share, table_name->str, 0,
                             (EXTRA_RECORD | OPEN_FRM_FILE_ONLY),
                             thd->open_options, &tbl, FALSE))
4536 4537 4538
  {
    tbl.s= share;
    table_list.table= &tbl;
Konstantin Osipov's avatar
Konstantin Osipov committed
4539
    table_list.view= (LEX*) share->is_view;
4540 4541
    res= schema_table->process_table(thd, &table_list, table,
                                     res, db_name, table_name);
4542
    free_root(&tbl.mem_root, MYF(0));
4543 4544
  }

4545

Konstantin Osipov's avatar
Konstantin Osipov committed
4546
end_share:
4547
  mysql_mutex_lock(&LOCK_open);
Konstantin Osipov's avatar
Konstantin Osipov committed
4548
  release_table_share(share);
Marc Alff's avatar
Marc Alff committed
4549
  mysql_mutex_unlock(&LOCK_open);
4550

Sergey Glukhov's avatar
Sergey Glukhov committed
4551
end:
4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570
  /*
    Release metadata lock we might have acquired.

    Without this step metadata locks acquired for each table processed
    will be accumulated. In situation when a lot of tables are processed
    by I_S query this will result in transaction with too many metadata
    locks. As result performance of acquisition of new lock will suffer.

    Of course, the fact that we don't hold metadata lock on tables which
    were processed till the end of I_S query makes execution less isolated
    from concurrent DDL. Consequently one might get 'dirty' results from
    such a query. But we have never promised serializability of I_S queries
    anyway.

    We don't have any tables open since we took backup, so rolling back to
    savepoint is safe.
  */
  DBUG_ASSERT(thd->open_tables == NULL);
  thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
4571 4572
  thd->clear_error();
  return res;
4573
}
4574

4575

4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614
/**
  Trigger_error_handler is intended to intercept and silence SQL conditions
  that might happen during trigger loading for SHOW statements.
  The potential SQL conditions are:

    - ER_PARSE_ERROR -- this error is thrown if a trigger definition file
      is damaged or contains invalid CREATE TRIGGER statement. That should
      not happen in normal life.

    - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a
      trigger created/imported in/from the version of MySQL, which does not
      support trigger definers.

    - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a
      trigger created/imported in/from the version of MySQL, which does not
      support trigger creation contexts.
*/

class Trigger_error_handler : public Internal_error_handler
{
public:
  bool handle_condition(THD *thd,
                        uint sql_errno,
                        const char* sqlstate,
                        MYSQL_ERROR::enum_warning_level level,
                        const char* msg,
                        MYSQL_ERROR ** cond_hdl)
  {
    if (sql_errno == ER_PARSE_ERROR ||
        sql_errno == ER_TRG_NO_DEFINER ||
        sql_errno == ER_TRG_NO_CREATION_CTX)
      return true;

    return false;
  }
};



4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633
/**
  @brief          Fill I_S tables whose data are retrieved
                  from frm files and storage engine

  @details        The information schema tables are internally represented as
                  temporary tables that are filled at query execution time.
                  Those I_S tables whose data are retrieved
                  from frm files and storage engine are filled by the function
                  get_all_tables().

  @param[in]      thd                      thread handler
  @param[in]      tables                   I_S table
  @param[in]      cond                     'WHERE' condition

  @return         Operation status
    @retval       0                        success
    @retval       1                        error
*/

4634 4635 4636 4637
int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  LEX *lex= thd->lex;
  TABLE *table= tables->table;
4638
  TABLE_LIST table_acl_check;
unknown's avatar
unknown committed
4639
  SELECT_LEX *lsel= tables->schema_select_lex;
4640
  ST_SCHEMA_TABLE *schema_table= tables->schema_table;
4641
  LOOKUP_FIELD_VALUES lookup_field_vals;
4642
  enum enum_schema_tables schema_table_idx;
4643
  Dynamic_array<LEX_STRING*> db_names;
4644
  COND *partial_cond= 0;
unknown's avatar
unknown committed
4645
  int error= 1;
4646
  Open_tables_backup open_tables_state_backup;
4647 4648 4649
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  Security_context *sctx= thd->security_ctx;
#endif
4650
  uint table_open_method;
Konstantin Osipov's avatar
Konstantin Osipov committed
4651
  bool can_deadlock;
4652 4653
  DBUG_ENTER("get_all_tables");

Konstantin Osipov's avatar
Konstantin Osipov committed
4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664
  /*
    In cases when SELECT from I_S table being filled by this call is
    part of statement which also uses other tables or is being executed
    under LOCK TABLES or is part of transaction which also uses other
    tables waiting for metadata locks which happens below might result
    in deadlocks.
    To avoid them we don't wait if conflicting metadata lock is
    encountered and skip table with emitting an appropriate warning.
  */
  can_deadlock= thd->mdl_context.has_locks();

4665
  /*
4666 4667
    We should not introduce deadlocks even if we already have some
    tables open and locked, since we won't lock tables which we will
Konstantin Osipov's avatar
Konstantin Osipov committed
4668 4669
    open and will ignore pending exclusive metadata locks for these
    tables by using high-priority requests for shared metadata locks.
4670
  */
4671 4672
  thd->reset_n_backup_open_tables_state(&open_tables_state_backup);

Sergey Glukhov's avatar
Sergey Glukhov committed
4673 4674 4675 4676
  schema_table_idx= get_schema_table_idx(schema_table);
  tables->table_open_method= table_open_method=
    get_table_open_method(tables, schema_table, schema_table_idx);
  DBUG_PRINT("open_method", ("%d", tables->table_open_method));
4677 4678 4679 4680 4681
  /* 
    this branch processes SHOW FIELDS, SHOW INDEXES commands.
    see sql_parse.cc, prepare_schema_table() function where
    this values are initialized
  */
4682
  if (lsel && lsel->table_list.first)
4683
  {
4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694
    LEX_STRING db_name, table_name;

    db_name.str= lsel->table_list.first->db;
    db_name.length= lsel->table_list.first->db_length;

    table_name.str= lsel->table_list.first->table_name;
    table_name.length= lsel->table_list.first->table_name_length;

    error= fill_schema_table_by_open(thd, TRUE,
                                     table, schema_table,
                                     &db_name, &table_name,
4695 4696
                                     &open_tables_state_backup,
                                     can_deadlock);
unknown's avatar
unknown committed
4697
    goto err;
4698 4699
  }

4700 4701 4702 4703 4704
  if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
  {
    error= 0;
    goto err;
  }
4705

Sergei Golubchik's avatar
Sergei Golubchik committed
4706 4707 4708
  DBUG_PRINT("info",("db_name='%s', table_name='%s'",
                     lookup_field_vals.db_value.str,
                     lookup_field_vals.table_value.str));
4709

4710 4711
  if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
  {
4712
    /*
4713 4714 4715
      if lookup value is empty string then
      it's impossible table name or db name
    */
Staale Smedseng's avatar
Staale Smedseng committed
4716 4717 4718 4719
    if ((lookup_field_vals.db_value.str &&
         !lookup_field_vals.db_value.str[0]) ||
        (lookup_field_vals.table_value.str &&
         !lookup_field_vals.table_value.str[0]))
4720 4721 4722 4723 4724 4725 4726 4727
    {
      error= 0;
      goto err;
    }
  }

  if (lookup_field_vals.db_value.length &&
      !lookup_field_vals.wild_db_value)
4728 4729
    tables->has_db_lookup_value= TRUE;
  if (lookup_field_vals.table_value.length &&
4730
      !lookup_field_vals.wild_table_value)
4731
    tables->has_table_lookup_value= TRUE;
4732

4733 4734 4735 4736 4737
  if (tables->has_db_lookup_value && tables->has_table_lookup_value)
    partial_cond= 0;
  else
    partial_cond= make_cond_for_info_schema(cond, tables);

4738 4739 4740 4741
  if (lex->describe)
  {
    /* EXPLAIN SELECT */
    error= 0;
unknown's avatar
unknown committed
4742
    goto err;
4743
  }
4744

4745 4746
  bzero((char*) &table_acl_check, sizeof(table_acl_check));

4747
  if (make_db_list(thd, &db_names, &lookup_field_vals))
4748
    goto err;
4749
  for (size_t i=0; i < db_names.elements(); i++)
4750
  {
4751
    LEX_STRING *db_name= db_names.at(i);
4752
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4753 4754
    if (!(check_access(thd, SELECT_ACL, db_name->str,
                       &thd->col_access, NULL, 0, 1) ||
4755
          (!thd->col_access && check_grant_db(thd, db_name->str))) ||
4756
        sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
4757
        acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
4758 4759
#endif
    {
4760
      Dynamic_array<LEX_STRING*> table_names;
4761
      int res= make_table_name_list(thd, &table_names, lex,
4762
                                    &lookup_field_vals, db_name);
4763 4764 4765 4766 4767
      if (res == 2)   /* Not fatal error, continue */
        continue;
      if (res)
        goto err;

4768
      for (size_t i=0; i < table_names.elements(); i++)
4769
      {
4770
        LEX_STRING *table_name= table_names.at(i);
4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783

#ifndef NO_EMBEDDED_ACCESS_CHECKS
        if (!(thd->col_access & TABLE_ACLS))
        {
          table_acl_check.db= db_name->str;
          table_acl_check.db_length= db_name->length;
          table_acl_check.table_name= table_name->str;
          table_acl_check.table_name_length= table_name->length;
          table_acl_check.grant.privilege= thd->col_access;
          if (check_grant(thd, TABLE_ACLS, &table_acl_check, TRUE, 1, TRUE))
            continue;
        }
#endif
4784 4785 4786 4787 4788 4789 4790
	restore_record(table, s->default_values);
        table->field[schema_table->idx_field1]->
          store(db_name->str, db_name->length, system_charset_info);
        table->field[schema_table->idx_field2]->
          store(table_name->str, table_name->length, system_charset_info);

        if (!partial_cond || partial_cond->val_int())
4791 4792
        {
          /*
4793
            If table is I_S.tables and open_table_method is 0 (eg SKIP_OPEN)
4794
            we can skip table opening and we don't have lookup value for
4795 4796
            table name or lookup value is wild string(table name list is
            already created by make_table_name_list() function).
4797
          */
4798 4799 4800
          if (!table_open_method && schema_table_idx == SCH_TABLES &&
              (!lookup_field_vals.table_value.length ||
               lookup_field_vals.wild_table_value))
4801
          {
4802
            table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
4803 4804
            if (schema_table_store_record(thd, table))
              goto err;      /* Out of space in temporary table */
4805 4806
            continue;
          }
4807

4808
          /* SHOW TABLE NAMES command */
4809 4810
          if (schema_table_idx == SCH_TABLE_NAMES)
          {
4811
            if (fill_schema_table_names(thd, tables, db_name, table_name))
4812
              continue;
4813 4814 4815
          }
          else
          {
Sergey Glukhov's avatar
Sergey Glukhov committed
4816
            if (!(table_open_method & ~OPEN_FRM_ONLY) &&
4817
                db_name != &INFORMATION_SCHEMA_NAME)
4818
            {
4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831
              /*
                Here we need to filter out warnings, which can happen
                during loading of triggers in fill_schema_table_from_frm(),
                because we don't need those warnings to pollute output of
                SELECT from I_S / SHOW-statements.
              */

              Trigger_error_handler err_handler;
              thd->push_internal_handler(&err_handler);

              int res= fill_schema_table_from_frm(thd, tables, schema_table,
                                                  db_name, table_name,
                                                  schema_table_idx,
4832
                                                  &open_tables_state_backup,
4833 4834 4835 4836 4837
                                                  can_deadlock);

              thd->pop_internal_handler();

              if (!res)
4838 4839 4840
                continue;
            }

4841
            DEBUG_SYNC(thd, "before_open_in_get_all_tables");
4842 4843 4844
            if (fill_schema_table_by_open(thd, FALSE,
                                          table, schema_table,
                                          db_name, table_name,
4845 4846
                                          &open_tables_state_backup,
                                          can_deadlock))
unknown's avatar
unknown committed
4847
              goto err;
4848 4849 4850 4851 4852
          }
        }
      }
    }
  }
unknown's avatar
unknown committed
4853 4854 4855

  error= 0;
err:
4856
  thd->restore_backup_open_tables_state(&open_tables_state_backup);
4857

unknown's avatar
unknown committed
4858
  DBUG_RETURN(error);
4859 4860 4861
}


4862
bool store_schema_shemata(THD* thd, TABLE *table, LEX_STRING *db_name,
4863
                          CHARSET_INFO *cs)
4864
{
4865
  restore_record(table, s->default_values);
4866
  table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
4867
  table->field[1]->store(db_name->str, db_name->length, system_charset_info);
4868 4869
  table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info);
  table->field[3]->store(cs->name, strlen(cs->name), system_charset_info);
4870
  return schema_table_store_record(thd, table);
4871 4872 4873
}


4874
int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
4875
{
4876 4877 4878 4879 4880
  /*
    TODO: fill_schema_shemata() is called when new client is connected.
    Returning error status in this case leads to client hangup.
  */

4881
  LOOKUP_FIELD_VALUES lookup_field_vals;
4882
  Dynamic_array<LEX_STRING*> db_names;
4883 4884
  HA_CREATE_INFO create;
  TABLE *table= tables->table;
4885
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4886
  Security_context *sctx= thd->security_ctx;
4887
#endif
4888
  DBUG_ENTER("fill_schema_shemata");
4889

4890 4891
  if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
    DBUG_RETURN(0);
4892
  DBUG_PRINT("INDEX VALUES",("db_name: %s  table_name: %s",
Sergei Golubchik's avatar
Sergei Golubchik committed
4893 4894
                             lookup_field_vals.db_value.str,
                             lookup_field_vals.table_value.str));
4895
  if (make_db_list(thd, &db_names, &lookup_field_vals))
4896
    DBUG_RETURN(1);
4897

4898 4899 4900
  /*
    If we have lookup db value we should check that the database exists
  */
4901
  if(lookup_field_vals.db_value.str && !lookup_field_vals.wild_db_value &&
4902
     db_names.at(0) != &INFORMATION_SCHEMA_NAME)
4903 4904 4905 4906 4907 4908
  {
    char path[FN_REFLEN+16];
    uint path_len;
    MY_STAT stat_info;
    if (!lookup_field_vals.db_value.str[0])
      DBUG_RETURN(0);
4909
    path_len= build_table_filename(path, sizeof(path) - 1,
4910 4911
                                   lookup_field_vals.db_value.str, "", "", 0);
    path[path_len-1]= 0;
Marc Alff's avatar
Marc Alff committed
4912
    if (!mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
4913 4914 4915
      DBUG_RETURN(0);
  }

4916
  for (size_t i=0; i < db_names.elements(); i++)
4917
  {
4918
    LEX_STRING *db_name= db_names.at(i);
4919
    if (db_name == &INFORMATION_SCHEMA_NAME)
4920
    {
4921
      if (store_schema_shemata(thd, table, db_name,
4922
                               system_charset_info))
4923
        DBUG_RETURN(1);
4924 4925
      continue;
    }
4926
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4927
    if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
4928 4929
	acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
	!check_grant_db(thd, db_name->str))
4930 4931
#endif
    {
4932 4933
      load_db_opt_by_name(thd, db_name->str, &create);
      if (store_schema_shemata(thd, table, db_name,
4934
                               create.default_table_charset))
4935
        DBUG_RETURN(1);
4936 4937
    }
  }
4938
  DBUG_RETURN(0);
4939 4940 4941
}


4942
static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
4943
				    TABLE *table, bool res,
4944 4945
				    LEX_STRING *db_name,
				    LEX_STRING *table_name)
4946 4947
{
  const char *tmp_buff;
4948
  MYSQL_TIME time;
4949
  int info_error= 0;
4950 4951
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_schema_tables_record");
4952 4953

  restore_record(table, s->default_values);
4954
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
4955 4956
  table->field[1]->store(db_name->str, db_name->length, cs);
  table->field[2]->store(table_name->str, table_name->length, cs);
4957

unknown's avatar
unknown committed
4958 4959
  if (res)
  {
4960
    /* There was a table open error, so set the table type and return */
4961 4962 4963 4964 4965 4966
    if (tables->view)
      table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
    else if (tables->schema_table)
      table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
    else
      table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
4967 4968

    goto err;
unknown's avatar
unknown committed
4969
  }
4970 4971

  if (tables->view)
4972
  {
4973 4974
    table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
    table->field[20]->store(STRING_WITH_LEN("VIEW"), cs);
4975 4976 4977
  }
  else
  {
4978
    char option_buff[350];
4979
    String str(option_buff,sizeof(option_buff), system_charset_info);
4980
    TABLE *show_table= tables->table;
4981
    TABLE_SHARE *share= show_table->s;
4982
    handler *file= show_table->file;
4983
    handlerton *tmp_db_type= share->db_type();
4984
#ifdef WITH_PARTITION_STORAGE_ENGINE
4985
    bool is_partitioned= FALSE;
4986
#endif
4987

4988
    if (share->tmp_table == SYSTEM_TMP_TABLE)
4989
      table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
4990
    else if (share->tmp_table)
4991
      table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs);
4992
    else
4993
      table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
4994

4995 4996
    for (int i= 4; i < 20; i++)
    {
4997
      if (i == 7 || (i > 12 && i < 17) || i == 18)
4998 4999 5000
        continue;
      table->field[i]->set_notnull();
    }
5001 5002 5003

    /* Collect table info from the table share */

5004 5005
#ifdef WITH_PARTITION_STORAGE_ENGINE
    if (share->db_type() == partition_hton &&
5006
        share->partition_info_str_len)
5007
    {
Sergei Golubchik's avatar
Sergei Golubchik committed
5008
      tmp_db_type= plugin_hton(share->default_part_plugin);
5009 5010
      is_partitioned= TRUE;
    }
5011
#endif
5012

5013
    tmp_buff= (char *) ha_resolve_storage_engine_name(tmp_db_type);
5014
    table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
5015
    table->field[5]->store((longlong) share->frm_version, TRUE);
5016

5017
    str.length(0);
5018

5019
    if (share->min_rows)
5020
    {
5021 5022
      str.qs_append(STRING_WITH_LEN(" min_rows="));
      str.qs_append(share->min_rows);
5023
    }
5024

5025
    if (share->max_rows)
5026
    {
5027 5028
      str.qs_append(STRING_WITH_LEN(" max_rows="));
      str.qs_append(share->max_rows);
5029
    }
5030

5031
    if (share->avg_row_length)
5032
    {
5033 5034
      str.qs_append(STRING_WITH_LEN(" avg_row_length="));
      str.qs_append(share->avg_row_length);
5035
    }
5036

5037
    if (share->db_create_options & HA_OPTION_PACK_KEYS)
5038
      str.qs_append(STRING_WITH_LEN(" pack_keys=1"));
5039

5040
    if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
5041
      str.qs_append(STRING_WITH_LEN(" pack_keys=0"));
5042

5043
    /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
5044
    if (share->db_create_options & HA_OPTION_CHECKSUM)
5045
      str.qs_append(STRING_WITH_LEN(" checksum=1"));
Sergei Golubchik's avatar
Sergei Golubchik committed
5046

5047
    if (share->page_checksum != HA_CHOICE_UNDEF)
5048 5049 5050 5051
    {
      str.qs_append(STRING_WITH_LEN(" page_checksum="));
      str.qs_append(ha_choice_values[(uint) share->page_checksum]);
    }
5052

5053
    if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
5054
      str.qs_append(STRING_WITH_LEN(" delay_key_write=1"));
5055

5056
    if (share->row_type != ROW_TYPE_DEFAULT)
5057 5058 5059 5060
    {
      str.qs_append(STRING_WITH_LEN(" row_format="));
      str.qs_append(ha_row_type[(uint) share->row_type]);
    }
5061

5062 5063
    if (share->key_block_size)
    {
5064 5065
      str.qs_append(STRING_WITH_LEN(" key_block_size="));
      str.qs_append(share->key_block_size);
5066
    }
5067

5068
#ifdef WITH_PARTITION_STORAGE_ENGINE
5069
    if (is_partitioned)
5070
      str.qs_append(STRING_WITH_LEN(" partitioned"));
5071
#endif
5072

5073
    if (share->transactional != HA_CHOICE_UNDEF)
Sergei Golubchik's avatar
Sergei Golubchik committed
5074 5075 5076 5077
    {
      str.qs_append(STRING_WITH_LEN(" transactional="));
      str.qs_append(ha_choice_values[(uint) share->transactional]);
    }
5078
    append_create_options(thd, &str, share->option_list);
Sergei Golubchik's avatar
Sergei Golubchik committed
5079

5080 5081
    if (str.length())
      table->field[19]->store(str.ptr()+1, str.length()-1, cs);
5082

5083 5084
    tmp_buff= (share->table_charset ?
               share->table_charset->name : "default");
5085

5086 5087
    table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);

5088 5089 5090
    if (share->comment.str)
      table->field[20]->store(share->comment.str, share->comment.length, cs);

5091 5092
    /* Collect table info from the storage engine  */

5093
    if(file)
5094
    {
5095 5096 5097
      /* If info() fails, then there's nothing else to do */
      if ((info_error= file->info(HA_STATUS_VARIABLE |
                                  HA_STATUS_TIME |
5098
                                  HA_STATUS_VARIABLE_EXTRA |
5099 5100 5101
                                  HA_STATUS_AUTO)) != 0)
        goto err;

5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125
      enum row_type row_type = file->get_row_type();
      switch (row_type) {
      case ROW_TYPE_NOT_USED:
      case ROW_TYPE_DEFAULT:
        tmp_buff= ((share->db_options_in_use &
                    HA_OPTION_COMPRESS_RECORD) ? "Compressed" :
                   (share->db_options_in_use & HA_OPTION_PACK_RECORD) ?
                   "Dynamic" : "Fixed");
        break;
      case ROW_TYPE_FIXED:
        tmp_buff= "Fixed";
        break;
      case ROW_TYPE_DYNAMIC:
        tmp_buff= "Dynamic";
        break;
      case ROW_TYPE_COMPRESSED:
        tmp_buff= "Compressed";
        break;
      case ROW_TYPE_REDUNDANT:
        tmp_buff= "Redundant";
        break;
      case ROW_TYPE_COMPACT:
        tmp_buff= "Compact";
        break;
5126
      case ROW_TYPE_PAGE:
unknown's avatar
unknown committed
5127
        tmp_buff= "Page";
5128 5129
        break;
      }
5130

5131
      table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
5132

5133
      if (!tables->schema_table)
5134
      {
5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156
        table->field[7]->store((longlong) file->stats.records, TRUE);
        table->field[7]->set_notnull();
      }
      table->field[8]->store((longlong) file->stats.mean_rec_length, TRUE);
      table->field[9]->store((longlong) file->stats.data_file_length, TRUE);
      if (file->stats.max_data_file_length)
      {
        table->field[10]->store((longlong) file->stats.max_data_file_length,
                                TRUE);
      }
      table->field[11]->store((longlong) file->stats.index_file_length, TRUE);
      table->field[12]->store((longlong) file->stats.delete_length, TRUE);
      if (show_table->found_next_number_field)
      {
        table->field[13]->store((longlong) file->stats.auto_increment_value,
                                TRUE);
        table->field[13]->set_notnull();
      }
      if (file->stats.create_time)
      {
        thd->variables.time_zone->gmt_sec_to_TIME(&time,
                                                  (my_time_t) file->stats.create_time);
5157
        table->field[14]->store_time(&time);
5158 5159 5160
        table->field[14]->set_notnull();
      }
      if (file->stats.update_time)
5161
      {
5162 5163
        thd->variables.time_zone->gmt_sec_to_TIME(&time,
                                                  (my_time_t) file->stats.update_time);
5164
        table->field[15]->store_time(&time);
5165 5166 5167 5168 5169 5170
        table->field[15]->set_notnull();
      }
      if (file->stats.check_time)
      {
        thd->variables.time_zone->gmt_sec_to_TIME(&time,
                                                  (my_time_t) file->stats.check_time);
5171
        table->field[16]->store_time(&time);
5172 5173
        table->field[16]->set_notnull();
      }
5174
      if (file->ha_table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM))
5175 5176 5177
      {
        table->field[18]->store((longlong) file->checksum(), TRUE);
        table->field[18]->set_notnull();
5178 5179
      }
    }
5180
  }
5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200

err:
  if (res || info_error)
  {
    /*
      If an error was encountered, push a warning, set the TABLE COMMENT
      column with the error text, and clear the error so that the operation
      can continue.
    */
    const char *error= thd->is_error() ? thd->stmt_da->message() : "";
    table->field[20]->store(error, strlen(error), cs);

    if (thd->is_error())
    {
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
      thd->clear_error();
    }
  }

5201
  DBUG_RETURN(schema_table_store_record(thd, table));
5202 5203 5204
}


Sergey Glukhov's avatar
Sergey Glukhov committed
5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216
/**
  @brief    Store field characteristics into appropriate I_S table columns

  @param[in]      table             I_S table
  @param[in]      field             processed field
  @param[in]      cs                I_S table charset
  @param[in]      offset            offset from beginning of table
                                    to DATE_TYPE column in I_S table
                                    
  @return         void
*/

Sergei Golubchik's avatar
Sergei Golubchik committed
5217 5218
static void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs,
                              uint offset)
Sergey Glukhov's avatar
Sergey Glukhov committed
5219 5220 5221 5222 5223 5224 5225 5226 5227
{
  bool is_blob;
  int decimals, field_length;
  const char *tmp_buff;
  char column_type_buff[MAX_FIELD_WIDTH];
  String column_type(column_type_buff, sizeof(column_type_buff), cs);

  field->sql_type(column_type);
  /* DTD_IDENTIFIER column */
Sergei Golubchik's avatar
Sergei Golubchik committed
5228 5229
  table->field[offset + 8]->store(column_type.ptr(), column_type.length(), cs);
  table->field[offset + 8]->set_notnull();
Sergey Glukhov's avatar
Sergey Glukhov committed
5230 5231 5232 5233 5234 5235
  /*
    DATA_TYPE column:
    MySQL column type has the following format:
    base_type [(dimension)] [unsigned] [zerofill].
    For DATA_TYPE column we extract only base type.
  */
Sergei Golubchik's avatar
Sergei Golubchik committed
5236
  tmp_buff= strchr(column_type.c_ptr_safe(), '(');
Sergey Glukhov's avatar
Sergey Glukhov committed
5237 5238 5239 5240 5241
  if (!tmp_buff)
    /*
      if there is no dimention part then check the presence of
      [unsigned] [zerofill] attributes and cut them of if exist.
    */
Sergei Golubchik's avatar
Sergei Golubchik committed
5242
    tmp_buff= strchr(column_type.c_ptr_safe(), ' ');
Sergey Glukhov's avatar
Sergey Glukhov committed
5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270
  table->field[offset]->store(column_type.ptr(),
                              (tmp_buff ? tmp_buff - column_type.ptr() :
                               column_type.length()), cs);

  is_blob= (field->type() == MYSQL_TYPE_BLOB);
  if (field->has_charset() || is_blob ||
      field->real_type() == MYSQL_TYPE_VARCHAR ||  // For varbinary type
      field->real_type() == MYSQL_TYPE_STRING)     // For binary type
  {
    uint32 octet_max_length= field->max_display_length();
    if (is_blob && octet_max_length != (uint32) 4294967295U)
      octet_max_length /= field->charset()->mbmaxlen;
    longlong char_max_len= is_blob ? 
      (longlong) octet_max_length / field->charset()->mbminlen :
      (longlong) octet_max_length / field->charset()->mbmaxlen;
    /* CHARACTER_MAXIMUM_LENGTH column*/
    table->field[offset + 1]->store(char_max_len, TRUE);
    table->field[offset + 1]->set_notnull();
    /* CHARACTER_OCTET_LENGTH column */
    table->field[offset + 2]->store((longlong) octet_max_length, TRUE);
    table->field[offset + 2]->set_notnull();
  }

  /*
    Calculate field_length and decimals.
    They are set to -1 if they should not be set (we should return NULL)
  */

Sergei Golubchik's avatar
Sergei Golubchik committed
5271
  field_length= -1;
Sergey Glukhov's avatar
Sergey Glukhov committed
5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285
  decimals= field->decimals();
  switch (field->type()) {
  case MYSQL_TYPE_NEWDECIMAL:
    field_length= ((Field_new_decimal*) field)->precision;
    break;
  case MYSQL_TYPE_DECIMAL:
    field_length= field->field_length - (decimals  ? 2 : 1);
    break;
  case MYSQL_TYPE_TINY:
  case MYSQL_TYPE_SHORT:
  case MYSQL_TYPE_LONG:
  case MYSQL_TYPE_INT24:
    field_length= field->max_display_length() - 1;
    break;
Georgi Kodinov's avatar
merge  
Georgi Kodinov committed
5286 5287 5288 5289
  case MYSQL_TYPE_LONGLONG:
    field_length= field->max_display_length() - 
      ((field->flags & UNSIGNED_FLAG) ? 0 : 1);
    break;
Sergey Glukhov's avatar
Sergey Glukhov committed
5290 5291 5292 5293 5294 5295 5296 5297 5298 5299
  case MYSQL_TYPE_BIT:
    field_length= field->max_display_length();
    decimals= -1;                             // return NULL
    break;
  case MYSQL_TYPE_FLOAT:  
  case MYSQL_TYPE_DOUBLE:
    field_length= field->field_length;
    if (decimals == NOT_FIXED_DEC)
      decimals= -1;                           // return NULL
    break;
Sergei Golubchik's avatar
Sergei Golubchik committed
5300 5301 5302 5303 5304 5305 5306
  case MYSQL_TYPE_TIME:
  case MYSQL_TYPE_TIMESTAMP:
  case MYSQL_TYPE_DATETIME:
    /* DATETIME_PRECISION column */
    table->field[offset + 5]->store((longlong) field->decimals(), TRUE);
    table->field[offset + 5]->set_notnull();
    break;
Sergey Glukhov's avatar
Sergey Glukhov committed
5307 5308 5309 5310 5311 5312 5313 5314 5315
  default:
    break;
  }

  /* NUMERIC_PRECISION column */
  if (field_length >= 0)
  {
    table->field[offset + 3]->store((longlong) field_length, TRUE);
    table->field[offset + 3]->set_notnull();
Sergei Golubchik's avatar
Sergei Golubchik committed
5316 5317 5318 5319 5320 5321 5322

    /* NUMERIC_SCALE column */
    if (decimals >= 0)
    {
      table->field[offset + 4]->store((longlong) decimals, TRUE);
      table->field[offset + 4]->set_notnull();
    }
Sergey Glukhov's avatar
Sergey Glukhov committed
5323 5324 5325 5326 5327 5328 5329
  }
  if (field->has_charset())
  {
    /* CHARACTER_SET_NAME column*/
    tmp_buff= field->charset()->csname;
    table->field[offset + 6]->store(tmp_buff, strlen(tmp_buff), cs);
    table->field[offset + 6]->set_notnull();
Sergei Golubchik's avatar
Sergei Golubchik committed
5330 5331 5332 5333
    /* COLLATION_NAME column */
    tmp_buff= field->charset()->name;
    table->field[offset + 7]->store(tmp_buff, strlen(tmp_buff), cs);
    table->field[offset + 7]->set_notnull();
Sergey Glukhov's avatar
Sergey Glukhov committed
5334 5335 5336 5337
  }
}


5338
static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
5339
				    TABLE *table, bool res,
5340 5341
				    LEX_STRING *db_name,
				    LEX_STRING *table_name)
5342
{
5343 5344
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
5345
  CHARSET_INFO *cs= system_charset_info;
5346
  TABLE *show_table;
5347
  Field **ptr, *field;
5348
  int count;
5349
  DBUG_ENTER("get_schema_column_record");
5350

5351 5352
  if (res)
  {
5353
    if (lex->sql_command != SQLCOM_SHOW_FIELDS)
5354 5355 5356 5357
    {
      /*
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
        rather than in SHOW COLUMNS
Sergey Glukhov's avatar
Sergey Glukhov committed
5358
      */
5359 5360
      if (thd->is_error())
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5361
                     thd->stmt_da->sql_errno(), thd->stmt_da->message());
5362 5363 5364 5365
      thd->clear_error();
      res= 0;
    }
    DBUG_RETURN(res);
5366 5367
  }

5368 5369
  show_table= tables->table;
  count= 0;
5370 5371 5372
  ptr= show_table->field;
  show_table->use_all_columns();               // Required for default
  restore_record(show_table, s->default_values);
Sergey Glukhov's avatar
Sergey Glukhov committed
5373 5374

  for (; (field= *ptr) ; ptr++)
5375
  {
5376
    uchar *pos;
5377 5378
    char tmp[MAX_FIELD_WIDTH];
    String type(tmp,sizeof(tmp), system_charset_info);
Sergey Glukhov's avatar
Sergey Glukhov committed
5379

5380
    DEBUG_SYNC(thd, "get_schema_column");
5381 5382 5383 5384 5385 5386 5387 5388

    if (wild && wild[0] &&
        wild_case_compare(system_charset_info, field->field_name,wild))
      continue;

    count++;
    /* Get default row, with all NULL fields set to NULL */
    restore_record(table, s->default_values);
5389 5390

#ifndef NO_EMBEDDED_ACCESS_CHECKS
5391
    uint col_access;
Sergey Glukhov's avatar
Sergey Glukhov committed
5392 5393 5394
    check_access(thd,SELECT_ACL, db_name->str,
                 &tables->grant.privilege, 0, 0, test(tables->schema_table));
    col_access= get_column_grant(thd, &tables->grant,
5395
                                 db_name->str, table_name->str,
5396
                                 field->field_name) & COL_ACLS;
5397
    if (!tables->schema_table && !col_access)
5398
      continue;
5399
    char *end= tmp;
5400 5401 5402
    for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
    {
      if (col_access & 1)
5403
      {
5404 5405
        *end++=',';
        end=strmov(end,grant_types.type_names[bitnr]);
5406
      }
5407
    }
5408
    table->field[18]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
5409

unknown's avatar
unknown committed
5410
#endif
5411
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
5412 5413
    table->field[1]->store(db_name->str, db_name->length, cs);
    table->field[2]->store(table_name->str, table_name->length, cs);
5414 5415
    table->field[3]->store(field->field_name, strlen(field->field_name),
                           cs);
5416
    table->field[4]->store((longlong) count, TRUE);
5417

5418
    if (get_field_default_value(thd, field, &type, 0))
5419
    {
5420
      table->field[5]->store(type.ptr(), type.length(), cs);
5421 5422
      table->field[5]->set_notnull();
    }
Sergey Glukhov's avatar
Sergey Glukhov committed
5423
    pos=(uchar*) ((field->flags & NOT_NULL_FLAG) ?  "NO" : "YES");
5424 5425
    table->field[6]->store((const char*) pos,
                           strlen((const char*) pos), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
5426
    store_column_type(table, field, cs, 7);
5427
    pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
5428 5429
                 (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
                 (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
5430
    table->field[16]->store((const char*) pos,
5431 5432 5433
                            strlen((const char*) pos), cs);

    if (field->unireg_check == Field::NEXT_NUMBER)
5434
      table->field[17]->store(STRING_WITH_LEN("auto_increment"), cs);
5435 5436
    if (print_on_update_clause(field, &type, true))
      table->field[17]->store(type.ptr(), type.length(), cs);
5437
    if (field->vcol_info)
5438 5439 5440 5441 5442 5443
    {
      if (field->stored_in_db)
        table->field[17]->store(STRING_WITH_LEN("PERSISTENT"), cs);
      else
        table->field[17]->store(STRING_WITH_LEN("VIRTUAL"), cs);
    }
5444
    table->field[19]->store(field->comment.str, field->comment.length, cs);
5445 5446
    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457
  }
  DBUG_RETURN(0);
}


int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
{
  CHARSET_INFO **cs;
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  TABLE *table= tables->table;
  CHARSET_INFO *scs= system_charset_info;
5458

5459 5460 5461
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets) ;
       cs++)
5462 5463
  {
    CHARSET_INFO *tmp_cs= cs[0];
5464
    if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) &&
5465
        (tmp_cs->state & MY_CS_AVAILABLE) &&
unknown's avatar
unknown committed
5466
        !(tmp_cs->state & MY_CS_HIDDEN) &&
5467 5468 5469
        !(wild && wild[0] &&
	  wild_case_compare(scs, tmp_cs->csname,wild)))
    {
5470
      const char *comment;
5471
      restore_record(table, s->default_values);
5472
      table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs);
5473
      table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs);
5474 5475
      comment= tmp_cs->comment ? tmp_cs->comment : "";
      table->field[2]->store(comment, strlen(comment), scs);
5476
      table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE);
5477 5478
      if (schema_table_store_record(thd, table))
        return 1;
5479 5480 5481 5482 5483 5484
    }
  }
  return 0;
}


unknown's avatar
WL#2936  
unknown committed
5485
static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
unknown's avatar
WL#3201  
unknown committed
5486
                                   void *ptable)
unknown's avatar
unknown committed
5487
{
unknown's avatar
WL#3201  
unknown committed
5488
  TABLE *table= (TABLE *) ptable;
Sergei Golubchik's avatar
Sergei Golubchik committed
5489
  handlerton *hton= plugin_hton(plugin);
unknown's avatar
unknown committed
5490 5491
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  CHARSET_INFO *scs= system_charset_info;
unknown's avatar
unknown committed
5492
  handlerton *default_type= ha_default_handlerton(thd);
unknown's avatar
WL#3201  
unknown committed
5493
  DBUG_ENTER("iter_schema_engines");
unknown's avatar
unknown committed
5494

5495 5496 5497 5498 5499

  /* Disabled plugins */
  if (plugin_state(plugin) != PLUGIN_IS_READY)
  {

unknown's avatar
unknown committed
5500
    struct st_maria_plugin *plug= plugin_decl(plugin);
5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513
    if (!(wild && wild[0] &&
          wild_case_compare(scs, plug->name,wild)))
    {
      restore_record(table, s->default_values);
      table->field[0]->store(plug->name, strlen(plug->name), scs);
      table->field[1]->store(C_STRING_WITH_LEN("NO"), scs);
      table->field[2]->store(plug->descr, strlen(plug->descr), scs);
      if (schema_table_store_record(thd, table))
        DBUG_RETURN(1);
    }
    DBUG_RETURN(0);
  }

unknown's avatar
WL#3201  
unknown committed
5514
  if (!(hton->flags & HTON_HIDDEN))
unknown's avatar
unknown committed
5515
  {
unknown's avatar
WL#2936  
unknown committed
5516
    LEX_STRING *name= plugin_name(plugin);
unknown's avatar
unknown committed
5517
    if (!(wild && wild[0] &&
unknown's avatar
WL#2936  
unknown committed
5518
          wild_case_compare(scs, name->str,wild)))
unknown's avatar
unknown committed
5519
    {
unknown's avatar
unknown committed
5520 5521
      LEX_STRING yesno[2]= {{ C_STRING_WITH_LEN("NO") },
                            { C_STRING_WITH_LEN("YES") }};
unknown's avatar
unknown committed
5522
      LEX_STRING *tmp;
5523
      const char *option_name= show_comp_option_name[(int) hton->state];
unknown's avatar
unknown committed
5524 5525
      restore_record(table, s->default_values);

unknown's avatar
WL#2936  
unknown committed
5526
      table->field[0]->store(name->str, name->length, scs);
unknown's avatar
unknown committed
5527
      if (hton->state == SHOW_OPTION_YES && default_type == hton)
5528 5529
        option_name= "DEFAULT";
      table->field[1]->store(option_name, strlen(option_name), scs);
unknown's avatar
WL#2936  
unknown committed
5530 5531
      table->field[2]->store(plugin_decl(plugin)->descr,
                             strlen(plugin_decl(plugin)->descr), scs);
unknown's avatar
unknown committed
5532 5533
      tmp= &yesno[test(hton->commit)];
      table->field[3]->store(tmp->str, tmp->length, scs);
5534
      table->field[3]->set_notnull();
unknown's avatar
unknown committed
5535 5536
      tmp= &yesno[test(hton->prepare)];
      table->field[4]->store(tmp->str, tmp->length, scs);
5537
      table->field[4]->set_notnull();
unknown's avatar
unknown committed
5538 5539
      tmp= &yesno[test(hton->savepoint_set)];
      table->field[5]->store(tmp->str, tmp->length, scs);
5540
      table->field[5]->set_notnull();
unknown's avatar
unknown committed
5541 5542 5543 5544 5545 5546 5547 5548

      if (schema_table_store_record(thd, table))
        DBUG_RETURN(1);
    }
  }
  DBUG_RETURN(0);
}

unknown's avatar
WL#3201  
unknown committed
5549 5550
int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond)
{
5551 5552 5553 5554 5555 5556
  DBUG_ENTER("fill_schema_engines");
  if (plugin_foreach_with_mask(thd, iter_schema_engines,
                               MYSQL_STORAGE_ENGINE_PLUGIN,
                               ~PLUGIN_IS_FREED, tables->table))
    DBUG_RETURN(1);
  DBUG_RETURN(0);
unknown's avatar
WL#3201  
unknown committed
5557 5558 5559
}


5560 5561 5562 5563 5564 5565
int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
{
  CHARSET_INFO **cs;
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  TABLE *table= tables->table;
  CHARSET_INFO *scs= system_charset_info;
5566 5567 5568
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets)  ;
       cs++ )
5569 5570 5571
  {
    CHARSET_INFO **cl;
    CHARSET_INFO *tmp_cs= cs[0];
unknown's avatar
unknown committed
5572
    if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
unknown's avatar
unknown committed
5573
         (tmp_cs->state & MY_CS_HIDDEN) ||
5574 5575
        !(tmp_cs->state & MY_CS_PRIMARY))
      continue;
5576 5577 5578
    for (cl= all_charsets;
         cl < all_charsets + array_elements(all_charsets)  ;
         cl ++)
5579 5580
    {
      CHARSET_INFO *tmp_cl= cl[0];
5581
      if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
5582 5583 5584 5585 5586 5587
          !my_charset_same(tmp_cs, tmp_cl))
	continue;
      if (!(wild && wild[0] &&
	  wild_case_compare(scs, tmp_cl->name,wild)))
      {
	const char *tmp_buff;
5588
	restore_record(table, s->default_values);
5589 5590
	table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
        table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
5591
        table->field[2]->store((longlong) tmp_cl->number, TRUE);
5592 5593 5594 5595
        tmp_buff= (tmp_cl->state & MY_CS_PRIMARY) ? "Yes" : "";
	table->field[3]->store(tmp_buff, strlen(tmp_buff), scs);
        tmp_buff= (tmp_cl->state & MY_CS_COMPILED)? "Yes" : "";
	table->field[4]->store(tmp_buff, strlen(tmp_buff), scs);
5596
        table->field[5]->store((longlong) tmp_cl->strxfrm_multiply, TRUE);
5597 5598
        if (schema_table_store_record(thd, table))
          return 1;
5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610
      }
    }
  }
  return 0;
}


int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
{
  CHARSET_INFO **cs;
  TABLE *table= tables->table;
  CHARSET_INFO *scs= system_charset_info;
5611 5612 5613
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets) ;
       cs++ )
5614 5615 5616
  {
    CHARSET_INFO **cl;
    CHARSET_INFO *tmp_cs= cs[0];
5617
    if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
5618 5619
        !(tmp_cs->state & MY_CS_PRIMARY))
      continue;
5620 5621 5622
    for (cl= all_charsets;
         cl < all_charsets + array_elements(all_charsets) ;
         cl ++)
5623 5624
    {
      CHARSET_INFO *tmp_cl= cl[0];
5625 5626
      if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
          (tmp_cl->state & MY_CS_HIDDEN) ||
5627 5628
          !my_charset_same(tmp_cs,tmp_cl))
	continue;
5629
      restore_record(table, s->default_values);
5630 5631
      table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
      table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
5632 5633
      if (schema_table_store_record(thd, table))
        return 1;
5634 5635 5636 5637 5638 5639
    }
  }
  return 0;
}


5640 5641 5642 5643 5644 5645 5646 5647 5648
static inline void copy_field_as_string(Field *to_field, Field *from_field)
{
  char buff[MAX_FIELD_WIDTH];
  String tmp_str(buff, sizeof(buff), system_charset_info);
  from_field->val_str(&tmp_str);
  to_field->store(tmp_str.ptr(), tmp_str.length(), system_charset_info);
}


Sergey Glukhov's avatar
Sergey Glukhov committed
5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674
/**
  @brief Store record into I_S.PARAMETERS table

  @param[in]      thd                   thread handler
  @param[in]      table                 I_S table
  @param[in]      proc_table            'mysql.proc' table
  @param[in]      wild                  wild string, not used for now,
                                        will be useful
                                        if we add 'SHOW PARAMETERs'
  @param[in]      full_access           if 1 user has privileges on the routine
  @param[in]      sp_user               user in 'user@host' format

  @return         Operation status
    @retval       0                     ok
    @retval       1                     error
*/

bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
                         const char *wild, bool full_access,
                         const char *sp_user)
{
  TABLE_SHARE share;
  TABLE tbl;
  CHARSET_INFO *cs= system_charset_info;
  char params_buff[MAX_FIELD_WIDTH], returns_buff[MAX_FIELD_WIDTH],
    sp_db_buff[NAME_LEN], sp_name_buff[NAME_LEN], path[FN_REFLEN],
5675
    definer_buff[DEFINER_LENGTH + 1];
Sergey Glukhov's avatar
Sergey Glukhov committed
5676 5677 5678 5679 5680 5681
  String params(params_buff, sizeof(params_buff), cs);
  String returns(returns_buff, sizeof(returns_buff), cs);
  String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
  String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
  String definer(definer_buff, sizeof(definer_buff), cs);
  sp_head *sp;
Sergei Golubchik's avatar
Sergei Golubchik committed
5682
  stored_procedure_type routine_type;
Sergey Glukhov's avatar
Sergey Glukhov committed
5683 5684 5685 5686 5687 5688 5689 5690 5691 5692
  bool free_sp_head;
  DBUG_ENTER("store_schema_params");

  bzero((char*) &tbl, sizeof(TABLE));
  (void) build_table_filename(path, sizeof(path), "", "", "", 0);
  init_tmp_table_share(thd, &share, "", 0, "", path);

  get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DB], &sp_db);
  get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_NAME], &sp_name);
  get_field(thd->mem_root,proc_table->field[MYSQL_PROC_FIELD_DEFINER],&definer);
Sergei Golubchik's avatar
Sergei Golubchik committed
5693
  routine_type= (stored_procedure_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
Sergey Glukhov's avatar
Sergey Glukhov committed
5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731

  if (!full_access)
    full_access= !strcmp(sp_user, definer.ptr());
  if (!full_access &&
      check_some_routine_access(thd, sp_db.ptr(),sp_name.ptr(),
                                routine_type == TYPE_ENUM_PROCEDURE))
    DBUG_RETURN(0);

  params.length(0);
  get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST],
            &params);
  returns.length(0);
  if (routine_type == TYPE_ENUM_FUNCTION)
    get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS],
              &returns);

  sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
                                     (ulong) proc_table->
                                     field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(),
                                     routine_type,
                                     returns.c_ptr_safe(),
                                     params.c_ptr_safe(),
                                     &free_sp_head);

  if (sp)
  {
    Field *field;
    Create_field *field_def;
    String tmp_string;
    if (routine_type == TYPE_ENUM_FUNCTION)
    {
      restore_record(table, s->default_values);
      table->field[0]->store(STRING_WITH_LEN("def"), cs);
      table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
      table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
      table->field[3]->store((longlong) 0, TRUE);
      get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
                &tmp_string);
Sergei Golubchik's avatar
Sergei Golubchik committed
5732
      table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784
      field_def= &sp->m_return_field_def;
      field= make_field(&share, (uchar*) 0, field_def->length,
                        (uchar*) "", 0, field_def->pack_flag,
                        field_def->sql_type, field_def->charset,
                        field_def->geom_type, Field::NONE,
                        field_def->interval, "");

      field->table= &tbl;
      tbl.in_use= thd;
      store_column_type(table, field, cs, 6);
      if (schema_table_store_record(thd, table))
      {
        free_table_share(&share);
        if (free_sp_head)
          delete sp;
        DBUG_RETURN(1);
      }
    }

    sp_pcontext *spcont= sp->get_parse_context();
    uint params= spcont->context_var_count();
    for (uint i= 0 ; i < params ; i++)
    {
      const char *tmp_buff;
      sp_variable_t *spvar= spcont->find_variable(i);
      field_def= &spvar->field_def;
      switch (spvar->mode) {
      case sp_param_in:
        tmp_buff= "IN";
        break;
      case sp_param_out:
        tmp_buff= "OUT";
        break;
      case sp_param_inout:
        tmp_buff= "INOUT";
        break;
      default:
        tmp_buff= "";
        break;
      }  

      restore_record(table, s->default_values);
      table->field[0]->store(STRING_WITH_LEN("def"), cs);
      table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
      table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
      table->field[3]->store((longlong) i + 1, TRUE);
      table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
      table->field[4]->set_notnull();
      table->field[5]->store(spvar->name.str, spvar->name.length, cs);
      table->field[5]->set_notnull();
      get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
                &tmp_string);
Sergei Golubchik's avatar
Sergei Golubchik committed
5785
      table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811

      field= make_field(&share, (uchar*) 0, field_def->length,
                        (uchar*) "", 0, field_def->pack_flag,
                        field_def->sql_type, field_def->charset,
                        field_def->geom_type, Field::NONE,
                        field_def->interval, spvar->name.str);

      field->table= &tbl;
      tbl.in_use= thd;
      store_column_type(table, field, cs, 6);
      if (schema_table_store_record(thd, table))
      {
        free_table_share(&share);
        if (free_sp_head)
          delete sp;
        DBUG_RETURN(1);
      }
    }
    if (free_sp_head)
      delete sp;
  }
  free_table_share(&share);
  DBUG_RETURN(0);
}


5812
bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
5813
                       const char *wild, bool full_access, const char *sp_user)
5814
{
5815
  MYSQL_TIME time;
5816 5817
  LEX *lex= thd->lex;
  CHARSET_INFO *cs= system_charset_info;
Sergei Golubchik's avatar
merge.  
Sergei Golubchik committed
5818
  char sp_db_buff[SAFE_NAME_LEN + 1], sp_name_buff[NAME_LEN + 1],
5819
    definer_buff[DEFINER_LENGTH + 1],
5820 5821
    returns_buff[MAX_FIELD_WIDTH];

5822 5823 5824
  String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
  String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
  String definer(definer_buff, sizeof(definer_buff), cs);
5825
  String returns(returns_buff, sizeof(returns_buff), cs);
5826

5827 5828 5829
  proc_table->field[MYSQL_PROC_FIELD_DB]->val_str(&sp_db);
  proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str(&sp_name);
  proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str(&definer);
5830

5831
  if (!full_access)
5832 5833 5834
    full_access= !strcmp(sp_user, definer.c_ptr_safe());
  if (!full_access &&
      check_some_routine_access(thd, sp_db.c_ptr_safe(), sp_name.c_ptr_safe(),
Sergey Glukhov's avatar
Sergey Glukhov committed
5835 5836
                                proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
                                val_int() == TYPE_ENUM_PROCEDURE))
5837
    return 0;
5838

Staale Smedseng's avatar
Staale Smedseng committed
5839
  if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
Sergey Glukhov's avatar
Sergey Glukhov committed
5840 5841
      proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
      TYPE_ENUM_PROCEDURE) ||
Staale Smedseng's avatar
Staale Smedseng committed
5842
      (lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
Sergey Glukhov's avatar
Sergey Glukhov committed
5843 5844
      proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
      TYPE_ENUM_FUNCTION) ||
5845
      (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
5846
  {
5847
    restore_record(table, s->default_values);
5848 5849
    if (!wild || !wild[0] || !wild_case_compare(system_charset_info,
                                                sp_name.c_ptr_safe(), wild))
5850
    {
Sergey Glukhov's avatar
Sergey Glukhov committed
5851
      int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int();
5852
      table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
5853 5854 5855

      copy_field_as_string(table->field[0],
                           proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]);
5856
      table->field[1]->store(STRING_WITH_LEN("def"), cs);
5857
      table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
5858 5859 5860
      copy_field_as_string(table->field[4],
                           proc_table->field[MYSQL_PROC_MYSQL_TYPE]);

Sergey Glukhov's avatar
Sergey Glukhov committed
5861 5862
      if (proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
          TYPE_ENUM_FUNCTION)
5863
      {
Sergey Glukhov's avatar
Sergey Glukhov committed
5864 5865
        sp_head *sp;
        bool free_sp_head;
5866
        proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str(&returns);
Sergey Glukhov's avatar
Sergey Glukhov committed
5867 5868 5869 5870 5871
        sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
                                           (ulong) proc_table->
                                           field[MYSQL_PROC_FIELD_SQL_MODE]->
                                           val_int(),
                                           TYPE_ENUM_FUNCTION,
5872
                                           returns.c_ptr_safe(),
Sergey Glukhov's avatar
Sergey Glukhov committed
5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898
                                           "", &free_sp_head);

        if (sp)
        {
          char path[FN_REFLEN];
          TABLE_SHARE share;
          TABLE tbl;
          Field *field;
          Create_field *field_def= &sp->m_return_field_def;

          bzero((char*) &tbl, sizeof(TABLE));
          (void) build_table_filename(path, sizeof(path), "", "", "", 0);
          init_tmp_table_share(thd, &share, "", 0, "", path);
          field= make_field(&share, (uchar*) 0, field_def->length,
                            (uchar*) "", 0, field_def->pack_flag,
                            field_def->sql_type, field_def->charset,
                            field_def->geom_type, Field::NONE,
                            field_def->interval, "");

          field->table= &tbl;
          tbl.in_use= thd;
          store_column_type(table, field, cs, 5);
          free_table_share(&share);
          if (free_sp_head)
            delete sp;
        }
5899
      }
Sergey Glukhov's avatar
Sergey Glukhov committed
5900

5901 5902
      if (full_access)
      {
Sergei Golubchik's avatar
Sergei Golubchik committed
5903
        copy_field_as_string(table->field[15],
5904
                             proc_table->field[MYSQL_PROC_FIELD_BODY_UTF8]);
Sergei Golubchik's avatar
Sergei Golubchik committed
5905
        table->field[15]->set_notnull();
5906
      }
Sergei Golubchik's avatar
Sergei Golubchik committed
5907 5908 5909
      table->field[14]->store(STRING_WITH_LEN("SQL"), cs);
      table->field[18]->store(STRING_WITH_LEN("SQL"), cs);
      copy_field_as_string(table->field[19],
5910
                           proc_table->field[MYSQL_PROC_FIELD_DETERMINISTIC]);
Sergei Golubchik's avatar
Sergei Golubchik committed
5911
      table->field[20]->store(sp_data_access_name[enum_idx].str, 
5912
                              sp_data_access_name[enum_idx].length , cs);
Sergei Golubchik's avatar
Sergei Golubchik committed
5913
      copy_field_as_string(table->field[22],
5914
                           proc_table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]);
Sergey Glukhov's avatar
Sergey Glukhov committed
5915

5916
      bzero((char *)&time, sizeof(time));
Sergey Glukhov's avatar
Sergey Glukhov committed
5917 5918
      ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_CREATED])->
        get_time(&time);
Sergei Golubchik's avatar
Sergei Golubchik committed
5919
      table->field[23]->store_time(&time);
5920
      bzero((char *)&time, sizeof(time));
Sergey Glukhov's avatar
Sergey Glukhov committed
5921 5922
      ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_MODIFIED])->
        get_time(&time);
Sergei Golubchik's avatar
Sergei Golubchik committed
5923
      table->field[24]->store_time(&time);
5924
      copy_field_as_string(table->field[25],
Sergei Golubchik's avatar
Sergei Golubchik committed
5925 5926
                           proc_table->field[MYSQL_PROC_FIELD_SQL_MODE]);
      copy_field_as_string(table->field[26],
5927
                           proc_table->field[MYSQL_PROC_FIELD_COMMENT]);
unknown's avatar
unknown committed
5928

Sergei Golubchik's avatar
Sergei Golubchik committed
5929 5930
      table->field[27]->store(definer.ptr(), definer.length(), cs);
      copy_field_as_string(table->field[28],
5931 5932
                           proc_table->
                           field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]);
Sergei Golubchik's avatar
Sergei Golubchik committed
5933
      copy_field_as_string(table->field[29],
5934 5935
                           proc_table->
                           field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]);
Sergei Golubchik's avatar
Sergei Golubchik committed
5936
      copy_field_as_string(table->field[30],
5937
			   proc_table->field[MYSQL_PROC_FIELD_DB_COLLATION]);
unknown's avatar
unknown committed
5938

5939
      return schema_table_store_record(thd, table);
5940 5941
    }
  }
5942
  return 0;
5943 5944 5945 5946 5947 5948 5949 5950 5951
}


int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
{
  TABLE *proc_table;
  TABLE_LIST proc_tables;
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  int res= 0;
5952
  TABLE *table= tables->table;
5953
  bool full_access;
5954
  char definer[USER_HOST_BUFF_SIZE];
5955
  Open_tables_backup open_tables_state_backup;
Sergey Glukhov's avatar
Sergey Glukhov committed
5956 5957
  enum enum_schema_tables schema_table_idx=
    get_schema_table_idx(tables->schema_table);
5958 5959
  DBUG_ENTER("fill_schema_proc");

5960 5961
  strxmov(definer, thd->security_ctx->priv_user, "@",
          thd->security_ctx->priv_host, NullS);
5962
  /* We use this TABLE_LIST instance only for checking of privileges. */
5963 5964
  bzero((char*) &proc_tables,sizeof(proc_tables));
  proc_tables.db= (char*) "mysql";
5965
  proc_tables.db_length= 5;
5966
  proc_tables.table_name= proc_tables.alias= (char*) "proc";
5967
  proc_tables.table_name_length= 4;
5968
  proc_tables.lock_type= TL_READ;
5969 5970
  full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, FALSE,
                                   1, TRUE);
5971
  if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup)))
5972 5973 5974
  {
    DBUG_RETURN(1);
  }
5975 5976 5977 5978 5979 5980 5981

  if (proc_table->file->ha_index_init(0, 1))
  {
    res= 1;
    goto err;
  }

5982
  if ((res= proc_table->file->ha_index_first(proc_table->record[0])))
5983 5984 5985 5986
  {
    res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
    goto err;
  }
Sergey Glukhov's avatar
Sergey Glukhov committed
5987 5988 5989 5990

  if (schema_table_idx == SCH_PROCEDURES ?
      store_schema_proc(thd, table, proc_table, wild, full_access, definer) :
      store_schema_params(thd, table, proc_table, wild, full_access, definer))
5991 5992 5993 5994
  {
    res= 1;
    goto err;
  }
5995
  while (!proc_table->file->ha_index_next(proc_table->record[0]))
5996
  {
Sergey Glukhov's avatar
Sergey Glukhov committed
5997 5998 5999
    if (schema_table_idx == SCH_PROCEDURES ?
        store_schema_proc(thd, table, proc_table, wild, full_access, definer): 
        store_schema_params(thd, table, proc_table, wild, full_access, definer))
6000 6001 6002 6003 6004
    {
      res= 1;
      goto err;
    }
  }
6005 6006

err:
6007 6008 6009
  if (proc_table->file->inited)
    (void) proc_table->file->ha_index_end();

6010
  close_system_tables(thd, &open_tables_state_backup);
6011 6012 6013 6014
  DBUG_RETURN(res);
}


6015
static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
6016
				  TABLE *table, bool res,
6017 6018
				  LEX_STRING *db_name,
				  LEX_STRING *table_name)
6019 6020 6021
{
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_schema_stat_record");
6022 6023
  if (res)
  {
6024
    if (thd->lex->sql_command != SQLCOM_SHOW_KEYS)
6025 6026 6027 6028
    {
      /*
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
        rather than in SHOW KEYS
6029
      */
6030
      if (thd->is_error())
6031
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
6032
                     thd->stmt_da->sql_errno(), thd->stmt_da->message());
6033 6034 6035 6036 6037 6038
      thd->clear_error();
      res= 0;
    }
    DBUG_RETURN(res);
  }
  else if (!tables->view)
6039 6040
  {
    TABLE *show_table= tables->table;
6041 6042
    KEY *key_info=show_table->s->key_info;
    if (show_table->file)
6043
    {
6044 6045 6046
      show_table->file->info(HA_STATUS_VARIABLE |
                             HA_STATUS_NO_LOCK |
                             HA_STATUS_TIME);
6047 6048
      set_statistics_for_table(thd, show_table);
    }
6049
    for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
6050 6051 6052 6053 6054
    {
      KEY_PART_INFO *key_part= key_info->key_part;
      const char *str;
      for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
      {
6055
        restore_record(table, s->default_values);
6056
        table->field[0]->store(STRING_WITH_LEN("def"), cs);
6057 6058
        table->field[1]->store(db_name->str, db_name->length, cs);
        table->field[2]->store(table_name->str, table_name->length, cs);
6059
        table->field[3]->store((longlong) ((key_info->flags &
6060
                                            HA_NOSAME) ? 0 : 1), TRUE);
6061
        table->field[4]->store(db_name->str, db_name->length, cs);
6062
        table->field[5]->store(key_info->name, strlen(key_info->name), cs);
6063
        table->field[6]->store((longlong) (j+1), TRUE);
6064 6065 6066
        str=(key_part->field ? key_part->field->field_name :
             "?unknown field?");
        table->field[7]->store(str, strlen(str), cs);
6067
        if (show_table->file)
6068
        {
6069 6070 6071 6072 6073 6074 6075 6076 6077 6078
          if (show_table->file->index_flags(i, j, 0) & HA_READ_ORDER)
          {
            table->field[8]->store(((key_part->key_part_flag &
                                     HA_REVERSE_SORT) ?
                                    "D" : "A"), 1, cs);
            table->field[8]->set_notnull();
          }
          KEY *key=show_table->key_info+i;
          if (key->rec_per_key[j])
          {
6079 6080
            ha_rows records= (ha_rows) ((double) show_table->stat_records() /
                                        key->actual_rec_per_key(j));
6081 6082 6083 6084 6085
            table->field[9]->store((longlong) records, TRUE);
            table->field[9]->set_notnull();
          }
          str= show_table->file->index_type(i);
          table->field[13]->store(str, strlen(str), cs);
6086
        }
6087 6088 6089
        if (!(key_info->flags & HA_FULLTEXT) &&
            (key_part->field &&
             key_part->length !=
6090
             show_table->s->field[key_part->fieldnr-1]->key_length()))
6091
        {
6092
          table->field[10]->store((longlong) key_part->length /
6093
                                  key_part->field->charset()->mbmaxlen, TRUE);
6094 6095 6096 6097 6098
          table->field[10]->set_notnull();
        }
        uint flags= key_part->field ? key_part->field->flags : 0;
        const char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
        table->field[12]->store(pos, strlen(pos), cs);
6099
        if (!show_table->s->keys_in_use.is_set(i))
6100
          table->field[14]->store(STRING_WITH_LEN("disabled"), cs);
6101 6102 6103
        else
          table->field[14]->store("", 0, cs);
        table->field[14]->set_notnull();
6104 6105 6106 6107 6108
        DBUG_ASSERT(test(key_info->flags & HA_USES_COMMENT) == 
                   (key_info->comment.length > 0));
        if (key_info->flags & HA_USES_COMMENT)
          table->field[15]->store(key_info->comment.str, 
                                  key_info->comment.length, cs);
6109 6110
        if (schema_table_store_record(thd, table))
          DBUG_RETURN(1);
6111 6112 6113
      }
    }
  }
unknown's avatar
unknown committed
6114
  DBUG_RETURN(res);
6115 6116 6117
}


6118
static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
6119
				   TABLE *table, bool res,
6120 6121
				   LEX_STRING *db_name,
				   LEX_STRING *table_name)
6122 6123
{
  CHARSET_INFO *cs= system_charset_info;
6124
  char definer[USER_HOST_BUFF_SIZE];
unknown's avatar
unknown committed
6125
  uint definer_len;
6126
  bool updatable_view;
Sergey Glukhov's avatar
Sergey Glukhov committed
6127
  DBUG_ENTER("get_schema_views_record");
unknown's avatar
unknown committed
6128

6129 6130
  if (tables->view)
  {
6131
    Security_context *sctx= thd->security_ctx;
Sergey Glukhov's avatar
Sergey Glukhov committed
6132
    if (!tables->allowed_show)
6133
    {
6134 6135 6136 6137 6138
      if (!my_strcasecmp(system_charset_info, tables->definer.user.str,
                         sctx->priv_user) &&
          !my_strcasecmp(system_charset_info, tables->definer.host.str,
                         sctx->priv_host))
        tables->allowed_show= TRUE;
6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      else
      {
        if ((thd->col_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
            (SHOW_VIEW_ACL|SELECT_ACL))
          tables->allowed_show= TRUE;
        else
        {
          TABLE_LIST table_list;
          uint view_access;
          memset(&table_list, 0, sizeof(table_list));
Sergey Glukhov's avatar
Sergey Glukhov committed
6150 6151
          table_list.db= tables->db;
          table_list.table_name= tables->table_name;
6152 6153
          table_list.grant.privilege= thd->col_access;
          view_access= get_table_grant(thd, &table_list);
Sergey Glukhov's avatar
Sergey Glukhov committed
6154 6155 6156
	  if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
	      (SHOW_VIEW_ACL|SELECT_ACL))
	    tables->allowed_show= TRUE;
6157 6158 6159
        }
      }
#endif
6160
    }
6161
    restore_record(table, s->default_values);
6162
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
6163 6164 6165 6166
    table->field[1]->store(db_name->str, db_name->length, cs);
    table->field[2]->store(table_name->str, table_name->length, cs);

    if (tables->allowed_show)
6167
    {
Sergey Glukhov's avatar
Sergey Glukhov committed
6168 6169 6170 6171
      table->field[3]->store(tables->view_body_utf8.str,
                             tables->view_body_utf8.length,
                             cs);
    }
6172

Sergey Glukhov's avatar
Sergey Glukhov committed
6173 6174 6175 6176
    if (tables->with_check != VIEW_CHECK_NONE)
    {
      if (tables->with_check == VIEW_CHECK_LOCAL)
        table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs);
unknown's avatar
unknown committed
6177
      else
Sergey Glukhov's avatar
Sergey Glukhov committed
6178 6179 6180 6181
        table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs);
    }
    else
      table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
6182

6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194
    /*
      Only try to fill in the information about view updatability
      if it is requested as part of the top-level query (i.e.
      it's select * from i_s.views, as opposed to, say, select
      security_type from i_s.views).  Do not try to access the
      underlying tables if there was an error when opening the
      view: all underlying tables are released back to the table
      definition cache on error inside open_normal_and_derived_tables().
      If a field is not assigned explicitly, it defaults to NULL.
    */
    if (res == FALSE &&
        table->pos_in_table_list->table_open_method & OPEN_FULL_TABLE)
Sergey Glukhov's avatar
Sergey Glukhov committed
6195
    {
6196 6197
      updatable_view= 0;
      if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE)
6198
      {
6199
        /*
6200 6201 6202 6203 6204 6205
          We should use tables->view->select_lex.item_list here
          and can not use Field_iterator_view because the view
          always uses temporary algorithm during opening for I_S
          and TABLE_LIST fields 'field_translation'
          & 'field_translation_end' are uninitialized is this
          case.
6206 6207 6208 6209 6210 6211 6212 6213 6214
        */
        List<Item> *fields= &tables->view->select_lex.item_list;
        List_iterator<Item> it(*fields);
        Item *item;
        Item_field *field;
        /*
          check that at least one column in view is updatable
        */
        while ((item= it++))
6215
        {
6216 6217 6218 6219 6220 6221
          if ((field= item->filed_for_view_update()) && field->field &&
              !field->field->table->pos_in_table_list->schema_table)
          {
            updatable_view= 1;
            break;
          }
6222
        }
6223 6224
        if (updatable_view && !tables->view->can_be_merged())
          updatable_view= 0;
6225
      }
6226 6227
      if (updatable_view)
        table->field[5]->store(STRING_WITH_LEN("YES"), cs);
unknown's avatar
unknown committed
6228
      else
6229
        table->field[5]->store(STRING_WITH_LEN("NO"), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
6230
    }
unknown's avatar
unknown committed
6231

Sergey Glukhov's avatar
Sergey Glukhov committed
6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247
    definer_len= (strxmov(definer, tables->definer.user.str, "@",
                          tables->definer.host.str, NullS) - definer);
    table->field[6]->store(definer, definer_len, cs);
    if (tables->view_suid)
      table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs);
    else
      table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs);

    table->field[8]->store(tables->view_creation_ctx->get_client_cs()->csname,
                           strlen(tables->view_creation_ctx->
                                  get_client_cs()->csname), cs);

    table->field[9]->store(tables->view_creation_ctx->
                           get_connection_cl()->name,
                           strlen(tables->view_creation_ctx->
                                  get_connection_cl()->name), cs);
unknown's avatar
unknown committed
6248

6249 6250 6251

    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
6252
    if (res && thd->is_error())
Sergey Glukhov's avatar
Sergey Glukhov committed
6253
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
6254
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
6255
  }
Sergey Glukhov's avatar
Sergey Glukhov committed
6256
  if (res)
6257
    thd->clear_error();
6258
  DBUG_RETURN(0);
6259 6260 6261
}


6262 6263
bool store_constraints(THD *thd, TABLE *table, LEX_STRING *db_name,
                       LEX_STRING *table_name, const char *key_name,
6264
                       uint key_len, const char *con_type, uint con_len)
6265 6266
{
  CHARSET_INFO *cs= system_charset_info;
6267
  restore_record(table, s->default_values);
6268
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
6269
  table->field[1]->store(db_name->str, db_name->length, cs);
6270
  table->field[2]->store(key_name, key_len, cs);
6271 6272
  table->field[3]->store(db_name->str, db_name->length, cs);
  table->field[4]->store(table_name->str, table_name->length, cs);
6273
  table->field[5]->store(con_type, con_len, cs);
6274
  return schema_table_store_record(thd, table);
6275 6276 6277
}


6278
static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
6279
					 TABLE *table, bool res,
6280 6281
					 LEX_STRING *db_name,
					 LEX_STRING *table_name)
6282
{
unknown's avatar
unknown committed
6283
  DBUG_ENTER("get_schema_constraints_record");
6284 6285
  if (res)
  {
6286
    if (thd->is_error())
6287
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
6288
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
6289 6290 6291 6292
    thd->clear_error();
    DBUG_RETURN(0);
  }
  else if (!tables->view)
6293 6294 6295 6296
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
    KEY *key_info=show_table->key_info;
6297
    uint primary_key= show_table->s->primary_key;
6298
    show_table->file->info(HA_STATUS_VARIABLE |
6299 6300
                           HA_STATUS_NO_LOCK |
                           HA_STATUS_TIME);
6301
    for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
6302 6303
    {
      if (i != primary_key && !(key_info->flags & HA_NOSAME))
6304 6305
        continue;

6306
      if (i == primary_key && !strcmp(key_info->name, primary_key_name))
6307
      {
6308
        if (store_constraints(thd, table, db_name, table_name, key_info->name,
6309 6310
                              strlen(key_info->name),
                              STRING_WITH_LEN("PRIMARY KEY")))
6311 6312
          DBUG_RETURN(1);
      }
6313
      else if (key_info->flags & HA_NOSAME)
6314
      {
6315
        if (store_constraints(thd, table, db_name, table_name, key_info->name,
6316 6317
                              strlen(key_info->name),
                              STRING_WITH_LEN("UNIQUE")))
6318 6319
          DBUG_RETURN(1);
      }
6320 6321 6322 6323 6324 6325 6326
    }

    show_table->file->get_foreign_key_list(thd, &f_key_list);
    FOREIGN_KEY_INFO *f_key_info;
    List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
    while ((f_key_info=it++))
    {
6327
      if (store_constraints(thd, table, db_name, table_name,
6328 6329
                            f_key_info->foreign_id->str,
                            strlen(f_key_info->foreign_id->str),
6330 6331
                            "FOREIGN KEY", 11))
        DBUG_RETURN(1);
6332 6333
    }
  }
unknown's avatar
unknown committed
6334
  DBUG_RETURN(res);
6335 6336 6337
}


6338 6339
static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name,
                          LEX_STRING *table_name, LEX_STRING *trigger_name,
6340 6341
                          enum trg_event_type event,
                          enum trg_action_time_type timing,
6342
                          LEX_STRING *trigger_stmt,
6343
                          ulong sql_mode,
unknown's avatar
unknown committed
6344 6345 6346 6347
                          LEX_STRING *definer_buffer,
                          LEX_STRING *client_cs_name,
                          LEX_STRING *connection_cl_name,
                          LEX_STRING *db_cl_name)
6348 6349
{
  CHARSET_INFO *cs= system_charset_info;
6350
  LEX_STRING sql_mode_rep;
6351

6352
  restore_record(table, s->default_values);
6353
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
6354
  table->field[1]->store(db_name->str, db_name->length, cs);
6355 6356 6357
  table->field[2]->store(trigger_name->str, trigger_name->length, cs);
  table->field[3]->store(trg_event_type_names[event].str,
                         trg_event_type_names[event].length, cs);
6358
  table->field[4]->store(STRING_WITH_LEN("def"), cs);
6359 6360
  table->field[5]->store(db_name->str, db_name->length, cs);
  table->field[6]->store(table_name->str, table_name->length, cs);
6361
  table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
6362
  table->field[10]->store(STRING_WITH_LEN("ROW"), cs);
6363 6364
  table->field[11]->store(trg_action_time_type_names[timing].str,
                          trg_action_time_type_names[timing].length, cs);
6365 6366
  table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
  table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
6367

6368
  sql_mode_string_representation(thd, sql_mode, &sql_mode_rep);
6369
  table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs);
unknown's avatar
unknown committed
6370 6371 6372 6373 6374 6375
  table->field[18]->store(definer_buffer->str, definer_buffer->length, cs);
  table->field[19]->store(client_cs_name->str, client_cs_name->length, cs);
  table->field[20]->store(connection_cl_name->str,
                          connection_cl_name->length, cs);
  table->field[21]->store(db_cl_name->str, db_cl_name->length, cs);

6376 6377 6378 6379
  return schema_table_store_record(thd, table);
}


6380
static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables,
6381
				      TABLE *table, bool res,
6382 6383
				      LEX_STRING *db_name,
				      LEX_STRING *table_name)
6384 6385 6386 6387 6388 6389 6390 6391
{
  DBUG_ENTER("get_schema_triggers_record");
  /*
    res can be non zero value when processed table is a view or
    error happened during opening of processed table.
  */
  if (res)
  {
6392
    if (thd->is_error())
6393
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
6394
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
6395 6396 6397 6398 6399 6400 6401
    thd->clear_error();
    DBUG_RETURN(0);
  }
  if (!tables->view && tables->table->triggers)
  {
    Table_triggers_list *triggers= tables->table->triggers;
    int event, timing;
6402

6403
    if (check_table_access(thd, TRIGGER_ACL, tables, FALSE, 1, TRUE))
6404 6405
      goto ret;

6406 6407 6408 6409 6410 6411
    for (event= 0; event < (int)TRG_EVENT_MAX; event++)
    {
      for (timing= 0; timing < (int)TRG_ACTION_MAX; timing++)
      {
        LEX_STRING trigger_name;
        LEX_STRING trigger_stmt;
6412
        ulong sql_mode;
6413
        char definer_holder[USER_HOST_BUFF_SIZE];
6414
        LEX_STRING definer_buffer;
unknown's avatar
unknown committed
6415 6416 6417 6418
        LEX_STRING client_cs_name;
        LEX_STRING connection_cl_name;
        LEX_STRING db_cl_name;

6419
        definer_buffer.str= definer_holder;
6420 6421
        if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
                                       (enum trg_action_time_type)timing,
6422
                                       &trigger_name, &trigger_stmt,
6423
                                       &sql_mode,
unknown's avatar
unknown committed
6424 6425 6426 6427
                                       &definer_buffer,
                                       &client_cs_name,
                                       &connection_cl_name,
                                       &db_cl_name))
6428
          continue;
6429

6430
        if (store_trigger(thd, table, db_name, table_name, &trigger_name,
6431
                         (enum trg_event_type) event,
6432
                         (enum trg_action_time_type) timing, &trigger_stmt,
6433
                         sql_mode,
unknown's avatar
unknown committed
6434 6435 6436 6437
                         &definer_buffer,
                         &client_cs_name,
                         &connection_cl_name,
                         &db_cl_name))
6438 6439 6440 6441
          DBUG_RETURN(1);
      }
    }
  }
6442
ret:
6443 6444 6445 6446
  DBUG_RETURN(0);
}


6447 6448 6449 6450
void store_key_column_usage(TABLE *table, LEX_STRING *db_name,
                            LEX_STRING *table_name, const char *key_name,
                            uint key_len, const char *con_type, uint con_len,
                            longlong idx)
6451 6452
{
  CHARSET_INFO *cs= system_charset_info;
6453
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
6454
  table->field[1]->store(db_name->str, db_name->length, cs);
6455
  table->field[2]->store(key_name, key_len, cs);
6456
  table->field[3]->store(STRING_WITH_LEN("def"), cs);
6457 6458
  table->field[4]->store(db_name->str, db_name->length, cs);
  table->field[5]->store(table_name->str, table_name->length, cs);
6459
  table->field[6]->store(con_type, con_len, cs);
6460
  table->field[7]->store((longlong) idx, TRUE);
6461 6462 6463
}


unknown's avatar
unknown committed
6464
static int get_schema_key_column_usage_record(THD *thd,
6465
					      TABLE_LIST *tables,
unknown's avatar
unknown committed
6466
					      TABLE *table, bool res,
6467 6468
					      LEX_STRING *db_name,
					      LEX_STRING *table_name)
6469 6470
{
  DBUG_ENTER("get_schema_key_column_usage_record");
6471 6472
  if (res)
  {
6473
    if (thd->is_error())
6474
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
6475
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
6476 6477 6478 6479
    thd->clear_error();
    DBUG_RETURN(0);
  }
  else if (!tables->view)
6480 6481 6482 6483
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
    KEY *key_info=show_table->key_info;
6484
    uint primary_key= show_table->s->primary_key;
6485
    show_table->file->info(HA_STATUS_VARIABLE |
6486 6487
                           HA_STATUS_NO_LOCK |
                           HA_STATUS_TIME);
6488
    for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
6489 6490
    {
      if (i != primary_key && !(key_info->flags & HA_NOSAME))
unknown's avatar
unknown committed
6491
        continue;
6492 6493 6494 6495 6496 6497 6498
      uint f_idx= 0;
      KEY_PART_INFO *key_part= key_info->key_part;
      for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
      {
        if (key_part->field)
        {
          f_idx++;
6499
          restore_record(table, s->default_values);
6500
          store_key_column_usage(table, db_name, table_name,
6501
                                 key_info->name,
6502 6503
                                 strlen(key_info->name),
                                 key_part->field->field_name,
6504 6505
                                 strlen(key_part->field->field_name),
                                 (longlong) f_idx);
6506 6507
          if (schema_table_store_record(thd, table))
            DBUG_RETURN(1);
6508 6509 6510 6511 6512 6513
        }
      }
    }

    show_table->file->get_foreign_key_list(thd, &f_key_list);
    FOREIGN_KEY_INFO *f_key_info;
6514 6515
    List_iterator_fast<FOREIGN_KEY_INFO> fkey_it(f_key_list);
    while ((f_key_info= fkey_it++))
6516
    {
6517
      LEX_STRING *f_info;
6518
      LEX_STRING *r_info;
6519 6520 6521 6522 6523
      List_iterator_fast<LEX_STRING> it(f_key_info->foreign_fields),
        it1(f_key_info->referenced_fields);
      uint f_idx= 0;
      while ((f_info= it++))
      {
6524
        r_info= it1++;
6525
        f_idx++;
6526
        restore_record(table, s->default_values);
6527
        store_key_column_usage(table, db_name, table_name,
6528 6529
                               f_key_info->foreign_id->str,
                               f_key_info->foreign_id->length,
6530 6531
                               f_info->str, f_info->length,
                               (longlong) f_idx);
6532
        table->field[8]->store((longlong) f_idx, TRUE);
6533
        table->field[8]->set_notnull();
6534 6535 6536 6537 6538
        table->field[9]->store(f_key_info->referenced_db->str,
                               f_key_info->referenced_db->length,
                               system_charset_info);
        table->field[9]->set_notnull();
        table->field[10]->store(f_key_info->referenced_table->str,
6539
                                f_key_info->referenced_table->length,
6540 6541 6542 6543 6544
                                system_charset_info);
        table->field[10]->set_notnull();
        table->field[11]->store(r_info->str, r_info->length,
                                system_charset_info);
        table->field[11]->set_notnull();
6545 6546
        if (schema_table_store_record(thd, table))
          DBUG_RETURN(1);
6547 6548 6549
      }
    }
  }
unknown's avatar
unknown committed
6550
  DBUG_RETURN(res);
6551 6552 6553
}


6554
#ifdef WITH_PARTITION_STORAGE_ENGINE
6555 6556
static void collect_partition_expr(THD *thd, List<char> &field_list,
                                   String *str)
6557 6558 6559 6560 6561 6562 6563
{
  List_iterator<char> part_it(field_list);
  ulong no_fields= field_list.elements;
  const char *field_str;
  str->length(0);
  while ((field_str= part_it++))
  {
6564
    append_identifier(thd, str, field_str, strlen(field_str));
6565 6566 6567 6568 6569
    if (--no_fields != 0)
      str->append(",");
  }
  return;
}
6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620


/*
  Convert a string in a given character set to a string which can be
  used for FRM file storage in which case use_hex is TRUE and we store
  the character constants as hex strings in the character set encoding
  their field have. In the case of SHOW CREATE TABLE and the
  PARTITIONS information schema table we instead provide utf8 strings
  to the user and convert to the utf8 character set.

  SYNOPSIS
    get_cs_converted_part_value_from_string()
    item                           Item from which constant comes
    input_str                      String as provided by val_str after
                                   conversion to character set
    output_str                     Out value: The string created
    cs                             Character set string is encoded in
                                   NULL for INT_RESULT's here
    use_hex                        TRUE => hex string created
                                   FALSE => utf8 constant string created

  RETURN VALUES
    TRUE                           Error
    FALSE                          Ok
*/

int get_cs_converted_part_value_from_string(THD *thd,
                                            Item *item,
                                            String *input_str,
                                            String *output_str,
                                            CHARSET_INFO *cs,
                                            bool use_hex)
{
  if (item->result_type() == INT_RESULT)
  {
    longlong value= item->val_int();
    output_str->set(value, system_charset_info);
    return FALSE;
  }
  if (!input_str)
  {
    my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
    return TRUE;
  }
  get_cs_converted_string_value(thd,
                                input_str,
                                output_str,
                                cs,
                                use_hex);
  return FALSE;
}
6621
#endif
6622 6623


6624 6625
static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
                                           TABLE *showing_table,
6626 6627 6628
                                           partition_element *part_elem,
                                           handler *file, uint part_id)
{
6629
  TABLE* table= schema_table;
6630
  CHARSET_INFO *cs= system_charset_info;
6631
  PARTITION_STATS stat_info;
6632
  MYSQL_TIME time;
6633
  file->get_dynamic_partition_info(&stat_info, part_id);
6634
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647
  table->field[12]->store((longlong) stat_info.records, TRUE);
  table->field[13]->store((longlong) stat_info.mean_rec_length, TRUE);
  table->field[14]->store((longlong) stat_info.data_file_length, TRUE);
  if (stat_info.max_data_file_length)
  {
    table->field[15]->store((longlong) stat_info.max_data_file_length, TRUE);
    table->field[15]->set_notnull();
  }
  table->field[16]->store((longlong) stat_info.index_file_length, TRUE);
  table->field[17]->store((longlong) stat_info.delete_length, TRUE);
  if (stat_info.create_time)
  {
    thd->variables.time_zone->gmt_sec_to_TIME(&time,
6648
                                              (my_time_t)stat_info.create_time);
6649
    table->field[18]->store_time(&time);
6650 6651 6652 6653 6654
    table->field[18]->set_notnull();
  }
  if (stat_info.update_time)
  {
    thd->variables.time_zone->gmt_sec_to_TIME(&time,
6655
                                              (my_time_t)stat_info.update_time);
6656
    table->field[19]->store_time(&time);
6657 6658 6659 6660
    table->field[19]->set_notnull();
  }
  if (stat_info.check_time)
  {
6661 6662
    thd->variables.time_zone->gmt_sec_to_TIME(&time,
                                              (my_time_t)stat_info.check_time);
6663
    table->field[20]->store_time(&time);
6664 6665
    table->field[20]->set_notnull();
  }
6666
  if (file->ha_table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM))
6667 6668 6669 6670 6671 6672 6673 6674 6675 6676
  {
    table->field[21]->store((longlong) stat_info.check_sum, TRUE);
    table->field[21]->set_notnull();
  }
  if (part_elem)
  {
    if (part_elem->part_comment)
      table->field[22]->store(part_elem->part_comment,
                              strlen(part_elem->part_comment), cs);
    else
6677
      table->field[22]->store(STRING_WITH_LEN(""), cs);
6678 6679 6680 6681
    if (part_elem->nodegroup_id != UNDEF_NODEGROUP)
      table->field[23]->store((longlong) part_elem->nodegroup_id, TRUE);
    else
      table->field[23]->store(STRING_WITH_LEN("default"), cs);
6682 6683

    table->field[24]->set_notnull();
6684 6685 6686 6687
    if (part_elem->tablespace_name)
      table->field[24]->store(part_elem->tablespace_name,
                              strlen(part_elem->tablespace_name), cs);
    else
6688
    {
Sergei Golubchik's avatar
Sergei Golubchik committed
6689
      char *ts= showing_table->file->get_tablespace_name(thd,0,0);
6690 6691 6692 6693 6694
      if(ts)
        table->field[24]->store(ts, strlen(ts), cs);
      else
        table->field[24]->set_null();
    }
6695 6696 6697 6698
  }
  return;
}

Alexander Nozdrin's avatar
Alexander Nozdrin committed
6699
#ifdef WITH_PARTITION_STORAGE_ENGINE
6700
static int
6701 6702
get_partition_column_description(THD *thd,
                                 partition_info *part_info,
6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718
                                 part_elem_value *list_value,
                                 String &tmp_str)
{
  uint num_elements= part_info->part_field_list.elements;
  uint i;
  DBUG_ENTER("get_partition_column_description");

  for (i= 0; i < num_elements; i++)
  {
    part_column_list_val *col_val= &list_value->col_val_array[i];
    if (col_val->max_value)
      tmp_str.append(partition_keywords[PKW_MAXVALUE].str);
    else if (col_val->null_value)
      tmp_str.append("NULL");
    else
    {
6719
      char buffer[MAX_KEY_LENGTH];
6720
      String str(buffer, sizeof(buffer), &my_charset_bin);
6721
      String val_conv;
6722 6723 6724 6725 6726 6727 6728 6729
      Item *item= col_val->item_expression;

      if (!(item= part_info->get_column_item(item,
                              part_info->part_field_array[i])))
      {
        DBUG_RETURN(1);
      }
      String *res= item->val_str(&str);
6730
      if (get_cs_converted_part_value_from_string(thd, item, res, &val_conv,
6731
                              part_info->part_field_array[i]->charset(),
6732
                              FALSE))
6733 6734 6735
      {
        DBUG_RETURN(1);
      }
6736
      tmp_str.append(val_conv);
6737 6738 6739 6740 6741 6742
    }
    if (i != num_elements - 1)
      tmp_str.append(",");
  }
  DBUG_RETURN(0);
}
Alexander Nozdrin's avatar
Alexander Nozdrin committed
6743
#endif /* WITH_PARTITION_STORAGE_ENGINE */
6744

6745
static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
6746
                                        TABLE *table, bool res,
6747 6748
                                        LEX_STRING *db_name,
                                        LEX_STRING *table_name)
6749 6750 6751 6752 6753 6754
{
  CHARSET_INFO *cs= system_charset_info;
  char buff[61];
  String tmp_res(buff, sizeof(buff), cs);
  String tmp_str;
  TABLE *show_table= tables->table;
6755
  handler *file;
unknown's avatar
unknown committed
6756
#ifdef WITH_PARTITION_STORAGE_ENGINE
6757
  partition_info *part_info;
unknown's avatar
unknown committed
6758
#endif
6759 6760 6761 6762
  DBUG_ENTER("get_schema_partitions_record");

  if (res)
  {
6763
    if (thd->is_error())
6764
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
6765
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
6766 6767 6768
    thd->clear_error();
    DBUG_RETURN(0);
  }
6769
  file= show_table->file;
unknown's avatar
unknown committed
6770
#ifdef WITH_PARTITION_STORAGE_ENGINE
6771
  part_info= show_table->part_info;
6772 6773 6774 6775 6776 6777 6778
  if (part_info)
  {
    partition_element *part_elem;
    List_iterator<partition_element> part_it(part_info->partitions);
    uint part_pos= 0, part_id= 0;

    restore_record(table, s->default_values);
6779
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
6780 6781
    table->field[1]->store(db_name->str, db_name->length, cs);
    table->field[2]->store(table_name->str, table_name->length, cs);
6782 6783 6784 6785 6786 6787


    /* Partition method*/
    switch (part_info->part_type) {
    case RANGE_PARTITION:
    case LIST_PARTITION:
6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798
      tmp_res.length(0);
      if (part_info->part_type == RANGE_PARTITION)
        tmp_res.append(partition_keywords[PKW_RANGE].str,
                       partition_keywords[PKW_RANGE].length);
      else
        tmp_res.append(partition_keywords[PKW_LIST].str,
                       partition_keywords[PKW_LIST].length);
      if (part_info->column_list)
        tmp_res.append(partition_keywords[PKW_COLUMNS].str,
                       partition_keywords[PKW_COLUMNS].length);
      table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs);
6799 6800 6801 6802 6803 6804 6805 6806 6807 6808
      break;
    case HASH_PARTITION:
      tmp_res.length(0);
      if (part_info->linear_hash_ind)
        tmp_res.append(partition_keywords[PKW_LINEAR].str,
                       partition_keywords[PKW_LINEAR].length);
      if (part_info->list_of_part_fields)
        tmp_res.append(partition_keywords[PKW_KEY].str,
                       partition_keywords[PKW_KEY].length);
      else
6809
        tmp_res.append(partition_keywords[PKW_HASH].str,
6810 6811 6812 6813 6814
                       partition_keywords[PKW_HASH].length);
      table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs);
      break;
    default:
      DBUG_ASSERT(0);
6815
      my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827
      DBUG_RETURN(1);
    }
    table->field[7]->set_notnull();

    /* Partition expression */
    if (part_info->part_expr)
    {
      table->field[9]->store(part_info->part_func_string,
                             part_info->part_func_len, cs);
    }
    else if (part_info->list_of_part_fields)
    {
6828
      collect_partition_expr(thd, part_info->part_field_list, &tmp_str);
6829 6830
      table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs);
    }
6831
    table->field[9]->set_notnull();
6832

6833
    if (part_info->is_sub_partitioned())
6834 6835
    {
      /* Subpartition method */
6836 6837 6838 6839
      tmp_res.length(0);
      if (part_info->linear_hash_ind)
        tmp_res.append(partition_keywords[PKW_LINEAR].str,
                       partition_keywords[PKW_LINEAR].length);
6840
      if (part_info->list_of_subpart_fields)
6841 6842
        tmp_res.append(partition_keywords[PKW_KEY].str,
                       partition_keywords[PKW_KEY].length);
6843
      else
6844
        tmp_res.append(partition_keywords[PKW_HASH].str,
6845 6846
                       partition_keywords[PKW_HASH].length);
      table->field[8]->store(tmp_res.ptr(), tmp_res.length(), cs);
6847 6848 6849 6850 6851 6852 6853 6854 6855 6856
      table->field[8]->set_notnull();

      /* Subpartition expression */
      if (part_info->subpart_expr)
      {
        table->field[10]->store(part_info->subpart_func_string,
                                part_info->subpart_func_len, cs);
      }
      else if (part_info->list_of_subpart_fields)
      {
6857
        collect_partition_expr(thd, part_info->subpart_field_list, &tmp_str);
6858 6859
        table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs);
      }
6860
      table->field[10]->set_notnull();
6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874
    }

    while ((part_elem= part_it++))
    {
      table->field[3]->store(part_elem->partition_name,
                             strlen(part_elem->partition_name), cs);
      table->field[3]->set_notnull();
      /* PARTITION_ORDINAL_POSITION */
      table->field[5]->store((longlong) ++part_pos, TRUE);
      table->field[5]->set_notnull();

      /* Partition description */
      if (part_info->part_type == RANGE_PARTITION)
      {
6875 6876 6877 6878 6879
        if (part_info->column_list)
        {
          List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
          part_elem_value *list_value= list_val_it++;
          tmp_str.length(0);
6880 6881
          if (get_partition_column_description(thd,
                                               part_info,
6882 6883 6884 6885 6886 6887 6888
                                               list_value,
                                               tmp_str))
          {
            DBUG_RETURN(1);
          }
          table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
        }
6889
        else
6890 6891 6892 6893 6894
        {
          if (part_elem->range_value != LONGLONG_MAX)
            table->field[11]->store((longlong) part_elem->range_value, FALSE);
          else
            table->field[11]->store(partition_keywords[PKW_MAXVALUE].str,
6895
                                 partition_keywords[PKW_MAXVALUE].length, cs);
6896
        }
6897 6898 6899 6900
        table->field[11]->set_notnull();
      }
      else if (part_info->part_type == LIST_PARTITION)
      {
6901 6902
        List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
        part_elem_value *list_value;
6903
        uint num_items= part_elem->list_val_list.elements;
6904 6905
        tmp_str.length(0);
        tmp_res.length(0);
6906 6907 6908
        if (part_elem->has_null_value)
        {
          tmp_str.append("NULL");
6909
          if (num_items > 0)
6910 6911
            tmp_str.append(",");
        }
6912 6913
        while ((list_value= list_val_it++))
        {
6914 6915 6916 6917
          if (part_info->column_list)
          {
            if (part_info->part_field_list.elements > 1U)
              tmp_str.append("(");
6918 6919
            if (get_partition_column_description(thd,
                                                 part_info,
6920 6921 6922 6923 6924 6925 6926 6927
                                                 list_value,
                                                 tmp_str))
            {
              DBUG_RETURN(1);
            }
            if (part_info->part_field_list.elements > 1U)
              tmp_str.append(")");
          }
6928
          else
6929 6930 6931 6932 6933 6934 6935 6936
          {
            if (!list_value->unsigned_flag)
              tmp_res.set(list_value->value, cs);
            else
              tmp_res.set((ulonglong)list_value->value, cs);
            tmp_str.append(tmp_res);
          }
          if (--num_items != 0)
6937
            tmp_str.append(",");
6938
        }
6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956
        table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
        table->field[11]->set_notnull();
      }

      if (part_elem->subpartitions.elements)
      {
        List_iterator<partition_element> sub_it(part_elem->subpartitions);
        partition_element *subpart_elem;
        uint subpart_pos= 0;

        while ((subpart_elem= sub_it++))
        {
          table->field[4]->store(subpart_elem->partition_name,
                                 strlen(subpart_elem->partition_name), cs);
          table->field[4]->set_notnull();
          /* SUBPARTITION_ORDINAL_POSITION */
          table->field[6]->store((longlong) ++subpart_pos, TRUE);
          table->field[6]->set_notnull();
6957

6958
          store_schema_partitions_record(thd, table, show_table, subpart_elem,
6959 6960 6961 6962 6963 6964 6965 6966
                                         file, part_id);
          part_id++;
          if(schema_table_store_record(thd, table))
            DBUG_RETURN(1);
        }
      }
      else
      {
6967
        store_schema_partitions_record(thd, table, show_table, part_elem,
6968 6969 6970 6971 6972 6973 6974 6975 6976
                                       file, part_id);
        part_id++;
        if(schema_table_store_record(thd, table))
          DBUG_RETURN(1);
      }
    }
    DBUG_RETURN(0);
  }
  else
unknown's avatar
unknown committed
6977
#endif
6978
  {
6979
    store_schema_partitions_record(thd, table, show_table, 0, file, 0);
6980 6981 6982 6983 6984 6985 6986
    if(schema_table_store_record(thd, table))
      DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


6987
#ifdef HAVE_EVENT_SCHEDULER
6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002
/*
  Loads an event from mysql.event and copies it's data to a row of
  I_S.EVENTS

  Synopsis
    copy_event_to_schema_table()
      thd         Thread
      sch_table   The schema table (information_schema.event)
      event_table The event table to use for loading (mysql.event).

  Returns
    0  OK
    1  Error
*/

unknown's avatar
unknown committed
7003
int
7004
copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
7005 7006 7007
{
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  CHARSET_INFO *scs= system_charset_info;
7008
  MYSQL_TIME time;
unknown's avatar
unknown committed
7009
  Event_timed et;
7010
  DBUG_ENTER("copy_event_to_schema_table");
7011 7012 7013

  restore_record(sch_table, s->default_values);

7014
  if (et.load_from_row(thd, event_table))
7015
  {
7016
    my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), event_table->alias.c_ptr());
7017 7018 7019
    DBUG_RETURN(1);
  }

7020
  if (!(!wild || !wild[0] || !wild_case_compare(scs, et.name.str, wild)))
7021
    DBUG_RETURN(0);
7022 7023 7024 7025 7026 7027

  /*
    Skip events in schemas one does not have access to. The check is
    optimized. It's guaranteed in case of SHOW EVENTS that the user
    has access.
  */
7028
  if (thd->lex->sql_command != SQLCOM_SHOW_EVENTS &&
Marc Alff's avatar
Marc Alff committed
7029
      check_access(thd, EVENT_ACL, et.dbname.str, NULL, NULL, 0, 1))
7030 7031
    DBUG_RETURN(0);

7032
  sch_table->field[ISE_EVENT_CATALOG]->store(STRING_WITH_LEN("def"), scs);
7033 7034 7035 7036 7037 7038
  sch_table->field[ISE_EVENT_SCHEMA]->
                                store(et.dbname.str, et.dbname.length,scs);
  sch_table->field[ISE_EVENT_NAME]->
                                store(et.name.str, et.name.length, scs);
  sch_table->field[ISE_DEFINER]->
                                store(et.definer.str, et.definer.length, scs);
7039 7040 7041
  const String *tz_name= et.time_zone->get_name();
  sch_table->field[ISE_TIME_ZONE]->
                                store(tz_name->ptr(), tz_name->length(), scs);
7042 7043
  sch_table->field[ISE_EVENT_BODY]->
                                store(STRING_WITH_LEN("SQL"), scs);
unknown's avatar
unknown committed
7044 7045
  sch_table->field[ISE_EVENT_DEFINITION]->store(
    et.body_utf8.str, et.body_utf8.length, scs);
7046 7047

  /* SQL_MODE */
7048
  {
7049
    LEX_STRING sql_mode;
7050
    sql_mode_string_representation(thd, et.sql_mode, &sql_mode);
7051
    sch_table->field[ISE_SQL_MODE]->
7052
                                store(sql_mode.str, sql_mode.length, scs);
7053
  }
7054

7055 7056
  int not_used=0;

7057 7058
  if (et.expression)
  {
7059
    String show_str;
7060
    /* type */
7061
    sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("RECURRING"), scs);
7062

7063 7064
    if (Events::reconstruct_interval_expression(&show_str, et.interval,
                                                et.expression))
7065
      DBUG_RETURN(1);
7066

7067 7068 7069
    sch_table->field[ISE_INTERVAL_VALUE]->set_notnull();
    sch_table->field[ISE_INTERVAL_VALUE]->
                                store(show_str.ptr(), show_str.length(), scs);
unknown's avatar
unknown committed
7070 7071

    LEX_STRING *ival= &interval_type_to_name[et.interval];
7072 7073
    sch_table->field[ISE_INTERVAL_FIELD]->set_notnull();
    sch_table->field[ISE_INTERVAL_FIELD]->store(ival->str, ival->length, scs);
7074

7075
    /* starts & ends . STARTS is always set - see sql_yacc.yy */
7076
    et.time_zone->gmt_sec_to_TIME(&time, et.starts);
7077
    sch_table->field[ISE_STARTS]->set_notnull();
7078
    sch_table->field[ISE_STARTS]->store_time(&time);
7079 7080 7081

    if (!et.ends_null)
    {
7082
      et.time_zone->gmt_sec_to_TIME(&time, et.ends);
7083
      sch_table->field[ISE_ENDS]->set_notnull();
7084
      sch_table->field[ISE_ENDS]->store_time(&time);
7085
    }
7086 7087 7088
  }
  else
  {
7089 7090
    /* type */
    sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("ONE TIME"), scs);
7091

7092
    et.time_zone->gmt_sec_to_TIME(&time, et.execute_at);
7093
    sch_table->field[ISE_EXECUTE_AT]->set_notnull();
7094
    sch_table->field[ISE_EXECUTE_AT]->store_time(&time);
7095 7096
  }

7097
  /* status */
7098 7099 7100

  switch (et.status)
  {
7101
    case Event_parse_data::ENABLED:
7102 7103
      sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("ENABLED"), scs);
      break;
7104
    case Event_parse_data::SLAVESIDE_DISABLED:
7105 7106 7107
      sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("SLAVESIDE_DISABLED"),
                                          scs);
      break;
7108
    case Event_parse_data::DISABLED:
7109 7110 7111 7112 7113 7114
      sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("DISABLED"), scs);
      break;
    default:
      DBUG_ASSERT(0);
  }
  sch_table->field[ISE_ORIGINATOR]->store(et.originator, TRUE);
7115

7116
  /* on_completion */
7117
  if (et.on_completion == Event_parse_data::ON_COMPLETION_DROP)
7118 7119
    sch_table->field[ISE_ON_COMPLETION]->
                                store(STRING_WITH_LEN("NOT PRESERVE"), scs);
7120
  else
7121 7122
    sch_table->field[ISE_ON_COMPLETION]->
                                store(STRING_WITH_LEN("PRESERVE"), scs);
7123

7124
  number_to_datetime(et.created, 0, &time, 0, &not_used);
7125
  DBUG_ASSERT(not_used==0);
7126
  sch_table->field[ISE_CREATED]->store_time(&time);
7127

7128
  number_to_datetime(et.modified, 0, &time, 0, &not_used);
7129
  DBUG_ASSERT(not_used==0);
7130
  sch_table->field[ISE_LAST_ALTERED]->store_time(&time);
7131

7132
  if (et.last_executed)
7133
  {
7134
    et.time_zone->gmt_sec_to_TIME(&time, et.last_executed);
7135
    sch_table->field[ISE_LAST_EXECUTED]->set_notnull();
7136
    sch_table->field[ISE_LAST_EXECUTED]->store_time(&time);
7137
  }
7138

7139 7140
  sch_table->field[ISE_EVENT_COMMENT]->
                      store(et.comment.str, et.comment.length, scs);
7141

unknown's avatar
unknown committed
7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159
  sch_table->field[ISE_CLIENT_CS]->set_notnull();
  sch_table->field[ISE_CLIENT_CS]->store(
    et.creation_ctx->get_client_cs()->csname,
    strlen(et.creation_ctx->get_client_cs()->csname),
    scs);

  sch_table->field[ISE_CONNECTION_CL]->set_notnull();
  sch_table->field[ISE_CONNECTION_CL]->store(
    et.creation_ctx->get_connection_cl()->name,
    strlen(et.creation_ctx->get_connection_cl()->name),
    scs);

  sch_table->field[ISE_DB_CL]->set_notnull();
  sch_table->field[ISE_DB_CL]->store(
    et.creation_ctx->get_db_cl()->name,
    strlen(et.creation_ctx->get_db_cl()->name),
    scs);

7160 7161 7162 7163 7164
  if (schema_table_store_record(thd, sch_table))
    DBUG_RETURN(1);

  DBUG_RETURN(0);
}
7165
#endif
7166

7167 7168 7169 7170 7171 7172 7173
int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  DBUG_ENTER("fill_open_tables");
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  TABLE *table= tables->table;
  CHARSET_INFO *cs= system_charset_info;
  OPEN_TABLE_LIST *open_list;
7174 7175
  if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild))
            && thd->is_fatal_error)
7176 7177 7178 7179
    DBUG_RETURN(1);

  for (; open_list ; open_list=open_list->next)
  {
7180
    restore_record(table, s->default_values);
7181 7182
    table->field[0]->store(open_list->db, strlen(open_list->db), cs);
    table->field[1]->store(open_list->table, strlen(open_list->table), cs);
7183 7184
    table->field[2]->store((longlong) open_list->in_use, TRUE);
    table->field[3]->store((longlong) open_list->locked, TRUE);
7185 7186
    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
7187 7188 7189 7190 7191 7192 7193 7194
  }
  DBUG_RETURN(0);
}


int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  DBUG_ENTER("fill_variables");
7195
  int res= 0;
7196 7197
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
7198 7199 7200 7201 7202 7203 7204 7205 7206 7207
  enum enum_schema_tables schema_table_idx=
    get_schema_table_idx(tables->schema_table);
  enum enum_var_type option_type= OPT_SESSION;
  bool upper_case_names= (schema_table_idx != SCH_VARIABLES);
  bool sorted_vars= (schema_table_idx == SCH_VARIABLES);

  if (lex->option_type == OPT_GLOBAL ||
      schema_table_idx == SCH_GLOBAL_VARIABLES)
    option_type= OPT_GLOBAL;

7208 7209
  COND *partial_cond= make_cond_for_info_schema(cond, tables);

Marc Alff's avatar
Marc Alff committed
7210
  mysql_rwlock_rdlock(&LOCK_system_variables_hash);
7211
  res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type),
7212 7213
                         option_type, NULL, "", tables->table,
                         upper_case_names, partial_cond);
Marc Alff's avatar
Marc Alff committed
7214
  mysql_rwlock_unlock(&LOCK_system_variables_hash);
7215 7216 7217 7218 7219 7220 7221 7222 7223 7224
  DBUG_RETURN(res);
}


int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
{
  DBUG_ENTER("fill_status");
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
  int res= 0;
7225 7226 7227 7228 7229 7230
  STATUS_VAR *tmp1, tmp;
  enum enum_schema_tables schema_table_idx=
    get_schema_table_idx(tables->schema_table);
  enum enum_var_type option_type;
  bool upper_case_names= (schema_table_idx != SCH_STATUS);

unknown's avatar
unknown committed
7231 7232 7233 7234 7235 7236 7237 7238 7239
  if (schema_table_idx == SCH_STATUS)
  {
    option_type= lex->option_type;
    if (option_type == OPT_GLOBAL)
      tmp1= &tmp;
    else
      tmp1= thd->initial_status_var;
  }
  else if (schema_table_idx == SCH_GLOBAL_STATUS)
7240 7241 7242 7243 7244
  {
    option_type= OPT_GLOBAL;
    tmp1= &tmp;
  }
  else
7245
  {
7246
    option_type= OPT_SESSION;
unknown's avatar
unknown committed
7247
    tmp1= &thd->status_var;
7248 7249
  }

7250 7251 7252 7253 7254
  COND *partial_cond= make_cond_for_info_schema(cond, tables);
  // Evaluate and cache const subqueries now, before the mutex.
  if (partial_cond)
    partial_cond->val_int();

Marc Alff's avatar
Marc Alff committed
7255
  mysql_mutex_lock(&LOCK_status);
7256
  if (option_type == OPT_GLOBAL)
7257
    calc_sum_of_all_status(&tmp);
7258 7259
  res= show_status_array(thd, wild,
                         (SHOW_VAR *)all_status_vars.buffer,
7260
                         option_type, tmp1, "", tables->table,
7261
                         upper_case_names, partial_cond);
Marc Alff's avatar
Marc Alff committed
7262
  mysql_mutex_unlock(&LOCK_status);
7263 7264 7265 7266
  DBUG_RETURN(res);
}


unknown's avatar
unknown committed
7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285
/*
  Fill and store records into I_S.referential_constraints table

  SYNOPSIS
    get_referential_constraints_record()
    thd                 thread handle
    tables              table list struct(processed table)
    table               I_S table
    res                 1 means the error during opening of the processed table
                        0 means processed table is opened without error
    base_name           db name
    file_name           table name

  RETURN
    0	ok
    #   error
*/

static int
7286
get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
7287
                                   TABLE *table, bool res,
7288
                                   LEX_STRING *db_name, LEX_STRING *table_name)
unknown's avatar
unknown committed
7289 7290 7291 7292 7293 7294
{
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_referential_constraints_record");

  if (res)
  {
7295
    if (thd->is_error())
unknown's avatar
unknown committed
7296
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
7297
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
unknown's avatar
unknown committed
7298 7299 7300 7301 7302 7303 7304
    thd->clear_error();
    DBUG_RETURN(0);
  }
  if (!tables->view)
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
7305
    show_table->file->info(HA_STATUS_VARIABLE |
unknown's avatar
unknown committed
7306 7307 7308 7309 7310 7311 7312 7313 7314
                           HA_STATUS_NO_LOCK |
                           HA_STATUS_TIME);

    show_table->file->get_foreign_key_list(thd, &f_key_list);
    FOREIGN_KEY_INFO *f_key_info;
    List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
    while ((f_key_info= it++))
    {
      restore_record(table, s->default_values);
7315
      table->field[0]->store(STRING_WITH_LEN("def"), cs);
7316 7317
      table->field[1]->store(db_name->str, db_name->length, cs);
      table->field[9]->store(table_name->str, table_name->length, cs);
7318 7319
      table->field[2]->store(f_key_info->foreign_id->str,
                             f_key_info->foreign_id->length, cs);
7320
      table->field[3]->store(STRING_WITH_LEN("def"), cs);
unknown's avatar
unknown committed
7321 7322
      table->field[4]->store(f_key_info->referenced_db->str, 
                             f_key_info->referenced_db->length, cs);
7323
      table->field[10]->store(f_key_info->referenced_table->str,
unknown's avatar
unknown committed
7324
                             f_key_info->referenced_table->length, cs);
7325 7326
      if (f_key_info->referenced_key_name)
      {
Michael Widenius's avatar
Michael Widenius committed
7327
        table->field[5]->store(f_key_info->referenced_key_name->str,
7328 7329 7330 7331 7332
                               f_key_info->referenced_key_name->length, cs);
        table->field[5]->set_notnull();
      }
      else
        table->field[5]->set_null();
unknown's avatar
unknown committed
7333
      table->field[6]->store(STRING_WITH_LEN("NONE"), cs);
7334
      table->field[7]->store(f_key_info->update_method->str,
unknown's avatar
unknown committed
7335
                             f_key_info->update_method->length, cs);
7336
      table->field[8]->store(f_key_info->delete_method->str,
unknown's avatar
unknown committed
7337 7338 7339 7340 7341 7342 7343 7344
                             f_key_info->delete_method->length, cs);
      if (schema_table_store_record(thd, table))
        DBUG_RETURN(1);
    }
  }
  DBUG_RETURN(0);
}

7345
struct schema_table_ref
unknown's avatar
unknown committed
7346 7347 7348 7349 7350
{
  const char *table_name;
  ST_SCHEMA_TABLE *schema_table;
};

7351 7352
ST_FIELD_INFO user_stats_fields_info[]=
{
7353
  {"USER", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User", SKIP_OPEN_TABLE},
7354 7355 7356
  {"TOTAL_CONNECTIONS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections",SKIP_OPEN_TABLE},
  {"CONCURRENT_CONNECTIONS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections",SKIP_OPEN_TABLE},
  {"CONNECTED_TIME", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time",SKIP_OPEN_TABLE},
7357 7358
  {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Busy_time",SKIP_OPEN_TABLE},
  {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Cpu_time",SKIP_OPEN_TABLE},
7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375
  {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_received",SKIP_OPEN_TABLE},
  {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_sent",SKIP_OPEN_TABLE},
  {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Binlog_bytes_written",SKIP_OPEN_TABLE},
  {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE},
  {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_sent",SKIP_OPEN_TABLE},
  {"ROWS_DELETED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_deleted",SKIP_OPEN_TABLE},
  {"ROWS_INSERTED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_inserted",SKIP_OPEN_TABLE},
  {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_updated",SKIP_OPEN_TABLE},
  {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Select_commands",SKIP_OPEN_TABLE},
  {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Update_commands",SKIP_OPEN_TABLE},
  {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Other_commands",SKIP_OPEN_TABLE},
  {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Commit_transactions",SKIP_OPEN_TABLE},
  {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rollback_transactions",SKIP_OPEN_TABLE},
  {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Denied_connections",SKIP_OPEN_TABLE},
  {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Lost_connections",SKIP_OPEN_TABLE},
  {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Access_denied",SKIP_OPEN_TABLE},
  {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Empty_queries",SKIP_OPEN_TABLE},
7376 7377 7378 7379 7380 7381
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
};

ST_FIELD_INFO client_stats_fields_info[]=
{
  {"CLIENT", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Client",SKIP_OPEN_TABLE},
7382 7383 7384
  {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Total_connections",SKIP_OPEN_TABLE},
  {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Concurrent_connections",SKIP_OPEN_TABLE},
  {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Connected_time",SKIP_OPEN_TABLE},
7385 7386
  {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Busy_time",SKIP_OPEN_TABLE},
  {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_DOUBLE, 0, 0, "Cpu_time",SKIP_OPEN_TABLE},
7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403
  {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_received",SKIP_OPEN_TABLE},
  {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Bytes_sent",SKIP_OPEN_TABLE},
  {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Binlog_bytes_written",SKIP_OPEN_TABLE},
  {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE},
  {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_sent",SKIP_OPEN_TABLE},
  {"ROWS_DELETED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_deleted",SKIP_OPEN_TABLE},
  {"ROWS_INSERTED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_inserted",SKIP_OPEN_TABLE},
  {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_updated",SKIP_OPEN_TABLE},
  {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Select_commands",SKIP_OPEN_TABLE},
  {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Update_commands",SKIP_OPEN_TABLE},
  {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Other_commands",SKIP_OPEN_TABLE},
  {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Commit_transactions",SKIP_OPEN_TABLE},
  {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rollback_transactions",SKIP_OPEN_TABLE},
  {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Denied_connections",SKIP_OPEN_TABLE},
  {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Lost_connections",SKIP_OPEN_TABLE},
  {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Access_denied",SKIP_OPEN_TABLE},
  {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Empty_queries",SKIP_OPEN_TABLE},
7404 7405 7406 7407 7408 7409 7410 7411
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
};


ST_FIELD_INFO table_stats_fields_info[]=
{
  {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema",SKIP_OPEN_TABLE},
  {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name",SKIP_OPEN_TABLE},
7412 7413 7414
  {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE},
  {"ROWS_CHANGED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_changed",SKIP_OPEN_TABLE},
  {"ROWS_CHANGED_X_INDEXES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_changed_x_#indexes",SKIP_OPEN_TABLE},
7415 7416 7417 7418 7419 7420 7421 7422
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
};

ST_FIELD_INFO index_stats_fields_info[]=
{
  {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema",SKIP_OPEN_TABLE},
  {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name",SKIP_OPEN_TABLE},
  {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Index_name",SKIP_OPEN_TABLE},
7423
  {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read",SKIP_OPEN_TABLE},
7424 7425
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0,0}
};
unknown's avatar
unknown committed
7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439

/*
  Find schema_tables elment by name

  SYNOPSIS
    find_schema_table_in_plugin()
    thd                 thread handler
    plugin              plugin
    table_name          table name

  RETURN
    0	table not found
    1   found the schema table
*/
unknown's avatar
WL#2936  
unknown committed
7440
static my_bool find_schema_table_in_plugin(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
7441 7442 7443 7444
                                           void* p_table)
{
  schema_table_ref *p_schema_table= (schema_table_ref *)p_table;
  const char* table_name= p_schema_table->table_name;
unknown's avatar
WL#2936  
unknown committed
7445
  ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
unknown's avatar
unknown committed
7446 7447 7448 7449 7450
  DBUG_ENTER("find_schema_table_in_plugin");

  if (!my_strcasecmp(system_charset_info,
                     schema_table->table_name,
                     table_name)) {
7451
    my_plugin_lock(thd, plugin);
unknown's avatar
unknown committed
7452 7453 7454 7455 7456 7457 7458
    p_schema_table->schema_table= schema_table;
    DBUG_RETURN(1);
  }

  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
7459

7460 7461 7462 7463 7464 7465 7466 7467 7468 7469
/*
  Find schema_tables elment by name

  SYNOPSIS
    find_schema_table()
    thd                 thread handler
    table_name          table name

  RETURN
    0	table not found
7470
    #   pointer to 'schema_tables' element
7471 7472 7473 7474
*/

ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
{
unknown's avatar
unknown committed
7475
  schema_table_ref schema_table_a;
7476
  ST_SCHEMA_TABLE *schema_table= schema_tables;
unknown's avatar
unknown committed
7477 7478
  DBUG_ENTER("find_schema_table");

7479
  for (; schema_table->table_name; schema_table++)
7480 7481 7482 7483
  {
    if (!my_strcasecmp(system_charset_info,
                       schema_table->table_name,
                       table_name))
unknown's avatar
unknown committed
7484
      DBUG_RETURN(schema_table);
7485
  }
unknown's avatar
unknown committed
7486 7487

  schema_table_a.table_name= table_name;
7488
  if (plugin_foreach(thd, find_schema_table_in_plugin,
unknown's avatar
unknown committed
7489 7490 7491 7492
                     MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a))
    DBUG_RETURN(schema_table_a.schema_table);

  DBUG_RETURN(NULL);
7493 7494 7495 7496 7497 7498 7499 7500 7501
}


ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx)
{
  return &schema_tables[schema_table_idx];
}


7502 7503
/**
  Create information_schema table using schema_table data.
7504

7505 7506 7507 7508 7509
  @note
    For MYSQL_TYPE_DECIMAL fields only, the field_length member has encoded
    into it two numbers, based on modulus of base-10 numbers.  In the ones
    position is the number of decimals.  Tens position is unused.  In the
    hundreds and thousands position is a two-digit decimal number representing
7510
    length.  Encode this value with  (length*100)+decimals  , where
7511 7512 7513
    0<decimals<10 and 0<=length<100 .

  @param
7514
    thd	       	          thread handler
7515 7516 7517

  @param table_list Used to pass I_S table information(fields info, tables
  parameters etc) and table name.
7518

7519 7520
  @retval  \#             Pointer to created table
  @retval  NULL           Can't create table
7521 7522
*/

7523
TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
7524 7525 7526 7527 7528
{
  int field_count= 0;
  Item *item;
  TABLE *table;
  List<Item> field_list;
7529
  ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
7530
  ST_FIELD_INFO *fields_info= schema_table->fields_info;
unknown's avatar
unknown committed
7531
  CHARSET_INFO *cs= system_charset_info;
7532 7533
  DBUG_ENTER("create_schema_table");

7534
  for (; fields_info->field_name; fields_info++)
7535 7536
  {
    switch (fields_info->field_type) {
7537
    case MYSQL_TYPE_TINY:
7538
    case MYSQL_TYPE_LONG:
7539 7540 7541 7542 7543 7544 7545
    case MYSQL_TYPE_SHORT:
    case MYSQL_TYPE_LONGLONG:
    case MYSQL_TYPE_INT24:
      if (!(item= new Item_return_int(fields_info->field_name,
                                      fields_info->field_length,
                                      fields_info->field_type,
                                      fields_info->value)))
7546 7547 7548
      {
        DBUG_RETURN(0);
      }
7549
      item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
7550
      break;
7551
    case MYSQL_TYPE_DATE:
7552
      if (!(item=new Item_return_date_time(fields_info->field_name,
7553
                                           strlen(fields_info->field_name),
7554 7555 7556
                                           fields_info->field_type)))
        DBUG_RETURN(0);
      break;
7557
    case MYSQL_TYPE_TIME:
7558
      if (!(item=new Item_return_date_time(fields_info->field_name,
7559
                                           strlen(fields_info->field_name),
7560 7561 7562
                                           fields_info->field_type)))
        DBUG_RETURN(0);
      break;
7563
    case MYSQL_TYPE_TIMESTAMP:
7564 7565
    case MYSQL_TYPE_DATETIME:
      if (!(item=new Item_return_date_time(fields_info->field_name,
7566
                                           strlen(fields_info->field_name),
7567
                                           fields_info->field_type)))
7568 7569
        DBUG_RETURN(0);
      break;
7570 7571
    case MYSQL_TYPE_FLOAT:
    case MYSQL_TYPE_DOUBLE:
7572
      if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC,
7573 7574 7575
                           fields_info->field_length)) == NULL)
        DBUG_RETURN(NULL);
      break;
7576
    case MYSQL_TYPE_DECIMAL:
7577
    case MYSQL_TYPE_NEWDECIMAL:
7578 7579 7580 7581
      if (!(item= new Item_decimal((longlong) fields_info->value, false)))
      {
        DBUG_RETURN(0);
      }
7582 7583 7584 7585 7586 7587
      /*
        Create a type holder, as we want the type of the item to defined
        the type of the object, not the value
      */
      if (!(item= new Item_type_holder(thd, item)))
        DBUG_RETURN(0);
7588
      item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
7589 7590 7591 7592 7593 7594 7595 7596 7597
      item->decimals= fields_info->field_length%10;
      item->max_length= (fields_info->field_length/100)%100;
      if (item->unsigned_flag == 0)
        item->max_length+= 1;
      if (item->decimals > 0)
        item->max_length+= 1;
      item->set_name(fields_info->field_name,
                     strlen(fields_info->field_name), cs);
      break;
7598 7599 7600 7601 7602 7603 7604 7605 7606 7607
    case MYSQL_TYPE_TINY_BLOB:
    case MYSQL_TYPE_MEDIUM_BLOB:
    case MYSQL_TYPE_LONG_BLOB:
    case MYSQL_TYPE_BLOB:
      if (!(item= new Item_blob(fields_info->field_name,
                                fields_info->field_length)))
      {
        DBUG_RETURN(0);
      }
      break;
7608
    default:
7609 7610 7611
      /* Don't let unimplemented types pass through. Could be a grave error. */
      DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING);

7612
      if (!(item= new Item_empty_string("", fields_info->field_length, cs)))
7613 7614 7615
      {
        DBUG_RETURN(0);
      }
unknown's avatar
unknown committed
7616 7617
      item->set_name(fields_info->field_name,
                     strlen(fields_info->field_name), cs);
7618 7619 7620
      break;
    }
    field_list.push_back(item);
7621
    item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL);
7622 7623 7624
    field_count++;
  }
  TMP_TABLE_PARAM *tmp_table_param =
7625
    (TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM)));
7626
  tmp_table_param->init();
unknown's avatar
unknown committed
7627
  tmp_table_param->table_charset= cs;
7628
  tmp_table_param->field_count= field_count;
7629
  tmp_table_param->schema_table= 1;
7630 7631 7632
  SELECT_LEX *select_lex= thd->lex->current_select;
  if (!(table= create_tmp_table(thd, tmp_table_param,
                                field_list, (ORDER*) 0, 0, 0, 
7633
                                (select_lex->options | thd->variables.option_bits |
7634
                                 TMP_TABLE_ALL_COLUMNS),
unknown's avatar
unknown committed
7635
                                HA_POS_ERROR, table_list->alias)))
7636
    DBUG_RETURN(0);
7637 7638 7639 7640 7641 7642
  my_bitmap_map* bitmaps=
    (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count));
  bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
              FALSE);
  table->read_set= &table->def_read_set;
  bitmap_clear_all(table->read_set);
7643
  table_list->schema_table_param= tmp_table_param;
7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658
  DBUG_RETURN(table);
}


/*
  For old SHOW compatibility. It is used when
  old SHOW doesn't have generated column names
  Make list of fields for SHOW

  SYNOPSIS
    make_old_format()
    thd			thread handler
    schema_table        pointer to 'schema_tables' element

  RETURN
7659 7660
   1	error
   0	success
7661 7662 7663 7664 7665
*/

int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
  ST_FIELD_INFO *field_info= schema_table->fields_info;
7666
  Name_resolution_context *context= &thd->lex->select_lex.context;
7667
  for (; field_info->field_name; field_info++)
7668 7669 7670
  {
    if (field_info->old_name)
    {
7671 7672
      Item_field *field= new Item_field(context,
                                        NullS, NullS, field_info->field_name);
7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691
      if (field)
      {
        field->set_name(field_info->old_name,
                        strlen(field_info->old_name),
                        system_charset_info);
        if (add_item_to_list(thd, field))
          return 1;
      }
    }
  }
  return 0;
}


int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
  char tmp[128];
  LEX *lex= thd->lex;
  SELECT_LEX *sel= lex->current_select;
7692
  Name_resolution_context *context= &sel->context;
7693 7694 7695 7696 7697

  if (!sel->item_list.elements)
  {
    ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
    String buffer(tmp,sizeof(tmp), system_charset_info);
7698 7699
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
7700 7701 7702 7703 7704 7705
    if (!field || add_item_to_list(thd, field))
      return 1;
    buffer.length(0);
    buffer.append(field_info->old_name);
    if (lex->wild && lex->wild->ptr())
    {
7706
      buffer.append(STRING_WITH_LEN(" ("));
7707
      buffer.append(lex->wild->ptr());
7708
      buffer.append(')');
7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720
    }
    field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
  }
  return 0;
}


int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
  char tmp[128];
  String buffer(tmp,sizeof(tmp), thd->charset());
  LEX *lex= thd->lex;
7721
  Name_resolution_context *context= &lex->select_lex.context;
7722 7723 7724 7725 7726 7727 7728

  ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
  buffer.length(0);
  buffer.append(field_info->old_name);
  buffer.append(lex->select_lex.db);
  if (lex->wild && lex->wild->ptr())
  {
7729
    buffer.append(STRING_WITH_LEN(" ("));
7730
    buffer.append(lex->wild->ptr());
7731
    buffer.append(')');
7732
  }
7733 7734
  Item_field *field= new Item_field(context,
                                    NullS, NullS, field_info->field_name);
7735 7736 7737 7738 7739 7740 7741
  if (add_item_to_list(thd, field))
    return 1;
  field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
  if (thd->lex->verbose)
  {
    field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
    field_info= &schema_table->fields_info[3];
7742
    field= new Item_field(context, NullS, NullS, field_info->field_name);
7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753
    if (add_item_to_list(thd, field))
      return 1;
    field->set_name(field_info->old_name, strlen(field_info->old_name),
                    system_charset_info);
  }
  return 0;
}


int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
7754
  int fields_arr[]= {3, 15, 14, 6, 16, 5, 17, 18, 19, -1};
7755 7756
  int *field_num= fields_arr;
  ST_FIELD_INFO *field_info;
7757 7758
  Name_resolution_context *context= &thd->lex->select_lex.context;

7759
  for (; *field_num >= 0; field_num++)
7760
  {
7761
    field_info= &schema_table->fields_info[*field_num];
7762 7763 7764
    if (!thd->lex->verbose && (*field_num == 14 ||
                               *field_num == 18 ||
                               *field_num == 19))
7765
      continue;
7766 7767
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
7768
    if (field)
7769
    {
7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780
      field->set_name(field_info->old_name,
                      strlen(field_info->old_name),
                      system_charset_info);
      if (add_item_to_list(thd, field))
        return 1;
    }
  }
  return 0;
}


7781 7782 7783 7784 7785
int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
  int fields_arr[]= {0, 2, 1, 3, -1};
  int *field_num= fields_arr;
  ST_FIELD_INFO *field_info;
7786 7787
  Name_resolution_context *context= &thd->lex->select_lex.context;

7788 7789 7790
  for (; *field_num >= 0; field_num++)
  {
    field_info= &schema_table->fields_info[*field_num];
7791 7792
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805
    if (field)
    {
      field->set_name(field_info->old_name,
                      strlen(field_info->old_name),
                      system_charset_info);
      if (add_item_to_list(thd, field))
        return 1;
    }
  }
  return 0;
}


7806 7807
int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
Sergei Golubchik's avatar
Sergei Golubchik committed
7808
  int fields_arr[]= {2, 3, 4, 27, 24, 23, 22, 26, 28, 29, 30, -1};
7809 7810
  int *field_num= fields_arr;
  ST_FIELD_INFO *field_info;
7811 7812
  Name_resolution_context *context= &thd->lex->select_lex.context;

7813 7814 7815
  for (; *field_num >= 0; field_num++)
  {
    field_info= &schema_table->fields_info[*field_num];
7816 7817
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
7818 7819 7820 7821 7822 7823 7824
    if (field)
    {
      field->set_name(field_info->old_name,
                      strlen(field_info->old_name),
                      system_charset_info);
      if (add_item_to_list(thd, field))
        return 1;
7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848
    }
  }
  return 0;
}


/*
  Create information_schema table

  SYNOPSIS
  mysql_schema_table()
    thd                thread handler
    lex                pointer to LEX
    table_list         pointer to table_list

  RETURN
    0	success
    1   error
*/

int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
{
  TABLE *table;
  DBUG_ENTER("mysql_schema_table");
7849
  if (!(table= table_list->schema_table->create_table(thd, table_list)))
7850
    DBUG_RETURN(1);
7851
  table->s->tmp_table= SYSTEM_TMP_TABLE;
7852
  table->grant.privilege= SELECT_ACL;
7853 7854 7855 7856 7857 7858 7859
  /*
    This test is necessary to make
    case insensitive file systems +
    upper case table names(information schema tables) +
    views
    working correctly
  */
7860 7861 7862 7863
  if (table_list->schema_table_name)
    table->alias_name_used= my_strcasecmp(table_alias_charset,
                                          table_list->schema_table_name,
                                          table_list->alias);
unknown's avatar
unknown committed
7864 7865
  table_list->table_name= table->s->table_name.str;
  table_list->table_name_length= table->s->table_name.length;
7866 7867 7868 7869
  table_list->table= table;
  table->next= thd->derived_tables;
  thd->derived_tables= table;
  table_list->select_lex->options |= OPTION_SCHEMA_TABLE;
7870
  lex->safe_to_cache_query= 0;
7871 7872 7873 7874 7875

  if (table_list->schema_table_reformed) // show command
  {
    SELECT_LEX *sel= lex->current_select;
    Item *item;
unknown's avatar
unknown committed
7876
    Field_translator *transl, *org_transl;
7877 7878 7879

    if (table_list->field_translation)
    {
7880
      Field_translator *end= table_list->field_translation_end;
7881 7882 7883
      for (transl= table_list->field_translation; transl < end; transl++)
      {
        if (!transl->item->fixed &&
7884
            transl->item->fix_fields(thd, &transl->item))
7885 7886 7887 7888 7889 7890
          DBUG_RETURN(1);
      }
      DBUG_RETURN(0);
    }
    List_iterator_fast<Item> it(sel->item_list);
    if (!(transl=
unknown's avatar
Rename:  
unknown committed
7891
          (Field_translator*)(thd->stmt_arena->
7892 7893 7894 7895 7896
                              alloc(sel->item_list.elements *
                                    sizeof(Field_translator)))))
    {
      DBUG_RETURN(1);
    }
unknown's avatar
unknown committed
7897
    for (org_transl= transl; (item= it++); transl++)
7898
    {
unknown's avatar
unknown committed
7899 7900 7901 7902
      transl->item= item;
      transl->name= item->name;
      if (!item->fixed && item->fix_fields(thd, &transl->item))
      {
7903
        DBUG_RETURN(1);
unknown's avatar
unknown committed
7904
      }
7905
    }
unknown's avatar
unknown committed
7906 7907
    table_list->field_translation= org_transl;
    table_list->field_translation_end= transl;
7908 7909
  }

7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932
  DBUG_RETURN(0);
}


/*
  Generate select from information_schema table

  SYNOPSIS
    make_schema_select()
    thd                  thread handler
    sel                  pointer to SELECT_LEX
    schema_table_idx     index of 'schema_tables' element

  RETURN
    0	success
    1   error
*/

int make_schema_select(THD *thd, SELECT_LEX *sel,
		       enum enum_schema_tables schema_table_idx)
{
  ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx);
  LEX_STRING db, table;
7933
  DBUG_ENTER("make_schema_select");
unknown's avatar
unknown committed
7934
  DBUG_PRINT("enter", ("mysql_schema_select: %s", schema_table->table_name));
7935
  /*
7936 7937 7938
     We have to make non const db_name & table_name
     because of lower_case_table_names
  */
Sergei Golubchik's avatar
Sergei Golubchik committed
7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951
  if (!thd->make_lex_string(&db, INFORMATION_SCHEMA_NAME.str,
                            INFORMATION_SCHEMA_NAME.length))
    DBUG_RETURN(1);

  if (!thd->make_lex_string(&table, schema_table->table_name,
                            strlen(schema_table->table_name)))
    DBUG_RETURN(1);

  if (schema_table->old_format(thd, schema_table))

    DBUG_RETURN(1);

  if (!sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
7952
                              0, 0, TL_READ, MDL_SHARED_READ))
7953
    DBUG_RETURN(1);
Sergei Golubchik's avatar
Sergei Golubchik committed
7954

7955 7956 7957 7958
  DBUG_RETURN(0);
}


7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004
/**
  Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area /
  Warning_info state after itself.

  This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which
  may "partially silence" some errors. The thing is that during
  fill_table() many errors might be emitted. These errors stem from the
  nature of fill_table().

  For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx'
  results in a number of 'Table <db name>.xxx does not exist' errors,
  because fill_table() tries to open the 'xxx' table in every possible
  database.

  Those errors are cleared (the error status is cleared from
  Diagnostics_area) inside fill_table(), but they remain in Warning_info
  (Warning_info is not cleared because it may contain useful warnings).

  This function is responsible for making sure that Warning_info does not
  contain warnings corresponding to the cleared errors.

  @note: THD::no_warnings_for_error used to be set before calling
  fill_table(), thus those errors didn't go to Warning_info. This is not
  the case now (THD::no_warnings_for_error was eliminated as a hack), so we
  need to take care of those warnings here.

  @param thd            Thread context.
  @param table_list     I_S table.
  @param join_table     JOIN/SELECT table.

  @return Error status.
  @retval TRUE Error.
  @retval FALSE Success.
*/
static bool do_fill_table(THD *thd,
                          TABLE_LIST *table_list,
                          JOIN_TAB *join_table)
{
  // NOTE: fill_table() may generate many "useless" warnings, which will be
  // ignored afterwards. On the other hand, there might be "useful"
  // warnings, which should be presented to the user. Warning_info usually
  // stores no more than THD::variables.max_error_count warnings.
  // The problem is that "useless warnings" may occupy all the slots in the
  // Warning_info, so "useful warnings" get rejected. In order to avoid
  // that problem we create a Warning_info instance, which is capable of
  // storing "unlimited" number of warnings.
Sergei Golubchik's avatar
Sergei Golubchik committed
8005
  Warning_info wi(thd->query_id, true);
8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044
  Warning_info *wi_saved= thd->warning_info;

  thd->warning_info= &wi;

  bool res= table_list->schema_table->fill_table(
    thd, table_list, join_table->select_cond);

  thd->warning_info= wi_saved;

  // Pass an error if any.

  if (thd->stmt_da->is_error())
  {
    thd->warning_info->push_warning(thd,
                                    thd->stmt_da->sql_errno(),
                                    thd->stmt_da->get_sqlstate(),
                                    MYSQL_ERROR::WARN_LEVEL_ERROR,
                                    thd->stmt_da->message());
  }

  // Pass warnings (if any).
  //
  // Filter out warnings with WARN_LEVEL_ERROR level, because they
  // correspond to the errors which were filtered out in fill_table().


  List_iterator_fast<MYSQL_ERROR> it(wi.warn_list());
  MYSQL_ERROR *err;

  while ((err= it++))
  {
    if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR)
      thd->warning_info->push_warning(thd, err);
  }

  return res;
}


8045
/*
8046
  Fill temporary schema tables before SELECT
8047 8048 8049 8050

  SYNOPSIS
    get_schema_tables_result()
    join  join which use schema tables
8051
    executed_place place where I_S table processed
8052 8053

  RETURN
unknown's avatar
unknown committed
8054 8055
    FALSE success
    TRUE  error
8056 8057
*/

8058 8059
bool get_schema_tables_result(JOIN *join,
                              enum enum_schema_table_state executed_place)
8060 8061
{
  THD *thd= join->thd;
unknown's avatar
unknown committed
8062 8063
  LEX *lex= thd->lex;
  bool result= 0;
8064 8065
  DBUG_ENTER("get_schema_tables_result");

8066
  for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES); 
8067
       tab; 
8068
       tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS))
8069
  {
8070 8071
    if (!tab->table || !tab->table->pos_in_table_list)
      break;
unknown's avatar
unknown committed
8072

unknown's avatar
unknown committed
8073
    TABLE_LIST *table_list= tab->table->pos_in_table_list;
8074
    if (table_list->schema_table && thd->fill_information_schema_tables())
8075
    {
8076 8077
      bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
                          lex->current_select->master_unit()->item);
8078

8079 8080 8081
      /* A value of 0 indicates a dummy implementation */
      if (table_list->schema_table->fill_table == 0)
        continue;
8082 8083 8084 8085 8086 8087

      /* skip I_S optimizations specific to get_all_tables */
      if (thd->lex->describe &&
          (table_list->schema_table->fill_table != get_all_tables))
        continue;

8088
      /*
8089 8090 8091 8092 8093 8094 8095
        If schema table is already processed and
        the statement is not a subselect then
        we don't need to fill this table again.
        If schema table is already processed and
        schema_table_state != executed_place then
        table is already processed and
        we should skip second data processing.
8096
      */
8097 8098
      if (table_list->schema_table_state &&
          (!is_subselect || table_list->schema_table_state != executed_place))
8099 8100
        continue;

8101 8102 8103 8104 8105 8106
      /*
        if table is used in a subselect and
        table has been processed earlier with the same
        'executed_place' value then we should refresh the table.
      */
      if (table_list->schema_table_state && is_subselect)
unknown's avatar
unknown committed
8107
      {
8108
        table_list->table->file->extra(HA_EXTRA_NO_CACHE);
unknown's avatar
unknown committed
8109
        table_list->table->file->extra(HA_EXTRA_RESET_STATE);
8110
        table_list->table->file->ha_delete_all_rows();
unknown's avatar
unknown committed
8111
        free_io_cache(table_list->table);
unknown's avatar
unknown committed
8112
        filesort_free_buffers(table_list->table,1);
8113
        table_list->table->null_row= 0;
unknown's avatar
unknown committed
8114 8115
      }
      else
8116
        table_list->table->file->stats.records= 0;
unknown's avatar
unknown committed
8117

8118
      if (do_fill_table(thd, table_list, tab))
8119
      {
unknown's avatar
unknown committed
8120
        result= 1;
8121
        join->error= 1;
8122
        tab->read_record.table->file= table_list->table->file;
8123
        table_list->schema_table_state= executed_place;
8124 8125
        if (!thd->is_error())
          my_error(ER_UNKNOWN_ERROR, MYF(0));
8126 8127
        break;
      }
8128
      tab->read_record.table->file= table_list->table->file;
8129
      table_list->schema_table_state= executed_place;
8130 8131
    }
  }
unknown's avatar
unknown committed
8132
  DBUG_RETURN(result);
8133 8134
}

8135
struct run_hton_fill_schema_table_args
8136 8137 8138 8139 8140
{
  TABLE_LIST *tables;
  COND *cond;
};

8141
static my_bool run_hton_fill_schema_table(THD *thd, plugin_ref plugin,
8142 8143
                                          void *arg)
{
8144 8145
  struct run_hton_fill_schema_table_args *args=
    (run_hton_fill_schema_table_args *) arg;
Sergei Golubchik's avatar
Sergei Golubchik committed
8146
  handlerton *hton= plugin_hton(plugin);
8147 8148 8149
  if (hton->fill_is_table && hton->state == SHOW_OPTION_YES)
      hton->fill_is_table(hton, thd, args->tables, args->cond,
            get_schema_table_idx(args->tables->schema_table));
8150 8151 8152
  return false;
}

8153
int hton_fill_schema_table(THD *thd, TABLE_LIST *tables, COND *cond)
8154
{
8155
  DBUG_ENTER("hton_fill_schema_table");
8156

8157
  struct run_hton_fill_schema_table_args args;
8158 8159 8160
  args.tables= tables;
  args.cond= cond;

8161
  plugin_foreach(thd, run_hton_fill_schema_table,
8162 8163 8164 8165
                 MYSQL_STORAGE_ENGINE_PLUGIN, &args);

  DBUG_RETURN(0);
}
8166

8167

8168 8169 8170 8171 8172 8173
static
int store_key_cache_table_record(THD *thd, TABLE *table,
                                 const char *name, uint name_length,
                                 KEY_CACHE *key_cache,
                                 uint partitions, uint partition_no)
{
Igor Babaev's avatar
Igor Babaev committed
8174
  KEY_CACHE_STATISTICS keycache_stats;
8175 8176 8177
  uint err;
  DBUG_ENTER("store_key_cache_table_record");

Igor Babaev's avatar
Igor Babaev committed
8178
  get_key_cache_statistics(key_cache, partition_no, &keycache_stats);
8179

Igor Babaev's avatar
Igor Babaev committed
8180
  if (!key_cache->key_cache_inited || keycache_stats.mem_size == 0)
8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199
    DBUG_RETURN(0);

  restore_record(table, s->default_values);
  table->field[0]->store(name, name_length, system_charset_info);
  if (partitions == 0)
    table->field[1]->set_null();
  else
  {
    table->field[1]->set_notnull(); 
    table->field[1]->store((long) partitions, TRUE);
  }

  if (partition_no == 0)
    table->field[2]->set_null();
  else
  {
    table->field[2]->set_notnull();
    table->field[2]->store((long) partition_no, TRUE);
  }
Igor Babaev's avatar
Igor Babaev committed
8200 8201 8202 8203 8204 8205 8206 8207 8208
  table->field[3]->store(keycache_stats.mem_size, TRUE);
  table->field[4]->store(keycache_stats.block_size, TRUE);
  table->field[5]->store(keycache_stats.blocks_used, TRUE);
  table->field[6]->store(keycache_stats.blocks_unused, TRUE);
  table->field[7]->store(keycache_stats.blocks_changed, TRUE);
  table->field[8]->store(keycache_stats.read_requests, TRUE);
  table->field[9]->store(keycache_stats.reads, TRUE);
  table->field[10]->store(keycache_stats.write_requests, TRUE);
  table->field[11]->store(keycache_stats.writes, TRUE);
8209 8210 8211 8212 8213

  err= schema_table_store_record(thd, table);
  DBUG_RETURN(err);
}

Sergei Golubchik's avatar
Sergei Golubchik committed
8214
int run_fill_key_cache_tables(const char *name, KEY_CACHE *key_cache, void *p)
8215
{
Sergei Golubchik's avatar
Sergei Golubchik committed
8216
  DBUG_ENTER("run_fill_key_cache_tables");
8217

Sergei Golubchik's avatar
Sergei Golubchik committed
8218 8219
  if (!key_cache->key_cache_inited)
    DBUG_RETURN(0);
8220

Sergei Golubchik's avatar
Sergei Golubchik committed
8221 8222 8223 8224 8225
  TABLE *table= (TABLE *)p;
  THD *thd= table->in_use;
  uint partitions= key_cache->partitions;    
  size_t namelen= strlen(name);
  DBUG_ASSERT(partitions <= MAX_KEY_CACHE_PARTITIONS);
8226

Sergei Golubchik's avatar
Sergei Golubchik committed
8227 8228 8229
  if (partitions)
  {
    for (uint i= 0; i < partitions; i++)
8230
    {
Sergei Golubchik's avatar
Sergei Golubchik committed
8231 8232 8233
      if (store_key_cache_table_record(thd, table, name, namelen,
                                       key_cache, partitions, i+1))
        DBUG_RETURN(1);
8234 8235
    }
  }
Sergei Golubchik's avatar
Sergei Golubchik committed
8236 8237 8238 8239

  if (store_key_cache_table_record(thd, table, name, namelen,
                                   key_cache, partitions, 0))
    DBUG_RETURN(1);
8240 8241 8242
  DBUG_RETURN(0);
}

Sergei Golubchik's avatar
Sergei Golubchik committed
8243 8244 8245 8246 8247 8248 8249 8250 8251
int fill_key_cache_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  DBUG_ENTER("fill_key_cache_tables");

  int res= process_key_caches(run_fill_key_cache_tables, tables->table);

  DBUG_RETURN(res);
}

8252

8253 8254
ST_FIELD_INFO schema_fields_info[]=
{
8255
  {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8256 8257
  {"SCHEMA_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
   SKIP_OPEN_TABLE},
8258 8259 8260
  {"DEFAULT_CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
   SKIP_OPEN_TABLE},
  {"DEFAULT_COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
8261 8262 8263
   SKIP_OPEN_TABLE},
  {"SQL_PATH", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8264 8265 8266 8267 8268
};


ST_FIELD_INFO tables_fields_info[]=
{
8269
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8270 8271 8272 8273 8274
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
   SKIP_OPEN_TABLE},
  {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine", OPEN_FRM_ONLY},
8275
  {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8276 8277
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version", OPEN_FRM_ONLY},
  {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", OPEN_FULL_TABLE},
8278
  {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8279
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", OPEN_FULL_TABLE},
8280
  {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8281
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", OPEN_FULL_TABLE},
8282
  {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8283
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", OPEN_FULL_TABLE},
8284
  {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8285
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", OPEN_FULL_TABLE},
8286
  {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8287
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", OPEN_FULL_TABLE},
8288
  {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8289
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", OPEN_FULL_TABLE},
8290
  {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0,
8291 8292 8293 8294
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Auto_increment", OPEN_FULL_TABLE},
  {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", OPEN_FULL_TABLE},
  {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", OPEN_FULL_TABLE},
  {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", OPEN_FULL_TABLE},
8295 8296
  {"TABLE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
   OPEN_FRM_ONLY},
8297
  {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8298 8299 8300
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", OPEN_FULL_TABLE},
  {"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options",
   OPEN_FRM_ONLY},
8301 8302
  {"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 
   "Comment", OPEN_FRM_ONLY},
8303
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8304 8305 8306 8307 8308
};


ST_FIELD_INFO columns_fields_info[]=
{
8309
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8310 8311 8312 8313
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field",
   OPEN_FRM_ONLY},
8314
  {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8315
   MY_I_S_UNSIGNED, 0, OPEN_FRM_ONLY},
8316
  {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0,
8317 8318 8319
   1, "Default", OPEN_FRM_ONLY},
  {"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null", OPEN_FRM_ONLY},
  {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8320
  {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8321
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
8322
  {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
8323
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
8324
  {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8325
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
8326
  {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
8327
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
8328
  {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8329
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
8330 8331 8332 8333
  {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, 0,
   OPEN_FRM_ONLY},
  {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
   OPEN_FRM_ONLY},
8334 8335
  {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type", OPEN_FRM_ONLY},
  {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY},
8336
  {"EXTRA", 27, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
8337
  {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY},
8338 8339
  {"COLUMN_COMMENT", COLUMN_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 
   "Comment", OPEN_FRM_ONLY},
8340
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8341 8342 8343 8344 8345
};


ST_FIELD_INFO charsets_fields_info[]=
{
8346
  {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
8347
   SKIP_OPEN_TABLE},
8348 8349
  {"DEFAULT_COLLATE_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
   "Default collation", SKIP_OPEN_TABLE},
8350 8351 8352 8353
  {"DESCRIPTION", 60, MYSQL_TYPE_STRING, 0, 0, "Description",
   SKIP_OPEN_TABLE},
  {"MAXLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Maxlen", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8354 8355 8356 8357 8358
};


ST_FIELD_INFO collation_fields_info[]=
{
8359 8360 8361
  {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Collation",
   SKIP_OPEN_TABLE},
  {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
8362 8363 8364 8365 8366 8367 8368
   SKIP_OPEN_TABLE},
  {"ID", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Id",
   SKIP_OPEN_TABLE},
  {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default", SKIP_OPEN_TABLE},
  {"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled", SKIP_OPEN_TABLE},
  {"SORTLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Sortlen", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8369 8370 8371
};


8372 8373 8374 8375 8376 8377 8378
ST_FIELD_INFO enabled_roles_fields_info[]=
{
  {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};


unknown's avatar
unknown committed
8379 8380
ST_FIELD_INFO engines_fields_info[]=
{
8381 8382
  {"ENGINE", 64, MYSQL_TYPE_STRING, 0, 0, "Engine", SKIP_OPEN_TABLE},
  {"SUPPORT", 8, MYSQL_TYPE_STRING, 0, 0, "Support", SKIP_OPEN_TABLE},
8383
  {"COMMENT", 160, MYSQL_TYPE_STRING, 0, 0, "Comment", SKIP_OPEN_TABLE},
8384 8385 8386
  {"TRANSACTIONS", 3, MYSQL_TYPE_STRING, 0, 1, "Transactions", SKIP_OPEN_TABLE},
  {"XA", 3, MYSQL_TYPE_STRING, 0, 1, "XA", SKIP_OPEN_TABLE},
  {"SAVEPOINTS", 3 ,MYSQL_TYPE_STRING, 0, 1, "Savepoints", SKIP_OPEN_TABLE},
8387
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
unknown's avatar
unknown committed
8388 8389 8390
};


8391 8392
ST_FIELD_INFO events_fields_info[]=
{
8393
  {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8394 8395 8396 8397
  {"EVENT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db",
   SKIP_OPEN_TABLE},
  {"EVENT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
   SKIP_OPEN_TABLE},
8398
  {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
8399 8400 8401 8402 8403 8404 8405 8406 8407
  {"TIME_ZONE", 64, MYSQL_TYPE_STRING, 0, 0, "Time zone", SKIP_OPEN_TABLE},
  {"EVENT_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"EVENT_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"EVENT_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
  {"EXECUTE_AT", 0, MYSQL_TYPE_DATETIME, 0, 1, "Execute at", SKIP_OPEN_TABLE},
  {"INTERVAL_VALUE", 256, MYSQL_TYPE_STRING, 0, 1, "Interval value",
   SKIP_OPEN_TABLE},
  {"INTERVAL_FIELD", 18, MYSQL_TYPE_STRING, 0, 1, "Interval field",
   SKIP_OPEN_TABLE},
8408
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8409 8410 8411 8412 8413 8414 8415 8416 8417
  {"STARTS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Starts", SKIP_OPEN_TABLE},
  {"ENDS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Ends", SKIP_OPEN_TABLE},
  {"STATUS", 18, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
  {"ON_COMPLETION", 12, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
  {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
  {"LAST_EXECUTED", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
  {"EVENT_COMMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"ORIGINATOR", 10, MYSQL_TYPE_LONGLONG, 0, 0, "Originator", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
8418
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8419
   "character_set_client", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
8420
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8421
   "collation_connection", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
8422
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8423 8424
   "Database Collation", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8425 8426 8427 8428
};



8429 8430
ST_FIELD_INFO coll_charset_app_fields_info[]=
{
8431 8432 8433 8434
  {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
   SKIP_OPEN_TABLE},
  {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
   SKIP_OPEN_TABLE},
8435
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8436 8437 8438 8439 8440
};


ST_FIELD_INFO proc_fields_info[]=
{
8441
  {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8442
  {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8443 8444 8445 8446 8447
  {"ROUTINE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db",
   SKIP_OPEN_TABLE},
  {"ROUTINE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
   SKIP_OPEN_TABLE},
  {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
Sergey Glukhov's avatar
Sergey Glukhov committed
8448 8449 8450 8451 8452
  {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
  {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
  {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
  {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
Sergei Golubchik's avatar
Sergei Golubchik committed
8453 8454
  {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
Sergey Glukhov's avatar
Sergey Glukhov committed
8455 8456 8457
  {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471
  {"ROUTINE_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"ROUTINE_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"EXTERNAL_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"EXTERNAL_LANGUAGE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   SKIP_OPEN_TABLE},
  {"PARAMETER_STYLE", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"IS_DETERMINISTIC", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"SQL_DATA_ACCESS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   SKIP_OPEN_TABLE},
  {"SQL_PATH", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, "Security_type",
   SKIP_OPEN_TABLE},
  {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Created", SKIP_OPEN_TABLE},
  {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Modified", SKIP_OPEN_TABLE},
8472
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8473
  {"ROUTINE_COMMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Comment",
8474
   SKIP_OPEN_TABLE},
8475
  {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
8476
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8477
   "character_set_client", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
8478
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8479
   "collation_connection", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
8480
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8481 8482
   "Database Collation", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8483 8484 8485 8486 8487
};


ST_FIELD_INFO stat_fields_info[]=
{
8488
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8489 8490 8491 8492 8493 8494 8495 8496 8497 8498
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", OPEN_FRM_ONLY},
  {"NON_UNIQUE", 1, MYSQL_TYPE_LONGLONG, 0, 0, "Non_unique", OPEN_FRM_ONLY},
  {"INDEX_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"INDEX_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Key_name",
   OPEN_FRM_ONLY},
  {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONGLONG, 0, 0, "Seq_in_index", OPEN_FRM_ONLY},
  {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name",
   OPEN_FRM_ONLY},
  {"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation", OPEN_FRM_ONLY},
8499
  {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 1,
8500 8501 8502 8503 8504 8505
   "Cardinality", OPEN_FULL_TABLE},
  {"SUB_PART", 3, MYSQL_TYPE_LONGLONG, 0, 1, "Sub_part", OPEN_FRM_ONLY},
  {"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed", OPEN_FRM_ONLY},
  {"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null", OPEN_FRM_ONLY},
  {"INDEX_TYPE", 16, MYSQL_TYPE_STRING, 0, 0, "Index_type", OPEN_FULL_TABLE},
  {"COMMENT", 16, MYSQL_TYPE_STRING, 0, 1, "Comment", OPEN_FRM_ONLY},
8506 8507
  {"INDEX_COMMENT", INDEX_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 
   "Index_comment", OPEN_FRM_ONLY},
8508
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8509 8510 8511 8512 8513
};


ST_FIELD_INFO view_fields_info[]=
{
8514
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8515 8516
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
Sergey Glukhov's avatar
Sergey Glukhov committed
8517 8518
  {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8519
  {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8520
  {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
Sergey Glukhov's avatar
Sergey Glukhov committed
8521
  {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8522
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
8523
   OPEN_FRM_ONLY},
8524
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
8525
   OPEN_FRM_ONLY},
8526
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8527 8528 8529 8530 8531
};


ST_FIELD_INFO user_privileges_fields_info[]=
{
8532
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8533
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8534 8535 8536
  {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8537 8538 8539 8540 8541
};


ST_FIELD_INFO schema_privileges_fields_info[]=
{
8542
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8543
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8544 8545 8546 8547
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8548 8549 8550 8551 8552
};


ST_FIELD_INFO table_privileges_fields_info[]=
{
8553
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8554
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8555 8556 8557 8558 8559
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8560 8561 8562 8563 8564
};


ST_FIELD_INFO column_privileges_fields_info[]=
{
8565
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8566
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8567 8568 8569 8570 8571 8572
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8573 8574 8575 8576 8577
};


ST_FIELD_INFO table_constraints_fields_info[]=
{
8578
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8579 8580 8581 8582 8583 8584 8585 8586 8587
  {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"CONSTRAINT_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8588 8589 8590 8591 8592
};


ST_FIELD_INFO key_column_usage_fields_info[]=
{
8593
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8594 8595 8596 8597
  {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
8598
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FULL_TABLE},
  {"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONGLONG, 0, 1, 0,
   OPEN_FULL_TABLE},
  {"REFERENCED_TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   OPEN_FULL_TABLE},
  {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   OPEN_FULL_TABLE},
  {"REFERENCED_COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   OPEN_FULL_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8612 8613 8614 8615 8616
};


ST_FIELD_INFO table_names_fields_info[]=
{
8617
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8618
  {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8619 8620
  {"TABLE_NAME", NAME_CHAR_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH,
   MYSQL_TYPE_STRING, 0, 0, "Tables_in_", SKIP_OPEN_TABLE},
8621 8622 8623
  {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type",
   OPEN_FRM_ONLY},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8624 8625 8626
};


8627 8628
ST_FIELD_INFO open_tables_fields_info[]=
{
8629 8630 8631 8632 8633 8634
  {"Database", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
   SKIP_OPEN_TABLE},
  {"Table",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", SKIP_OPEN_TABLE},
  {"In_use", 1, MYSQL_TYPE_LONGLONG, 0, 0, "In_use", SKIP_OPEN_TABLE},
  {"Name_locked", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Name_locked", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8635 8636 8637
};


8638 8639
ST_FIELD_INFO triggers_fields_info[]=
{
Sergey Glukhov's avatar
Sergey Glukhov committed
8640 8641
  {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"TRIGGER_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8642
  {"TRIGGER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger",
Sergey Glukhov's avatar
Sergey Glukhov committed
8643 8644
   OPEN_FRM_ONLY},
  {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FRM_ONLY},
8645
  {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
8646
   OPEN_FRM_ONLY},
8647
  {"EVENT_OBJECT_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
8648
   OPEN_FRM_ONLY},
8649
  {"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table",
Sergey Glukhov's avatar
Sergey Glukhov committed
8650 8651 8652
   OPEN_FRM_ONLY},
  {"ACTION_ORDER", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FRM_ONLY},
  {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY},
8653
  {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement",
Sergey Glukhov's avatar
Sergey Glukhov committed
8654 8655 8656
   OPEN_FRM_ONLY},
  {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing", OPEN_FRM_ONLY},
8657
  {"ACTION_REFERENCE_OLD_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
8658
   OPEN_FRM_ONLY},
8659
  {"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
8660 8661 8662 8663 8664
   OPEN_FRM_ONLY},
  {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FRM_ONLY},
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FRM_ONLY},
8665
  {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FRM_ONLY},
unknown's avatar
unknown committed
8666
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
8667
   "character_set_client", OPEN_FRM_ONLY},
unknown's avatar
unknown committed
8668
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
8669
   "collation_connection", OPEN_FRM_ONLY},
unknown's avatar
unknown committed
8670
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
8671
   "Database Collation", OPEN_FRM_ONLY},
8672
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8673 8674 8675
};


8676 8677
ST_FIELD_INFO partitions_fields_info[]=
{
8678
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8679 8680 8681 8682 8683
  {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"PARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
  {"SUBPARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   OPEN_FULL_TABLE},
8684
  {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
8685
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
8686
  {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
8687
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
8688
  {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699
  {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
  {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
  {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0,
   OPEN_FULL_TABLE},
  {"PARTITION_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
  {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
   OPEN_FULL_TABLE},
  {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
   OPEN_FULL_TABLE},
  {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
   OPEN_FULL_TABLE},
8700
  {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
8701 8702 8703 8704 8705 8706 8707 8708
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
  {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
   OPEN_FULL_TABLE},
  {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
   OPEN_FULL_TABLE},
  {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
  {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
  {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
8709
  {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
8710 8711 8712 8713 8714 8715
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
  {"PARTITION_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"NODEGROUP", 12 , MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   OPEN_FULL_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8716 8717 8718
};


8719 8720
ST_FIELD_INFO variables_fields_info[]=
{
8721 8722
  {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name",
   SKIP_OPEN_TABLE},
8723
  {"VARIABLE_VALUE", 1024, MYSQL_TYPE_STRING, 0, 1, "Value", SKIP_OPEN_TABLE},
8724
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8725 8726 8727
};


8728 8729
ST_FIELD_INFO processlist_fields_info[]=
{
8730
  {"ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Id", SKIP_OPEN_TABLE},
8731 8732
  {"USER", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User",
   SKIP_OPEN_TABLE},
8733 8734 8735 8736
  {"HOST", LIST_PROCESS_HOST_LEN,  MYSQL_TYPE_STRING, 0, 0, "Host",
   SKIP_OPEN_TABLE},
  {"DB", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Db", SKIP_OPEN_TABLE},
  {"COMMAND", 16, MYSQL_TYPE_STRING, 0, 0, "Command", SKIP_OPEN_TABLE},
8737
  {"TIME", 7, MYSQL_TYPE_LONG, 0, 0, "Time", SKIP_OPEN_TABLE},
8738 8739 8740
  {"STATE", 64, MYSQL_TYPE_STRING, 0, 1, "State", SKIP_OPEN_TABLE},
  {"INFO", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_STRING, 0, 1, "Info",
   SKIP_OPEN_TABLE},
8741 8742
  {"TIME_MS", 100 * (MY_INT64_NUM_DECIMAL_DIGITS + 1) + 3, MYSQL_TYPE_DECIMAL,
   0, 0, "Time_ms", SKIP_OPEN_TABLE},
8743 8744 8745 8746
  {"STAGE", 2, MYSQL_TYPE_TINY,  0, 0, "Stage", SKIP_OPEN_TABLE},
  {"MAX_STAGE", 2, MYSQL_TYPE_TINY,  0, 0, "Max_stage", SKIP_OPEN_TABLE},
  {"PROGRESS", 703, MYSQL_TYPE_DECIMAL,  0, 0, "Progress",
   SKIP_OPEN_TABLE},
8747 8748
  {"MEMORY_USED", 7, MYSQL_TYPE_LONG, 0, 0, "Memory_used", SKIP_OPEN_TABLE},
  {"EXAMINED_ROWS", 7, MYSQL_TYPE_LONG, 0, 0, "Examined_rows", SKIP_OPEN_TABLE},
8749
  {"QUERY_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
8750
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8751 8752 8753
};


unknown's avatar
unknown committed
8754 8755
ST_FIELD_INFO plugin_fields_info[]=
{
8756 8757 8758
  {"PLUGIN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
   SKIP_OPEN_TABLE},
  {"PLUGIN_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8759
  {"PLUGIN_STATUS", 16, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
8760 8761 8762 8763 8764 8765 8766
  {"PLUGIN_TYPE", 80, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
  {"PLUGIN_TYPE_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"PLUGIN_LIBRARY", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Library",
   SKIP_OPEN_TABLE},
  {"PLUGIN_LIBRARY_VERSION", 20, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"PLUGIN_AUTHOR", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"PLUGIN_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
Sergei Golubchik's avatar
Sergei Golubchik committed
8767
  {"PLUGIN_LICENSE", 80, MYSQL_TYPE_STRING, 0, 0, "License", SKIP_OPEN_TABLE},
8768
  {"LOAD_OPTION", 64, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
Sergei Golubchik's avatar
Sergei Golubchik committed
8769
  {"PLUGIN_MATURITY", 12, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
8770
  {"PLUGIN_AUTH_VERSION", 80, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8771
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
unknown's avatar
unknown committed
8772 8773
};

8774 8775
ST_FIELD_INFO files_fields_info[]=
{
8776 8777 8778 8779 8780
  {"FILE_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
  {"FILE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"FILE_TYPE", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   SKIP_OPEN_TABLE},
8781
  {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793
  {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   SKIP_OPEN_TABLE},
  {"LOGFILE_GROUP_NUMBER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
  {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"FULLTEXT_KEYS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"DELETED_ROWS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
  {"UPDATE_COUNT", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
  {"FREE_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
  {"TOTAL_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
  {"EXTENT_SIZE", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
8794
  {"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
8795
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
8796
  {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
8797
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
8798
  {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
8799 8800 8801 8802 8803 8804
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
  {"CREATION_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
  {"LAST_UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
  {"LAST_ACCESS_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
  {"RECOVER_TIME", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
  {"TRANSACTION_COUNTER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
8805
  {"VERSION", 21 , MYSQL_TYPE_LONGLONG, 0,
8806 8807
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version", SKIP_OPEN_TABLE},
  {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", SKIP_OPEN_TABLE},
8808
  {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0,
8809
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", SKIP_OPEN_TABLE},
8810
  {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
8811
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", SKIP_OPEN_TABLE},
8812
  {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
8813
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", SKIP_OPEN_TABLE},
8814
  {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
8815
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", SKIP_OPEN_TABLE},
8816
  {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
8817
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", SKIP_OPEN_TABLE},
8818
  {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0,
8819 8820 8821 8822
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", SKIP_OPEN_TABLE},
  {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", SKIP_OPEN_TABLE},
  {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", SKIP_OPEN_TABLE},
  {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", SKIP_OPEN_TABLE},
8823
  {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
8824 8825 8826 8827
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", SKIP_OPEN_TABLE},
  {"STATUS", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"EXTRA", 255, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8828
};
unknown's avatar
unknown committed
8829

8830 8831 8832 8833 8834 8835 8836 8837 8838 8839
void init_fill_schema_files_row(TABLE* table)
{
  int i;
  for(i=0; files_fields_info[i].field_name!=NULL; i++)
    table->field[i]->set_null();

  table->field[IS_FILES_STATUS]->set_notnull();
  table->field[IS_FILES_STATUS]->store("NORMAL", 6, system_charset_info);
}

unknown's avatar
unknown committed
8840 8841
ST_FIELD_INFO referential_constraints_fields_info[]=
{
8842
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8843 8844 8845 8846
  {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
8847
  {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
8848 8849 8850
   OPEN_FULL_TABLE},
  {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
8851 8852
  {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0,
   MY_I_S_MAYBE_NULL, 0, OPEN_FULL_TABLE},
8853 8854 8855 8856 8857 8858 8859
  {"MATCH_OPTION", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"UPDATE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"DELETE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
unknown's avatar
unknown committed
8860 8861 8862
};


Sergey Glukhov's avatar
Sergey Glukhov committed
8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876
ST_FIELD_INFO parameters_fields_info[]=
{
  {"SPECIFIC_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"SPECIFIC_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0, OPEN_FULL_TABLE},
  {"PARAMETER_MODE", 5, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
  {"PARAMETER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
  {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
  {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
  {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
  {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
Sergei Golubchik's avatar
Sergei Golubchik committed
8877 8878
  {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
Sergey Glukhov's avatar
Sergey Glukhov committed
8879 8880 8881 8882 8883 8884 8885 8886
  {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
  {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
  {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}
};


8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909
ST_FIELD_INFO tablespaces_fields_info[]=
{
  {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   SKIP_OPEN_TABLE},
  {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"TABLESPACE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL,
   0, SKIP_OPEN_TABLE},
  {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL,
   0, SKIP_OPEN_TABLE},
  {"EXTENT_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
   MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
  {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
   MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
  {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
   MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
  {"NODEGROUP_ID", 21, MYSQL_TYPE_LONGLONG, 0,
   MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
  {"TABLESPACE_COMMENT", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0,
   SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};


8910 8911 8912
ST_FIELD_INFO keycache_fields_info[]=
{
  {"KEY_CACHE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8913
  {"SEGMENTS", 3, MYSQL_TYPE_LONG, 0, 
8914
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED) , 0, SKIP_OPEN_TABLE},
8915
  {"SEGMENT_NUMBER", 3, MYSQL_TYPE_LONG, 0,
8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
  {"FULL_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
   (MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
  {"BLOCK_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
   (MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE },
  {"USED_BLOCKS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
    (MY_I_S_UNSIGNED), "Key_blocks_used", SKIP_OPEN_TABLE},
  {"UNUSED_BLOCKS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
   (MY_I_S_UNSIGNED), "Key_blocks_unused", SKIP_OPEN_TABLE},
  {"DIRTY_BLOCKS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
   (MY_I_S_UNSIGNED), "Key_blocks_not_flushed", SKIP_OPEN_TABLE},
  {"READ_REQUESTS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
   (MY_I_S_UNSIGNED), "Key_read_requests", SKIP_OPEN_TABLE},
  {"READS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
   (MY_I_S_UNSIGNED), "Key_reads", SKIP_OPEN_TABLE},
  {"WRITE_REQUESTS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
   (MY_I_S_UNSIGNED), "Key_write_requests", SKIP_OPEN_TABLE},
  {"WRITES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
   (MY_I_S_UNSIGNED), "Key_writes", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};


8939 8940 8941 8942 8943 8944 8945 8946 8947
ST_FIELD_INFO show_explain_fields_info[]=
{
  /* field_name, length, type, value, field_flags, old_name*/
  {"id", 3, MYSQL_TYPE_LONGLONG, 0 /*value*/, MY_I_S_MAYBE_NULL, "id", 
    SKIP_OPEN_TABLE},
  {"select_type", 19, MYSQL_TYPE_STRING, 0 /*value*/, 0, "select_type", 
    SKIP_OPEN_TABLE},
  {"table", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0 /*value*/, MY_I_S_MAYBE_NULL,
   "table", SKIP_OPEN_TABLE},
8948
  {"type", 15, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "type", SKIP_OPEN_TABLE},
8949 8950
  {"possible_keys", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
    MY_I_S_MAYBE_NULL, "possible_keys", SKIP_OPEN_TABLE},
8951 8952
  {"key", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/, 
    MY_I_S_MAYBE_NULL, "key", SKIP_OPEN_TABLE},
8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964
  {"key_len", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/, 
    MY_I_S_MAYBE_NULL, "key_len", SKIP_OPEN_TABLE},
  {"ref", NAME_CHAR_LEN*MAX_REF_PARTS, MYSQL_TYPE_STRING, 0/*value*/,
    MY_I_S_MAYBE_NULL, "ref", SKIP_OPEN_TABLE},
  {"rows", 10, MYSQL_TYPE_LONGLONG, 0/*value*/, MY_I_S_MAYBE_NULL, "rows", 
    SKIP_OPEN_TABLE},
  {"Extra", 255, MYSQL_TYPE_STRING, 0/*value*/, 0 /*flags*/, "Extra", 
    SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};


8965 8966
/*
  Description of ST_FIELD_INFO in table.h
unknown's avatar
unknown committed
8967 8968 8969

  Make sure that the order of schema_tables and enum_schema_tables are the same.

8970 8971 8972 8973
*/

ST_SCHEMA_TABLE schema_tables[]=
{
8974 8975
  {"ALL_PLUGINS", plugin_fields_info, create_schema_table,
   fill_all_plugins, make_old_format, 0, 5, -1, 0, 0},
8976
  {"CHARACTER_SETS", charsets_fields_info, create_schema_table,
8977
   fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0},
8978 8979
  {"CLIENT_STATISTICS", client_stats_fields_info, create_schema_table, 
   fill_schema_client_stats, make_old_format, 0, -1, -1, 0, 0},
8980
  {"COLLATIONS", collation_fields_info, create_schema_table,
8981
   fill_schema_collation, make_old_format, 0, -1, -1, 0, 0},
8982
  {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
8983
   create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0, 0},
8984
  {"COLUMNS", columns_fields_info, create_schema_table,
8985
   get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0,
8986
   OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
8987
  {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
8988
   fill_schema_column_privileges, 0, 0, -1, -1, 0, 0},
8989 8990
  {"ENABLED_ROLES", enabled_roles_fields_info, create_schema_table,
   fill_schema_enabled_roles, 0, 0, -1, -1, 0, 0},
unknown's avatar
unknown committed
8991
  {"ENGINES", engines_fields_info, create_schema_table,
8992
   fill_schema_engines, make_old_format, 0, -1, -1, 0, 0},
8993
#ifdef HAVE_EVENT_SCHEDULER
8994
  {"EVENTS", events_fields_info, create_schema_table,
8995
   Events::fill_schema_events, make_old_format, 0, -1, -1, 0, 0},
8996 8997 8998
#else
  {"EVENTS", events_fields_info, create_schema_table,
   0, make_old_format, 0, -1, -1, 0, 0},
8999
#endif
9000 9001
  {"EXPLAIN", show_explain_fields_info, create_schema_table, fill_show_explain,
  make_old_format, 0, -1, -1, TRUE /*hidden*/ , 0},
9002
  {"FILES", files_fields_info, create_schema_table,
9003
   hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
9004
  {"GLOBAL_STATUS", variables_fields_info, create_schema_table,
9005
   fill_status, make_old_format, 0, 0, -1, 0, 0},
9006
  {"GLOBAL_VARIABLES", variables_fields_info, create_schema_table,
9007
   fill_variables, make_old_format, 0, 0, -1, 0, 0},
9008 9009
  {"INDEX_STATISTICS", index_stats_fields_info, create_schema_table,
   fill_schema_index_stats, make_old_format, 0, -1, -1, 0, 0},
9010 9011
  {"KEY_CACHES", keycache_fields_info, create_schema_table,
   fill_key_cache_tables, make_old_format, 0, -1,-1, 0, 0}, 
9012
  {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
9013
   get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0,
9014
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
9015
  {"OPEN_TABLES", open_tables_fields_info, create_schema_table,
9016
   fill_open_tables, make_old_format, 0, -1, -1, 1, 0},
Sergey Glukhov's avatar
Sergey Glukhov committed
9017 9018
  {"PARAMETERS", parameters_fields_info, create_schema_table,
   fill_schema_proc, 0, 0, -1, -1, 0, 0},
9019
  {"PARTITIONS", partitions_fields_info, create_schema_table,
9020 9021
   get_all_tables, 0, get_schema_partitions_record, 1, 2, 0,
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
unknown's avatar
unknown committed
9022
  {"PLUGINS", plugin_fields_info, create_schema_table,
9023
   fill_plugins, make_old_format, 0, -1, -1, 0, 0},
9024
  {"PROCESSLIST", processlist_fields_info, create_schema_table,
9025
   fill_schema_processlist, make_old_format, 0, -1, -1, 0, 0},
9026
  {"PROFILING", query_profile_statistics_info, create_schema_table,
Michael Widenius's avatar
Michael Widenius committed
9027
    fill_query_profile_statistics_info, make_profile_table_for_show,
9028
    NULL, -1, -1, false, 0},
unknown's avatar
unknown committed
9029 9030
  {"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info,
   create_schema_table, get_all_tables, 0, get_referential_constraints_record,
9031
   1, 9, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
9032
  {"ROUTINES", proc_fields_info, create_schema_table, 
9033
   fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0},
9034
  {"SCHEMATA", schema_fields_info, create_schema_table,
9035
   fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0},
9036
  {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table,
9037
   fill_schema_schema_privileges, 0, 0, -1, -1, 0, 0},
9038
  {"SESSION_STATUS", variables_fields_info, create_schema_table,
9039
   fill_status, make_old_format, 0, 0, -1, 0, 0},
9040
  {"SESSION_VARIABLES", variables_fields_info, create_schema_table,
9041
   fill_variables, make_old_format, 0, 0, -1, 0, 0},
Michael Widenius's avatar
Michael Widenius committed
9042
  {"STATISTICS", stat_fields_info, create_schema_table,
9043
   get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0,
9044
   OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
Michael Widenius's avatar
Michael Widenius committed
9045
  {"STATUS", variables_fields_info, create_schema_table, fill_status,
9046
   make_old_format, 0, 0, -1, 1, 0},
Michael Widenius's avatar
Michael Widenius committed
9047
  {"TABLES", tables_fields_info, create_schema_table,
9048 9049
   get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0,
   OPTIMIZE_I_S_TABLE},
9050 9051
  {"TABLESPACES", tablespaces_fields_info, create_schema_table,
   hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
9052
  {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table,
9053 9054
   get_all_tables, 0, get_schema_constraints_record, 3, 4, 0,
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
9055
  {"TABLE_NAMES", table_names_fields_info, create_schema_table,
9056
   get_all_tables, make_table_names_old_format, 0, 1, 2, 1, OPTIMIZE_I_S_TABLE},
9057
  {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
9058
   fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
9059 9060
  {"TABLE_STATISTICS", table_stats_fields_info, create_schema_table,
   fill_schema_table_stats, make_old_format, 0, -1, -1, 0, 0},
9061
  {"TRIGGERS", triggers_fields_info, create_schema_table,
9062
   get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
9063
   OPEN_TRIGGER_ONLY|OPTIMIZE_I_S_TABLE},
9064
  {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, 
9065
   fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
9066 9067
  {"USER_STATISTICS", user_stats_fields_info, create_schema_table, 
   fill_schema_user_stats, make_old_format, 0, -1, -1, 0, 0},
9068
  {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
9069
   make_old_format, 0, 0, -1, 1, 0},
Michael Widenius's avatar
Michael Widenius committed
9070
  {"VIEWS", view_fields_info, create_schema_table,
9071 9072 9073
   get_all_tables, 0, get_schema_views_record, 1, 2, 0,
   OPEN_VIEW_ONLY|OPTIMIZE_I_S_TABLE},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
9074 9075 9076
};


unknown's avatar
unknown committed
9077 9078 9079 9080 9081 9082
int initialize_schema_table(st_plugin_int *plugin)
{
  ST_SCHEMA_TABLE *schema_table;
  DBUG_ENTER("initialize_schema_table");

  if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(sizeof(ST_SCHEMA_TABLE),
9083
                                                   MYF(MY_WME | MY_ZEROFILL))))
unknown's avatar
unknown committed
9084 9085 9086 9087 9088 9089 9090
      DBUG_RETURN(1);
  /* Historical Requirement */
  plugin->data= schema_table; // shortcut for the future
  if (plugin->plugin->init)
  {
    schema_table->create_table= create_schema_table;
    schema_table->old_format= make_old_format;
9091 9092
    schema_table->idx_field1= -1,
    schema_table->idx_field2= -1;
unknown's avatar
unknown committed
9093

9094
    /* Make the name available to the init() function. */
9095
    schema_table->table_name= plugin->name.str;
unknown's avatar
unknown committed
9096 9097 9098 9099 9100

    if (plugin->plugin->init(schema_table))
    {
      sql_print_error("Plugin '%s' init function returned error.",
                      plugin->name.str);
9101
      plugin->data= NULL;
9102
      my_free(schema_table);
9103
      DBUG_RETURN(1);
unknown's avatar
unknown committed
9104
    }
9105

9106
    /* Make sure the plugin name is not set inside the init() function. */
unknown's avatar
unknown committed
9107 9108 9109 9110 9111 9112 9113 9114 9115 9116
    schema_table->table_name= plugin->name.str;
  }
  DBUG_RETURN(0);
}

int finalize_schema_table(st_plugin_int *plugin)
{
  ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
  DBUG_ENTER("finalize_schema_table");

9117
  if (schema_table)
unknown's avatar
unknown committed
9118
  {
9119
    if (plugin->plugin->deinit)
unknown's avatar
unknown committed
9120
    {
9121 9122 9123 9124 9125 9126
      DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
      if (plugin->plugin->deinit(NULL))
      {
        DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
                               plugin->name.str));
      }
unknown's avatar
unknown committed
9127
    }
9128
    my_free(schema_table);
unknown's avatar
unknown committed
9129 9130 9131
  }
  DBUG_RETURN(0);
}
unknown's avatar
unknown committed
9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162


/**
  Output trigger information (SHOW CREATE TRIGGER) to the client.

  @param thd          Thread context.
  @param triggers     List of triggers for the table.
  @param trigger_idx  Index of the trigger to dump.

  @return Operation status
    @retval TRUE Error.
    @retval FALSE Success.
*/

static bool show_create_trigger_impl(THD *thd,
                                     Table_triggers_list *triggers,
                                     int trigger_idx)
{
  int ret_code;

  Protocol *p= thd->protocol;
  List<Item> fields;

  LEX_STRING trg_name;
  ulonglong trg_sql_mode;
  LEX_STRING trg_sql_mode_str;
  LEX_STRING trg_sql_original_stmt;
  LEX_STRING trg_client_cs_name;
  LEX_STRING trg_connection_cl_name;
  LEX_STRING trg_db_cl_name;

9163 9164
  CHARSET_INFO *trg_client_cs;

unknown's avatar
unknown committed
9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185
  /*
    TODO: Check privileges here. This functionality will be added by
    implementation of the following WL items:
      - WL#2227: New privileges for new objects
      - WL#3482: Protect SHOW CREATE PROCEDURE | FUNCTION | VIEW | TRIGGER
        properly

    SHOW TRIGGERS and I_S.TRIGGERS will be affected too.
  */

  /* Prepare trigger "object". */

  triggers->get_trigger_info(thd,
                             trigger_idx,
                             &trg_name,
                             &trg_sql_mode,
                             &trg_sql_original_stmt,
                             &trg_client_cs_name,
                             &trg_connection_cl_name,
                             &trg_db_cl_name);

9186
  sql_mode_string_representation(thd, trg_sql_mode, &trg_sql_mode_str);
unknown's avatar
unknown committed
9187

9188 9189 9190 9191 9192
  /* Resolve trigger client character set. */

  if (resolve_charset(trg_client_cs_name.str, NULL, &trg_client_cs))
    return TRUE;

unknown's avatar
unknown committed
9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221
  /* Send header. */

  fields.push_back(new Item_empty_string("Trigger", NAME_LEN));
  fields.push_back(new Item_empty_string("sql_mode", trg_sql_mode_str.length));

  {
    /*
      NOTE: SQL statement field must be not less than 1024 in order not to
      confuse old clients.
    */

    Item_empty_string *stmt_fld=
      new Item_empty_string("SQL Original Statement",
                            max(trg_sql_original_stmt.length, 1024));

    stmt_fld->maybe_null= TRUE;

    fields.push_back(stmt_fld);
  }

  fields.push_back(new Item_empty_string("character_set_client",
                                         MY_CS_NAME_SIZE));

  fields.push_back(new Item_empty_string("collation_connection",
                                         MY_CS_NAME_SIZE));

  fields.push_back(new Item_empty_string("Database Collation",
                                         MY_CS_NAME_SIZE));

9222
  if (p->send_result_set_metadata(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238
    return TRUE;

  /* Send data. */

  p->prepare_for_resend();

  p->store(trg_name.str,
           trg_name.length,
           system_charset_info);

  p->store(trg_sql_mode_str.str,
           trg_sql_mode_str.length,
           system_charset_info);

  p->store(trg_sql_original_stmt.str,
           trg_sql_original_stmt.length,
9239
           trg_client_cs);
unknown's avatar
unknown committed
9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255

  p->store(trg_client_cs_name.str,
           trg_client_cs_name.length,
           system_charset_info);

  p->store(trg_connection_cl_name.str,
           trg_connection_cl_name.length,
           system_charset_info);

  p->store(trg_db_cl_name.str,
           trg_db_cl_name.length,
           system_charset_info);

  ret_code= p->write();

  if (!ret_code)
9256
    my_eof(thd);
unknown's avatar
unknown committed
9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285

  return ret_code != 0;
}


/**
  Read TRN and TRG files to obtain base table name for the specified
  trigger name and construct TABE_LIST object for the base table.

  @param thd      Thread context.
  @param trg_name Trigger name.

  @return TABLE_LIST object corresponding to the base table.

  TODO: This function is a copy&paste from add_table_to_list() and
  sp_add_to_query_tables(). The problem is that in order to be compatible
  with Stored Programs (Prepared Statements), we should not touch thd->lex.
  The "source" functions also add created TABLE_LIST object to the
  thd->lex->query_tables.

  The plan to eliminate this copy&paste is to:

    - get rid of sp_add_to_query_tables() and use Lex::add_table_to_list().
      Only add_table_to_list() must be used to add tables from the parser
      into Lex::query_tables list.

    - do not update Lex::query_tables in add_table_to_list().
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
9286
static
9287
TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
unknown's avatar
unknown committed
9288 9289 9290
{
  char trn_path_buff[FN_REFLEN];
  LEX_STRING trn_path= { trn_path_buff, 0 };
Konstantin Osipov's avatar
Konstantin Osipov committed
9291
  LEX_STRING db;
unknown's avatar
unknown committed
9292
  LEX_STRING tbl_name;
Konstantin Osipov's avatar
Konstantin Osipov committed
9293
  TABLE_LIST *table;
unknown's avatar
unknown committed
9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306

  build_trn_path(thd, trg_name, &trn_path);

  if (check_trn_exists(&trn_path))
  {
    my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
    return NULL;
  }

  if (load_table_name_for_trigger(thd, trg_name, &trn_path, &tbl_name))
    return NULL;

  /* We need to reset statement table list to be PS/SP friendly. */
Konstantin Osipov's avatar
Konstantin Osipov committed
9307
  if (!(table= (TABLE_LIST*) thd->alloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
9308 9309
    return NULL;

Konstantin Osipov's avatar
Konstantin Osipov committed
9310
  db= trg_name->m_db;
unknown's avatar
unknown committed
9311

Konstantin Osipov's avatar
Konstantin Osipov committed
9312 9313
  db.str= thd->strmake(db.str, db.length);
  tbl_name.str= thd->strmake(tbl_name.str, tbl_name.length);
unknown's avatar
unknown committed
9314

Konstantin Osipov's avatar
Konstantin Osipov committed
9315 9316
  if (db.str == NULL || tbl_name.str == NULL)
    return NULL;
unknown's avatar
unknown committed
9317

Konstantin Osipov's avatar
Konstantin Osipov committed
9318 9319
  table->init_one_table(db.str, db.length, tbl_name.str, tbl_name.length,
                        tbl_name.str, TL_IGNORE);
unknown's avatar
unknown committed
9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338

  return table;
}


/**
  SHOW CREATE TRIGGER high-level implementation.

  @param thd      Thread context.
  @param trg_name Trigger name.

  @return Operation status
    @retval TRUE Error.
    @retval FALSE Success.
*/

bool show_create_trigger(THD *thd, const sp_name *trg_name)
{
  TABLE_LIST *lst= get_trigger_table(thd, trg_name);
9339 9340 9341 9342
  uint num_tables; /* NOTE: unused, only to pass to open_tables(). */
  Table_triggers_list *triggers;
  int trigger_idx;
  bool error= TRUE;
unknown's avatar
unknown committed
9343

9344 9345 9346
  if (!lst)
    return TRUE;

9347
  if (check_table_access(thd, TRIGGER_ACL, lst, FALSE, 1, TRUE))
9348 9349 9350 9351 9352
  {
    my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "TRIGGER");
    return TRUE;
  }

unknown's avatar
unknown committed
9353
  /*
9354 9355
    Metadata locks taken during SHOW CREATE TRIGGER should be released when
    the statement completes as it is an information statement.
unknown's avatar
unknown committed
9356
  */
9357
  MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
unknown's avatar
unknown committed
9358

9359 9360 9361 9362 9363
  /*
    Open the table by name in order to load Table_triggers_list object.
  */
  if (open_tables(thd, &lst, &num_tables,
                  MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
unknown's avatar
unknown committed
9364 9365 9366 9367 9368
  {
    my_error(ER_TRG_CANT_OPEN_TABLE, MYF(0),
             (const char *) trg_name->m_db.str,
             (const char *) lst->table_name);

9369
    goto exit;
unknown's avatar
unknown committed
9370 9371 9372 9373

    /* Perform closing actions and return error status. */
  }

9374
  triggers= lst->table->triggers;
unknown's avatar
unknown committed
9375 9376 9377 9378

  if (!triggers)
  {
    my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
9379
    goto exit;
unknown's avatar
unknown committed
9380 9381
  }

9382
  trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name);
unknown's avatar
unknown committed
9383 9384 9385 9386 9387 9388 9389

  if (trigger_idx < 0)
  {
    my_error(ER_TRG_CORRUPTED_FILE, MYF(0),
             (const char *) trg_name->m_db.str,
             (const char *) lst->table_name);

9390
    goto exit;
unknown's avatar
unknown committed
9391 9392
  }

9393
  error= show_create_trigger_impl(thd, triggers, trigger_idx);
unknown's avatar
unknown committed
9394 9395 9396 9397 9398 9399

  /*
    NOTE: if show_create_trigger_impl() failed, that means we could not
    send data to the client. In this case we simply raise the error
    status and client connection will be closed.
  */
9400 9401 9402 9403 9404 9405

exit:
  close_thread_tables(thd);
  /* Release any metadata locks taken during SHOW CREATE TRIGGER. */
  thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
  return error;
unknown's avatar
unknown committed
9406
}
9407

Marc Alff's avatar
Marc Alff committed
9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457
class IS_internal_schema_access : public ACL_internal_schema_access
{
public:
  IS_internal_schema_access()
  {}

  ~IS_internal_schema_access()
  {}

  ACL_internal_access_result check(ulong want_access,
                                   ulong *save_priv) const;

  const ACL_internal_table_access *lookup(const char *name) const;
};

ACL_internal_access_result
IS_internal_schema_access::check(ulong want_access,
                                 ulong *save_priv) const
{
  want_access &= ~SELECT_ACL;

  /*
    We don't allow any simple privileges but SELECT_ACL on
    the information_schema database.
  */
  if (unlikely(want_access & DB_ACLS))
    return ACL_INTERNAL_ACCESS_DENIED;

  /* Always grant SELECT for the information schema. */
  *save_priv|= SELECT_ACL;

  return want_access ? ACL_INTERNAL_ACCESS_CHECK_GRANT :
                       ACL_INTERNAL_ACCESS_GRANTED;
}

const ACL_internal_table_access *
IS_internal_schema_access::lookup(const char *name) const
{
  /* There are no per table rules for the information schema. */
  return NULL;
}

static IS_internal_schema_access is_internal_schema_access;

void initialize_information_schema_acl()
{
  ACL_internal_schema_registry::register_schema(&INFORMATION_SCHEMA_NAME,
                                                &is_internal_schema_access);
}

Georgi Kodinov's avatar
merge  
Georgi Kodinov committed
9458
#ifdef WITH_PARTITION_STORAGE_ENGINE
9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549
/*
  Convert a string in character set in column character set format
  to utf8 character set if possible, the utf8 character set string
  will later possibly be converted to character set used by client.
  Thus we attempt conversion from column character set to both
  utf8 and to character set client.

  Examples of strings that should fail conversion to utf8 are unassigned
  characters as e.g. 0x81 in cp1250 (Windows character set for for countries
  like Czech and Poland). Example of string that should fail conversion to
  character set on client (e.g. if this is latin1) is 0x2020 (daggger) in
  ucs2.

  If the conversion fails we will as a fall back convert the string to
  hex encoded format. The caller of the function can also ask for hex
  encoded format of output string unconditionally.

  SYNOPSIS
    get_cs_converted_string_value()
    thd                             Thread object
    input_str                       Input string in cs character set
    output_str                      Output string to be produced in utf8
    cs                              Character set of input string
    use_hex                         Use hex string unconditionally
 

  RETURN VALUES
    No return value
*/

static void get_cs_converted_string_value(THD *thd,
                                          String *input_str,
                                          String *output_str,
                                          CHARSET_INFO *cs,
                                          bool use_hex)
{

  output_str->length(0);
  if (input_str->length() == 0)
  {
    output_str->append("''");
    return;
  }
  if (!use_hex)
  {
    String try_val;
    uint try_conv_error= 0;

    try_val.copy(input_str->ptr(), input_str->length(), cs,
                 thd->variables.character_set_client, &try_conv_error);
    if (!try_conv_error)
    {
      String val;
      uint conv_error= 0;

      val.copy(input_str->ptr(), input_str->length(), cs,
               system_charset_info, &conv_error);
      if (!conv_error)
      {
        append_unescaped(output_str, val.ptr(), val.length());
        return;
      }
    }
    /* We had a conversion error, use hex encoded string for safety */
  }
  {
    const uchar *ptr;
    uint i, len;
    char buf[3];

    output_str->append("_");
    output_str->append(cs->csname);
    output_str->append(" ");
    output_str->append("0x");
    len= input_str->length();
    ptr= (uchar*)input_str->ptr();
    for (i= 0; i < len; i++)
    {
      uint high, low;

      high= (*ptr) >> 4;
      low= (*ptr) & 0x0F;
      buf[0]= _dig_vec_upper[high];
      buf[1]= _dig_vec_upper[low];
      buf[2]= 0;
      output_str->append((const char*)buf);
      ptr++;
    }
  }
  return;
}
Georgi Kodinov's avatar
merge  
Georgi Kodinov committed
9550
#endif