sql_show.cc 269 KB
Newer Older
1
/* Copyright 2000, 2010 Oracle and/or its affiliates. All rights reserved.
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4
   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
5
   the Free Software Foundation; version 2 of the License.
6

bk@work.mysql.com's avatar
bk@work.mysql.com committed
7 8 9 10
   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.
11

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


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

19
#include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
20 21 22
#include "sql_priv.h"
#include "unireg.h"
#include "sql_acl.h"                        // fill_schema_*_privileges
23
#include "sql_select.h"                         // For select_describe
24
#include "sql_base.h"                       // close_tables_for_reopen
25
#include "sql_show.h"
26 27 28
#include "sql_table.h"                        // filename_to_tablename,
                                              // primary_key_name,
                                              // build_table_filename
29
#include "repl_failsafe.h"
30 31 32 33 34 35 36 37
#include "sql_parse.h"             // check_access, check_table_access
#include "sql_partition.h"         // partition_element
#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
38
#include "sp.h"
39
#include "sp_head.h"
Sergey Glukhov's avatar
Sergey Glukhov committed
40
#include "sp_pcontext.h"
41
#include "set_var.h"
42
#include "sql_trigger.h"
brian@grrr.local's avatar
brian@grrr.local committed
43
#include "authors.h"
44
#include "contributors.h"
45
#include "sql_partition.h"
46
#ifdef HAVE_EVENT_SCHEDULER
47
#include "events.h"
48
#include "event_data_objects.h"
49
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
50
#include <my_dir.h>
51
#include "lock.h"                           // MYSQL_OPEN_IGNORE_FLUSH
52 53
#include "debug_sync.h"
#include "datadict.h"   // dd_frm_type()
54

55 56
#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")

57 58 59
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
60 61 62 63 64 65
enum enum_i_s_events_fields
{
  ISE_EVENT_CATALOG= 0,
  ISE_EVENT_SCHEMA,
  ISE_EVENT_NAME,
  ISE_DEFINER,
66
  ISE_TIME_ZONE,
67 68 69 70 71 72 73 74 75 76 77 78 79 80
  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,
81
  ISE_EVENT_COMMENT,
82 83 84 85
  ISE_ORIGINATOR,
  ISE_CLIENT_CS,
  ISE_CONNECTION_CL,
  ISE_DB_CL
86 87
};

88
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
89 90 91 92 93
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 **),
94
                               "grant_types",
95
                               grant_names, NULL};
96
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
97

98 99 100
static void store_key_options(THD *thd, String *packet, TABLE *table,
                              KEY *key_info);

Georgi Kodinov's avatar
merge  
Georgi Kodinov committed
101
#ifdef WITH_PARTITION_STORAGE_ENGINE
102 103 104 105 106
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
107
#endif
108

109 110
static void
append_algorithm(TABLE_LIST *table, String *buff);
111

112
static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
113

114
/***************************************************************************
115
** List all table types supported
116 117
***************************************************************************/

118 119
static int make_version_string(char *buf, int buf_length, uint version)
{
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
120
  return my_snprintf(buf, buf_length, "%d.%d", version>>8,version&0xff);
121 122
}

antony@ppcg5.local's avatar
antony@ppcg5.local committed
123
static my_bool show_plugins(THD *thd, plugin_ref plugin,
124 125 126
                            void *arg)
{
  TABLE *table= (TABLE*) arg;
antony@ppcg5.local's avatar
antony@ppcg5.local committed
127 128
  struct st_mysql_plugin *plug= plugin_decl(plugin);
  struct st_plugin_dl *plugin_dl= plugin_dlib(plugin);
129 130 131 132 133
  CHARSET_INFO *cs= system_charset_info;
  char version_buf[20];

  restore_record(table, s->default_values);

antony@ppcg5.local's avatar
antony@ppcg5.local committed
134 135
  table->field[0]->store(plugin_name(plugin)->str,
                         plugin_name(plugin)->length, cs);
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
136 137 138 139 140

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

serg@sergbook.mysql.com's avatar
fixes  
serg@sergbook.mysql.com committed
141

antony@ppcg5.local's avatar
antony@ppcg5.local committed
142
  switch (plugin_state(plugin)) {
143 144
  /* case PLUGIN_IS_FREED: does not happen */
  case PLUGIN_IS_DELETED:
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
145
    table->field[2]->store(STRING_WITH_LEN("DELETED"), cs);
146 147
    break;
  case PLUGIN_IS_UNINITIALIZED:
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
148
    table->field[2]->store(STRING_WITH_LEN("INACTIVE"), cs);
149 150
    break;
  case PLUGIN_IS_READY:
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
151
    table->field[2]->store(STRING_WITH_LEN("ACTIVE"), cs);
152
    break;
153 154 155
  case PLUGIN_IS_DISABLED:
    table->field[2]->store(STRING_WITH_LEN("DISABLED"), cs);
    break;
156 157 158 159
  default:
    DBUG_ASSERT(0);
  }

serg@serg.mylan's avatar
serg@serg.mylan committed
160 161 162
  table->field[3]->store(plugin_type_names[plug->type].str,
                         plugin_type_names[plug->type].length,
                         cs);
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
163
  table->field[4]->store(version_buf,
serg@serg.mylan's avatar
serg@serg.mylan committed
164
        make_version_string(version_buf, sizeof(version_buf),
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
165
                            *(uint *)plug->info), cs);
166

antony@ppcg5.local's avatar
antony@ppcg5.local committed
167
  if (plugin_dl)
168
  {
antony@ppcg5.local's avatar
antony@ppcg5.local committed
169
    table->field[5]->store(plugin_dl->dl.str, plugin_dl->dl.length, cs);
170
    table->field[5]->set_notnull();
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
171
    table->field[6]->store(version_buf,
serg@serg.mylan's avatar
serg@serg.mylan committed
172
          make_version_string(version_buf, sizeof(version_buf),
antony@ppcg5.local's avatar
antony@ppcg5.local committed
173
                              plugin_dl->version),
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
174 175
          cs);
    table->field[6]->set_notnull();
176 177
  }
  else
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
178
  {
179
    table->field[5]->set_null();
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
180 181 182 183
    table->field[6]->set_null();
  }


184 185
  if (plug->author)
  {
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
186 187
    table->field[7]->store(plug->author, strlen(plug->author), cs);
    table->field[7]->set_notnull();
188 189
  }
  else
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
190
    table->field[7]->set_null();
191 192 193

  if (plug->descr)
  {
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
194 195
    table->field[8]->store(plug->descr, strlen(plug->descr), cs);
    table->field[8]->set_notnull();
196 197
  }
  else
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
198
    table->field[8]->set_null();
199

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
  switch (plug->license) {
  case PLUGIN_LICENSE_GPL:
    table->field[9]->store(PLUGIN_LICENSE_GPL_STRING, 
                           strlen(PLUGIN_LICENSE_GPL_STRING), cs);
    break;
  case PLUGIN_LICENSE_BSD:
    table->field[9]->store(PLUGIN_LICENSE_BSD_STRING, 
                           strlen(PLUGIN_LICENSE_BSD_STRING), cs);
    break;
  default:
    table->field[9]->store(PLUGIN_LICENSE_PROPRIETARY_STRING, 
                           strlen(PLUGIN_LICENSE_PROPRIETARY_STRING), cs);
    break;
  }
  table->field[9]->set_notnull();

216 217 218 219 220
  table->field[10]->store(
    global_plugin_typelib_names[plugin_load_option(plugin)],
    strlen(global_plugin_typelib_names[plugin_load_option(plugin)]),
    cs);

221 222 223 224 225 226 227 228 229
  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;

230 231
  if (plugin_foreach_with_mask(thd, show_plugins, MYSQL_ANY_PLUGIN,
                               ~PLUGIN_IS_FREED, table))
232
    DBUG_RETURN(1);
233

234 235 236 237
  DBUG_RETURN(0);
}


brian@grrr.local's avatar
brian@grrr.local committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
/***************************************************************************
** 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));

253
  if (protocol->send_result_set_metadata(&field_list,
brian@grrr.local's avatar
brian@grrr.local committed
254 255 256 257 258 259 260 261 262 263 264 265 266
                            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);
  }
267
  my_eof(thd);
brian@grrr.local's avatar
brian@grrr.local committed
268 269
  DBUG_RETURN(FALSE);
}
270

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

/***************************************************************************
** 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));

287
  if (protocol->send_result_set_metadata(&field_list,
288 289 290 291 292 293 294 295 296 297 298 299 300
                            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);
  }
301
  my_eof(thd);
302 303 304 305
  DBUG_RETURN(FALSE);
}


306
/***************************************************************************
307
 List all privileges supported
308 309
***************************************************************************/

310 311 312 313
struct show_privileges_st {
  const char *privilege;
  const char *context;
  const char *comment;
314 315
};

316 317
static struct show_privileges_st sys_privileges[]=
{
318
  {"Alter", "Tables",  "To alter the table"},
319
  {"Alter routine", "Functions,Procedures",  "To alter or drop stored functions/procedures"},
320
  {"Create", "Databases,Tables,Indexes",  "To create new databases and tables"},
321
  {"Create routine","Databases","To use CREATE FUNCTION/PROCEDURE"},
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
322 323
  {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
  {"Create view", "Tables",  "To create new views"},
324
  {"Create user", "Server Admin",  "To create new users"},
325
  {"Delete", "Tables",  "To delete existing rows"},
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
326
  {"Drop", "Databases,Tables", "To drop databases, tables, and views"},
327
#ifdef HAVE_EVENT_SCHEDULER
328
  {"Event","Server Admin","To create, alter, drop and execute events"},
329
#endif
330
  {"Execute", "Functions,Procedures", "To execute stored routines"},
331
  {"File", "File access on server",   "To read and write files on the server"},
332
  {"Grant option",  "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"},
333 334 335 336
  {"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"},
337
  {"References", "Databases,Tables", "To have references on tables"},
338 339 340 341 342
  {"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"},
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
343 344
  {"Show view","Tables","To see views with SHOW CREATE VIEW"},
  {"Shutdown","Server Admin", "To shut down the server"},
345
  {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
346
  {"Trigger","Tables", "To use triggers"},
347
  {"Create tablespace", "Server Admin", "To create/alter/drop tablespaces"},
348 349
  {"Update", "Tables",  "To update existing rows"},
  {"Usage","Server Admin","No privileges - allow connect only"},
350 351 352
  {NullS, NullS, NullS}
};

353
bool mysqld_show_privileges(THD *thd)
354 355
{
  List<Item> field_list;
356
  Protocol *protocol= thd->protocol;
357 358 359 360
  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));
361
  field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
362

363
  if (protocol->send_result_set_metadata(&field_list,
364
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
365
    DBUG_RETURN(TRUE);
366

367 368
  show_privileges_st *privilege= sys_privileges;
  for (privilege= sys_privileges; privilege->privilege ; privilege++)
369
  {
370
    protocol->prepare_for_resend();
371 372 373
    protocol->store(privilege->privilege, system_charset_info);
    protocol->store(privilege->context, system_charset_info);
    protocol->store(privilege->comment, system_charset_info);
374
    if (protocol->write())
375
      DBUG_RETURN(TRUE);
376
  }
377
  my_eof(thd);
378
  DBUG_RETURN(FALSE);
379 380 381
}


382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
/*
  find_files() - find files in a given directory.

  SYNOPSIS
    find_files()
    thd                 thread handler
    files               put found files in this list
    db                  database name to set in TABLE_LIST structure
    path                path to database
    wild                filter for found files
    dir                 read databases in path if TRUE, read .frm files in
                        database otherwise

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


find_files_result
403
find_files(THD *thd, List<LEX_STRING> *files, const char *db,
404
           const char *path, const char *wild, bool dir)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
405 406 407 408 409
{
  uint i;
  char *ext;
  MY_DIR *dirp;
  FILEINFO *file;
410 411
  LEX_STRING *file_name= 0;
  uint file_name_len;
412
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
413
  uint col_access=thd->col_access;
414
#endif
415
  uint wild_length= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
416
  TABLE_LIST table_list;
417
  DBUG_ENTER("find_files");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
418

419 420 421 422 423 424 425 426
  if (wild)
  {
    if (!wild[0])
      wild= 0;
    else
      wild_length= strlen(wild);
  }

427 428


bk@work.mysql.com's avatar
bk@work.mysql.com committed
429 430
  bzero((char*) &table_list,sizeof(table_list));

431 432 433 434 435 436
  if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0))))
  {
    if (my_errno == ENOENT)
      my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db);
    else
      my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
437
    DBUG_RETURN(FIND_FILES_DIR);
438
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
439

440
  for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
441
  {
442
    char uname[NAME_LEN + 1];                   /* Unencoded name */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
443 444
    file=dirp->dir_entry+i;
    if (dir)
445
    {                                           /* Return databases */
446 447 448 449
      if ((file->name[0] == '.' && 
          ((file->name[1] == '.' && file->name[2] == '\0') ||
            file->name[1] == '\0')))
        continue;                               /* . or .. */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
450 451
#ifdef USE_SYMDIR
      char *ext;
452
      char buff[FN_REFLEN];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
453
      if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
454 455
      {
	/* Only show the sym file if it points to a directory */
456
	char *end;
457
        *ext=0;                                 /* Remove extension */
458 459 460 461
	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
462
        if (!mysql_file_stat(key_file_misc, buff, file->mystat, MYF(0)))
463 464
               continue;
       }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
465
#endif
466 467
      if (!MY_S_ISDIR(file->mystat->st_mode))
        continue;
468 469

      file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
Georgi Kodinov's avatar
Georgi Kodinov committed
470 471 472 473 474 475 476 477 478 479 480 481 482
      if (wild)
      {
	if (lower_case_table_names)
	{
          if (my_wildcmp(files_charset_info,
                         uname, uname + file_name_len,
                         wild, wild + wild_length,
                         wild_prefix, wild_one,wild_many))
            continue;
	}
	else if (wild_compare(uname, wild, 0))
	  continue;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
483 484 485
    }
    else
    {
486
        // Return only .frm files which aren't temp files.
487
      if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),reg_ext) ||
488
          is_prefix(file->name, tmp_file_prefix))
489
        continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
490
      *ext=0;
491
      file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
492 493 494 495
      if (wild)
      {
	if (lower_case_table_names)
	{
496
          if (my_wildcmp(files_charset_info,
497
                         uname, uname + file_name_len,
498 499 500
                         wild, wild + wild_length,
                         wild_prefix, wild_one,wild_many))
            continue;
501
	}
502
	else if (wild_compare(uname, wild, 0))
503 504
	  continue;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
505
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
506
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
507 508 509 510
    /* Don't show tables where we don't have any privileges */
    if (db && !(col_access & TABLE_ACLS))
    {
      table_list.db= (char*) db;
511
      table_list.db_length= strlen(db);
512 513
      table_list.table_name= uname;
      table_list.table_name_length= file_name_len;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
514
      table_list.grant.privilege=col_access;
515
      if (check_grant(thd, TABLE_ACLS, &table_list, TRUE, 1, TRUE))
516
        continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
517
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
518
#endif
519 520 521
    if (!(file_name= 
          thd->make_lex_string(file_name, uname, file_name_len, TRUE)) ||
        files->push_back(file_name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
522 523
    {
      my_dirend(dirp);
524
      DBUG_RETURN(FIND_FILES_OOM);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
525 526 527 528
    }
  }
  DBUG_PRINT("info",("found: %d files", files->elements));
  my_dirend(dirp);
529

Konstantin Osipov's avatar
Konstantin Osipov committed
530
  (void) ha_find_files(thd, db, path, wild, dir, files);
531

532
  DBUG_RETURN(FIND_FILES_OK);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
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
/**
   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;
  }

599
  bool handle_condition(THD *thd, uint sql_errno, const char * /* sqlstate */,
600
                        MYSQL_ERROR::enum_warning_level level,
601
                        const char *message, MYSQL_ERROR ** /* cond_hdl */)
602
  {
603
    /*
604 605 606 607 608 609 610 611 612
       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;
613

614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
    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:
      /* 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;
  }
};


658
bool
bk@work.mysql.com's avatar
bk@work.mysql.com committed
659 660
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
661 662 663
  Protocol *protocol= thd->protocol;
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
664 665
  List<Item> field_list;
  bool error= TRUE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
666 667
  DBUG_ENTER("mysqld_show_create");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
668
                      table_list->table_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
669

670 671 672 673
  /*
    Metadata locks taken during SHOW CREATE should be released when
    the statmement completes as it is an information statement.
  */
674
  MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
675

676 677 678
  /* We want to preserve the tree for views. */
  thd->lex->view_prepare_mode= TRUE;

679
  {
680 681
    Show_create_error_handler view_error_suppressor(thd, table_list);
    thd->push_internal_handler(&view_error_suppressor);
682
    bool open_error=
683 684
      open_normal_and_derived_tables(thd, table_list,
                                     MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL);
685
    thd->pop_internal_handler();
686 687
    if (open_error && (thd->killed || thd->is_error()))
      goto exit;
688
  }
689

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
690 691 692
  /* TODO: add environment variables show when it become possible */
  if (thd->lex->only_view && !table_list->view)
  {
693
    my_error(ER_WRONG_OBJECT, MYF(0),
694
             table_list->db, table_list->table_name, "VIEW");
695
    goto exit;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
696
  }
697

698
  buffer.length(0);
699 700 701 702

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

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
703 704
  if ((table_list->view ?
       view_store_create_info(thd, table_list, &buffer) :
705 706
       store_create_info(thd, table_list, &buffer, NULL,
                         FALSE /* show_database */)))
707
    goto exit;
708

709 710
  if (table_list->view)
  {
711
    field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN));
712 713
    field_list.push_back(new Item_empty_string("Create View",
                                               max(buffer.length(),1024)));
714 715 716 717
    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));
718 719 720
  }
  else
  {
721
    field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
722 723 724 725
    // 1024 is for not to confuse old clients
    field_list.push_back(new Item_empty_string("Create Table",
                                               max(buffer.length(),1024)));
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
726

727
  if (protocol->send_result_set_metadata(&field_list,
728
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
729 730
    goto exit;

731
  protocol->prepare_for_resend();
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
732 733 734 735
  if (table_list->view)
    protocol->store(table_list->view_name.str, system_charset_info);
  else
  {
736
    if (table_list->schema_table)
737 738
      protocol->store(table_list->schema_table->table_name,
                      system_charset_info);
739
    else
740
      protocol->store(table_list->table->alias, system_charset_info);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
741
  }
742 743 744

  if (table_list->view)
  {
745 746
    protocol->store(buffer.ptr(), buffer.length(),
                    table_list->view_creation_ctx->get_client_cs());
747 748 749 750 751 752 753 754 755

    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());
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
756

757
  if (protocol->write())
758
    goto exit;
759

760
  error= FALSE;
761
  my_eof(thd);
762 763 764 765 766 767

exit:
  close_thread_tables(thd);
  /* Release any metadata locks taken during SHOW CREATE. */
  thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
  DBUG_RETURN(error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
768 769
}

770 771
bool mysqld_show_create_db(THD *thd, char *dbname,
                           HA_CREATE_INFO *create_info)
772 773 774
{
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
775
#ifndef NO_EMBEDDED_ACCESS_CHECKS
776
  Security_context *sctx= thd->security_ctx;
777
  uint db_access;
778
#endif
779 780 781 782 783 784
  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
785
  if (test_all_bits(sctx->master_access, DB_ACLS))
786 787
    db_access=DB_ACLS;
  else
788 789
    db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
		sctx->master_access);
790
  if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname))
791
  {
792
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
793
             sctx->priv_user, sctx->host_or_ip, dbname);
794 795
    general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
                      sctx->priv_user, sctx->host_or_ip, dbname);
796
    DBUG_RETURN(TRUE);
797 798
  }
#endif
799
  if (is_infoschema_db(dbname))
800
  {
801
    dbname= INFORMATION_SCHEMA_NAME.str;
802
    create.default_table_charset= system_charset_info;
803
  }
804
  else
805
  {
806
    if (check_db_dir_existence(dbname))
807 808 809 810
    {
      my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
      DBUG_RETURN(TRUE);
    }
811 812

    load_db_opt_by_name(thd, dbname, &create);
813 814
  }
  List<Item> field_list;
815
  field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
816 817
  field_list.push_back(new Item_empty_string("Create Database",1024));

818
  if (protocol->send_result_set_metadata(&field_list,
819
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
820
    DBUG_RETURN(TRUE);
821 822 823 824

  protocol->prepare_for_resend();
  protocol->store(dbname, strlen(dbname), system_charset_info);
  buffer.length(0);
825
  buffer.append(STRING_WITH_LEN("CREATE DATABASE "));
826
  if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
827
    buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ "));
828 829 830 831
  append_identifier(thd, &buffer, dbname, strlen(dbname));

  if (create.default_table_charset)
  {
832 833
    buffer.append(STRING_WITH_LEN(" /*!40100"));
    buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET "));
834 835 836
    buffer.append(create.default_table_charset->csname);
    if (!(create.default_table_charset->state & MY_CS_PRIMARY))
    {
837
      buffer.append(STRING_WITH_LEN(" COLLATE "));
838 839
      buffer.append(create.default_table_charset->name);
    }
840
    buffer.append(STRING_WITH_LEN(" */"));
841 842 843 844
  }
  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());

  if (protocol->write())
845
    DBUG_RETURN(TRUE);
846
  my_eof(thd);
847
  DBUG_RETURN(FALSE);
848
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
849

tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
850 851


bk@work.mysql.com's avatar
bk@work.mysql.com committed
852
/****************************************************************************
853 854
  Return only fields for API mysql_list_fields
  Use "show table wildcard" in mysql instead of this
bk@work.mysql.com's avatar
bk@work.mysql.com committed
855 856 857 858 859 860 861
****************************************************************************/

void
mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
{
  TABLE *table;
  DBUG_ENTER("mysqld_list_fields");
862
  DBUG_PRINT("enter",("table: %s",table_list->table_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
863

864 865
  if (open_normal_and_derived_tables(thd, table_list,
                                     MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
866
    DBUG_VOID_RETURN;
867 868
  table= table_list->table;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
869 870 871 872 873
  List<Item> field_list;

  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
874 875
    if (!wild || !wild[0] || 
        !wild_case_compare(system_charset_info, field->field_name,wild))
876 877 878 879 880 881 882 883
    {
      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));
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
884
  }
885
  restore_record(table, s->default_values);              // Get empty record
886
  table->use_all_columns();
887
  if (thd->protocol->send_result_set_metadata(&field_list, Protocol::SEND_DEFAULTS))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
888
    DBUG_VOID_RETURN;
889
  my_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
890 891 892
  DBUG_VOID_RETURN;
}

893
/*
894
  Go through all character combinations and ensure that sql_lex.cc can
895
  parse it as an identifier.
896 897

  SYNOPSIS
898 899 900 901 902 903 904
  require_quotes()
  name			attribute name
  name_length		length of name

  RETURN
    #	Pointer to conflicting character
    0	No conflicting character
905 906
*/

907
static const char *require_quotes(const char *name, uint name_length)
908
{
909
  uint length;
910
  bool pure_digit= TRUE;
911 912
  const char *end= name + name_length;

913
  for (; name < end ; name++)
914
  {
915 916 917 918
    uchar chr= (uchar) *name;
    length= my_mbcharlen(system_charset_info, chr);
    if (length == 1 && !system_charset_info->ident_map[chr])
      return name;
919 920
    if (length == 1 && (chr < '0' || chr > '9'))
      pure_digit= FALSE;
921
  }
922 923
  if (pure_digit)
    return name;
924 925
  return 0;
}
926

927

928 929 930 931 932 933 934 935 936 937 938 939
/*
  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
*/

940 941
void
append_identifier(THD *thd, String *packet, const char *name, uint length)
942
{
943 944
  const char *name_end;
  char quote_char;
945
  int q= get_quote_char_for_identifier(thd, name, length);
946

947
  if (q == EOF)
948
  {
949
    packet->append(name, length, packet->charset());
950 951 952
    return;
  }

953 954 955 956
  /*
    The identifier must be quoted as it includes a quote character or
   it's a keyword
  */
957

Konstantin Osipov's avatar
Konstantin Osipov committed
958
  (void) packet->reserve(length*2 + 2);
959
  quote_char= (char) q;
960 961 962 963
  packet->append(&quote_char, 1, system_charset_info);

  for (name_end= name+length ; name < name_end ; name+= length)
  {
964
    uchar chr= (uchar) *name;
965
    length= my_mbcharlen(system_charset_info, chr);
966
    /*
967
      my_mbcharlen can return 0 on a wrong multibyte
968 969 970 971 972 973 974
      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;
975
    if (length == 1 && chr == (uchar) quote_char)
976
      packet->append(&quote_char, 1, system_charset_info);
977
    packet->append(name, length, system_charset_info);
978
  }
979
  packet->append(&quote_char, 1, system_charset_info);
980 981
}

982

983 984 985 986 987 988 989 990 991 992
/*
  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
993 994 995 996 997
    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;
998 999 1000 1001 1002 1003 1004
    Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE
    is set.

  RETURN
    EOF	  No quote character is needed
    #	  Quote character
*/
1005 1006 1007

int get_quote_char_for_identifier(THD *thd, const char *name, uint length)
{
anozdrin@mysql.com's avatar
anozdrin@mysql.com committed
1008
  if (length &&
1009
      !is_keyword(name,length) &&
1010
      !require_quotes(name, length) &&
1011
      !(thd->variables.option_bits & OPTION_QUOTE_SHOW_CREATE))
1012
    return EOF;
1013
  if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
1014
    return '"';
1015
  return '`';
1016 1017 1018
}


1019 1020 1021 1022 1023
/* Append directory name (if exists) to CREATE INFO */

static void append_directory(THD *thd, String *packet, const char *dir_type,
			     const char *filename)
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1024
  if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
1025
  {
1026
    uint length= dirname_length(filename);
1027 1028
    packet->append(' ');
    packet->append(dir_type);
1029
    packet->append(STRING_WITH_LEN(" DIRECTORY='"));
1030
#ifdef __WIN__
monty@mysql.com's avatar
monty@mysql.com committed
1031 1032 1033 1034 1035 1036 1037 1038 1039
    /* 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;
1040
#endif
monty@mysql.com's avatar
monty@mysql.com committed
1041
    packet->append(filename, length);
1042 1043 1044 1045 1046
    packet->append('\'');
  }
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1047
#define LIST_PROCESS_HOST_LEN 64
1048

Sergey Glukhov's avatar
Sergey Glukhov committed
1049
static bool get_field_default_value(THD *thd, Field *timestamp_field,
1050 1051 1052 1053 1054
                                    Field *field, String *def_value,
                                    bool quoted)
{
  bool has_default;
  bool has_now_default;
1055
  enum enum_field_types field_type= field->type();
Sergey Glukhov's avatar
Sergey Glukhov committed
1056 1057

  /*
1058 1059 1060
     We are using CURRENT_TIMESTAMP instead of NOW because it is
     more standard
  */
Sergey Glukhov's avatar
Sergey Glukhov committed
1061 1062 1063
  has_now_default= (timestamp_field == field &&
                    field->unireg_check != Field::TIMESTAMP_UN_FIELD);

1064
  has_default= (field_type != FIELD_TYPE_BLOB &&
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
                !(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)
      def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
    else if (!field->is_null())
    {                                             // Not null by default
      char tmp[MAX_FIELD_WIDTH];
      String type(tmp, sizeof(tmp), field->charset());
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
      if (field_type == MYSQL_TYPE_BIT)
      {
        longlong dec= field->val_int();
        char *ptr= longlong2str(dec, tmp + 2, 2);
        uint32 length= (uint32) (ptr - tmp);
        tmp[0]= 'b';
        tmp[1]= '\'';        
        tmp[length]= '\'';
        type.length(length + 1);
        quoted= 0;
      }
      else
        field->val_str(&type);
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
      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
1116

1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
/*
  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.
1131
  
1132 1133 1134
  NOTE
    Currently always return 0, but might return error code in the
    future.
1135
    
1136 1137 1138
  RETURN
    0       OK
 */
1139 1140

int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
1141
                      HA_CREATE_INFO *create_info_arg, bool show_database)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1142
{
1143
  List<Item> field_list;
1144
  char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH];
1145
  const char *alias;
1146
  String type(tmp, sizeof(tmp), system_charset_info);
1147
  String def_value(def_value_buf, sizeof(def_value_buf), system_charset_info);
1148 1149 1150
  Field **ptr,*field;
  uint primary_key;
  KEY *key_info;
1151
  TABLE *table= table_list->table;
1152
  handler *file= table->file;
1153
  TABLE_SHARE *share= table->s;
1154
  HA_CREATE_INFO create_info;
1155
  bool show_table_options= FALSE;
1156 1157 1158 1159 1160 1161
  bool foreign_db_mode=  (thd->variables.sql_mode & (MODE_POSTGRESQL |
                                                     MODE_ORACLE |
                                                     MODE_MSSQL |
                                                     MODE_DB2 |
                                                     MODE_MAXDB |
                                                     MODE_ANSI)) != 0;
msvensson@neptunus.(none)'s avatar
msvensson@neptunus.(none) committed
1162 1163 1164
  bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS |
                                                       MODE_MYSQL323 |
                                                       MODE_MYSQL40)) != 0;
1165
  my_bitmap_map *old_map;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1166
  DBUG_ENTER("store_create_info");
1167
  DBUG_PRINT("enter",("table: %s", table->s->table_name.str));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1168

1169
  restore_record(table, s->default_values); // Get empty record
1170

1171
  if (share->tmp_table)
1172
    packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
1173
  else
1174
    packet->append(STRING_WITH_LEN("CREATE TABLE "));
1175 1176 1177
  if (create_info_arg &&
      (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS))
    packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
1178
  if (table_list->schema_table)
1179
    alias= table_list->schema_table->table_name;
1180
  else
1181 1182 1183 1184 1185 1186 1187 1188
  {
    if (lower_case_table_names == 2)
      alias= table->alias;
    else
    {
      alias= share->table_name.str;
    }
  }
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200

  /*
    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;
1201
    if (!thd->db || strcmp(db->str, thd->db))
1202 1203 1204 1205 1206 1207
    {
      append_identifier(thd, packet, db->str, db->length);
      packet->append(STRING_WITH_LEN("."));
    }
  }

monty@mysql.com's avatar
monty@mysql.com committed
1208
  append_identifier(thd, packet, alias, strlen(alias));
1209
  packet->append(STRING_WITH_LEN(" (\n"));
1210 1211 1212 1213 1214 1215
  /*
    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);
1216

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1217 1218
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1219 1220
    uint flags = field->flags;

1221
    if (ptr != table->field)
1222
      packet->append(STRING_WITH_LEN(",\n"));
1223

1224
    packet->append(STRING_WITH_LEN("  "));
1225
    append_identifier(thd,packet,field->field_name, strlen(field->field_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1226 1227
    packet->append(' ');
    // check for surprises from the previous call to Field::sql_type()
1228
    if (type.ptr() != tmp)
1229
      type.set(tmp, sizeof(tmp), system_charset_info);
1230 1231
    else
      type.set_charset(system_charset_info);
1232

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1233
    field->sql_type(type);
1234
    packet->append(type.ptr(), type.length(), system_charset_info);
1235

1236 1237
    if (field->has_charset() && 
        !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
1238
    {
1239
      if (field->charset() != share->table_charset)
1240
      {
1241
	packet->append(STRING_WITH_LEN(" CHARACTER SET "));
1242 1243 1244 1245 1246 1247 1248 1249
	packet->append(field->charset()->csname);
      }
      /* 
	For string types dump collation name only if 
	collation is not primary for the given charset
      */
      if (!(field->charset()->state & MY_CS_PRIMARY))
      {
1250
	packet->append(STRING_WITH_LEN(" COLLATE "));
1251
	packet->append(field->charset()->name);
1252
      }
1253
    }
1254

1255
    if (flags & NOT_NULL_FLAG)
1256
      packet->append(STRING_WITH_LEN(" NOT NULL"));
1257
    else if (field->type() == MYSQL_TYPE_TIMESTAMP)
1258 1259 1260 1261 1262
    {
      /*
        TIMESTAMP field require explicit NULL flag, because unlike
        all other fields they are treated as NOT NULL by default.
      */
1263
      packet->append(STRING_WITH_LEN(" NULL"));
1264
    }
1265

Sergey Glukhov's avatar
Sergey Glukhov committed
1266 1267
    if (get_field_default_value(thd, table->timestamp_field,
                                field, &def_value, 1))
1268
    {
1269
      packet->append(STRING_WITH_LEN(" DEFAULT "));
1270
      packet->append(def_value.ptr(), def_value.length(), system_charset_info);
1271
    }
1272

1273
    if (!limited_mysql_mode && table->timestamp_field == field && 
1274
        field->unireg_check != Field::TIMESTAMP_DN_FIELD)
1275
      packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
1276

1277 1278
    if (field->unireg_check == Field::NEXT_NUMBER && 
        !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
1279
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
1280 1281 1282

    if (field->comment.length)
    {
1283
      packet->append(STRING_WITH_LEN(" COMMENT "));
1284 1285
      append_unescaped(packet, field->comment.str, field->comment.length);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1286 1287
  }

1288
  key_info= table->key_info;
1289
  bzero((char*) &create_info, sizeof(create_info));
1290 1291
  /* Allow update_create_info to update row type */
  create_info.row_type= share->row_type;
1292
  file->update_create_info(&create_info);
1293
  primary_key= share->primary_key;
1294

1295
  for (uint i=0 ; i < share->keys ; i++,key_info++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1296
  {
1297 1298
    KEY_PART_INFO *key_part= key_info->key_part;
    bool found_primary=0;
1299
    packet->append(STRING_WITH_LEN(",\n  "));
1300

1301
    if (i == primary_key && !strcmp(key_info->name, primary_key_name))
1302 1303
    {
      found_primary=1;
1304 1305 1306 1307 1308
      /*
        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"));
1309
    }
1310
    else if (key_info->flags & HA_NOSAME)
1311
      packet->append(STRING_WITH_LEN("UNIQUE KEY "));
1312
    else if (key_info->flags & HA_FULLTEXT)
1313
      packet->append(STRING_WITH_LEN("FULLTEXT KEY "));
1314
    else if (key_info->flags & HA_SPATIAL)
1315 1316 1317
      packet->append(STRING_WITH_LEN("SPATIAL KEY "));
    else
      packet->append(STRING_WITH_LEN("KEY "));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1318

1319
    if (!found_primary)
1320
     append_identifier(thd, packet, key_info->name, strlen(key_info->name));
1321

1322
    packet->append(STRING_WITH_LEN(" ("));
1323

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1324 1325
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
1326
      if (j)
1327
        packet->append(',');
1328

1329
      if (key_part->field)
1330 1331
        append_identifier(thd,packet,key_part->field->field_name,
			  strlen(key_part->field->field_name));
1332
      if (key_part->field &&
1333 1334
          (key_part->length !=
           table->field[key_part->fieldnr-1]->key_length() &&
gkodinov/kgeorge@magare.gmz's avatar
gkodinov/kgeorge@magare.gmz committed
1335
           !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1336
      {
1337
        char *end;
1338
        buff[0] = '(';
1339 1340 1341
        end= int10_to_str((long) key_part->length /
                          key_part->field->charset()->mbmaxlen,
                          buff + 1,10);
1342 1343
        *end++ = ')';
        packet->append(buff,(uint) (end-buff));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1344 1345 1346
      }
    }
    packet->append(')');
1347
    store_key_options(thd, packet, table, key_info);
1348 1349
    if (key_info->parser)
    {
antony@ppcg5.local's avatar
antony@ppcg5.local committed
1350
      LEX_STRING *parser_name= plugin_name(key_info->parser);
1351
      packet->append(STRING_WITH_LEN(" /*!50100 WITH PARSER "));
antony@ppcg5.local's avatar
antony@ppcg5.local committed
1352
      append_identifier(thd, packet, parser_name->str, parser_name->length);
1353
      packet->append(STRING_WITH_LEN(" */ "));
1354
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1355
  }
1356

1357 1358 1359 1360
  /*
    Get possible foreign key definitions stored in InnoDB and append them
    to the CREATE TABLE statement
  */
1361

1362
  if ((for_str= file->get_foreign_key_create_info()))
1363 1364 1365
  {
    packet->append(for_str, strlen(for_str));
    file->free_foreign_key_create_info(for_str);
1366 1367
  }

1368
  packet->append(STRING_WITH_LEN("\n)"));
1369
  if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
1370
  {
1371
    show_table_options= TRUE;
1372 1373 1374 1375 1376
    /*
      Get possible table space definitions and append them
      to the CREATE TABLE statement
    */

1377
    if ((for_str= file->get_tablespace_name(thd,0,0)))
1378
    {
1379
      packet->append(STRING_WITH_LEN(" /*!50100 TABLESPACE "));
1380
      packet->append(for_str, strlen(for_str));
1381
      packet->append(STRING_WITH_LEN(" STORAGE DISK */"));
1382
      my_free(for_str);
1383 1384
    }

1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
    /*
      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="));
1396
#ifdef WITH_PARTITION_STORAGE_ENGINE
1397
    if (table->part_info)
1398 1399
      packet->append(ha_resolve_storage_engine_name(
                        table->part_info->default_engine_type));
1400
    else
1401
      packet->append(file->table_type());
1402
#else
1403
      packet->append(file->table_type());
1404
#endif
1405
    }
1406

1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
    /*
      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.
    */

1418
    if (create_info.auto_increment_value > 1)
1419
    {
1420
      char *end;
1421
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT="));
1422 1423 1424
      end= longlong10_to_str(create_info.auto_increment_value, buff,10);
      packet->append(buff, (uint) (end - buff));
    }
1425
    
1426
    if (share->table_charset &&
1427 1428
	!(thd->variables.sql_mode & MODE_MYSQL323) &&
	!(thd->variables.sql_mode & MODE_MYSQL40))
1429
    {
1430 1431 1432 1433 1434 1435
      /*
        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))
1436
      {
1437 1438 1439 1440 1441 1442 1443
        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);
        }
1444
      }
1445
    }
1446

1447
    if (share->min_rows)
1448
    {
1449
      char *end;
1450
      packet->append(STRING_WITH_LEN(" MIN_ROWS="));
1451
      end= longlong10_to_str(share->min_rows, buff, 10);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1452
      packet->append(buff, (uint) (end- buff));
1453
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1454

1455
    if (share->max_rows && !table_list->schema_table)
1456
    {
1457
      char *end;
1458
      packet->append(STRING_WITH_LEN(" MAX_ROWS="));
1459
      end= longlong10_to_str(share->max_rows, buff, 10);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1460
      packet->append(buff, (uint) (end - buff));
1461
    }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1462

1463
    if (share->avg_row_length)
1464
    {
1465
      char *end;
1466
      packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
1467
      end= longlong10_to_str(share->avg_row_length, buff,10);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1468
      packet->append(buff, (uint) (end - buff));
1469
    }
1470

1471
    if (share->db_create_options & HA_OPTION_PACK_KEYS)
1472
      packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
1473
    if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
1474
      packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
1475
    /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
1476
    if (share->db_create_options & HA_OPTION_CHECKSUM)
1477
      packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
1478
    if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
1479
      packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1"));
1480
    if (create_info.row_type != ROW_TYPE_DEFAULT)
1481
    {
1482
      packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
1483
      packet->append(ha_row_type[(uint) create_info.row_type]);
1484
    }
1485 1486
    if (table->s->key_block_size)
    {
1487
      char *end;
1488 1489 1490 1491
      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));
    }
1492
    table->file->append_create_info(packet);
1493
    if (share->comment.length)
1494
    {
1495
      packet->append(STRING_WITH_LEN(" COMMENT="));
1496
      append_unescaped(packet, share->comment.str, share->comment.length);
1497
    }
1498 1499
    if (share->connect_string.length)
    {
1500
      packet->append(STRING_WITH_LEN(" CONNECTION="));
1501 1502
      append_unescaped(packet, share->connect_string.str, share->connect_string.length);
    }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1503 1504
    append_directory(thd, packet, "DATA",  create_info.data_file_name);
    append_directory(thd, packet, "INDEX", create_info.index_file_name);
1505
  }
1506
#ifdef WITH_PARTITION_STORAGE_ENGINE
1507 1508 1509 1510 1511 1512
  {
    /*
      Partition syntax for CREATE TABLE is at the end of the syntax.
    */
    uint part_syntax_len;
    char *part_syntax;
1513
    if (table->part_info &&
1514
        (!table->part_info->is_auto_partitioned) &&
1515
        ((part_syntax= generate_partition_syntax(table->part_info,
1516
                                                  &part_syntax_len,
1517
                                                  FALSE,
1518 1519
                                                  show_table_options,
                                                  NULL, NULL))))
1520
    {
1521
       table->part_info->set_show_version_string(packet);
1522
       packet->append(part_syntax, part_syntax_len);
rburnett@bk-internal.mysql.com's avatar
rburnett@bk-internal.mysql.com committed
1523
       packet->append(STRING_WITH_LEN(" */"));
1524
       my_free(part_syntax);
1525 1526 1527
    }
  }
#endif
1528
  tmp_restore_column_map(table->read_set, old_map);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1529 1530 1531
  DBUG_RETURN(0);
}

1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568

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));
    }
1569 1570 1571 1572 1573 1574 1575 1576
    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);
    }
1577 1578 1579 1580
  }
}


1581 1582
void
view_store_options(THD *thd, TABLE_LIST *table, String *buff)
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604
{
  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.
  
  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)
1605
{
1606
  buff->append(STRING_WITH_LEN("ALGORITHM="));
1607 1608
  switch ((int8)table->algorithm) {
  case VIEW_ALGORITHM_UNDEFINED:
1609
    buff->append(STRING_WITH_LEN("UNDEFINED "));
1610 1611
    break;
  case VIEW_ALGORITHM_TMPTABLE:
1612
    buff->append(STRING_WITH_LEN("TEMPTABLE "));
1613 1614
    break;
  case VIEW_ALGORITHM_MERGE:
1615
    buff->append(STRING_WITH_LEN("MERGE "));
1616 1617 1618 1619 1620
    break;
  default:
    DBUG_ASSERT(0); // never should happen
  }
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1621

1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
/*
  Append DEFINER clause to the given buffer.
  
  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(' ');
}


1644
int
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1645 1646
view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
{
1647
  my_bool compact_view_name= TRUE;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1648 1649 1650 1651 1652 1653
  my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
                                                       MODE_ORACLE |
                                                       MODE_MSSQL |
                                                       MODE_DB2 |
                                                       MODE_MAXDB |
                                                       MODE_ANSI)) != 0;
1654

1655
  if (!thd->db || strcmp(thd->db, table->view_db.str))
1656 1657 1658 1659
    /*
      print compact view name if the view belongs to the current database
    */
    compact_view_name= table->compact_view_format= FALSE;
1660 1661
  else
  {
1662 1663 1664 1665
    /*
      Compact output format for view body can be used
      if this view only references table inside it's own db
    */
1666
    TABLE_LIST *tbl;
1667
    table->compact_view_format= TRUE;
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679
    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;
      }
    }
  }

1680
  buff->append(STRING_WITH_LEN("CREATE "));
1681
  if (!foreign_db_mode)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1682
  {
1683
    view_store_options(thd, table, buff);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1684
  }
1685
  buff->append(STRING_WITH_LEN("VIEW "));
1686
  if (!compact_view_name)
1687 1688 1689 1690
  {
    append_identifier(thd, buff, table->view_db.str, table->view_db.length);
    buff->append('.');
  }
1691
  append_identifier(thd, buff, table->view_name.str, table->view_name.length);
1692
  buff->append(STRING_WITH_LEN(" AS "));
1693 1694 1695 1696 1697

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

1700 1701 1702
  if (table->with_check != VIEW_CHECK_NONE)
  {
    if (table->with_check == VIEW_CHECK_LOCAL)
1703
      buff->append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION"));
1704
    else
1705
      buff->append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION"));
1706
  }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1707 1708 1709 1710
  return 0;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
1711
/****************************************************************************
1712 1713
  Return info about all processes
  returns for each thread: thread id, user, host, db, command, info
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1714 1715 1716 1717
****************************************************************************/

class thread_info :public ilink {
public:
1718 1719 1720 1721
  static void *operator new(size_t size)
  {
    return (void*) sql_alloc((uint) size);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1722
  static void operator delete(void *ptr __attribute__((unused)),
1723 1724
                              size_t size __attribute__((unused)))
  { TRASH(ptr, size); }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1725

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1726 1727
  ulong thread_id;
  time_t start_time;
1728
  uint   command;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1729
  const char *user,*host,*db,*proc_info,*state_info;
1730
  CSET_STRING query_string;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1731 1732
};

1733
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1734 1735 1736
template class I_List<thread_info>;
#endif

1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760
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;
  }
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1761 1762 1763 1764 1765
void mysqld_list_processes(THD *thd,const char *user, bool verbose)
{
  Item *field;
  List<Item> field_list;
  I_List<thread_info> thread_infos;
1766 1767
  ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
			   PROCESS_LIST_WIDTH);
1768
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1769 1770
  DBUG_ENTER("mysqld_list_processes");

1771
  field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1772
  field_list.push_back(new Item_empty_string("User",16));
1773
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
1774
  field_list.push_back(field=new Item_empty_string("db",NAME_CHAR_LEN));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1775 1776
  field->maybe_null=1;
  field_list.push_back(new Item_empty_string("Command",16));
1777
  field_list.push_back(field= new Item_return_int("Time",7, MYSQL_TYPE_LONG));
1778
  field->unsigned_flag= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1779 1780 1781 1782
  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;
1783
  if (protocol->send_result_set_metadata(&field_list,
1784
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1785 1786
    DBUG_VOID_RETURN;

Marc Alff's avatar
Marc Alff committed
1787
  mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1788 1789 1790 1791 1792 1793
  if (!thd->killed)
  {
    I_List_iterator<THD> it(threads);
    THD *tmp;
    while ((tmp=it++))
    {
1794
      Security_context *tmp_sctx= tmp->security_ctx;
1795
      struct st_my_thread_var *mysys_var;
1796
      if ((tmp->vio_ok() || tmp->system_thread) &&
1797
          (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1798
      {
1799
        thread_info *thd_info= new thread_info;
1800 1801

        thd_info->thread_id=tmp->thread_id;
1802 1803 1804 1805 1806
        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])
1807
	{
1808
	  if ((thd_info->host= (char*) thd->alloc(LIST_PROCESS_HOST_LEN+1)))
1809
	    my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
1810
			"%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
1811 1812
	}
	else
1813 1814 1815
	  thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ? 
                                      tmp_sctx->host_or_ip : 
                                      tmp_sctx->host ? tmp_sctx->host : "");
1816 1817 1818
        if ((thd_info->db=tmp->db))             // Safe test
          thd_info->db=thd->strdup(thd_info->db);
        thd_info->command=(int) tmp->command;
1819
        mysql_mutex_lock(&tmp->LOCK_thd_data);
1820
        if ((mysys_var= tmp->mysys_var))
Marc Alff's avatar
Marc Alff committed
1821
          mysql_mutex_lock(&mysys_var->mutex);
hf@genie.(none)'s avatar
SCRUM  
hf@genie.(none) committed
1822
        thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
1823
        thd_info->state_info= thread_state_info(tmp);
1824
        if (mysys_var)
Marc Alff's avatar
Marc Alff committed
1825
          mysql_mutex_unlock(&mysys_var->mutex);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1826

1827
        /* Lock THD mutex that protects its data when looking at it. */
1828
        if (tmp->query())
1829
        {
1830
          uint length= min(max_query_length, tmp->query_length());
1831 1832 1833 1834
          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());
1835
        }
Marc Alff's avatar
Marc Alff committed
1836
        mysql_mutex_unlock(&tmp->LOCK_thd_data);
1837
        thd_info->start_time= tmp->start_time;
1838
        thread_infos.append(thd_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1839 1840 1841
      }
    }
  }
Marc Alff's avatar
Marc Alff committed
1842
  mysql_mutex_unlock(&LOCK_thread_count);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1843 1844

  thread_info *thd_info;
1845
  time_t now= my_time(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1846 1847
  while ((thd_info=thread_infos.get()))
  {
1848 1849
    protocol->prepare_for_resend();
    protocol->store((ulonglong) thd_info->thread_id);
1850 1851 1852
    protocol->store(thd_info->user, system_charset_info);
    protocol->store(thd_info->host, system_charset_info);
    protocol->store(thd_info->db, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1853
    if (thd_info->proc_info)
1854
      protocol->store(thd_info->proc_info, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1855
    else
1856
      protocol->store(command_name[thd_info->command].str, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1857
    if (thd_info->start_time)
1858
      protocol->store_long ((longlong) (now - thd_info->start_time));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1859
    else
1860
      protocol->store_null();
1861
    protocol->store(thd_info->state_info, system_charset_info);
1862 1863
    protocol->store(thd_info->query_string.str(),
                    thd_info->query_string.charset());
1864
    if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1865 1866
      break; /* purecov: inspected */
  }
1867
  my_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1868 1869 1870
  DBUG_VOID_RETURN;
}

1871 1872 1873 1874 1875
int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
{
  TABLE *table= tables->table;
  CHARSET_INFO *cs= system_charset_info;
  char *user;
1876
  time_t now= my_time(0);
1877 1878 1879 1880 1881
  DBUG_ENTER("fill_process_list");

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

Marc Alff's avatar
Marc Alff committed
1882
  mysql_mutex_lock(&LOCK_thread_count);
1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924

  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;

      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();
      }

1925
      mysql_mutex_lock(&tmp->LOCK_thd_data);
1926
      if ((mysys_var= tmp->mysys_var))
Marc Alff's avatar
Marc Alff committed
1927
        mysql_mutex_lock(&mysys_var->mutex);
1928 1929 1930 1931 1932 1933
      /* COMMAND */
      if ((val= (char *) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0)))
        table->field[4]->store(val, strlen(val), cs);
      else
        table->field[4]->store(command_name[tmp->command].str,
                               command_name[tmp->command].length, cs);
1934
      /* MYSQL_TIME */
1935 1936
      table->field[5]->store((longlong)(tmp->start_time ?
                                      now - tmp->start_time : 0), FALSE);
1937
      /* STATE */
1938
      if ((val= thread_state_info(tmp)))
1939 1940 1941 1942 1943 1944
      {
        table->field[6]->store(val, strlen(val), cs);
        table->field[6]->set_notnull();
      }

      if (mysys_var)
Marc Alff's avatar
Marc Alff committed
1945
        mysql_mutex_unlock(&mysys_var->mutex);
1946
      mysql_mutex_unlock(&tmp->LOCK_thd_data);
1947 1948

      /* INFO */
1949
      /* Lock THD mutex that protects its data when looking at it. */
1950
      mysql_mutex_lock(&tmp->LOCK_thd_data);
1951
      if (tmp->query())
1952
      {
1953
        table->field[7]->store(tmp->query(),
1954
                               min(PROCESS_LIST_INFO_WIDTH,
1955
                                   tmp->query_length()), cs);
1956 1957
        table->field[7]->set_notnull();
      }
1958
      mysql_mutex_unlock(&tmp->LOCK_thd_data);
1959 1960 1961

      if (schema_table_store_record(thd, table))
      {
Marc Alff's avatar
Marc Alff committed
1962
        mysql_mutex_unlock(&LOCK_thread_count);
1963 1964 1965 1966 1967
        DBUG_RETURN(1);
      }
    }
  }

Marc Alff's avatar
Marc Alff committed
1968
  mysql_mutex_unlock(&LOCK_thread_count);
1969 1970 1971
  DBUG_RETURN(0);
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1972
/*****************************************************************************
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1973
  Status functions
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1974 1975
*****************************************************************************/

1976 1977
static DYNAMIC_ARRAY all_status_vars;
static bool status_vars_inited= 0;
1978 1979

C_MODE_START
1980 1981 1982 1983
static int show_var_cmp(const void *var1, const void *var2)
{
  return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
}
1984
C_MODE_END
1985 1986 1987 1988 1989 1990 1991

/*
  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)
{
1992
  uint a,b;
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029
  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
2030
    mysql_mutex_lock(&LOCK_status);
2031 2032 2033 2034 2035 2036 2037
  if (!all_status_vars.buffer && // array is not allocated yet - do it now
      my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 200, 20))
  {
    res= 1;
    goto err;
  }
  while (list->name)
2038 2039
    res|= insert_dynamic(&all_status_vars, (uchar*)list++);
  res|= insert_dynamic(&all_status_vars, (uchar*)list); // appending NULL-element
2040 2041 2042 2043 2044
  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
2045
    mysql_mutex_unlock(&LOCK_status);
2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062
  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);
}

antony@ppcg5.local's avatar
antony@ppcg5.local committed
2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
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;
  }  
}

2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101
/*
  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.
*/
2102

2103 2104 2105 2106
void remove_status_vars(SHOW_VAR *list)
{
  if (status_vars_inited)
  {
Marc Alff's avatar
Marc Alff committed
2107
    mysql_mutex_lock(&LOCK_status);
2108
    SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
2109
    int a= 0, b= all_status_vars.elements, c= (a+b)/2;
2110 2111 2112

    for (; list->name; list++)
    {
2113
      int res= 0;
2114 2115 2116 2117 2118 2119 2120
      for (a= 0, b= all_status_vars.elements; b-a > 1; c= (a+b)/2)
      {
        res= show_var_cmp(list, all+c);
        if (res < 0)
          b= c;
        else if (res > 0)
          a= c;
2121 2122
        else
          break;
2123 2124 2125 2126 2127
      }
      if (res == 0)
        all[c].type= SHOW_UNDEF;
    }
    shrink_var_array(&all_status_vars);
Marc Alff's avatar
Marc Alff committed
2128
    mysql_mutex_unlock(&LOCK_status);
2129 2130 2131 2132
  }
  else
  {
    SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
2133
    uint i;
2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147
    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);
  }
}

2148 2149 2150 2151 2152 2153
inline void make_upper(char *buf)
{
  for (; *buf; buf++)
    *buf= my_toupper(system_charset_info, *buf);
}

2154
static bool show_status_array(THD *thd, const char *wild,
2155
                              SHOW_VAR *variables,
2156 2157
                              enum enum_var_type value_type,
                              struct system_status_var *status_var,
2158
                              const char *prefix, TABLE *table,
2159 2160
                              bool ucase_names,
                              COND *cond)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2161
{
2162 2163
  my_aligned_storage<SHOW_VAR_FUNC_BUFF_SIZE, MY_ALIGNOF(long)> buffer;
  char * const buff= buffer.data;
2164
  char *prefix_end;
2165 2166
  /* the variable name should not be longer than 64 characters */
  char name_buffer[64];
2167
  int len;
2168
  LEX_STRING null_lex_str;
2169
  SHOW_VAR tmp, *var;
2170 2171 2172
  COND *partial_cond= 0;
  enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
  bool res= FALSE;
2173
  CHARSET_INFO *charset= system_charset_info;
2174
  DBUG_ENTER("show_status_array");
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2175

2176
  thd->count_cuted_fields= CHECK_FIELD_WARN;  
2177
  null_lex_str.str= 0;				// For sys_var->value_ptr()
2178
  null_lex_str.length= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2179

2180
  prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1);
2181 2182
  if (*prefix)
    *prefix_end++= '_';
2183
  len=name_buffer + sizeof(name_buffer) - prefix_end;
2184
  partial_cond= make_cond_for_info_schema(cond, table->pos_in_table_list);
2185

2186
  for (; variables->name; variables++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2187
  {
2188 2189
    strnmov(prefix_end, variables->name, len);
    name_buffer[sizeof(name_buffer)-1]=0;       /* Safety */
2190 2191
    if (ucase_names)
      make_upper(name_buffer);
2192

2193 2194 2195
    restore_record(table, s->default_values);
    table->field[0]->store(name_buffer, strlen(name_buffer),
                           system_charset_info);
2196 2197 2198 2199
    /*
      if var->type is SHOW_FUNC, call the function.
      Repeat as necessary, if new var is again SHOW_FUNC
    */
2200
    for (var=variables; var->type == SHOW_FUNC; var= &tmp)
2201
      ((mysql_show_var_func)(var->value))(thd, &tmp, buff);
2202 2203 2204

    SHOW_TYPE show_type=var->type;
    if (show_type == SHOW_ARRAY)
2205
    {
2206
      show_status_array(thd, wild, (SHOW_VAR *) var->value, value_type,
2207
                        status_var, name_buffer, table, ucase_names, partial_cond);
2208 2209
    }
    else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2210
    {
2211
      if (!(wild && wild[0] && wild_case_compare(system_charset_info,
2212 2213
                                                 name_buffer, wild)) &&
          (!partial_cond || partial_cond->val_int()))
2214
      {
2215
        char *value=var->value;
2216
        const char *pos, *end;                  // We assign a lot of const's
2217

Marc Alff's avatar
Marc Alff committed
2218
        mysql_mutex_lock(&LOCK_global_system_variables);
antony@ppcg5.local's avatar
antony@ppcg5.local committed
2219

2220 2221
        if (show_type == SHOW_SYS)
        {
2222
          sys_var *var= ((sys_var *) value);
2223 2224 2225
          show_type= var->show_type();
          value= (char*) var->value_ptr(thd, value_type, &null_lex_str);
          charset= var->charset(thd);
2226 2227 2228
        }

        pos= end= buff;
2229 2230 2231 2232
        /*
          note that value may be == buff. All SHOW_xxx code below
          should still work in this case
        */
2233
        switch (show_type) {
2234 2235
        case SHOW_DOUBLE_STATUS:
          value= ((char *) status_var + (ulong) value);
2236 2237
          /* fall through */
        case SHOW_DOUBLE:
2238 2239
          /* 6 is the default precision for '%f' in sprintf() */
          end= buff + my_fcvt(*(double *) value, 6, buff, NULL);
2240
          break;
2241 2242 2243 2244
        case SHOW_LONG_STATUS:
          value= ((char *) status_var + (ulong) value);
          /* fall through */
        case SHOW_LONG:
2245
        case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
2246 2247
          end= int10_to_str(*(long*) value, buff, 10);
          break;
2248 2249
        case SHOW_LONGLONG_STATUS:
          value= ((char *) status_var + (ulonglong) value);
2250
          /* fall through */
2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266
        case SHOW_LONGLONG:
          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;
        case SHOW_INT:
          end= int10_to_str((long) *(uint32*) value, buff, 10);
          break;
        case SHOW_HAVE:
petr@mysql.com's avatar
petr@mysql.com committed
2267 2268 2269 2270 2271 2272
        {
          SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
          pos= show_comp_option_name[(int) tmp];
          end= strend(pos);
          break;
        }
2273
        case SHOW_CHAR:
petr@mysql.com's avatar
petr@mysql.com committed
2274 2275 2276 2277 2278 2279
        {
          if (!(pos= value))
            pos= "";
          end= strend(pos);
          break;
        }
2280
       case SHOW_CHAR_PTR:
petr@mysql.com's avatar
petr@mysql.com committed
2281 2282 2283 2284 2285 2286
        {
          if (!(pos= *(char**) value))
            pos= "";
          end= strend(pos);
          break;
        }
2287 2288 2289 2290 2291 2292 2293 2294 2295
        case SHOW_LEX_STRING:
        {
          LEX_STRING *ls=(LEX_STRING*)value;
          if (!(pos= ls->str))
            end= pos= "";
          else
            end= pos + ls->length;
          break;
        }
2296
        case SHOW_KEY_CACHE_LONG:
2297
          value= (char*) dflt_key_cache + (ulong)value;
2298 2299
          end= int10_to_str(*(long*) value, buff, 10);
          break;
2300
        case SHOW_KEY_CACHE_LONGLONG:
2301
          value= (char*) dflt_key_cache + (ulong)value;
2302 2303
	  end= longlong10_to_str(*(longlong*) value, buff, 10);
	  break;
2304
        case SHOW_UNDEF:
2305 2306
          break;                                        // Return empty string
        case SHOW_SYS:                                  // Cannot happen
2307
        default:
2308
          DBUG_ASSERT(0);
2309 2310
          break;
        }
2311
        table->field[1]->store(pos, (uint32) (end - pos), charset);
2312
        thd->count_cuted_fields= CHECK_FIELD_IGNORE;
2313
        table->field[1]->set_notnull();
antony@ppcg5.local's avatar
antony@ppcg5.local committed
2314

Marc Alff's avatar
Marc Alff committed
2315
        mysql_mutex_unlock(&LOCK_global_system_variables);
antony@ppcg5.local's avatar
antony@ppcg5.local committed
2316

2317
        if (schema_table_store_record(thd, table))
2318 2319 2320 2321
        {
          res= TRUE;
          goto end;
        }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2322 2323 2324
      }
    }
  }
2325 2326 2327
end:
  thd->count_cuted_fields= save_count_cuted_fields;
  DBUG_RETURN(res);
2328 2329 2330
}


2331 2332 2333 2334 2335 2336 2337
/* 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
2338
  mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349

  I_List_iterator<THD> it(threads);
  THD *tmp;
  
  /* Get global values as base */
  *to= global_status_var;
  
  /* Add to this status from existing threads */
  while ((tmp= it++))
    add_to_status(to, &tmp->status_var);
  
Marc Alff's avatar
Marc Alff committed
2350
  mysql_mutex_unlock(&LOCK_thread_count);
2351 2352 2353 2354
  DBUG_VOID_RETURN;
}


2355
/* This is only used internally, but we need it here as a forward reference */
2356 2357
extern ST_SCHEMA_TABLE schema_tables[];

2358
typedef struct st_lookup_field_values
2359
{
2360 2361 2362
  LEX_STRING db_value, table_value;
  bool wild_db_value, wild_table_value;
} LOOKUP_FIELD_VALUES;
2363 2364


2365 2366 2367 2368 2369 2370 2371
/*
  Store record to I_S table, convert HEAP table
  to MyISAM if necessary

  SYNOPSIS
    schema_table_store_record()
    thd                   thread handler
2372 2373
    table                 Information schema table to be updated

2374 2375
  RETURN
    0	                  success
2376
    1	                  error
2377 2378
*/

2379
bool schema_table_store_record(THD *thd, TABLE *table)
2380 2381
{
  int error;
2382
  if ((error= table->file->ha_write_row(table->record[0])))
2383 2384 2385 2386 2387 2388 2389 2390 2391 2392
  {
    if (create_myisam_from_heap(thd, table, 
                                table->pos_in_table_list->schema_table_param,
                                error, 0))
      return 1;
  }
  return 0;
}


2393
int make_table_list(THD *thd, SELECT_LEX *sel,
2394
                    LEX_STRING *db_name, LEX_STRING *table_name)
2395 2396
{
  Table_ident *table_ident;
2397
  table_ident= new Table_ident(thd, *db_name, *table_name, 1);
2398
  sel->init_query();
2399
  if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ))
2400 2401 2402 2403 2404
    return 1;
  return 0;
}


2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417
/**
  @brief    Get lookup value from the part of 'WHERE' condition 

  @details This function gets lookup value from 
           the part of 'WHERE' condition if it's possible and 
           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
  @param[in, out] lookup_field_vals     Struct which holds lookup values 

2418 2419 2420
  @return
    0             success
    1             error, there can be no matching records for the condition
2421 2422
*/

2423
bool get_lookup_value(THD *thd, Item_func *item_func,
2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455
                      TABLE_LIST *table, 
                      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;

    if (item_func->arguments()[0]->type() == Item::FIELD_ITEM &&
        item_func->arguments()[1]->const_item())
    {
      idx_field= 0;
      idx_val= 1;
    }
    else if (item_func->arguments()[1]->type() == Item::FIELD_ITEM &&
             item_func->arguments()[0]->const_item())
    {
      idx_field= 1;
      idx_val= 0;
    }
    else
2456
      return 0;
2457 2458 2459

    item_field= (Item_field*) item_func->arguments()[idx_field];
    if (table->table != item_field->field->table)
2460
      return 0;
2461 2462
    tmp_str= item_func->arguments()[idx_val]->val_str(&str_buff);

2463 2464 2465 2466
    /* impossible value */
    if (!tmp_str)
      return 1;

2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484
    /* 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))
    {
      thd->make_lex_string(&lookup_field_vals->db_value, tmp_str->ptr(),
                           tmp_str->length(), FALSE);
    }
    /* 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))
    {
      thd->make_lex_string(&lookup_field_vals->table_value, tmp_str->ptr(),
                           tmp_str->length(), FALSE);
    }
  }
2485
  return 0;
2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500
}


/**
  @brief    Calculates lookup values from 'WHERE' condition 

  @details This function calculates lookup value(database name, table name)
           from 'WHERE' condition if it's possible and 
           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
  @param[in, out] lookup_field_vals     Struct which holds lookup values 

2501 2502 2503
  @return
    0             success
    1             error, there can be no matching records for the condition
2504 2505
*/

2506
bool calc_lookup_values_from_cond(THD *thd, COND *cond, TABLE_LIST *table,
2507 2508 2509
                                  LOOKUP_FIELD_VALUES *lookup_field_vals)
{
  if (!cond)
2510
    return 0;
2511 2512 2513 2514 2515 2516 2517 2518 2519 2520

  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)
2521 2522 2523 2524
        {
          if (get_lookup_value(thd, (Item_func*)item, table, lookup_field_vals))
            return 1;
        }
2525
        else
2526 2527 2528 2529
        {
          if (calc_lookup_values_from_cond(thd, item, table, lookup_field_vals))
            return 1;
        }
2530 2531
      }
    }
2532
    return 0;
2533
  }
2534 2535 2536 2537
  else if (cond->type() == Item::FUNC_ITEM &&
           get_lookup_value(thd, (Item_func*) cond, table, lookup_field_vals))
    return 1;
  return 0;
2538 2539 2540
}


2541 2542 2543 2544 2545
bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
{
  if (item->type() == Item::FUNC_ITEM)
  {
    Item_func *item_func= (Item_func*)item;
2546
    for (uint i=0; i<item_func->argument_count(); i++)
2547
    {
2548
      if (!uses_only_table_name_fields(item_func->arguments()[i], table))
2549
        return 0;
2550
    }
2551 2552 2553 2554 2555 2556 2557
  }
  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;
2558 2559 2560 2561
    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 : "";
2562 2563
    if (table->table != item_field->field->table ||
        (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
2564
                               (uchar *) item_field->field_name,
2565 2566
                               strlen(item_field->field_name), 0) &&
         cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2),
2567
                               (uchar *) item_field->field_name,
2568
                               strlen(item_field->field_name), 0)))
2569 2570
      return 0;
  }
2571 2572
  else if (item->type() == Item::REF_ITEM)
    return uses_only_table_name_fields(item->real_item(), table);
2573 2574

  if (item->type() == Item::SUBSELECT_ITEM && !item->const_item())
2575 2576
    return 0;

2577
  return 1;
2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 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 2632 2633 2634 2635 2636
}


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;
}


2637 2638 2639 2640 2641 2642 2643 2644 2645 2646
/**
  @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
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
2647 2648
  @param[in]      tables                I_S table
  @param[in, out] lookup_field_values   Struct which holds lookup values 
2649

2650 2651 2652
  @return
    0             success
    1             error, there can be no matching records for the condition
2653 2654
*/

2655
bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables,
2656 2657 2658 2659
                             LOOKUP_FIELD_VALUES *lookup_field_values)
{
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
2660 2661
  bool rc= 0;

2662 2663 2664 2665 2666
  bzero((char*) lookup_field_values, sizeof(LOOKUP_FIELD_VALUES));
  switch (lex->sql_command) {
  case SQLCOM_SHOW_DATABASES:
    if (wild)
    {
2667 2668
      thd->make_lex_string(&lookup_field_values->db_value, 
                           wild, strlen(wild), 0);
2669 2670
      lookup_field_values->wild_db_value= 1;
    }
2671
    break;
2672 2673 2674 2675
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SHOW_TABLE_STATUS:
  case SQLCOM_SHOW_TRIGGERS:
  case SQLCOM_SHOW_EVENTS:
2676 2677
    thd->make_lex_string(&lookup_field_values->db_value, 
                         lex->select_lex.db, strlen(lex->select_lex.db), 0);
2678 2679
    if (wild)
    {
2680 2681
      thd->make_lex_string(&lookup_field_values->table_value, 
                           wild, strlen(wild), 0);
2682 2683
      lookup_field_values->wild_table_value= 1;
    }
2684
    break;
2685 2686 2687 2688 2689
  default:
    /*
      The "default" is for queries over I_S.
      All previous cases handle SHOW commands.
    */
2690 2691
    rc= calc_lookup_values_from_cond(thd, cond, tables, lookup_field_values);
    break;
2692
  }
2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707

  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;
2708 2709 2710
}


2711 2712 2713 2714 2715 2716
enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
{
  return (enum enum_schema_tables) (schema_table - &schema_tables[0]);
}


2717
/*
2718
  Create db names list. Information schema name always is first in list
2719 2720

  SYNOPSIS
2721
    make_db_list()
2722 2723 2724
    thd                   thread handler
    files                 list of db names
    wild                  wild string
2725 2726
    idx_field_vals        idx_field_vals->db_name contains db name or
                          wild string
2727
    with_i_schema         returns 1 if we added 'IS' name to list
2728
                          otherwise returns 0 
2729 2730

  RETURN
2731 2732
    zero                  success
    non-zero              error
2733 2734
*/

2735 2736 2737
int make_db_list(THD *thd, List<LEX_STRING> *files,
                 LOOKUP_FIELD_VALUES *lookup_field_vals,
                 bool *with_i_schema)
2738
{
2739 2740 2741 2742
  LEX_STRING *i_s_name_copy= 0;
  i_s_name_copy= thd->make_lex_string(i_s_name_copy,
                                      INFORMATION_SCHEMA_NAME.str,
                                      INFORMATION_SCHEMA_NAME.length, TRUE);
2743
  *with_i_schema= 0;
2744
  if (lookup_field_vals->wild_db_value)
2745
  {
2746 2747 2748 2749 2750
    /*
      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)
    */
2751
    if (!lookup_field_vals->db_value.str ||
2752
        !wild_case_compare(system_charset_info, 
2753
                           INFORMATION_SCHEMA_NAME.str,
2754
                           lookup_field_vals->db_value.str))
2755 2756
    {
      *with_i_schema= 1;
2757
      if (files->push_back(i_s_name_copy))
2758 2759
        return 1;
    }
2760
    return (find_files(thd, files, NullS, mysql_data_home,
2761
                       lookup_field_vals->db_value.str, 1) != FIND_FILES_OK);
2762
  }
2763

2764

2765
  /*
2766 2767
    If we have db lookup vaule we just add it to list and
    exit from the function
2768
  */
2769
  if (lookup_field_vals->db_value.str)
2770
  {
2771 2772
    if (is_infoschema_db(lookup_field_vals->db_value.str,
                         lookup_field_vals->db_value.length))
2773 2774
    {
      *with_i_schema= 1;
2775
      if (files->push_back(i_s_name_copy))
2776 2777
        return 1;
      return 0;
2778
    }
2779 2780 2781
    if (files->push_back(&lookup_field_vals->db_value))
      return 1;
    return 0;
2782 2783
  }

2784 2785 2786 2787
  /*
    Create list of existing databases. It is used in case
    of select from information schema table
  */
2788
  if (files->push_back(i_s_name_copy))
2789 2790
    return 1;
  *with_i_schema= 1;
2791 2792
  return (find_files(thd, files, NullS,
                     mysql_data_home, NullS, 1) != FIND_FILES_OK);
2793 2794
}

2795

brian@zim.(none)'s avatar
brian@zim.(none) committed
2796 2797
struct st_add_schema_table 
{
2798
  List<LEX_STRING> *files;
brian@zim.(none)'s avatar
brian@zim.(none) committed
2799 2800 2801
  const char *wild;
};

2802

antony@ppcg5.local's avatar
antony@ppcg5.local committed
2803
static my_bool add_schema_table(THD *thd, plugin_ref plugin,
brian@zim.(none)'s avatar
brian@zim.(none) committed
2804 2805
                                void* p_data)
{
2806
  LEX_STRING *file_name= 0;
brian@zim.(none)'s avatar
brian@zim.(none) committed
2807
  st_add_schema_table *data= (st_add_schema_table *)p_data;
2808
  List<LEX_STRING> *file_list= data->files;
brian@zim.(none)'s avatar
brian@zim.(none) committed
2809
  const char *wild= data->wild;
antony@ppcg5.local's avatar
antony@ppcg5.local committed
2810
  ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
brian@zim.(none)'s avatar
brian@zim.(none) committed
2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827
  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);
  }

2828 2829 2830 2831 2832 2833
  if ((file_name= thd->make_lex_string(file_name, schema_table->table_name,
                                       strlen(schema_table->table_name),
                                       TRUE)) &&
      !file_list->push_back(file_name))
    DBUG_RETURN(0);
  DBUG_RETURN(1);
brian@zim.(none)'s avatar
brian@zim.(none) committed
2834
}
2835

2836 2837

int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
2838
{
2839
  LEX_STRING *file_name= 0;
2840
  ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
brian@zim.(none)'s avatar
brian@zim.(none) committed
2841 2842 2843
  st_add_schema_table add_data;
  DBUG_ENTER("schema_tables_add");

2844
  for (; tmp_schema_table->table_name; tmp_schema_table++)
2845
  {
2846 2847
    if (tmp_schema_table->hidden)
      continue;
2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859
    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;
    }
2860 2861 2862 2863 2864 2865
    if ((file_name= 
         thd->make_lex_string(file_name, tmp_schema_table->table_name,
                              strlen(tmp_schema_table->table_name), TRUE)) &&
        !files->push_back(file_name))
      continue;
    DBUG_RETURN(1);
2866
  }
brian@zim.(none)'s avatar
brian@zim.(none) committed
2867 2868 2869 2870 2871 2872 2873 2874

  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);
2875 2876 2877
}


2878 2879
/**
  @brief          Create table names list
2880

2881 2882
  @details        The function creates the list of table names in
                  database
2883

2884 2885 2886 2887 2888 2889
  @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]      with_i_schema         TRUE means that we add I_S tables to list
  @param[in]      db_name               database name
2890

2891 2892 2893 2894 2895
  @return         Operation status
    @retval       0           ok
    @retval       1           fatal error
    @retval       2           Not fatal error; Safe to ignore this file list
*/
2896

2897 2898 2899 2900 2901
static int
make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
                     LOOKUP_FIELD_VALUES *lookup_field_vals,
                     bool with_i_schema, LEX_STRING *db_name)
{
2902 2903
  char path[FN_REFLEN + 1];
  build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0);
2904 2905
  if (!lookup_field_vals->wild_table_value &&
      lookup_field_vals->table_value.str)
2906
  {
2907 2908
    if (with_i_schema)
    {
2909
      LEX_STRING *name;
2910 2911 2912
      ST_SCHEMA_TABLE *schema_table=
        find_schema_table(thd, lookup_field_vals->table_value.str);
      if (schema_table && !schema_table->hidden)
2913
      {
2914 2915 2916 2917
        if (!(name= 
              thd->make_lex_string(NULL, schema_table->table_name,
                                   strlen(schema_table->table_name), TRUE)) ||
            table_names->push_back(name))
2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928
          return 1;
      }
    }
    else
    {    
      if (table_names->push_back(&lookup_field_vals->table_value))
        return 1;
      /*
        Check that table is relevant in current transaction.
        (used for ndb engine, see ndbcluster_find_files(), ha_ndbcluster.cc)
      */
Konstantin Osipov's avatar
Konstantin Osipov committed
2929
      (void) ha_find_files(thd, db_name->str, path,
2930
                         lookup_field_vals->table_value.str, 0,
Konstantin Osipov's avatar
Konstantin Osipov committed
2931
                         table_names);
2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952
    }
    return 0;
  }

  /*
    This call will add all matching the wildcards (if specified) IS tables
    to the list
  */
  if (with_i_schema)
    return (schema_tables_add(thd, table_names,
                              lookup_field_vals->table_value.str));

  find_files_result res= find_files(thd, table_names, db_name->str, path,
                                    lookup_field_vals->table_value.str, 0);
  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.
2953
    */
2954 2955
    if (res == FIND_FILES_DIR)
    {
2956
      if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)
2957 2958 2959 2960 2961
        return 1;
      thd->clear_error();
      return 2;
    }
    return 1;
2962
  }
2963 2964
  return 0;
}
2965

2966

2967 2968 2969 2970 2971 2972
/**
  @brief          Fill I_S table for SHOW COLUMNS|INDEX commands

  @param[in]      thd                      thread handler
  @param[in]      tables                   TABLE_LIST for I_S table
  @param[in]      schema_table             pointer to I_S structure
Konstantin Osipov's avatar
Konstantin Osipov committed
2973 2974 2975 2976
  @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.
2977
  @param[in]      open_tables_state_backup pointer to Open_tables_backup object
2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989
                                           which is used to save|restore original
                                           status of variables related to
                                           open tables state

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

static int 
fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
                              ST_SCHEMA_TABLE *schema_table,
Konstantin Osipov's avatar
Konstantin Osipov committed
2990
                              bool can_deadlock,
2991
                              Open_tables_backup *open_tables_state_backup)
2992 2993 2994 2995 2996
{
  LEX *lex= thd->lex;
  bool res;
  LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name;
  enum_sql_command save_sql_command= lex->sql_command;
2997
  TABLE_LIST *show_table_list= tables->schema_select_lex->table_list.first;
2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017
  TABLE *table= tables->table;
  int error= 1;
  DBUG_ENTER("fill_schema_show");

  lex->all_selects_list= tables->schema_select_lex;
  /*
    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;
  /*
    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.
    SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' 
  */
  lex->sql_command= SQLCOM_SHOW_FIELDS;
  res= open_normal_and_derived_tables(thd, show_table_list,
3018
                                      (MYSQL_OPEN_IGNORE_FLUSH |
3019
                                       MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
Konstantin Osipov's avatar
Konstantin Osipov committed
3020 3021
                                       (can_deadlock ?
                                        MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
3022
  lex->sql_command= save_sql_command;
3023 3024 3025

  DEBUG_SYNC(thd, "after_open_table_ignore_flush");

3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049
  /*
    get_all_tables() returns 1 on failure and 0 on success thus
    return only these and not the result code of ::process_table()

    We should use show_table_list->alias instead of 
    show_table_list->table_name because table_name
    could be changed during opening of I_S tables. It's safe
    to use alias because alias contains original table name 
    in this case(this part of code is used only for 
    'show columns' & 'show statistics' commands).
  */
   table_name= thd->make_lex_string(&tmp_lex_string1, show_table_list->alias,
                                    strlen(show_table_list->alias), FALSE);
   if (!show_table_list->view)
     db_name= thd->make_lex_string(&tmp_lex_string, show_table_list->db,
                                   show_table_list->db_length, FALSE);
   else
     db_name= &show_table_list->view_db;
      

   error= test(schema_table->process_table(thd, show_table_list,
                                           table, res, db_name,
                                           table_name));
   thd->temporary_tables= 0;
3050 3051
   close_tables_for_reopen(thd, &show_table_list,
                           open_tables_state_backup->mdl_system_tables_svp);
3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081
   DBUG_RETURN(error);
}


/**
  @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
  @param[in]      with_i_schema            I_S table if TRUE

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

static int fill_schema_table_names(THD *thd, TABLE *table,
                                   LEX_STRING *db_name, LEX_STRING *table_name,
                                   bool with_i_schema)
{
  if (with_i_schema)
  {
    table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
                           system_charset_info);
  }
  else
  {
    enum legacy_db_type not_used;
3082 3083
    char path[FN_REFLEN + 1];
    (void) build_table_filename(path, sizeof(path) - 1, db_name->str, 
3084
                                table_name->str, reg_ext, 0);
3085
    switch (dd_frm_type(thd, path, &not_used)) {
3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100
    case FRMTYPE_ERROR:
      table->field[3]->store(STRING_WITH_LEN("ERROR"),
                             system_charset_info);
      break;
    case FRMTYPE_TABLE:
      table->field[3]->store(STRING_WITH_LEN("BASE TABLE"),
                             system_charset_info);
      break;
    case FRMTYPE_VIEW:
      table->field[3]->store(STRING_WITH_LEN("VIEW"),
                             system_charset_info);
      break;
    default:
      DBUG_ASSERT(0);
    }
Marc Alff's avatar
Marc Alff committed
3101
    if (thd->is_error() && thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128
    {
      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
*/

3129
uint get_table_open_method(TABLE_LIST *tables,
3130 3131 3132 3133 3134 3135 3136 3137 3138 3139
                                  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;
3140 3141
    uint star_table_open_method= OPEN_FULL_TABLE;
    bool used_star= true;                  // true if '*' is used in select
3142 3143
    for (ptr=tables->table->field; (field= *ptr) ; ptr++)
    {
3144 3145 3146
      star_table_open_method=
        min(star_table_open_method,
            schema_table->fields_info[field_indx].open_method);
3147
      if (bitmap_is_set(tables->table->read_set, field->field_index))
3148 3149
      {
        used_star= false;
3150
        table_open_method|= schema_table->fields_info[field_indx].open_method;
3151
      }
3152 3153
      field_indx++;
    }
3154 3155
    if (used_star)
      return star_table_open_method;
3156 3157 3158 3159 3160 3161 3162
    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
3163
/**
Konstantin Osipov's avatar
Konstantin Osipov committed
3164 3165
   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
3166 3167

   @param thd            Thread context.
Konstantin Osipov's avatar
Konstantin Osipov committed
3168
   @param mdl_request    Pointer to memory to be used for MDL_request
Konstantin Osipov's avatar
Konstantin Osipov committed
3169 3170
                         object for a lock request.
   @param table          Table list element for the table
Konstantin Osipov's avatar
Konstantin Osipov committed
3171 3172 3173
   @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
3174 3175 3176 3177 3178 3179 3180

   @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
3181 3182
   @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
3183 3184 3185 3186
   @retval TRUE   Some error occured (probably thread was killed).
*/

static bool
Konstantin Osipov's avatar
Konstantin Osipov committed
3187 3188
try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
                                      bool can_deadlock)
Konstantin Osipov's avatar
Konstantin Osipov committed
3189 3190
{
  bool error;
Konstantin Osipov's avatar
Konstantin Osipov committed
3191
  table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
3192
                          MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION);
3193 3194

  if (can_deadlock)
Konstantin Osipov's avatar
Konstantin Osipov committed
3195
  {
3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208
    /*
      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
3209
  }
3210 3211 3212 3213
  else
    error= thd->mdl_context.acquire_lock(&table->mdl_request,
                                         thd->variables.lock_wait_timeout);

Konstantin Osipov's avatar
Konstantin Osipov committed
3214
  return error;
Konstantin Osipov's avatar
Konstantin Osipov committed
3215 3216 3217
}


3218 3219 3220 3221 3222 3223 3224 3225 3226
/**
  @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
Konstantin Osipov's avatar
Konstantin Osipov committed
3227 3228 3229 3230
  @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.
3231 3232 3233 3234 3235 3236 3237 3238

  @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
3239 3240
static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
                                      ST_SCHEMA_TABLE *schema_table,
3241 3242
                                      LEX_STRING *db_name,
                                      LEX_STRING *table_name,
Konstantin Osipov's avatar
Konstantin Osipov committed
3243 3244
                                      enum enum_schema_tables schema_table_idx,
                                      bool can_deadlock)
3245
{
Sergey Glukhov's avatar
Sergey Glukhov committed
3246
  TABLE *table= tables->table;
3247
  TABLE_SHARE *share;
3248 3249
  TABLE tbl;
  TABLE_LIST table_list;
3250
  uint res= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
3251
  int not_used;
3252
  my_hash_value_type hash_value;
3253 3254
  char key[MAX_DBKEY_LENGTH];
  uint key_length;
3255
  char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1];
3256

3257 3258
  bzero((char*) &table_list, sizeof(TABLE_LIST));
  bzero((char*) &tbl, sizeof(TABLE));
3259

3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279
  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;
  }

3280 3281
  /*
    TODO: investigate if in this particular situation we can get by
3282 3283
          simply obtaining internal lock of the data-dictionary
          instead of obtaining full-blown metadata lock.
3284
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
3285
  if (try_acquire_high_prio_shared_mdl_lock(thd, &table_list, can_deadlock))
3286
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
3287 3288 3289 3290 3291 3292
    /*
      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;
3293 3294
  }

Konstantin Osipov's avatar
Konstantin Osipov committed
3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310
  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
3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325
  if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY)
  {
    init_sql_alloc(&tbl.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
    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;
  }

3326
  key_length= create_table_def_key(thd, key, &table_list, 0);
3327
  hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
Marc Alff's avatar
Marc Alff committed
3328
  mysql_mutex_lock(&LOCK_open);
3329
  share= get_table_share(thd, &table_list, key,
3330
                         key_length, OPEN_VIEW, &not_used, hash_value);
3331
  if (!share)
3332
  {
3333
    res= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
3334
    goto end_unlock;
3335
  }
Sergey Glukhov's avatar
Sergey Glukhov committed
3336

3337 3338 3339
  if (share->is_view)
  {
    if (schema_table->i_s_requested_object & OPEN_TABLE_ONLY)
3340
    {
3341 3342
      /* skip view processing */
      res= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
3343
      goto end_share;
3344
    }
3345 3346 3347
    else if (schema_table->i_s_requested_object & OPEN_VIEW_FULL)
    {
      /*
Sergey Glukhov's avatar
Sergey Glukhov committed
3348
        tell get_all_tables() to fall back to
3349 3350 3351
        open_normal_and_derived_tables()
      */
      res= 1;
Konstantin Osipov's avatar
Konstantin Osipov committed
3352
      goto end_share;
3353
    }
3354 3355
  }

Sergey Glukhov's avatar
Sergey Glukhov committed
3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370
  if (share->is_view)
  {
    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;
  }

3371 3372 3373
  if (!open_table_from_share(thd, share, table_name->str, 0,
                             (EXTRA_RECORD | OPEN_FRM_FILE_ONLY),
                             thd->open_options, &tbl, FALSE))
3374 3375 3376
  {
    tbl.s= share;
    table_list.table= &tbl;
Konstantin Osipov's avatar
Konstantin Osipov committed
3377
    table_list.view= (LEX*) share->is_view;
3378 3379
    res= schema_table->process_table(thd, &table_list, table,
                                     res, db_name, table_name);
3380
    free_root(&tbl.mem_root, MYF(0));
3381
    my_free((void *) tbl.alias);
3382 3383
  }

Konstantin Osipov's avatar
Konstantin Osipov committed
3384
end_share:
Konstantin Osipov's avatar
Konstantin Osipov committed
3385
  release_table_share(share);
3386

Konstantin Osipov's avatar
Konstantin Osipov committed
3387
end_unlock:
Marc Alff's avatar
Marc Alff committed
3388
  mysql_mutex_unlock(&LOCK_open);
3389 3390 3391 3392 3393
  /*
    Don't release the MDL lock, it can be part of a transaction.
    If it is not, it will be released by the call to
    MDL_context::rollback_to_savepoint() in the caller.
  */
3394

Sergey Glukhov's avatar
Sergey Glukhov committed
3395
end:
3396 3397
  thd->clear_error();
  return res;
3398
}
3399

3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419

/**
  @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
*/

3420 3421 3422 3423
int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  LEX *lex= thd->lex;
  TABLE *table= tables->table;
3424
  SELECT_LEX *old_all_select_lex= lex->all_selects_list;
3425
  SELECT_LEX *lsel= tables->schema_select_lex;
3426
  ST_SCHEMA_TABLE *schema_table= tables->schema_table;
3427
  SELECT_LEX sel;
3428 3429
  LOOKUP_FIELD_VALUES lookup_field_vals;
  LEX_STRING *db_name, *table_name;
3430 3431
  bool with_i_schema;
  enum enum_schema_tables schema_table_idx;
3432 3433
  List<LEX_STRING> db_names;
  List_iterator_fast<LEX_STRING> it(db_names);
3434
  COND *partial_cond= 0;
3435
  uint derived_tables= lex->derived_tables; 
monty@mysql.com's avatar
monty@mysql.com committed
3436
  int error= 1;
3437
  Open_tables_backup open_tables_state_backup;
3438
  bool save_view_prepare_mode= lex->view_prepare_mode;
3439
  Query_tables_list query_tables_list_backup;
3440 3441 3442
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  Security_context *sctx= thd->security_ctx;
#endif
3443
  uint table_open_method;
Konstantin Osipov's avatar
Konstantin Osipov committed
3444
  bool can_deadlock;
3445 3446
  DBUG_ENTER("get_all_tables");

Konstantin Osipov's avatar
Konstantin Osipov committed
3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457
  /*
    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();

3458
  lex->view_prepare_mode= TRUE;
3459
  lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
3460 3461 3462 3463 3464 3465
  /*
    Restore Query_tables_list::sql_command value, which was reset
    above, as ST_SCHEMA_TABLE::process_table() functions often rely
    that this value reflects which SHOW statement is executed.
  */
  lex->sql_command= query_tables_list_backup.sql_command;
3466 3467

  /*
3468 3469
    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
3470 3471
    open and will ignore pending exclusive metadata locks for these
    tables by using high-priority requests for shared metadata locks.
3472
  */
3473 3474
  thd->reset_n_backup_open_tables_state(&open_tables_state_backup);

Sergey Glukhov's avatar
Sergey Glukhov committed
3475 3476 3477 3478
  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));
3479 3480 3481 3482 3483
  /* 
    this branch processes SHOW FIELDS, SHOW INDEXES commands.
    see sql_parse.cc, prepare_schema_table() function where
    this values are initialized
  */
3484
  if (lsel && lsel->table_list.first)
3485
  {
3486
    error= fill_schema_show_cols_or_idxs(thd, tables, schema_table,
Konstantin Osipov's avatar
Konstantin Osipov committed
3487
                                         can_deadlock,
3488
                                         &open_tables_state_backup);
monty@mysql.com's avatar
monty@mysql.com committed
3489
    goto err;
3490 3491
  }

3492 3493 3494 3495 3496
  if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
  {
    error= 0;
    goto err;
  }
3497

3498
  DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'",
3499 3500
                             STR_OR_NIL(lookup_field_vals.db_value.str),
                             STR_OR_NIL(lookup_field_vals.table_value.str)));
3501

3502 3503 3504 3505 3506 3507
  if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
  {
    /* 
      if lookup value is empty string then
      it's impossible table name or db name
    */
Staale Smedseng's avatar
Staale Smedseng committed
3508 3509 3510 3511
    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]))
3512 3513 3514 3515 3516 3517 3518 3519
    {
      error= 0;
      goto err;
    }
  }

  if (lookup_field_vals.db_value.length &&
      !lookup_field_vals.wild_db_value)
3520 3521 3522 3523
    tables->has_db_lookup_value= TRUE;
  if (lookup_field_vals.table_value.length &&
      !lookup_field_vals.wild_table_value) 
    tables->has_table_lookup_value= TRUE;
3524

3525 3526 3527 3528 3529
  if (tables->has_db_lookup_value && tables->has_table_lookup_value)
    partial_cond= 0;
  else
    partial_cond= make_cond_for_info_schema(cond, tables);

3530 3531 3532 3533
  if (lex->describe)
  {
    /* EXPLAIN SELECT */
    error= 0;
monty@mysql.com's avatar
monty@mysql.com committed
3534
    goto err;
3535
  }
3536

3537 3538
  if (make_db_list(thd, &db_names, &lookup_field_vals, &with_i_schema))
    goto err;
monty@mysql.com's avatar
monty@mysql.com committed
3539
  it.rewind(); /* To get access to new elements in basis list */
3540
  while ((db_name= it++))
3541 3542
  {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3543 3544
    if (!(check_access(thd, SELECT_ACL, db_name->str,
                       &thd->col_access, NULL, 0, 1) ||
3545
          (!thd->col_access && check_grant_db(thd, db_name->str))) ||
3546
        sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
3547
        acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
3548 3549
#endif
    {
3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561
      thd->no_warnings_for_error= 1;
      List<LEX_STRING> table_names;
      int res= make_table_name_list(thd, &table_names, lex,
                                    &lookup_field_vals,
                                    with_i_schema, db_name);
      if (res == 2)   /* Not fatal error, continue */
        continue;
      if (res)
        goto err;

      List_iterator_fast<LEX_STRING> it_files(table_names);
      while ((table_name= it_files++))
3562
      {
3563 3564 3565 3566 3567 3568 3569
	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())
3570 3571
        {
          /*
3572 3573 3574 3575
            If table is I_S.tables and open_table_method is 0 (eg SKIP_OPEN)
            we can skip table opening and we don't have lookup value for 
            table name or lookup value is wild string(table name list is
            already created by make_table_name_list() function).
3576
          */
3577 3578 3579
          if (!table_open_method && schema_table_idx == SCH_TABLES &&
              (!lookup_field_vals.table_value.length ||
               lookup_field_vals.wild_table_value))
3580
          {
3581
            table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
3582 3583
            if (schema_table_store_record(thd, table))
              goto err;      /* Out of space in temporary table */
3584 3585
            continue;
          }
3586

3587
          /* SHOW TABLE NAMES command */
3588 3589
          if (schema_table_idx == SCH_TABLE_NAMES)
          {
3590 3591 3592
            if (fill_schema_table_names(thd, tables->table, db_name,
                                        table_name, with_i_schema))
              continue;
3593 3594 3595
          }
          else
          {
Sergey Glukhov's avatar
Sergey Glukhov committed
3596
            if (!(table_open_method & ~OPEN_FRM_ONLY) &&
3597 3598
                !with_i_schema)
            {
Sergey Glukhov's avatar
Sergey Glukhov committed
3599
              if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name,
Konstantin Osipov's avatar
Konstantin Osipov committed
3600 3601
                                              table_name, schema_table_idx,
                                              can_deadlock))
3602 3603 3604
                continue;
            }

3605
            int res;
3606
            LEX_STRING tmp_lex_string, orig_db_name;
3607
            /*
3608 3609
              Set the parent lex of 'sel' because it is needed by
              sel.init_query() which is called inside make_table_list.
3610
            */
3611
            thd->no_warnings_for_error= 1;
3612
            sel.parent_lex= lex;
3613 3614 3615 3616 3617
            /* db_name can be changed in make_table_list() func */
            if (!thd->make_lex_string(&orig_db_name, db_name->str,
                                      db_name->length, FALSE))
              goto err;
            if (make_table_list(thd, &sel, db_name, table_name))
monty@mysql.com's avatar
monty@mysql.com committed
3618
              goto err;
3619
            TABLE_LIST *show_table_list= sel.table_list.first;
3620 3621
            lex->all_selects_list= &sel;
            lex->derived_tables= 0;
3622
            lex->sql_command= SQLCOM_SHOW_FIELDS;
3623 3624
            show_table_list->i_s_requested_object=
              schema_table->i_s_requested_object;
3625
            DEBUG_SYNC(thd, "before_open_in_get_all_tables");
3626
            res= open_normal_and_derived_tables(thd, show_table_list,
3627
                   (MYSQL_OPEN_IGNORE_FLUSH |
3628
                    MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
Konstantin Osipov's avatar
Konstantin Osipov committed
3629
                    (can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
3630
            lex->sql_command= query_tables_list_backup.sql_command;
3631 3632 3633 3634 3635 3636
            /*
              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() only then
Marc Alff's avatar
Marc Alff committed
3637
              for thd->stmt_da->sql_errno().
3638 3639
            */
            if (res && thd->is_error() &&
Marc Alff's avatar
Marc Alff committed
3640
                thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
3641
            {
3642 3643 3644 3645 3646 3647
              /*
                Hide error for not existing table.
                This error can occur for example when we use
                where condition with db name and table name and this
                table does not exist.
              */
3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659
              res= 0;
              thd->clear_error();
            }
            else
            {
              /*
                We should use show_table_list->alias instead of 
                show_table_list->table_name because table_name
                could be changed during opening of I_S tables. It's safe
                to use alias because alias contains original table name 
                in this case.
              */
3660 3661
              thd->make_lex_string(&tmp_lex_string, show_table_list->alias,
                                   strlen(show_table_list->alias), FALSE);
3662
              res= schema_table->process_table(thd, show_table_list, table,
3663 3664
                                               res, &orig_db_name,
                                               &tmp_lex_string);
3665 3666
              close_tables_for_reopen(thd, &show_table_list,
                                      open_tables_state_backup.mdl_system_tables_svp);
3667
            }
3668
            DBUG_ASSERT(!lex->query_tables_own_last);
3669
            if (res)
monty@mysql.com's avatar
monty@mysql.com committed
3670
              goto err;
3671 3672 3673
          }
        }
      }
3674 3675 3676 3677
      /*
        If we have information schema its always the first table and only
        the first table. Reset for other tables.
      */
3678
      with_i_schema= 0;
3679 3680
    }
  }
monty@mysql.com's avatar
monty@mysql.com committed
3681 3682 3683

  error= 0;
err:
3684
  thd->restore_backup_open_tables_state(&open_tables_state_backup);
3685
  lex->restore_backup_query_tables_list(&query_tables_list_backup);
3686 3687
  lex->derived_tables= derived_tables;
  lex->all_selects_list= old_all_select_lex;
3688
  lex->view_prepare_mode= save_view_prepare_mode;
monty@mysql.com's avatar
monty@mysql.com committed
3689
  DBUG_RETURN(error);
3690 3691 3692
}


3693
bool store_schema_shemata(THD* thd, TABLE *table, LEX_STRING *db_name,
3694
                          CHARSET_INFO *cs)
3695
{
3696
  restore_record(table, s->default_values);
3697
  table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
3698
  table->field[1]->store(db_name->str, db_name->length, system_charset_info);
3699 3700
  table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info);
  table->field[3]->store(cs->name, strlen(cs->name), system_charset_info);
3701
  return schema_table_store_record(thd, table);
3702 3703 3704
}


3705
int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
3706
{
3707 3708 3709 3710 3711
  /*
    TODO: fill_schema_shemata() is called when new client is connected.
    Returning error status in this case leads to client hangup.
  */

3712 3713 3714
  LOOKUP_FIELD_VALUES lookup_field_vals;
  List<LEX_STRING> db_names;
  LEX_STRING *db_name;
3715
  bool with_i_schema;
3716 3717
  HA_CREATE_INFO create;
  TABLE *table= tables->table;
3718
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3719
  Security_context *sctx= thd->security_ctx;
3720
#endif
3721
  DBUG_ENTER("fill_schema_shemata");
3722

3723 3724
  if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
    DBUG_RETURN(0);
3725 3726 3727 3728 3729
  DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'",
                             lookup_field_vals.db_value.str,
                             lookup_field_vals.table_value.str));
  if (make_db_list(thd, &db_names, &lookup_field_vals,
                   &with_i_schema))
3730
    DBUG_RETURN(1);
3731

3732 3733 3734
  /*
    If we have lookup db value we should check that the database exists
  */
3735 3736
  if(lookup_field_vals.db_value.str && !lookup_field_vals.wild_db_value &&
     !with_i_schema)
3737 3738 3739 3740 3741 3742
  {
    char path[FN_REFLEN+16];
    uint path_len;
    MY_STAT stat_info;
    if (!lookup_field_vals.db_value.str[0])
      DBUG_RETURN(0);
3743
    path_len= build_table_filename(path, sizeof(path) - 1,
3744 3745
                                   lookup_field_vals.db_value.str, "", "", 0);
    path[path_len-1]= 0;
Marc Alff's avatar
Marc Alff committed
3746
    if (!mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
3747 3748 3749
      DBUG_RETURN(0);
  }

3750 3751
  List_iterator_fast<LEX_STRING> it(db_names);
  while ((db_name=it++))
3752
  {
3753 3754
    if (with_i_schema)       // information schema name is always first in list
    {
3755
      if (store_schema_shemata(thd, table, db_name,
3756
                               system_charset_info))
3757
        DBUG_RETURN(1);
3758 3759 3760
      with_i_schema= 0;
      continue;
    }
3761
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3762
    if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
3763 3764
	acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
	!check_grant_db(thd, db_name->str))
3765 3766
#endif
    {
3767 3768
      load_db_opt_by_name(thd, db_name->str, &create);
      if (store_schema_shemata(thd, table, db_name,
3769
                               create.default_table_charset))
3770
        DBUG_RETURN(1);
3771 3772
    }
  }
3773
  DBUG_RETURN(0);
3774 3775 3776
}


3777
static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3778
				    TABLE *table, bool res,
3779 3780
				    LEX_STRING *db_name,
				    LEX_STRING *table_name)
3781 3782
{
  const char *tmp_buff;
3783
  MYSQL_TIME time;
3784 3785
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_schema_tables_record");
3786 3787

  restore_record(table, s->default_values);
3788
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
3789 3790
  table->field[1]->store(db_name->str, db_name->length, cs);
  table->field[2]->store(table_name->str, table_name->length, cs);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3791 3792 3793 3794 3795
  if (res)
  {
    /*
      there was errors during opening tables
    */
Marc Alff's avatar
Marc Alff committed
3796
    const char *error= thd->is_error() ? thd->stmt_da->message() : "";
3797 3798 3799 3800 3801 3802
    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);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3803 3804 3805 3806
    table->field[20]->store(error, strlen(error), cs);
    thd->clear_error();
  }
  else if (tables->view)
3807
  {
3808 3809
    table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
    table->field[20]->store(STRING_WITH_LEN("VIEW"), cs);
3810 3811 3812
  }
  else
  {
3813
    char option_buff[350],*ptr;
3814
    TABLE *show_table= tables->table;
3815
    TABLE_SHARE *share= show_table->s;
3816
    handler *file= show_table->file;
3817
    handlerton *tmp_db_type= share->db_type();
3818
#ifdef WITH_PARTITION_STORAGE_ENGINE
3819
    bool is_partitioned= FALSE;
3820
#endif
3821
    if (share->tmp_table == SYSTEM_TMP_TABLE)
3822
      table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
3823
    else if (share->tmp_table)
3824
      table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs);
3825
    else
3826
      table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
3827

3828 3829
    for (int i= 4; i < 20; i++)
    {
3830
      if (i == 7 || (i > 12 && i < 17) || i == 18)
3831 3832 3833
        continue;
      table->field[i]->set_notnull();
    }
3834 3835
#ifdef WITH_PARTITION_STORAGE_ENGINE
    if (share->db_type() == partition_hton &&
3836
        share->partition_info_str_len)
3837
    {
3838
      tmp_db_type= share->default_part_db_type;
3839 3840
      is_partitioned= TRUE;
    }
3841 3842
#endif
    tmp_buff= (char *) ha_resolve_storage_engine_name(tmp_db_type);
3843
    table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
3844
    table->field[5]->store((longlong) share->frm_version, TRUE);
3845 3846

    ptr=option_buff;
3847
    if (share->min_rows)
3848 3849
    {
      ptr=strmov(ptr," min_rows=");
3850
      ptr=longlong10_to_str(share->min_rows,ptr,10);
3851
    }
3852
    if (share->max_rows)
3853 3854
    {
      ptr=strmov(ptr," max_rows=");
3855
      ptr=longlong10_to_str(share->max_rows,ptr,10);
3856
    }
3857
    if (share->avg_row_length)
3858 3859
    {
      ptr=strmov(ptr," avg_row_length=");
3860
      ptr=longlong10_to_str(share->avg_row_length,ptr,10);
3861
    }
3862
    if (share->db_create_options & HA_OPTION_PACK_KEYS)
3863
      ptr=strmov(ptr," pack_keys=1");
3864
    if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
3865
      ptr=strmov(ptr," pack_keys=0");
3866
    /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
3867
    if (share->db_create_options & HA_OPTION_CHECKSUM)
3868
      ptr=strmov(ptr," checksum=1");
3869
    if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
3870
      ptr=strmov(ptr," delay_key_write=1");
3871
    if (share->row_type != ROW_TYPE_DEFAULT)
3872
      ptr=strxmov(ptr, " row_format=", 
3873
                  ha_row_type[(uint) share->row_type],
3874
                  NullS);
3875 3876 3877 3878 3879
    if (share->key_block_size)
    {
      ptr= strmov(ptr, " KEY_BLOCK_SIZE=");
      ptr= longlong10_to_str(share->key_block_size, ptr, 10);
    }
3880
#ifdef WITH_PARTITION_STORAGE_ENGINE
3881
    if (is_partitioned)
3882 3883
      ptr= strmov(ptr, " partitioned");
#endif
3884 3885 3886
    table->field[19]->store(option_buff+1,
                            (ptr == option_buff ? 0 : 
                             (uint) (ptr-option_buff)-1), cs);
3887

3888 3889 3890 3891
    tmp_buff= (share->table_charset ?
               share->table_charset->name : "default");
    table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);

3892 3893 3894 3895
    if (share->comment.str)
      table->field[20]->store(share->comment.str, share->comment.length, cs);

    if(file)
3896
    {
3897
      file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO);
3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921
      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;
3922
      case ROW_TYPE_PAGE:
3923 3924 3925 3926 3927
        tmp_buff= "Paged";
        break;
      }
      table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
      if (!tables->schema_table)
3928
      {
3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954
        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);
        table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
        table->field[14]->set_notnull();
      }
      if (file->stats.update_time)
3955
      {
3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971
        thd->variables.time_zone->gmt_sec_to_TIME(&time,
                                                  (my_time_t) file->stats.update_time);
        table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
        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);
        table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
        table->field[16]->set_notnull();
      }
      if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
      {
        table->field[18]->store((longlong) file->checksum(), TRUE);
        table->field[18]->set_notnull();
3972 3973
      }
    }
3974
  }
3975
  DBUG_RETURN(schema_table_store_record(thd, table));
3976 3977 3978
}


Sergey Glukhov's avatar
Sergey Glukhov committed
3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058
/**
  @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
*/

void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs,
                       uint offset)
{
  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 */
  table->field[offset + 7]->store(column_type.ptr(), column_type.length(), cs);
  table->field[offset + 7]->set_notnull();
  /*
    DATA_TYPE column:
    MySQL column type has the following format:
    base_type [(dimension)] [unsigned] [zerofill].
    For DATA_TYPE column we extract only base type.
  */
  tmp_buff= strchr(column_type.ptr(), '(');
  if (!tmp_buff)
    /*
      if there is no dimention part then check the presence of
      [unsigned] [zerofill] attributes and cut them of if exist.
    */
    tmp_buff= strchr(column_type.ptr(), ' ');
  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)
  */

  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
4059 4060 4061 4062
  case MYSQL_TYPE_LONGLONG:
    field_length= field->max_display_length() - 
      ((field->flags & UNSIGNED_FLAG) ? 0 : 1);
    break;
Sergey Glukhov's avatar
Sergey Glukhov committed
4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103
  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;
  default:
    field_length= decimals= -1;
    break;
  }

  /* NUMERIC_PRECISION column */
  if (field_length >= 0)
  {
    table->field[offset + 3]->store((longlong) field_length, TRUE);
    table->field[offset + 3]->set_notnull();
  }
  /* NUMERIC_SCALE column */
  if (decimals >= 0)
  {
    table->field[offset + 4]->store((longlong) decimals, TRUE);
    table->field[offset + 4]->set_notnull();
  }
  if (field->has_charset())
  {
    /* CHARACTER_SET_NAME column*/
    tmp_buff= field->charset()->csname;
    table->field[offset + 5]->store(tmp_buff, strlen(tmp_buff), cs);
    table->field[offset + 5]->set_notnull();
    /* COLLATION_NAME column */
    tmp_buff= field->charset()->name;
    table->field[offset + 6]->store(tmp_buff, strlen(tmp_buff), cs);
    table->field[offset + 6]->set_notnull();
  }
}


4104
static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4105
				    TABLE *table, bool res,
4106 4107
				    LEX_STRING *db_name,
				    LEX_STRING *table_name)
4108
{
4109 4110
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
4111
  CHARSET_INFO *cs= system_charset_info;
4112
  TABLE *show_table;
Sergey Glukhov's avatar
Sergey Glukhov committed
4113
  Field **ptr, *field, *timestamp_field;
4114
  int count;
4115
  DBUG_ENTER("get_schema_column_record");
4116

4117 4118
  if (res)
  {
4119
    if (lex->sql_command != SQLCOM_SHOW_FIELDS)
4120 4121 4122 4123
    {
      /*
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
        rather than in SHOW COLUMNS
Sergey Glukhov's avatar
Sergey Glukhov committed
4124
      */
4125 4126
      if (thd->is_error())
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4127
                     thd->stmt_da->sql_errno(), thd->stmt_da->message());
4128 4129 4130 4131
      thd->clear_error();
      res= 0;
    }
    DBUG_RETURN(res);
4132 4133
  }

4134 4135
  show_table= tables->table;
  count= 0;
4136 4137 4138 4139
  ptr= show_table->field;
  timestamp_field= show_table->timestamp_field;
  show_table->use_all_columns();               // Required for default
  restore_record(show_table, s->default_values);
Sergey Glukhov's avatar
Sergey Glukhov committed
4140 4141

  for (; (field= *ptr) ; ptr++)
4142
  {
4143
    uchar *pos;
4144 4145
    char tmp[MAX_FIELD_WIDTH];
    String type(tmp,sizeof(tmp), system_charset_info);
Sergey Glukhov's avatar
Sergey Glukhov committed
4146

4147
    DEBUG_SYNC(thd, "get_schema_column");
4148 4149 4150 4151 4152 4153 4154 4155

    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);
4156 4157

#ifndef NO_EMBEDDED_ACCESS_CHECKS
4158
    uint col_access;
Sergey Glukhov's avatar
Sergey Glukhov committed
4159 4160 4161
    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,
4162
                                 db_name->str, table_name->str,
4163
                                 field->field_name) & COL_ACLS;
4164
    if (!tables->schema_table && !col_access)
4165
      continue;
4166
    char *end= tmp;
4167 4168 4169
    for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
    {
      if (col_access & 1)
4170
      {
4171 4172
        *end++=',';
        end=strmov(end,grant_types.type_names[bitnr]);
4173
      }
4174
    }
4175
    table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
4176

4177
#endif
4178
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
4179 4180
    table->field[1]->store(db_name->str, db_name->length, cs);
    table->field[2]->store(table_name->str, table_name->length, cs);
4181 4182
    table->field[3]->store(field->field_name, strlen(field->field_name),
                           cs);
4183
    table->field[4]->store((longlong) count, TRUE);
4184
    field->sql_type(type);
4185
    table->field[14]->store(type.ptr(), type.length(), cs);
4186

Sergey Glukhov's avatar
Sergey Glukhov committed
4187
    if (get_field_default_value(thd, timestamp_field, field, &type, 0))
4188
    {
4189
      table->field[5]->store(type.ptr(), type.length(), cs);
4190 4191
      table->field[5]->set_notnull();
    }
Sergey Glukhov's avatar
Sergey Glukhov committed
4192
    pos=(uchar*) ((field->flags & NOT_NULL_FLAG) ?  "NO" : "YES");
4193 4194
    table->field[6]->store((const char*) pos,
                           strlen((const char*) pos), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4195
    store_column_type(table, field, cs, 7);
4196
    pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
4197 4198 4199 4200 4201 4202
                 (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
                 (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
    table->field[15]->store((const char*) pos,
                            strlen((const char*) pos), cs);

    if (field->unireg_check == Field::NEXT_NUMBER)
4203
      table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4204
    if (timestamp_field == field &&
4205 4206 4207
        field->unireg_check != Field::TIMESTAMP_DN_FIELD)
      table->field[16]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
                              cs);
4208 4209 4210 4211

    table->field[18]->store(field->comment.str, field->comment.length, cs);
    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222
  }
  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;
4223

4224 4225 4226
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets) ;
       cs++)
4227 4228 4229 4230
  {
    CHARSET_INFO *tmp_cs= cs[0];
    if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && 
        (tmp_cs->state & MY_CS_AVAILABLE) &&
bar@mysql.com's avatar
bar@mysql.com committed
4231
        !(tmp_cs->state & MY_CS_HIDDEN) &&
4232 4233 4234
        !(wild && wild[0] &&
	  wild_case_compare(scs, tmp_cs->csname,wild)))
    {
4235
      const char *comment;
4236
      restore_record(table, s->default_values);
4237
      table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs);
4238
      table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs);
4239 4240
      comment= tmp_cs->comment ? tmp_cs->comment : "";
      table->field[2]->store(comment, strlen(comment), scs);
4241
      table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE);
4242 4243
      if (schema_table_store_record(thd, table))
        return 1;
4244 4245 4246 4247 4248 4249
    }
  }
  return 0;
}


antony@ppcg5.local's avatar
antony@ppcg5.local committed
4250
static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
4251
                                   void *ptable)
4252
{
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
4253
  TABLE *table= (TABLE *) ptable;
antony@ppcg5.local's avatar
antony@ppcg5.local committed
4254
  handlerton *hton= plugin_data(plugin, handlerton *);
4255 4256
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  CHARSET_INFO *scs= system_charset_info;
4257
  handlerton *default_type= ha_default_handlerton(thd);
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
4258
  DBUG_ENTER("iter_schema_engines");
4259

4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278

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

    struct st_mysql_plugin *plug= plugin_decl(plugin);
    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);
  }

acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
4279
  if (!(hton->flags & HTON_HIDDEN))
4280
  {
antony@ppcg5.local's avatar
antony@ppcg5.local committed
4281
    LEX_STRING *name= plugin_name(plugin);
4282
    if (!(wild && wild[0] &&
antony@ppcg5.local's avatar
antony@ppcg5.local committed
4283
          wild_case_compare(scs, name->str,wild)))
4284
    {
andrey@example.com's avatar
andrey@example.com committed
4285 4286
      LEX_STRING yesno[2]= {{ C_STRING_WITH_LEN("NO") },
                            { C_STRING_WITH_LEN("YES") }};
4287
      LEX_STRING *tmp;
4288
      const char *option_name= show_comp_option_name[(int) hton->state];
4289 4290
      restore_record(table, s->default_values);

antony@ppcg5.local's avatar
antony@ppcg5.local committed
4291
      table->field[0]->store(name->str, name->length, scs);
4292
      if (hton->state == SHOW_OPTION_YES && default_type == hton)
4293 4294
        option_name= "DEFAULT";
      table->field[1]->store(option_name, strlen(option_name), scs);
antony@ppcg5.local's avatar
antony@ppcg5.local committed
4295 4296
      table->field[2]->store(plugin_decl(plugin)->descr,
                             strlen(plugin_decl(plugin)->descr), scs);
4297 4298
      tmp= &yesno[test(hton->commit)];
      table->field[3]->store(tmp->str, tmp->length, scs);
4299
      table->field[3]->set_notnull();
4300 4301
      tmp= &yesno[test(hton->prepare)];
      table->field[4]->store(tmp->str, tmp->length, scs);
4302
      table->field[4]->set_notnull();
4303 4304
      tmp= &yesno[test(hton->savepoint_set)];
      table->field[5]->store(tmp->str, tmp->length, scs);
4305
      table->field[5]->set_notnull();
4306 4307 4308 4309 4310 4311 4312 4313

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

acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
4314 4315
int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond)
{
4316 4317 4318 4319 4320 4321
  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);
acurtis@xiphis.org's avatar
acurtis@xiphis.org committed
4322 4323 4324
}


4325 4326 4327 4328 4329 4330
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;
4331 4332 4333
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets)  ;
       cs++ )
4334 4335 4336
  {
    CHARSET_INFO **cl;
    CHARSET_INFO *tmp_cs= cs[0];
4337
    if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
bar@mysql.com's avatar
bar@mysql.com committed
4338
         (tmp_cs->state & MY_CS_HIDDEN) ||
4339 4340
        !(tmp_cs->state & MY_CS_PRIMARY))
      continue;
4341 4342 4343
    for (cl= all_charsets;
         cl < all_charsets + array_elements(all_charsets)  ;
         cl ++)
4344 4345 4346 4347 4348 4349 4350 4351 4352
    {
      CHARSET_INFO *tmp_cl= cl[0];
      if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || 
          !my_charset_same(tmp_cs, tmp_cl))
	continue;
      if (!(wild && wild[0] &&
	  wild_case_compare(scs, tmp_cl->name,wild)))
      {
	const char *tmp_buff;
4353
	restore_record(table, s->default_values);
4354 4355
	table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
        table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
4356
        table->field[2]->store((longlong) tmp_cl->number, TRUE);
4357 4358 4359 4360
        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);
4361
        table->field[5]->store((longlong) tmp_cl->strxfrm_multiply, TRUE);
4362 4363
        if (schema_table_store_record(thd, table))
          return 1;
4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375
      }
    }
  }
  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;
4376 4377 4378
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets) ;
       cs++ )
4379 4380 4381 4382 4383 4384
  {
    CHARSET_INFO **cl;
    CHARSET_INFO *tmp_cs= cs[0];
    if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || 
        !(tmp_cs->state & MY_CS_PRIMARY))
      continue;
4385 4386 4387
    for (cl= all_charsets;
         cl < all_charsets + array_elements(all_charsets) ;
         cl ++)
4388 4389
    {
      CHARSET_INFO *tmp_cl= cl[0];
4390 4391
      if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
          (tmp_cl->state & MY_CS_HIDDEN) ||
4392 4393
          !my_charset_same(tmp_cs,tmp_cl))
	continue;
4394
      restore_record(table, s->default_values);
4395 4396
      table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
      table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
4397 4398
      if (schema_table_store_record(thd, table))
        return 1;
4399 4400 4401 4402 4403 4404
    }
  }
  return 0;
}


4405 4406 4407 4408 4409 4410 4411 4412 4413
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
4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576
/**
  @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],
    definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 1];
  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;
  uint routine_type;
  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);
  routine_type= (uint) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();

  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);
      table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
      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);
      table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);

      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);
}


4577
bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
4578
                       const char *wild, bool full_access, const char *sp_user)
4579
{
4580
  MYSQL_TIME time;
4581 4582
  LEX *lex= thd->lex;
  CHARSET_INFO *cs= system_charset_info;
4583
  char sp_db_buff[NAME_LEN + 1], sp_name_buff[NAME_LEN + 1],
4584 4585 4586
    definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 2],
    returns_buff[MAX_FIELD_WIDTH];

4587 4588 4589
  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);
4590
  String returns(returns_buff, sizeof(returns_buff), cs);
4591

4592 4593 4594
  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);
4595

4596
  if (!full_access)
4597 4598 4599
    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
4600 4601
                                proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
                                val_int() == TYPE_ENUM_PROCEDURE))
4602
    return 0;
4603

Staale Smedseng's avatar
Staale Smedseng committed
4604
  if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
Sergey Glukhov's avatar
Sergey Glukhov committed
4605 4606
      proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
      TYPE_ENUM_PROCEDURE) ||
Staale Smedseng's avatar
Staale Smedseng committed
4607
      (lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
Sergey Glukhov's avatar
Sergey Glukhov committed
4608 4609
      proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
      TYPE_ENUM_FUNCTION) ||
4610
      (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
4611
  {
4612
    restore_record(table, s->default_values);
4613
    if (!wild || !wild[0] || !wild_compare(sp_name.c_ptr_safe(), wild, 0))
4614
    {
Sergey Glukhov's avatar
Sergey Glukhov committed
4615
      int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int();
4616
      table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
4617 4618 4619

      copy_field_as_string(table->field[0],
                           proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]);
4620
      table->field[1]->store(STRING_WITH_LEN("def"), cs);
4621
      table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
4622 4623 4624
      copy_field_as_string(table->field[4],
                           proc_table->field[MYSQL_PROC_MYSQL_TYPE]);

Sergey Glukhov's avatar
Sergey Glukhov committed
4625 4626
      if (proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
          TYPE_ENUM_FUNCTION)
4627
      {
Sergey Glukhov's avatar
Sergey Glukhov committed
4628 4629
        sp_head *sp;
        bool free_sp_head;
4630
        proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str(&returns);
Sergey Glukhov's avatar
Sergey Glukhov committed
4631 4632 4633 4634 4635
        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,
4636
                                           returns.c_ptr_safe(),
Sergey Glukhov's avatar
Sergey Glukhov committed
4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662
                                           "", &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;
        }
4663
      }
Sergey Glukhov's avatar
Sergey Glukhov committed
4664

4665 4666
      if (full_access)
      {
4667 4668
        copy_field_as_string(table->field[14],
                             proc_table->field[MYSQL_PROC_FIELD_BODY_UTF8]);
Sergey Glukhov's avatar
Sergey Glukhov committed
4669
        table->field[14]->set_notnull();
4670
      }
Sergey Glukhov's avatar
Sergey Glukhov committed
4671 4672
      table->field[13]->store(STRING_WITH_LEN("SQL"), cs);
      table->field[17]->store(STRING_WITH_LEN("SQL"), cs);
4673 4674
      copy_field_as_string(table->field[18],
                           proc_table->field[MYSQL_PROC_FIELD_DETERMINISTIC]);
Sergey Glukhov's avatar
Sergey Glukhov committed
4675
      table->field[19]->store(sp_data_access_name[enum_idx].str, 
4676
                              sp_data_access_name[enum_idx].length , cs);
4677 4678
      copy_field_as_string(table->field[21],
                           proc_table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]);
Sergey Glukhov's avatar
Sergey Glukhov committed
4679

4680
      bzero((char *)&time, sizeof(time));
Sergey Glukhov's avatar
Sergey Glukhov committed
4681 4682 4683
      ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_CREATED])->
        get_time(&time);
      table->field[22]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
4684
      bzero((char *)&time, sizeof(time));
Sergey Glukhov's avatar
Sergey Glukhov committed
4685 4686 4687
      ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_MODIFIED])->
        get_time(&time);
      table->field[23]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
4688 4689 4690 4691
      copy_field_as_string(table->field[24],
                           proc_table->field[MYSQL_PROC_FIELD_SQL_MODE]);
      copy_field_as_string(table->field[25],
                           proc_table->field[MYSQL_PROC_FIELD_COMMENT]);
4692

Sergey Glukhov's avatar
Sergey Glukhov committed
4693
      table->field[26]->store(definer.ptr(), definer.length(), cs);
4694 4695 4696 4697 4698 4699 4700 4701
      copy_field_as_string(table->field[27],
                           proc_table->
                           field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]);
      copy_field_as_string(table->field[28],
                           proc_table->
                           field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]);
      copy_field_as_string(table->field[29],
			   proc_table->field[MYSQL_PROC_FIELD_DB_COLLATION]);
4702

4703
      return schema_table_store_record(thd, table);
4704 4705
    }
  }
4706
  return 0;
4707 4708 4709 4710 4711 4712 4713 4714 4715
}


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;
4716
  TABLE *table= tables->table;
4717
  bool full_access;
4718
  char definer[USER_HOST_BUFF_SIZE];
4719
  Open_tables_backup open_tables_state_backup;
Sergey Glukhov's avatar
Sergey Glukhov committed
4720 4721
  enum enum_schema_tables schema_table_idx=
    get_schema_table_idx(tables->schema_table);
4722 4723
  DBUG_ENTER("fill_schema_proc");

4724 4725
  strxmov(definer, thd->security_ctx->priv_user, "@",
          thd->security_ctx->priv_host, NullS);
4726
  /* We use this TABLE_LIST instance only for checking of privileges. */
4727 4728
  bzero((char*) &proc_tables,sizeof(proc_tables));
  proc_tables.db= (char*) "mysql";
4729
  proc_tables.db_length= 5;
4730
  proc_tables.table_name= proc_tables.alias= (char*) "proc";
4731
  proc_tables.table_name_length= 4;
4732
  proc_tables.lock_type= TL_READ;
4733 4734
  full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, FALSE,
                                   1, TRUE);
4735
  if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup)))
4736 4737 4738
  {
    DBUG_RETURN(1);
  }
4739
  proc_table->file->ha_index_init(0, 1);
4740 4741 4742 4743 4744
  if ((res= proc_table->file->index_first(proc_table->record[0])))
  {
    res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
    goto err;
  }
Sergey Glukhov's avatar
Sergey Glukhov committed
4745 4746 4747 4748

  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))
4749 4750 4751 4752
  {
    res= 1;
    goto err;
  }
4753
  while (!proc_table->file->index_next(proc_table->record[0]))
4754
  {
Sergey Glukhov's avatar
Sergey Glukhov committed
4755 4756 4757
    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))
4758 4759 4760 4761 4762
    {
      res= 1;
      goto err;
    }
  }
4763 4764 4765

err:
  proc_table->file->ha_index_end();
4766
  close_system_tables(thd, &open_tables_state_backup);
4767 4768 4769 4770
  DBUG_RETURN(res);
}


4771
static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4772
				  TABLE *table, bool res,
4773 4774
				  LEX_STRING *db_name,
				  LEX_STRING *table_name)
4775 4776 4777
{
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_schema_stat_record");
4778 4779
  if (res)
  {
4780
    if (thd->lex->sql_command != SQLCOM_SHOW_KEYS)
4781 4782 4783 4784
    {
      /*
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
        rather than in SHOW KEYS
4785
      */
4786
      if (thd->is_error())
4787
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4788
                     thd->stmt_da->sql_errno(), thd->stmt_da->message());
4789 4790 4791 4792 4793 4794
      thd->clear_error();
      res= 0;
    }
    DBUG_RETURN(res);
  }
  else if (!tables->view)
4795 4796
  {
    TABLE *show_table= tables->table;
4797 4798 4799 4800 4801
    KEY *key_info=show_table->s->key_info;
    if (show_table->file)
      show_table->file->info(HA_STATUS_VARIABLE |
                             HA_STATUS_NO_LOCK |
                             HA_STATUS_TIME);
4802
    for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
4803 4804 4805 4806 4807
    {
      KEY_PART_INFO *key_part= key_info->key_part;
      const char *str;
      for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
      {
4808
        restore_record(table, s->default_values);
4809
        table->field[0]->store(STRING_WITH_LEN("def"), cs);
4810 4811
        table->field[1]->store(db_name->str, db_name->length, cs);
        table->field[2]->store(table_name->str, table_name->length, cs);
4812
        table->field[3]->store((longlong) ((key_info->flags &
4813
                                            HA_NOSAME) ? 0 : 1), TRUE);
4814
        table->field[4]->store(db_name->str, db_name->length, cs);
4815
        table->field[5]->store(key_info->name, strlen(key_info->name), cs);
4816
        table->field[6]->store((longlong) (j+1), TRUE);
4817 4818 4819
        str=(key_part->field ? key_part->field->field_name :
             "?unknown field?");
        table->field[7]->store(str, strlen(str), cs);
4820
        if (show_table->file)
4821
        {
4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838
          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])
          {
            ha_rows records=(show_table->file->stats.records /
                             key->rec_per_key[j]);
            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);
4839
        }
4840 4841 4842
        if (!(key_info->flags & HA_FULLTEXT) &&
            (key_part->field &&
             key_part->length !=
4843
             show_table->s->field[key_part->fieldnr-1]->key_length()))
4844
        {
4845
          table->field[10]->store((longlong) key_part->length /
4846
                                  key_part->field->charset()->mbmaxlen, TRUE);
4847 4848 4849 4850 4851
          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);
4852
        if (!show_table->s->keys_in_use.is_set(i))
4853
          table->field[14]->store(STRING_WITH_LEN("disabled"), cs);
4854 4855 4856
        else
          table->field[14]->store("", 0, cs);
        table->field[14]->set_notnull();
4857 4858 4859 4860 4861
        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);
4862 4863
        if (schema_table_store_record(thd, table))
          DBUG_RETURN(1);
4864 4865 4866
      }
    }
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4867
  DBUG_RETURN(res);
4868 4869 4870
}


4871
static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4872
				   TABLE *table, bool res,
4873 4874
				   LEX_STRING *db_name,
				   LEX_STRING *table_name)
4875 4876
{
  CHARSET_INFO *cs= system_charset_info;
4877
  char definer[USER_HOST_BUFF_SIZE];
4878
  uint definer_len;
4879
  bool updatable_view;
Sergey Glukhov's avatar
Sergey Glukhov committed
4880
  DBUG_ENTER("get_schema_views_record");
4881

4882 4883
  if (tables->view)
  {
4884
    Security_context *sctx= thd->security_ctx;
Sergey Glukhov's avatar
Sergey Glukhov committed
4885
    if (!tables->allowed_show)
4886
    {
4887 4888 4889 4890 4891
      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;
4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902
#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
4903 4904
          table_list.db= tables->db;
          table_list.table_name= tables->table_name;
4905 4906
          table_list.grant.privilege= thd->col_access;
          view_access= get_table_grant(thd, &table_list);
Sergey Glukhov's avatar
Sergey Glukhov committed
4907 4908 4909
	  if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
	      (SHOW_VIEW_ACL|SELECT_ACL))
	    tables->allowed_show= TRUE;
4910 4911 4912
        }
      }
#endif
4913
    }
4914
    restore_record(table, s->default_values);
4915
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4916 4917 4918 4919
    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)
4920
    {
Sergey Glukhov's avatar
Sergey Glukhov committed
4921 4922 4923 4924
      table->field[3]->store(tables->view_body_utf8.str,
                             tables->view_body_utf8.length,
                             cs);
    }
4925

Sergey Glukhov's avatar
Sergey Glukhov committed
4926 4927 4928 4929
    if (tables->with_check != VIEW_CHECK_NONE)
    {
      if (tables->with_check == VIEW_CHECK_LOCAL)
        table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs);
4930
      else
Sergey Glukhov's avatar
Sergey Glukhov committed
4931 4932 4933 4934
        table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs);
    }
    else
      table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
4935

4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947
    /*
      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
4948
    {
4949 4950
      updatable_view= 0;
      if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE)
4951
      {
4952
        /*
4953 4954 4955 4956 4957 4958
          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.
4959 4960 4961 4962 4963 4964 4965 4966 4967
        */
        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++))
4968
        {
4969 4970 4971 4972 4973 4974
          if ((field= item->filed_for_view_update()) && field->field &&
              !field->field->table->pos_in_table_list->schema_table)
          {
            updatable_view= 1;
            break;
          }
4975
        }
4976 4977
        if (updatable_view && !tables->view->can_be_merged())
          updatable_view= 0;
4978
      }
4979 4980
      if (updatable_view)
        table->field[5]->store(STRING_WITH_LEN("YES"), cs);
4981
      else
4982
        table->field[5]->store(STRING_WITH_LEN("NO"), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4983
    }
4984

Sergey Glukhov's avatar
Sergey Glukhov committed
4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000
    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);
5001

5002 5003 5004

    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
5005
    if (res && thd->is_error())
Sergey Glukhov's avatar
Sergey Glukhov committed
5006
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5007
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5008
  }
Sergey Glukhov's avatar
Sergey Glukhov committed
5009
  if (res)
5010
    thd->clear_error();
5011
  DBUG_RETURN(0);
5012 5013 5014
}


5015 5016
bool store_constraints(THD *thd, TABLE *table, LEX_STRING *db_name,
                       LEX_STRING *table_name, const char *key_name,
5017
                       uint key_len, const char *con_type, uint con_len)
5018 5019
{
  CHARSET_INFO *cs= system_charset_info;
5020
  restore_record(table, s->default_values);
5021
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
5022
  table->field[1]->store(db_name->str, db_name->length, cs);
5023
  table->field[2]->store(key_name, key_len, cs);
5024 5025
  table->field[3]->store(db_name->str, db_name->length, cs);
  table->field[4]->store(table_name->str, table_name->length, cs);
5026
  table->field[5]->store(con_type, con_len, cs);
5027
  return schema_table_store_record(thd, table);
5028 5029 5030
}


5031
static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5032
					 TABLE *table, bool res,
5033 5034
					 LEX_STRING *db_name,
					 LEX_STRING *table_name)
5035
{
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
5036
  DBUG_ENTER("get_schema_constraints_record");
5037 5038
  if (res)
  {
5039
    if (thd->is_error())
5040
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5041
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5042 5043 5044 5045
    thd->clear_error();
    DBUG_RETURN(0);
  }
  else if (!tables->view)
5046 5047 5048 5049
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
    KEY *key_info=show_table->key_info;
5050
    uint primary_key= show_table->s->primary_key;
5051 5052 5053
    show_table->file->info(HA_STATUS_VARIABLE | 
                           HA_STATUS_NO_LOCK |
                           HA_STATUS_TIME);
5054
    for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
5055 5056
    {
      if (i != primary_key && !(key_info->flags & HA_NOSAME))
5057 5058
        continue;

5059
      if (i == primary_key && !strcmp(key_info->name, primary_key_name))
5060
      {
5061
        if (store_constraints(thd, table, db_name, table_name, key_info->name,
5062 5063
                              strlen(key_info->name),
                              STRING_WITH_LEN("PRIMARY KEY")))
5064 5065
          DBUG_RETURN(1);
      }
5066
      else if (key_info->flags & HA_NOSAME)
5067
      {
5068
        if (store_constraints(thd, table, db_name, table_name, key_info->name,
5069 5070
                              strlen(key_info->name),
                              STRING_WITH_LEN("UNIQUE")))
5071 5072
          DBUG_RETURN(1);
      }
5073 5074 5075 5076 5077 5078 5079
    }

    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++))
    {
5080
      if (store_constraints(thd, table, db_name, table_name, 
5081 5082
                            f_key_info->foreign_id->str,
                            strlen(f_key_info->foreign_id->str),
5083 5084
                            "FOREIGN KEY", 11))
        DBUG_RETURN(1);
5085 5086
    }
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5087
  DBUG_RETURN(res);
5088 5089 5090
}


5091 5092
static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name,
                          LEX_STRING *table_name, LEX_STRING *trigger_name,
5093 5094
                          enum trg_event_type event,
                          enum trg_action_time_type timing,
5095
                          LEX_STRING *trigger_stmt,
5096
                          ulong sql_mode,
5097 5098 5099 5100
                          LEX_STRING *definer_buffer,
                          LEX_STRING *client_cs_name,
                          LEX_STRING *connection_cl_name,
                          LEX_STRING *db_cl_name)
5101 5102
{
  CHARSET_INFO *cs= system_charset_info;
5103
  LEX_STRING sql_mode_rep;
5104

5105
  restore_record(table, s->default_values);
5106
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
5107
  table->field[1]->store(db_name->str, db_name->length, cs);
5108 5109 5110
  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);
5111
  table->field[4]->store(STRING_WITH_LEN("def"), cs);
5112 5113
  table->field[5]->store(db_name->str, db_name->length, cs);
  table->field[6]->store(table_name->str, table_name->length, cs);
5114
  table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
5115
  table->field[10]->store(STRING_WITH_LEN("ROW"), cs);
5116 5117
  table->field[11]->store(trg_action_time_type_names[timing].str,
                          trg_action_time_type_names[timing].length, cs);
5118 5119
  table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
  table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
5120

5121
  sql_mode_string_representation(thd, sql_mode, &sql_mode_rep);
5122
  table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs);
5123 5124 5125 5126 5127 5128
  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);

5129 5130 5131 5132
  return schema_table_store_record(thd, table);
}


5133
static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables,
5134
				      TABLE *table, bool res,
5135 5136
				      LEX_STRING *db_name,
				      LEX_STRING *table_name)
5137 5138 5139 5140 5141 5142 5143 5144
{
  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)
  {
5145
    if (thd->is_error())
5146
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5147
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5148 5149 5150 5151 5152 5153 5154
    thd->clear_error();
    DBUG_RETURN(0);
  }
  if (!tables->view && tables->table->triggers)
  {
    Table_triggers_list *triggers= tables->table->triggers;
    int event, timing;
5155

5156
    if (check_table_access(thd, TRIGGER_ACL, tables, FALSE, 1, TRUE))
5157 5158
      goto ret;

5159 5160 5161 5162 5163 5164
    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;
5165
        ulong sql_mode;
5166
        char definer_holder[USER_HOST_BUFF_SIZE];
5167
        LEX_STRING definer_buffer;
5168 5169 5170 5171
        LEX_STRING client_cs_name;
        LEX_STRING connection_cl_name;
        LEX_STRING db_cl_name;

5172
        definer_buffer.str= definer_holder;
5173 5174
        if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
                                       (enum trg_action_time_type)timing,
5175
                                       &trigger_name, &trigger_stmt,
5176
                                       &sql_mode,
5177 5178 5179 5180
                                       &definer_buffer,
                                       &client_cs_name,
                                       &connection_cl_name,
                                       &db_cl_name))
5181
          continue;
5182

5183
        if (store_trigger(thd, table, db_name, table_name, &trigger_name,
5184
                         (enum trg_event_type) event,
5185
                         (enum trg_action_time_type) timing, &trigger_stmt,
5186
                         sql_mode,
5187 5188 5189 5190
                         &definer_buffer,
                         &client_cs_name,
                         &connection_cl_name,
                         &db_cl_name))
5191 5192 5193 5194
          DBUG_RETURN(1);
      }
    }
  }
5195
ret:
5196 5197 5198 5199
  DBUG_RETURN(0);
}


5200 5201 5202 5203
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)
5204 5205
{
  CHARSET_INFO *cs= system_charset_info;
5206
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
5207
  table->field[1]->store(db_name->str, db_name->length, cs);
5208
  table->field[2]->store(key_name, key_len, cs);
5209
  table->field[3]->store(STRING_WITH_LEN("def"), cs);
5210 5211
  table->field[4]->store(db_name->str, db_name->length, cs);
  table->field[5]->store(table_name->str, table_name->length, cs);
5212
  table->field[6]->store(con_type, con_len, cs);
5213
  table->field[7]->store((longlong) idx, TRUE);
5214 5215 5216
}


bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5217
static int get_schema_key_column_usage_record(THD *thd,
5218
					      TABLE_LIST *tables,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5219
					      TABLE *table, bool res,
5220 5221
					      LEX_STRING *db_name,
					      LEX_STRING *table_name)
5222 5223
{
  DBUG_ENTER("get_schema_key_column_usage_record");
5224 5225
  if (res)
  {
5226
    if (thd->is_error())
5227
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5228
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5229 5230 5231 5232
    thd->clear_error();
    DBUG_RETURN(0);
  }
  else if (!tables->view)
5233 5234 5235 5236
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
    KEY *key_info=show_table->key_info;
5237
    uint primary_key= show_table->s->primary_key;
5238 5239 5240
    show_table->file->info(HA_STATUS_VARIABLE | 
                           HA_STATUS_NO_LOCK |
                           HA_STATUS_TIME);
5241
    for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
5242 5243
    {
      if (i != primary_key && !(key_info->flags & HA_NOSAME))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5244
        continue;
5245 5246 5247 5248 5249 5250 5251
      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++;
5252
          restore_record(table, s->default_values);
5253
          store_key_column_usage(table, db_name, table_name,
5254 5255 5256 5257 5258
                                 key_info->name,
                                 strlen(key_info->name), 
                                 key_part->field->field_name, 
                                 strlen(key_part->field->field_name),
                                 (longlong) f_idx);
5259 5260
          if (schema_table_store_record(thd, table))
            DBUG_RETURN(1);
5261 5262 5263 5264 5265 5266
        }
      }
    }

    show_table->file->get_foreign_key_list(thd, &f_key_list);
    FOREIGN_KEY_INFO *f_key_info;
5267 5268
    List_iterator_fast<FOREIGN_KEY_INFO> fkey_it(f_key_list);
    while ((f_key_info= fkey_it++))
5269
    {
5270
      LEX_STRING *f_info;
5271
      LEX_STRING *r_info;
5272 5273 5274 5275 5276
      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++))
      {
5277
        r_info= it1++;
5278
        f_idx++;
5279
        restore_record(table, s->default_values);
5280
        store_key_column_usage(table, db_name, table_name,
5281 5282
                               f_key_info->foreign_id->str,
                               f_key_info->foreign_id->length,
5283 5284
                               f_info->str, f_info->length,
                               (longlong) f_idx);
5285
        table->field[8]->store((longlong) f_idx, TRUE);
5286
        table->field[8]->set_notnull();
5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297
        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,
                                f_key_info->referenced_table->length, 
                                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();
5298 5299
        if (schema_table_store_record(thd, table))
          DBUG_RETURN(1);
5300 5301 5302
      }
    }
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5303
  DBUG_RETURN(res);
5304 5305 5306
}


5307
#ifdef WITH_PARTITION_STORAGE_ENGINE
5308 5309
static void collect_partition_expr(THD *thd, List<char> &field_list,
                                   String *str)
5310 5311 5312 5313 5314 5315 5316
{
  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++))
  {
5317
    append_identifier(thd, str, field_str, strlen(field_str));
5318 5319 5320 5321 5322
    if (--no_fields != 0)
      str->append(",");
  }
  return;
}
5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373


/*
  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;
}
5374
#endif
5375 5376


5377 5378
static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
                                           TABLE *showing_table,
5379 5380 5381
                                           partition_element *part_elem,
                                           handler *file, uint part_id)
{
5382
  TABLE* table= schema_table;
5383
  CHARSET_INFO *cs= system_charset_info;
5384
  PARTITION_STATS stat_info;
5385
  MYSQL_TIME time;
5386
  file->get_dynamic_partition_info(&stat_info, part_id);
5387
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400
  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,
5401
                                              (my_time_t)stat_info.create_time);
5402 5403 5404 5405 5406 5407
    table->field[18]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
    table->field[18]->set_notnull();
  }
  if (stat_info.update_time)
  {
    thd->variables.time_zone->gmt_sec_to_TIME(&time,
5408
                                              (my_time_t)stat_info.update_time);
5409 5410 5411 5412 5413
    table->field[19]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
    table->field[19]->set_notnull();
  }
  if (stat_info.check_time)
  {
5414 5415
    thd->variables.time_zone->gmt_sec_to_TIME(&time,
                                              (my_time_t)stat_info.check_time);
5416 5417 5418
    table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
    table->field[20]->set_notnull();
  }
5419
  if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
5420 5421 5422 5423 5424 5425 5426 5427 5428 5429
  {
    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
5430
      table->field[22]->store(STRING_WITH_LEN(""), cs);
5431 5432 5433 5434
    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);
5435 5436

    table->field[24]->set_notnull();
5437 5438 5439 5440
    if (part_elem->tablespace_name)
      table->field[24]->store(part_elem->tablespace_name,
                              strlen(part_elem->tablespace_name), cs);
    else
5441
    {
5442
      char *ts= showing_table->file->get_tablespace_name(thd,0,0);
5443
      if(ts)
5444
      {
5445
        table->field[24]->store(ts, strlen(ts), cs);
5446
        my_free(ts);
5447
      }
5448 5449 5450
      else
        table->field[24]->set_null();
    }
5451 5452 5453 5454
  }
  return;
}

Alexander Nozdrin's avatar
Alexander Nozdrin committed
5455
#ifdef WITH_PARTITION_STORAGE_ENGINE
5456
static int
5457 5458
get_partition_column_description(THD *thd,
                                 partition_info *part_info,
5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474
                                 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
    {
5475
      char buffer[MAX_KEY_LENGTH];
5476
      String str(buffer, sizeof(buffer), &my_charset_bin);
5477
      String val_conv;
5478 5479 5480 5481 5482 5483 5484 5485
      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);
5486
      if (get_cs_converted_part_value_from_string(thd, item, res, &val_conv,
5487
                              part_info->part_field_array[i]->charset(),
5488
                              FALSE))
5489 5490 5491
      {
        DBUG_RETURN(1);
      }
5492
      tmp_str.append(val_conv);
5493 5494 5495 5496 5497 5498
    }
    if (i != num_elements - 1)
      tmp_str.append(",");
  }
  DBUG_RETURN(0);
}
Alexander Nozdrin's avatar
Alexander Nozdrin committed
5499
#endif /* WITH_PARTITION_STORAGE_ENGINE */
5500

5501
static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
5502
                                        TABLE *table, bool res,
5503 5504
                                        LEX_STRING *db_name,
                                        LEX_STRING *table_name)
5505 5506 5507 5508 5509 5510
{
  CHARSET_INFO *cs= system_charset_info;
  char buff[61];
  String tmp_res(buff, sizeof(buff), cs);
  String tmp_str;
  TABLE *show_table= tables->table;
5511
  handler *file;
5512
#ifdef WITH_PARTITION_STORAGE_ENGINE
5513
  partition_info *part_info;
5514
#endif
5515 5516 5517 5518
  DBUG_ENTER("get_schema_partitions_record");

  if (res)
  {
5519
    if (thd->is_error())
5520
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5521
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5522 5523 5524
    thd->clear_error();
    DBUG_RETURN(0);
  }
5525
  file= show_table->file;
5526
#ifdef WITH_PARTITION_STORAGE_ENGINE
5527
  part_info= show_table->part_info;
5528 5529 5530 5531 5532 5533 5534
  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);
5535
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
5536 5537
    table->field[1]->store(db_name->str, db_name->length, cs);
    table->field[2]->store(table_name->str, table_name->length, cs);
5538 5539 5540 5541 5542 5543


    /* Partition method*/
    switch (part_info->part_type) {
    case RANGE_PARTITION:
    case LIST_PARTITION:
5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554
      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);
5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570
      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
        tmp_res.append(partition_keywords[PKW_HASH].str, 
                       partition_keywords[PKW_HASH].length);
      table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs);
      break;
    default:
      DBUG_ASSERT(0);
5571
      my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583
      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)
    {
5584
      collect_partition_expr(thd, part_info->part_field_list, &tmp_str);
5585 5586
      table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs);
    }
5587
    table->field[9]->set_notnull();
5588

5589
    if (part_info->is_sub_partitioned())
5590 5591
    {
      /* Subpartition method */
5592 5593 5594 5595
      tmp_res.length(0);
      if (part_info->linear_hash_ind)
        tmp_res.append(partition_keywords[PKW_LINEAR].str,
                       partition_keywords[PKW_LINEAR].length);
5596
      if (part_info->list_of_subpart_fields)
5597 5598
        tmp_res.append(partition_keywords[PKW_KEY].str,
                       partition_keywords[PKW_KEY].length);
5599
      else
5600 5601 5602
        tmp_res.append(partition_keywords[PKW_HASH].str, 
                       partition_keywords[PKW_HASH].length);
      table->field[8]->store(tmp_res.ptr(), tmp_res.length(), cs);
5603 5604 5605 5606 5607 5608 5609 5610 5611 5612
      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)
      {
5613
        collect_partition_expr(thd, part_info->subpart_field_list, &tmp_str);
5614 5615
        table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs);
      }
5616
      table->field[10]->set_notnull();
5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630
    }

    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)
      {
5631 5632 5633 5634 5635
        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);
5636 5637
          if (get_partition_column_description(thd,
                                               part_info,
5638 5639 5640 5641 5642 5643 5644
                                               list_value,
                                               tmp_str))
          {
            DBUG_RETURN(1);
          }
          table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
        }
5645
        else
5646 5647 5648 5649 5650
        {
          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,
5651
                                 partition_keywords[PKW_MAXVALUE].length, cs);
5652
        }
5653 5654 5655 5656
        table->field[11]->set_notnull();
      }
      else if (part_info->part_type == LIST_PARTITION)
      {
5657 5658
        List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
        part_elem_value *list_value;
5659
        uint num_items= part_elem->list_val_list.elements;
5660 5661
        tmp_str.length(0);
        tmp_res.length(0);
5662 5663 5664
        if (part_elem->has_null_value)
        {
          tmp_str.append("NULL");
5665
          if (num_items > 0)
5666 5667
            tmp_str.append(",");
        }
5668 5669
        while ((list_value= list_val_it++))
        {
5670 5671 5672 5673
          if (part_info->column_list)
          {
            if (part_info->part_field_list.elements > 1U)
              tmp_str.append("(");
5674 5675
            if (get_partition_column_description(thd,
                                                 part_info,
5676 5677 5678 5679 5680 5681 5682 5683
                                                 list_value,
                                                 tmp_str))
            {
              DBUG_RETURN(1);
            }
            if (part_info->part_field_list.elements > 1U)
              tmp_str.append(")");
          }
5684
          else
5685 5686 5687 5688 5689 5690 5691 5692
          {
            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)
5693
            tmp_str.append(",");
5694
        }
5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713
        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();
          
5714
          store_schema_partitions_record(thd, table, show_table, subpart_elem,
5715 5716 5717 5718 5719 5720 5721 5722
                                         file, part_id);
          part_id++;
          if(schema_table_store_record(thd, table))
            DBUG_RETURN(1);
        }
      }
      else
      {
5723
        store_schema_partitions_record(thd, table, show_table, part_elem,
5724 5725 5726 5727 5728 5729 5730 5731 5732
                                       file, part_id);
        part_id++;
        if(schema_table_store_record(thd, table))
          DBUG_RETURN(1);
      }
    }
    DBUG_RETURN(0);
  }
  else
5733
#endif
5734
  {
5735
    store_schema_partitions_record(thd, table, show_table, 0, file, 0);
5736 5737 5738 5739 5740 5741 5742
    if(schema_table_store_record(thd, table))
      DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


5743
#ifdef HAVE_EVENT_SCHEDULER
5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758
/*
  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
*/

5759
int
5760
copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
5761 5762 5763
{
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  CHARSET_INFO *scs= system_charset_info;
5764
  MYSQL_TIME time;
5765
  Event_timed et;
5766
  DBUG_ENTER("copy_event_to_schema_table");
5767 5768 5769

  restore_record(sch_table, s->default_values);

5770
  if (et.load_from_row(thd, event_table))
5771
  {
5772
    my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), event_table->alias);
5773 5774 5775 5776 5777
    DBUG_RETURN(1);
  }

  if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0)))
    DBUG_RETURN(0);
5778 5779 5780 5781 5782 5783

  /*
    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.
  */
5784
  if (thd->lex->sql_command != SQLCOM_SHOW_EVENTS &&
Marc Alff's avatar
Marc Alff committed
5785
      check_access(thd, EVENT_ACL, et.dbname.str, NULL, NULL, 0, 1))
5786 5787
    DBUG_RETURN(0);

5788
  sch_table->field[ISE_EVENT_CATALOG]->store(STRING_WITH_LEN("def"), scs);
5789 5790 5791 5792 5793 5794
  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);
5795 5796 5797
  const String *tz_name= et.time_zone->get_name();
  sch_table->field[ISE_TIME_ZONE]->
                                store(tz_name->ptr(), tz_name->length(), scs);
5798 5799
  sch_table->field[ISE_EVENT_BODY]->
                                store(STRING_WITH_LEN("SQL"), scs);
5800 5801
  sch_table->field[ISE_EVENT_DEFINITION]->store(
    et.body_utf8.str, et.body_utf8.length, scs);
5802 5803

  /* SQL_MODE */
5804
  {
5805
    LEX_STRING sql_mode;
5806
    sql_mode_string_representation(thd, et.sql_mode, &sql_mode);
5807
    sch_table->field[ISE_SQL_MODE]->
5808
                                store(sql_mode.str, sql_mode.length, scs);
5809
  }
5810

5811 5812
  int not_used=0;

5813 5814
  if (et.expression)
  {
5815
    String show_str;
5816
    /* type */
5817
    sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("RECURRING"), scs);
5818

5819 5820
    if (Events::reconstruct_interval_expression(&show_str, et.interval,
                                                et.expression))
5821
      DBUG_RETURN(1);
5822

5823 5824 5825
    sch_table->field[ISE_INTERVAL_VALUE]->set_notnull();
    sch_table->field[ISE_INTERVAL_VALUE]->
                                store(show_str.ptr(), show_str.length(), scs);
5826 5827

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

5831
    /* starts & ends . STARTS is always set - see sql_yacc.yy */
5832
    et.time_zone->gmt_sec_to_TIME(&time, et.starts);
5833 5834
    sch_table->field[ISE_STARTS]->set_notnull();
    sch_table->field[ISE_STARTS]->
5835
                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5836 5837 5838

    if (!et.ends_null)
    {
5839
      et.time_zone->gmt_sec_to_TIME(&time, et.ends);
5840 5841
      sch_table->field[ISE_ENDS]->set_notnull();
      sch_table->field[ISE_ENDS]->
5842
                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5843
    }
5844 5845 5846
  }
  else
  {
5847 5848
    /* type */
    sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("ONE TIME"), scs);
5849

5850
    et.time_zone->gmt_sec_to_TIME(&time, et.execute_at);
5851 5852
    sch_table->field[ISE_EXECUTE_AT]->set_notnull();
    sch_table->field[ISE_EXECUTE_AT]->
5853
                          store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5854 5855
  }

5856
  /* status */
5857 5858 5859

  switch (et.status)
  {
5860
    case Event_parse_data::ENABLED:
5861 5862
      sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("ENABLED"), scs);
      break;
5863
    case Event_parse_data::SLAVESIDE_DISABLED:
5864 5865 5866
      sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("SLAVESIDE_DISABLED"),
                                          scs);
      break;
5867
    case Event_parse_data::DISABLED:
5868 5869 5870 5871 5872 5873
      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);
5874

5875
  /* on_completion */
5876
  if (et.on_completion == Event_parse_data::ON_COMPLETION_DROP)
5877 5878
    sch_table->field[ISE_ON_COMPLETION]->
                                store(STRING_WITH_LEN("NOT PRESERVE"), scs);
5879
  else
5880 5881
    sch_table->field[ISE_ON_COMPLETION]->
                                store(STRING_WITH_LEN("PRESERVE"), scs);
5882 5883 5884
    
  number_to_datetime(et.created, &time, 0, &not_used);
  DBUG_ASSERT(not_used==0);
5885
  sch_table->field[ISE_CREATED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5886 5887 5888

  number_to_datetime(et.modified, &time, 0, &not_used);
  DBUG_ASSERT(not_used==0);
5889 5890
  sch_table->field[ISE_LAST_ALTERED]->
                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5891

5892
  if (et.last_executed)
5893
  {
5894
    et.time_zone->gmt_sec_to_TIME(&time, et.last_executed);
5895 5896
    sch_table->field[ISE_LAST_EXECUTED]->set_notnull();
    sch_table->field[ISE_LAST_EXECUTED]->
5897
                       store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5898
  }
5899

5900 5901
  sch_table->field[ISE_EVENT_COMMENT]->
                      store(et.comment.str, et.comment.length, scs);
5902

5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920
  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);

5921 5922 5923 5924 5925
  if (schema_table_store_record(thd, sch_table))
    DBUG_RETURN(1);

  DBUG_RETURN(0);
}
5926
#endif
5927

5928 5929 5930 5931 5932 5933 5934
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;
5935 5936
  if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild))
            && thd->is_fatal_error)
5937 5938 5939 5940
    DBUG_RETURN(1);

  for (; open_list ; open_list=open_list->next)
  {
5941
    restore_record(table, s->default_values);
5942 5943
    table->field[0]->store(open_list->db, strlen(open_list->db), cs);
    table->field[1]->store(open_list->table, strlen(open_list->table), cs);
5944 5945
    table->field[2]->store((longlong) open_list->in_use, TRUE);
    table->field[3]->store((longlong) open_list->locked, TRUE);
5946 5947
    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
5948 5949 5950 5951 5952 5953 5954 5955
  }
  DBUG_RETURN(0);
}


int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  DBUG_ENTER("fill_variables");
5956
  int res= 0;
5957 5958
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
5959 5960 5961 5962 5963 5964 5965 5966 5967 5968
  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;

Marc Alff's avatar
Marc Alff committed
5969
  mysql_rwlock_rdlock(&LOCK_system_variables_hash);
5970
  res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type),
5971
                         option_type, NULL, "", tables->table, upper_case_names, cond);
Marc Alff's avatar
Marc Alff committed
5972
  mysql_rwlock_unlock(&LOCK_system_variables_hash);
5973 5974 5975 5976 5977 5978 5979 5980 5981 5982
  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;
5983 5984 5985 5986 5987 5988
  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);

5989 5990 5991 5992 5993 5994 5995 5996 5997
  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)
5998 5999 6000 6001 6002
  {
    option_type= OPT_GLOBAL;
    tmp1= &tmp;
  }
  else
6003
  { 
6004
    option_type= OPT_SESSION;
6005
    tmp1= &thd->status_var;
6006 6007
  }

Marc Alff's avatar
Marc Alff committed
6008
  mysql_mutex_lock(&LOCK_status);
6009
  if (option_type == OPT_GLOBAL)
6010
    calc_sum_of_all_status(&tmp);
6011 6012
  res= show_status_array(thd, wild,
                         (SHOW_VAR *)all_status_vars.buffer,
6013
                         option_type, tmp1, "", tables->table,
6014
                         upper_case_names, cond);
Marc Alff's avatar
Marc Alff committed
6015
  mysql_mutex_unlock(&LOCK_status);
6016 6017 6018 6019
  DBUG_RETURN(res);
}


6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038
/*
  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
6039
get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
6040
                                   TABLE *table, bool res,
6041
                                   LEX_STRING *db_name, LEX_STRING *table_name)
6042 6043 6044 6045 6046 6047
{
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_referential_constraints_record");

  if (res)
  {
6048
    if (thd->is_error())
6049
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
6050
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067
    thd->clear_error();
    DBUG_RETURN(0);
  }
  if (!tables->view)
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
    show_table->file->info(HA_STATUS_VARIABLE | 
                           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);
6068
      table->field[0]->store(STRING_WITH_LEN("def"), cs);
6069 6070
      table->field[1]->store(db_name->str, db_name->length, cs);
      table->field[9]->store(table_name->str, table_name->length, cs);
6071 6072
      table->field[2]->store(f_key_info->foreign_id->str,
                             f_key_info->foreign_id->length, cs);
6073
      table->field[3]->store(STRING_WITH_LEN("def"), cs);
6074 6075
      table->field[4]->store(f_key_info->referenced_db->str, 
                             f_key_info->referenced_db->length, cs);
6076
      table->field[10]->store(f_key_info->referenced_table->str, 
6077
                             f_key_info->referenced_table->length, cs);
6078 6079 6080 6081 6082 6083 6084 6085
      if (f_key_info->referenced_key_name)
      {
        table->field[5]->store(f_key_info->referenced_key_name->str, 
                               f_key_info->referenced_key_name->length, cs);
        table->field[5]->set_notnull();
      }
      else
        table->field[5]->set_null();
6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097
      table->field[6]->store(STRING_WITH_LEN("NONE"), cs);
      table->field[7]->store(f_key_info->update_method->str, 
                             f_key_info->update_method->length, cs);
      table->field[8]->store(f_key_info->delete_method->str, 
                             f_key_info->delete_method->length, cs);
      if (schema_table_store_record(thd, table))
        DBUG_RETURN(1);
    }
  }
  DBUG_RETURN(0);
}

brian@zim.(none)'s avatar
brian@zim.(none) committed
6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117
struct schema_table_ref 
{
  const char *table_name;
  ST_SCHEMA_TABLE *schema_table;
};


/*
  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
*/
antony@ppcg5.local's avatar
antony@ppcg5.local committed
6118
static my_bool find_schema_table_in_plugin(THD *thd, plugin_ref plugin,
brian@zim.(none)'s avatar
brian@zim.(none) committed
6119 6120 6121 6122
                                           void* p_table)
{
  schema_table_ref *p_schema_table= (schema_table_ref *)p_table;
  const char* table_name= p_schema_table->table_name;
antony@ppcg5.local's avatar
antony@ppcg5.local committed
6123
  ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
brian@zim.(none)'s avatar
brian@zim.(none) committed
6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135
  DBUG_ENTER("find_schema_table_in_plugin");

  if (!my_strcasecmp(system_charset_info,
                     schema_table->table_name,
                     table_name)) {
    p_schema_table->schema_table= schema_table;
    DBUG_RETURN(1);
  }

  DBUG_RETURN(0);
}

6136

6137 6138 6139 6140 6141 6142 6143 6144 6145 6146
/*
  Find schema_tables elment by name

  SYNOPSIS
    find_schema_table()
    thd                 thread handler
    table_name          table name

  RETURN
    0	table not found
6147
    #   pointer to 'schema_tables' element
6148 6149 6150 6151
*/

ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
{
brian@zim.(none)'s avatar
brian@zim.(none) committed
6152
  schema_table_ref schema_table_a;
6153
  ST_SCHEMA_TABLE *schema_table= schema_tables;
brian@zim.(none)'s avatar
brian@zim.(none) committed
6154 6155
  DBUG_ENTER("find_schema_table");

6156
  for (; schema_table->table_name; schema_table++)
6157 6158 6159 6160
  {
    if (!my_strcasecmp(system_charset_info,
                       schema_table->table_name,
                       table_name))
brian@zim.(none)'s avatar
brian@zim.(none) committed
6161
      DBUG_RETURN(schema_table);
6162
  }
brian@zim.(none)'s avatar
brian@zim.(none) committed
6163 6164 6165 6166 6167 6168 6169

  schema_table_a.table_name= table_name;
  if (plugin_foreach(thd, find_schema_table_in_plugin, 
                     MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a))
    DBUG_RETURN(schema_table_a.schema_table);

  DBUG_RETURN(NULL);
6170 6171 6172 6173 6174 6175 6176 6177 6178
}


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


6179 6180
/**
  Create information_schema table using schema_table data.
6181

6182 6183 6184 6185 6186 6187 6188 6189 6190
  @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
    length.  Encode this value with  (decimals*100)+length  , where
    0<decimals<10 and 0<=length<100 .

  @param
6191
    thd	       	          thread handler
6192 6193 6194

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

6196 6197
  @retval  \#             Pointer to created table
  @retval  NULL           Can't create table
6198 6199
*/

6200
TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
6201 6202 6203 6204 6205
{
  int field_count= 0;
  Item *item;
  TABLE *table;
  List<Item> field_list;
6206
  ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
6207
  ST_FIELD_INFO *fields_info= schema_table->fields_info;
6208
  CHARSET_INFO *cs= system_charset_info;
6209 6210
  DBUG_ENTER("create_schema_table");

6211
  for (; fields_info->field_name; fields_info++)
6212 6213
  {
    switch (fields_info->field_type) {
6214
    case MYSQL_TYPE_TINY:
6215
    case MYSQL_TYPE_LONG:
6216 6217 6218 6219 6220 6221 6222
    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)))
6223 6224 6225
      {
        DBUG_RETURN(0);
      }
6226
      item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
6227
      break;
6228 6229
    case MYSQL_TYPE_DATE:
    case MYSQL_TYPE_TIME:
6230
    case MYSQL_TYPE_TIMESTAMP:
6231 6232 6233
    case MYSQL_TYPE_DATETIME:
      if (!(item=new Item_return_date_time(fields_info->field_name,
                                           fields_info->field_type)))
6234 6235 6236 6237
      {
        DBUG_RETURN(0);
      }
      break;
6238 6239 6240 6241 6242 6243
    case MYSQL_TYPE_FLOAT:
    case MYSQL_TYPE_DOUBLE:
      if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC, 
                           fields_info->field_length)) == NULL)
        DBUG_RETURN(NULL);
      break;
6244
    case MYSQL_TYPE_DECIMAL:
6245
    case MYSQL_TYPE_NEWDECIMAL:
6246 6247 6248 6249
      if (!(item= new Item_decimal((longlong) fields_info->value, false)))
      {
        DBUG_RETURN(0);
      }
6250
      item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
6251 6252 6253 6254 6255 6256 6257 6258 6259
      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;
6260 6261 6262 6263 6264 6265 6266 6267 6268 6269
    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;
6270
    default:
6271 6272 6273
      /* Don't let unimplemented types pass through. Could be a grave error. */
      DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING);

6274
      if (!(item= new Item_empty_string("", fields_info->field_length, cs)))
6275 6276 6277
      {
        DBUG_RETURN(0);
      }
6278 6279
      item->set_name(fields_info->field_name,
                     strlen(fields_info->field_name), cs);
6280 6281 6282
      break;
    }
    field_list.push_back(item);
6283
    item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL);
6284 6285 6286
    field_count++;
  }
  TMP_TABLE_PARAM *tmp_table_param =
6287
    (TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM)));
6288
  tmp_table_param->init();
6289
  tmp_table_param->table_charset= cs;
6290
  tmp_table_param->field_count= field_count;
6291
  tmp_table_param->schema_table= 1;
6292 6293 6294
  SELECT_LEX *select_lex= thd->lex->current_select;
  if (!(table= create_tmp_table(thd, tmp_table_param,
                                field_list, (ORDER*) 0, 0, 0, 
6295
                                (select_lex->options | thd->variables.option_bits |
6296
                                 TMP_TABLE_ALL_COLUMNS),
6297
                                HA_POS_ERROR, table_list->alias)))
6298
    DBUG_RETURN(0);
6299 6300 6301 6302 6303 6304
  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);
6305
  table_list->schema_table_param= tmp_table_param;
6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320
  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
6321 6322
   1	error
   0	success
6323 6324 6325 6326 6327
*/

int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
  ST_FIELD_INFO *field_info= schema_table->fields_info;
6328
  Name_resolution_context *context= &thd->lex->select_lex.context;
6329
  for (; field_info->field_name; field_info++)
6330 6331 6332
  {
    if (field_info->old_name)
    {
6333 6334
      Item_field *field= new Item_field(context,
                                        NullS, NullS, field_info->field_name);
6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353
      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;
6354
  Name_resolution_context *context= &sel->context;
6355 6356 6357 6358 6359

  if (!sel->item_list.elements)
  {
    ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
    String buffer(tmp,sizeof(tmp), system_charset_info);
6360 6361
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
6362 6363 6364 6365 6366 6367
    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())
    {
6368
      buffer.append(STRING_WITH_LEN(" ("));
6369
      buffer.append(lex->wild->ptr());
6370
      buffer.append(')');
6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382
    }
    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;
6383
  Name_resolution_context *context= &lex->select_lex.context;
6384 6385 6386 6387 6388 6389 6390

  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())
  {
6391
    buffer.append(STRING_WITH_LEN(" ("));
6392
    buffer.append(lex->wild->ptr());
6393
    buffer.append(')');
6394
  }
6395 6396
  Item_field *field= new Item_field(context,
                                    NullS, NullS, field_info->field_name);
6397 6398 6399 6400 6401 6402 6403
  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];
6404
    field= new Item_field(context, NullS, NullS, field_info->field_name);
6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415
    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)
{
6416 6417 6418
  int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1};
  int *field_num= fields_arr;
  ST_FIELD_INFO *field_info;
6419 6420
  Name_resolution_context *context= &thd->lex->select_lex.context;

6421
  for (; *field_num >= 0; field_num++)
6422
  {
6423 6424 6425 6426 6427
    field_info= &schema_table->fields_info[*field_num];
    if (!thd->lex->verbose && (*field_num == 13 ||
                               *field_num == 17 ||
                               *field_num == 18))
      continue;
6428 6429
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
6430
    if (field)
6431
    {
6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442
      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;
}


6443 6444 6445 6446 6447
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;
6448 6449
  Name_resolution_context *context= &thd->lex->select_lex.context;

6450 6451 6452
  for (; *field_num >= 0; field_num++)
  {
    field_info= &schema_table->fields_info[*field_num];
6453 6454
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467
    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;
}


6468 6469
int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
Sergey Glukhov's avatar
Sergey Glukhov committed
6470
  int fields_arr[]= {2, 3, 4, 26, 23, 22, 21, 25, 27, 28, 29, -1};
6471 6472
  int *field_num= fields_arr;
  ST_FIELD_INFO *field_info;
6473 6474
  Name_resolution_context *context= &thd->lex->select_lex.context;

6475 6476 6477
  for (; *field_num >= 0; field_num++)
  {
    field_info= &schema_table->fields_info[*field_num];
6478 6479
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
6480 6481 6482 6483 6484 6485 6486
    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;
6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510
    }
  }
  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");
6511
  if (!(table= table_list->schema_table->create_table(thd, table_list)))
6512
    DBUG_RETURN(1);
6513
  table->s->tmp_table= SYSTEM_TMP_TABLE;
6514
  table->grant.privilege= SELECT_ACL;
6515 6516 6517 6518 6519 6520 6521
  /*
    This test is necessary to make
    case insensitive file systems +
    upper case table names(information schema tables) +
    views
    working correctly
  */
6522 6523 6524 6525
  if (table_list->schema_table_name)
    table->alias_name_used= my_strcasecmp(table_alias_charset,
                                          table_list->schema_table_name,
                                          table_list->alias);
6526 6527
  table_list->table_name= table->s->table_name.str;
  table_list->table_name_length= table->s->table_name.length;
6528 6529 6530 6531
  table_list->table= table;
  table->next= thd->derived_tables;
  thd->derived_tables= table;
  table_list->select_lex->options |= OPTION_SCHEMA_TABLE;
6532
  lex->safe_to_cache_query= 0;
6533 6534 6535 6536 6537

  if (table_list->schema_table_reformed) // show command
  {
    SELECT_LEX *sel= lex->current_select;
    Item *item;
6538
    Field_translator *transl, *org_transl;
6539 6540 6541

    if (table_list->field_translation)
    {
6542
      Field_translator *end= table_list->field_translation_end;
6543 6544 6545
      for (transl= table_list->field_translation; transl < end; transl++)
      {
        if (!transl->item->fixed &&
6546
            transl->item->fix_fields(thd, &transl->item))
6547 6548 6549 6550 6551 6552
          DBUG_RETURN(1);
      }
      DBUG_RETURN(0);
    }
    List_iterator_fast<Item> it(sel->item_list);
    if (!(transl=
konstantin@mysql.com's avatar
konstantin@mysql.com committed
6553
          (Field_translator*)(thd->stmt_arena->
6554 6555 6556 6557 6558
                              alloc(sel->item_list.elements *
                                    sizeof(Field_translator)))))
    {
      DBUG_RETURN(1);
    }
6559
    for (org_transl= transl; (item= it++); transl++)
6560
    {
6561 6562 6563 6564
      transl->item= item;
      transl->name= item->name;
      if (!item->fixed && item->fix_fields(thd, &transl->item))
      {
6565
        DBUG_RETURN(1);
6566
      }
6567
    }
6568 6569
    table_list->field_translation= org_transl;
    table_list->field_translation_end= transl;
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
  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;
6595
  DBUG_ENTER("make_schema_select");
6596
  DBUG_PRINT("enter", ("mysql_schema_select: %s", schema_table->table_name));
6597
  /*
6598 6599 6600
     We have to make non const db_name & table_name
     because of lower_case_table_names
  */
6601 6602 6603 6604
  thd->make_lex_string(&db, INFORMATION_SCHEMA_NAME.str,
                       INFORMATION_SCHEMA_NAME.length, 0);
  thd->make_lex_string(&table, schema_table->table_name,
                       strlen(schema_table->table_name), 0);
6605
  if (schema_table->old_format(thd, schema_table) ||   /* Handle old syntax */
6606
      !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
6607
                              0, 0, TL_READ, MDL_SHARED_READ))
6608 6609 6610 6611 6612 6613 6614 6615
  {
    DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


/*
6616
  Fill temporary schema tables before SELECT
6617 6618 6619 6620

  SYNOPSIS
    get_schema_tables_result()
    join  join which use schema tables
6621
    executed_place place where I_S table processed
6622 6623

  RETURN
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
6624 6625
    FALSE success
    TRUE  error
6626 6627
*/

6628 6629
bool get_schema_tables_result(JOIN *join,
                              enum enum_schema_table_state executed_place)
6630 6631 6632
{
  JOIN_TAB *tmp_join_tab= join->join_tab+join->tables;
  THD *thd= join->thd;
6633 6634
  LEX *lex= thd->lex;
  bool result= 0;
6635 6636 6637
  DBUG_ENTER("get_schema_tables_result");

  thd->no_warnings_for_error= 1;
6638 6639 6640 6641
  for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
  {  
    if (!tab->table || !tab->table->pos_in_table_list)
      break;
6642

6643
    TABLE_LIST *table_list= tab->table->pos_in_table_list;
6644
    if (table_list->schema_table && thd->fill_information_schema_tables())
6645
    {
6646 6647
      bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
                          lex->current_select->master_unit()->item);
6648

6649 6650 6651
      /* A value of 0 indicates a dummy implementation */
      if (table_list->schema_table->fill_table == 0)
        continue;
6652 6653 6654 6655 6656 6657

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

6658
      /*
6659 6660 6661 6662 6663 6664 6665
        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.
6666
      */
6667 6668
      if (table_list->schema_table_state &&
          (!is_subselect || table_list->schema_table_state != executed_place))
6669 6670
        continue;

6671 6672 6673 6674 6675 6676
      /*
        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)
6677
      {
6678
        table_list->table->file->extra(HA_EXTRA_NO_CACHE);
6679
        table_list->table->file->extra(HA_EXTRA_RESET_STATE);
6680
        table_list->table->file->ha_delete_all_rows();
6681
        free_io_cache(table_list->table);
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
6682
        filesort_free_buffers(table_list->table,1);
6683
        table_list->table->null_row= 0;
6684 6685
      }
      else
6686
        table_list->table->file->stats.records= 0;
6687

6688 6689
      if (table_list->schema_table->fill_table(thd, table_list,
                                               tab->select_cond))
6690
      {
6691
        result= 1;
6692
        join->error= 1;
6693
        tab->read_record.file= table_list->table->file;
6694
        table_list->schema_table_state= executed_place;
6695 6696
        break;
      }
6697
      tab->read_record.file= table_list->table->file;
6698
      table_list->schema_table_state= executed_place;
6699 6700
    }
  }
6701
  thd->no_warnings_for_error= 0;
6702
  DBUG_RETURN(result);
6703 6704
}

6705
struct run_hton_fill_schema_table_args
6706 6707 6708 6709 6710
{
  TABLE_LIST *tables;
  COND *cond;
};

6711
static my_bool run_hton_fill_schema_table(THD *thd, plugin_ref plugin,
6712 6713
                                          void *arg)
{
6714 6715
  struct run_hton_fill_schema_table_args *args=
    (run_hton_fill_schema_table_args *) arg;
antony@ppcg5.local's avatar
antony@ppcg5.local committed
6716
  handlerton *hton= plugin_data(plugin, handlerton *);
6717 6718 6719
  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));
6720 6721 6722
  return false;
}

6723
int hton_fill_schema_table(THD *thd, TABLE_LIST *tables, COND *cond)
6724
{
6725
  DBUG_ENTER("hton_fill_schema_table");
6726

6727
  struct run_hton_fill_schema_table_args args;
6728 6729 6730
  args.tables= tables;
  args.cond= cond;

6731
  plugin_foreach(thd, run_hton_fill_schema_table,
6732 6733 6734 6735
                 MYSQL_STORAGE_ENGINE_PLUGIN, &args);

  DBUG_RETURN(0);
}
6736

6737

6738 6739
ST_FIELD_INFO schema_fields_info[]=
{
6740
  {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6741 6742
  {"SCHEMA_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
   SKIP_OPEN_TABLE},
6743 6744 6745
  {"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,
6746 6747 6748
   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}
6749 6750 6751 6752 6753
};


ST_FIELD_INFO tables_fields_info[]=
{
6754
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6755 6756 6757 6758 6759
  {"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},
6760
  {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6761 6762
   (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},
6763
  {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6764
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", OPEN_FULL_TABLE},
6765
  {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 
6766
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", OPEN_FULL_TABLE},
6767
  {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 
6768
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", OPEN_FULL_TABLE},
6769
  {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6770
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", OPEN_FULL_TABLE},
6771
  {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 
6772
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", OPEN_FULL_TABLE},
6773
  {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6774
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", OPEN_FULL_TABLE},
6775
  {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0, 
6776 6777 6778 6779
   (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},
6780 6781
  {"TABLE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
   OPEN_FRM_ONLY},
6782
  {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6783 6784 6785
   (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},
6786 6787
  {"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 
   "Comment", OPEN_FRM_ONLY},
6788
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6789 6790 6791 6792 6793
};


ST_FIELD_INFO columns_fields_info[]=
{
6794
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6795 6796 6797 6798
  {"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},
6799
  {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6800
   MY_I_S_UNSIGNED, 0, OPEN_FRM_ONLY},
6801
  {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0,
6802 6803 6804
   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},
6805
  {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
6806
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6807
  {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
6808
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6809
  {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
6810
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6811
  {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
6812
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6813 6814 6815 6816
  {"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},
6817 6818
  {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type", OPEN_FRM_ONLY},
  {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY},
6819
  {"EXTRA", 27, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
6820
  {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY},
6821 6822
  {"COLUMN_COMMENT", COLUMN_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 
   "Comment", OPEN_FRM_ONLY},
6823
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6824 6825 6826 6827 6828
};


ST_FIELD_INFO charsets_fields_info[]=
{
6829
  {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
6830
   SKIP_OPEN_TABLE},
6831 6832
  {"DEFAULT_COLLATE_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
   "Default collation", SKIP_OPEN_TABLE},
6833 6834 6835 6836
  {"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}
6837 6838 6839 6840 6841
};


ST_FIELD_INFO collation_fields_info[]=
{
6842 6843 6844
  {"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",
6845 6846 6847 6848 6849 6850 6851
   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}
6852 6853 6854
};


6855 6856
ST_FIELD_INFO engines_fields_info[]=
{
6857 6858 6859
  {"ENGINE", 64, MYSQL_TYPE_STRING, 0, 0, "Engine", SKIP_OPEN_TABLE},
  {"SUPPORT", 8, MYSQL_TYPE_STRING, 0, 0, "Support", SKIP_OPEN_TABLE},
  {"COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment", SKIP_OPEN_TABLE},
6860 6861 6862
  {"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},
6863
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6864 6865 6866
};


6867 6868
ST_FIELD_INFO events_fields_info[]=
{
6869
  {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883
  {"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},
  {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
  {"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},
6884
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6885 6886 6887 6888 6889 6890 6891 6892 6893
  {"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},
6894
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6895
   "character_set_client", SKIP_OPEN_TABLE},
6896
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6897
   "collation_connection", SKIP_OPEN_TABLE},
6898
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6899 6900
   "Database Collation", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6901 6902 6903 6904
};



6905 6906
ST_FIELD_INFO coll_charset_app_fields_info[]=
{
6907 6908 6909 6910
  {"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},
6911
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6912 6913 6914 6915 6916
};


ST_FIELD_INFO proc_fields_info[]=
{
6917
  {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6918
  {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6919 6920 6921 6922 6923
  {"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
6924 6925 6926 6927 6928 6929 6930 6931
  {"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},
  {"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},
6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945
  {"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},
6946
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6947
  {"ROUTINE_COMMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Comment",
6948 6949
   SKIP_OPEN_TABLE},
  {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
6950
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6951
   "character_set_client", SKIP_OPEN_TABLE},
6952
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6953
   "collation_connection", SKIP_OPEN_TABLE},
6954
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6955 6956
   "Database Collation", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6957 6958 6959 6960 6961
};


ST_FIELD_INFO stat_fields_info[]=
{
6962
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6963 6964 6965 6966 6967 6968 6969 6970 6971 6972
  {"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},
6973
  {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 1,
6974 6975 6976 6977 6978 6979
   "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},
6980 6981
  {"INDEX_COMMENT", INDEX_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 
   "Index_comment", OPEN_FRM_ONLY},
6982
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6983 6984 6985 6986 6987
};


ST_FIELD_INFO view_fields_info[]=
{
6988
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6989 6990
  {"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
6991 6992
  {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6993
  {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
Sergey Glukhov's avatar
Sergey Glukhov committed
6994 6995
  {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6996
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
6997
   OPEN_FRM_ONLY},
6998
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
6999
   OPEN_FRM_ONLY},
7000
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
7001 7002 7003 7004 7005
};


ST_FIELD_INFO user_privileges_fields_info[]=
{
7006
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7007
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7008 7009 7010
  {"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}
7011 7012 7013 7014 7015
};


ST_FIELD_INFO schema_privileges_fields_info[]=
{
7016
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7017
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7018 7019 7020 7021
  {"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}
7022 7023 7024 7025 7026
};


ST_FIELD_INFO table_privileges_fields_info[]=
{
7027
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7028
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7029 7030 7031 7032 7033
  {"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}
7034 7035 7036 7037 7038
};


ST_FIELD_INFO column_privileges_fields_info[]=
{
7039
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7040
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7041 7042 7043 7044 7045 7046
  {"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}
7047 7048 7049 7050 7051
};


ST_FIELD_INFO table_constraints_fields_info[]=
{
7052
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7053 7054 7055 7056 7057 7058 7059 7060 7061
  {"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}
7062 7063 7064 7065 7066
};


ST_FIELD_INFO key_column_usage_fields_info[]=
{
7067
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7068 7069 7070 7071
  {"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},
7072
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085
  {"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}
7086 7087 7088 7089 7090
};


ST_FIELD_INFO table_names_fields_info[]=
{
7091
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7092 7093 7094 7095 7096 7097
  {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Tables_in_",
   SKIP_OPEN_TABLE},
  {"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}
7098 7099 7100
};


7101 7102
ST_FIELD_INFO open_tables_fields_info[]=
{
7103 7104 7105 7106 7107 7108
  {"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}
7109 7110 7111
};


7112 7113
ST_FIELD_INFO triggers_fields_info[]=
{
Sergey Glukhov's avatar
Sergey Glukhov committed
7114 7115
  {"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},
7116
  {"TRIGGER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger",
Sergey Glukhov's avatar
Sergey Glukhov committed
7117 7118
   OPEN_FRM_ONLY},
  {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FRM_ONLY},
7119
  {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7120
   OPEN_FRM_ONLY},
7121
  {"EVENT_OBJECT_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7122
   OPEN_FRM_ONLY},
7123
  {"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table",
Sergey Glukhov's avatar
Sergey Glukhov committed
7124 7125 7126
   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},
7127
  {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement",
Sergey Glukhov's avatar
Sergey Glukhov committed
7128 7129 7130
   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},
7131
  {"ACTION_REFERENCE_OLD_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7132
   OPEN_FRM_ONLY},
7133
  {"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7134 7135 7136 7137 7138 7139
   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},
  {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FRM_ONLY},
7140
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7141
   "character_set_client", OPEN_FRM_ONLY},
7142
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7143
   "collation_connection", OPEN_FRM_ONLY},
7144
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7145
   "Database Collation", OPEN_FRM_ONLY},
7146
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
7147 7148 7149
};


7150 7151
ST_FIELD_INFO partitions_fields_info[]=
{
7152
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7153 7154 7155 7156 7157
  {"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},
7158
  {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
7159
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
7160
  {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
7161
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
7162
  {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173
  {"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},
7174
  {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
7175 7176 7177 7178 7179 7180 7181 7182
   (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},
7183
  {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
7184 7185 7186 7187 7188 7189
   (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}
7190 7191 7192
};


7193 7194
ST_FIELD_INFO variables_fields_info[]=
{
7195 7196
  {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name",
   SKIP_OPEN_TABLE},
7197
  {"VARIABLE_VALUE", 1024, MYSQL_TYPE_STRING, 0, 1, "Value", SKIP_OPEN_TABLE},
7198
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
7199 7200 7201
};


7202 7203
ST_FIELD_INFO processlist_fields_info[]=
{
7204 7205 7206 7207 7208 7209
  {"ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Id", SKIP_OPEN_TABLE},
  {"USER", 16, MYSQL_TYPE_STRING, 0, 0, "User", SKIP_OPEN_TABLE},
  {"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},
7210
  {"TIME", 7, MYSQL_TYPE_LONG, 0, 0, "Time", SKIP_OPEN_TABLE},
7211 7212 7213 7214
  {"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},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
7215 7216 7217
};


7218 7219
ST_FIELD_INFO plugin_fields_info[]=
{
7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231
  {"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},
  {"PLUGIN_STATUS", 10, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
  {"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},
  {"PLUGIN_LICENSE", 80, MYSQL_TYPE_STRING, 0, 1, "License", SKIP_OPEN_TABLE},
7232
  {"LOAD_OPTION", 64, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7233
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
7234 7235
};

7236 7237
ST_FIELD_INFO files_fields_info[]=
{
7238 7239 7240 7241 7242
  {"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},
7243
  {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255
  {"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},
7256
  {"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
7257
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
7258
  {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, 
7259
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
7260
  {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, 
7261 7262 7263 7264 7265 7266
   (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},
7267
  {"VERSION", 21 , MYSQL_TYPE_LONGLONG, 0,
7268 7269
   (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},
7270
  {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0,
7271
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", SKIP_OPEN_TABLE},
7272
  {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
7273
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", SKIP_OPEN_TABLE},
7274
  {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
7275
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", SKIP_OPEN_TABLE},
7276
  {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
7277
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", SKIP_OPEN_TABLE},
7278
  {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
7279
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", SKIP_OPEN_TABLE},
7280
  {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, 
7281 7282 7283 7284
   (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},
7285
  {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0, 
7286 7287 7288 7289
   (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}
7290
};
7291

7292 7293 7294 7295 7296 7297 7298 7299 7300 7301
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);
}

7302 7303
ST_FIELD_INFO referential_constraints_fields_info[]=
{
7304
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7305 7306 7307 7308
  {"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},
7309
  {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
7310 7311 7312
   OPEN_FULL_TABLE},
  {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
7313 7314
  {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0,
   MY_I_S_MAYBE_NULL, 0, OPEN_FULL_TABLE},
7315 7316 7317 7318 7319 7320 7321
  {"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}
7322 7323 7324
};


Sergey Glukhov's avatar
Sergey Glukhov committed
7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346
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},
  {"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}
};


7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369
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}
};


7370 7371
/*
  Description of ST_FIELD_INFO in table.h
7372 7373 7374

  Make sure that the order of schema_tables and enum_schema_tables are the same.

7375 7376 7377 7378 7379
*/

ST_SCHEMA_TABLE schema_tables[]=
{
  {"CHARACTER_SETS", charsets_fields_info, create_schema_table, 
7380
   fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0},
7381
  {"COLLATIONS", collation_fields_info, create_schema_table, 
7382
   fill_schema_collation, make_old_format, 0, -1, -1, 0, 0},
7383
  {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
7384
   create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0, 0},
7385
  {"COLUMNS", columns_fields_info, create_schema_table, 
7386
   get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0,
7387
   OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
7388
  {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
7389
   fill_schema_column_privileges, 0, 0, -1, -1, 0, 0},
7390
  {"ENGINES", engines_fields_info, create_schema_table,
7391
   fill_schema_engines, make_old_format, 0, -1, -1, 0, 0},
7392
#ifdef HAVE_EVENT_SCHEDULER
7393
  {"EVENTS", events_fields_info, create_schema_table,
7394
   Events::fill_schema_events, make_old_format, 0, -1, -1, 0, 0},
7395 7396 7397
#else
  {"EVENTS", events_fields_info, create_schema_table,
   0, make_old_format, 0, -1, -1, 0, 0},
7398
#endif
7399
  {"FILES", files_fields_info, create_schema_table,
7400
   hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
7401
  {"GLOBAL_STATUS", variables_fields_info, create_schema_table,
7402
   fill_status, make_old_format, 0, 0, -1, 0, 0},
7403
  {"GLOBAL_VARIABLES", variables_fields_info, create_schema_table,
7404
   fill_variables, make_old_format, 0, 0, -1, 0, 0},
7405
  {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
7406
   get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0,
7407
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
7408
  {"OPEN_TABLES", open_tables_fields_info, create_schema_table,
7409
   fill_open_tables, make_old_format, 0, -1, -1, 1, 0},
Sergey Glukhov's avatar
Sergey Glukhov committed
7410 7411
  {"PARAMETERS", parameters_fields_info, create_schema_table,
   fill_schema_proc, 0, 0, -1, -1, 0, 0},
7412
  {"PARTITIONS", partitions_fields_info, create_schema_table,
7413 7414
   get_all_tables, 0, get_schema_partitions_record, 1, 2, 0,
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
7415
  {"PLUGINS", plugin_fields_info, create_schema_table,
7416
   fill_plugins, make_old_format, 0, -1, -1, 0, 0},
7417
  {"PROCESSLIST", processlist_fields_info, create_schema_table,
7418
   fill_schema_processlist, make_old_format, 0, -1, -1, 0, 0},
7419
  {"PROFILING", query_profile_statistics_info, create_schema_table,
7420 7421
    fill_query_profile_statistics_info, make_profile_table_for_show, 
    NULL, -1, -1, false, 0},
7422 7423
  {"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info,
   create_schema_table, get_all_tables, 0, get_referential_constraints_record,
7424
   1, 9, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
7425
  {"ROUTINES", proc_fields_info, create_schema_table, 
7426
   fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0},
7427
  {"SCHEMATA", schema_fields_info, create_schema_table,
7428
   fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0},
7429
  {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table,
7430
   fill_schema_schema_privileges, 0, 0, -1, -1, 0, 0},
7431
  {"SESSION_STATUS", variables_fields_info, create_schema_table,
7432
   fill_status, make_old_format, 0, 0, -1, 0, 0},
7433
  {"SESSION_VARIABLES", variables_fields_info, create_schema_table,
7434
   fill_variables, make_old_format, 0, 0, -1, 0, 0},
7435
  {"STATISTICS", stat_fields_info, create_schema_table, 
7436
   get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0,
7437
   OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
7438
  {"STATUS", variables_fields_info, create_schema_table, fill_status, 
7439
   make_old_format, 0, 0, -1, 1, 0},
7440
  {"TABLES", tables_fields_info, create_schema_table, 
7441 7442
   get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0,
   OPTIMIZE_I_S_TABLE},
7443 7444
  {"TABLESPACES", tablespaces_fields_info, create_schema_table,
   hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
7445
  {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table,
7446 7447
   get_all_tables, 0, get_schema_constraints_record, 3, 4, 0,
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
7448
  {"TABLE_NAMES", table_names_fields_info, create_schema_table,
7449
   get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0},
7450
  {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
7451
   fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
7452
  {"TRIGGERS", triggers_fields_info, create_schema_table,
7453
   get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7454
   OPEN_TRIGGER_ONLY|OPTIMIZE_I_S_TABLE},
7455
  {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, 
7456
   fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
7457
  {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
7458
   make_old_format, 0, 0, -1, 1, 0},
7459
  {"VIEWS", view_fields_info, create_schema_table, 
7460 7461 7462
   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}
7463 7464 7465
};


7466
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
7467
template class List_iterator_fast<char>;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
7468 7469
template class List<char>;
#endif
brian@zim.(none)'s avatar
brian@zim.(none) committed
7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487

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),
                                MYF(MY_WME | MY_ZEROFILL))))
      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;
    schema_table->idx_field1= -1, 
    schema_table->idx_field2= -1; 

7488
    /* Make the name available to the init() function. */
7489
    schema_table->table_name= plugin->name.str;
brian@zim.(none)'s avatar
brian@zim.(none) committed
7490 7491 7492 7493 7494

    if (plugin->plugin->init(schema_table))
    {
      sql_print_error("Plugin '%s' init function returned error.",
                      plugin->name.str);
7495
      plugin->data= NULL;
7496
      my_free(schema_table);
7497
      DBUG_RETURN(1);
brian@zim.(none)'s avatar
brian@zim.(none) committed
7498
    }
7499 7500
    
    /* Make sure the plugin name is not set inside the init() function. */
brian@zim.(none)'s avatar
brian@zim.(none) committed
7501 7502 7503 7504 7505 7506 7507 7508 7509 7510
    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");

7511
  if (schema_table)
brian@zim.(none)'s avatar
brian@zim.(none) committed
7512
  {
7513
    if (plugin->plugin->deinit)
brian@zim.(none)'s avatar
brian@zim.(none) committed
7514
    {
7515 7516 7517 7518 7519 7520
      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));
      }
brian@zim.(none)'s avatar
brian@zim.(none) committed
7521
    }
7522
    my_free(schema_table);
brian@zim.(none)'s avatar
brian@zim.(none) committed
7523 7524 7525
  }
  DBUG_RETURN(0);
}
7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556


/**
  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;

7557 7558
  CHARSET_INFO *trg_client_cs;

7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579
  /*
    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);

7580
  sql_mode_string_representation(thd, trg_sql_mode, &trg_sql_mode_str);
7581

7582 7583 7584 7585 7586
  /* Resolve trigger client character set. */

  if (resolve_charset(trg_client_cs_name.str, NULL, &trg_client_cs))
    return TRUE;

7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615
  /* 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));

7616
  if (p->send_result_set_metadata(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632
    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,
7633
           trg_client_cs);
7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649

  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)
7650
    my_eof(thd);
7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679

  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
7680
static
7681
TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
7682 7683 7684
{
  char trn_path_buff[FN_REFLEN];
  LEX_STRING trn_path= { trn_path_buff, 0 };
Konstantin Osipov's avatar
Konstantin Osipov committed
7685
  LEX_STRING db;
7686
  LEX_STRING tbl_name;
Konstantin Osipov's avatar
Konstantin Osipov committed
7687
  TABLE_LIST *table;
7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700

  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
7701
  if (!(table= (TABLE_LIST*) thd->alloc(sizeof(TABLE_LIST))))
7702 7703
    return NULL;

Konstantin Osipov's avatar
Konstantin Osipov committed
7704
  db= trg_name->m_db;
7705

Konstantin Osipov's avatar
Konstantin Osipov committed
7706 7707
  db.str= thd->strmake(db.str, db.length);
  tbl_name.str= thd->strmake(tbl_name.str, tbl_name.length);
7708

Konstantin Osipov's avatar
Konstantin Osipov committed
7709 7710
  if (db.str == NULL || tbl_name.str == NULL)
    return NULL;
7711

Konstantin Osipov's avatar
Konstantin Osipov committed
7712 7713
  table->init_one_table(db.str, db.length, tbl_name.str, tbl_name.length,
                        tbl_name.str, TL_IGNORE);
7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732

  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);
7733 7734 7735 7736
  uint num_tables; /* NOTE: unused, only to pass to open_tables(). */
  Table_triggers_list *triggers;
  int trigger_idx;
  bool error= TRUE;
7737

7738 7739 7740
  if (!lst)
    return TRUE;

7741
  if (check_table_access(thd, TRIGGER_ACL, lst, FALSE, 1, TRUE))
7742 7743 7744 7745 7746
  {
    my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "TRIGGER");
    return TRUE;
  }

7747
  /*
7748 7749
    Metadata locks taken during SHOW CREATE TRIGGER should be released when
    the statement completes as it is an information statement.
7750
  */
7751
  MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
7752

7753 7754 7755 7756 7757
  /*
    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))
7758 7759 7760 7761 7762
  {
    my_error(ER_TRG_CANT_OPEN_TABLE, MYF(0),
             (const char *) trg_name->m_db.str,
             (const char *) lst->table_name);

7763
    goto exit;
7764 7765 7766 7767

    /* Perform closing actions and return error status. */
  }

7768
  triggers= lst->table->triggers;
7769 7770 7771 7772

  if (!triggers)
  {
    my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
7773
    goto exit;
7774 7775
  }

7776
  trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name);
7777 7778 7779 7780 7781 7782 7783

  if (trigger_idx < 0)
  {
    my_error(ER_TRG_CORRUPTED_FILE, MYF(0),
             (const char *) trg_name->m_db.str,
             (const char *) lst->table_name);

7784
    goto exit;
7785 7786
  }

7787
  error= show_create_trigger_impl(thd, triggers, trigger_idx);
7788 7789 7790 7791 7792 7793

  /*
    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.
  */
7794 7795 7796 7797 7798 7799

exit:
  close_thread_tables(thd);
  /* Release any metadata locks taken during SHOW CREATE TRIGGER. */
  thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
  return error;
7800
}
7801

Marc Alff's avatar
Marc Alff committed
7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851
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
7852
#ifdef WITH_PARTITION_STORAGE_ENGINE
7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 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 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943
/*
  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
7944
#endif