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

unknown's avatar
unknown 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
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
6

unknown's avatar
unknown 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

unknown's avatar
unknown 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 */
unknown's avatar
unknown 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 38
#include "sql_view.h"                           // mysql_frm_type
#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
39
#include "sp.h"
40
#include "sp_head.h"
Sergey Glukhov's avatar
Sergey Glukhov committed
41
#include "sp_pcontext.h"
42
#include "set_var.h"
43
#include "sql_trigger.h"
unknown's avatar
unknown committed
44
#include "authors.h"
45
#include "contributors.h"
46
#include "sql_partition.h"
47
#ifdef HAVE_EVENT_SCHEDULER
48
#include "events.h"
49
#include "event_data_objects.h"
50
#endif
unknown's avatar
unknown committed
51
#include <my_dir.h>
52
#include "lock.h"                           // MYSQL_LOCK_IGNORE_FLUSH
unknown's avatar
unknown committed
53

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

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

87
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
88 89 90 91 92
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 **),
93
                               "grant_types",
94
                               grant_names, NULL};
unknown's avatar
unknown committed
95
#endif
unknown's avatar
unknown committed
96

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

100 101 102 103 104 105
static void get_cs_converted_string_value(THD *thd,
                                          String *input_str,
                                          String *output_str,
                                          CHARSET_INFO *cs,
                                          bool use_hex);

106 107
static void
append_algorithm(TABLE_LIST *table, String *buff);
108

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

unknown's avatar
unknown committed
111
/***************************************************************************
unknown's avatar
unknown committed
112
** List all table types supported
unknown's avatar
unknown committed
113 114
***************************************************************************/

unknown's avatar
unknown committed
115 116
static int make_version_string(char *buf, int buf_length, uint version)
{
unknown's avatar
unknown committed
117
  return my_snprintf(buf, buf_length, "%d.%d", version>>8,version&0xff);
unknown's avatar
unknown committed
118 119
}

unknown's avatar
unknown committed
120
static my_bool show_plugins(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
121 122 123
                            void *arg)
{
  TABLE *table= (TABLE*) arg;
unknown's avatar
unknown committed
124 125
  struct st_mysql_plugin *plug= plugin_decl(plugin);
  struct st_plugin_dl *plugin_dl= plugin_dlib(plugin);
unknown's avatar
unknown committed
126 127 128 129 130
  CHARSET_INFO *cs= system_charset_info;
  char version_buf[20];

  restore_record(table, s->default_values);

unknown's avatar
unknown committed
131 132
  table->field[0]->store(plugin_name(plugin)->str,
                         plugin_name(plugin)->length, cs);
unknown's avatar
unknown committed
133 134 135 136 137

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

unknown's avatar
fixes  
unknown committed
138

unknown's avatar
unknown committed
139
  switch (plugin_state(plugin)) {
unknown's avatar
unknown committed
140 141
  /* case PLUGIN_IS_FREED: does not happen */
  case PLUGIN_IS_DELETED:
unknown's avatar
unknown committed
142
    table->field[2]->store(STRING_WITH_LEN("DELETED"), cs);
unknown's avatar
unknown committed
143 144
    break;
  case PLUGIN_IS_UNINITIALIZED:
unknown's avatar
unknown committed
145
    table->field[2]->store(STRING_WITH_LEN("INACTIVE"), cs);
unknown's avatar
unknown committed
146 147
    break;
  case PLUGIN_IS_READY:
unknown's avatar
unknown committed
148
    table->field[2]->store(STRING_WITH_LEN("ACTIVE"), cs);
unknown's avatar
unknown committed
149
    break;
150 151 152
  case PLUGIN_IS_DISABLED:
    table->field[2]->store(STRING_WITH_LEN("DISABLED"), cs);
    break;
unknown's avatar
unknown committed
153 154 155 156
  default:
    DBUG_ASSERT(0);
  }

unknown's avatar
unknown committed
157 158 159
  table->field[3]->store(plugin_type_names[plug->type].str,
                         plugin_type_names[plug->type].length,
                         cs);
unknown's avatar
unknown committed
160
  table->field[4]->store(version_buf,
unknown's avatar
unknown committed
161
        make_version_string(version_buf, sizeof(version_buf),
unknown's avatar
unknown committed
162
                            *(uint *)plug->info), cs);
unknown's avatar
unknown committed
163

unknown's avatar
unknown committed
164
  if (plugin_dl)
unknown's avatar
unknown committed
165
  {
unknown's avatar
unknown committed
166
    table->field[5]->store(plugin_dl->dl.str, plugin_dl->dl.length, cs);
unknown's avatar
unknown committed
167
    table->field[5]->set_notnull();
unknown's avatar
unknown committed
168
    table->field[6]->store(version_buf,
unknown's avatar
unknown committed
169
          make_version_string(version_buf, sizeof(version_buf),
unknown's avatar
unknown committed
170
                              plugin_dl->version),
unknown's avatar
unknown committed
171 172
          cs);
    table->field[6]->set_notnull();
unknown's avatar
unknown committed
173 174
  }
  else
unknown's avatar
unknown committed
175
  {
unknown's avatar
unknown committed
176
    table->field[5]->set_null();
unknown's avatar
unknown committed
177 178 179 180
    table->field[6]->set_null();
  }


unknown's avatar
unknown committed
181 182
  if (plug->author)
  {
unknown's avatar
unknown committed
183 184
    table->field[7]->store(plug->author, strlen(plug->author), cs);
    table->field[7]->set_notnull();
unknown's avatar
unknown committed
185 186
  }
  else
unknown's avatar
unknown committed
187
    table->field[7]->set_null();
unknown's avatar
unknown committed
188 189 190

  if (plug->descr)
  {
unknown's avatar
unknown committed
191 192
    table->field[8]->store(plug->descr, strlen(plug->descr), cs);
    table->field[8]->set_notnull();
unknown's avatar
unknown committed
193 194
  }
  else
unknown's avatar
unknown committed
195
    table->field[8]->set_null();
unknown's avatar
unknown committed
196

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
  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();

unknown's avatar
unknown committed
213 214 215 216 217 218 219 220 221
  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;

222 223
  if (plugin_foreach_with_mask(thd, show_plugins, MYSQL_ANY_PLUGIN,
                               ~PLUGIN_IS_FREED, table))
unknown's avatar
unknown committed
224
    DBUG_RETURN(1);
225

unknown's avatar
unknown committed
226 227 228 229
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
/***************************************************************************
** 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));

245
  if (protocol->send_result_set_metadata(&field_list,
unknown's avatar
unknown committed
246 247 248 249 250 251 252 253 254 255 256 257 258
                            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);
  }
259
  my_eof(thd);
unknown's avatar
unknown committed
260 261
  DBUG_RETURN(FALSE);
}
262

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278

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

279
  if (protocol->send_result_set_metadata(&field_list,
280 281 282 283 284 285 286 287 288 289 290 291 292
                            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);
  }
293
  my_eof(thd);
294 295 296 297
  DBUG_RETURN(FALSE);
}


unknown's avatar
unknown committed
298
/***************************************************************************
299
 List all privileges supported
unknown's avatar
unknown committed
300 301
***************************************************************************/

302 303 304 305
struct show_privileges_st {
  const char *privilege;
  const char *context;
  const char *comment;
unknown's avatar
unknown committed
306 307
};

308 309
static struct show_privileges_st sys_privileges[]=
{
unknown's avatar
unknown committed
310
  {"Alter", "Tables",  "To alter the table"},
311
  {"Alter routine", "Functions,Procedures",  "To alter or drop stored functions/procedures"},
312
  {"Create", "Databases,Tables,Indexes",  "To create new databases and tables"},
313
  {"Create routine","Databases","To use CREATE FUNCTION/PROCEDURE"},
unknown's avatar
unknown committed
314 315
  {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
  {"Create view", "Tables",  "To create new views"},
316
  {"Create user", "Server Admin",  "To create new users"},
unknown's avatar
unknown committed
317
  {"Delete", "Tables",  "To delete existing rows"},
unknown's avatar
unknown committed
318
  {"Drop", "Databases,Tables", "To drop databases, tables, and views"},
319
#ifdef HAVE_EVENT_SCHEDULER
320
  {"Event","Server Admin","To create, alter, drop and execute events"},
321
#endif
322
  {"Execute", "Functions,Procedures", "To execute stored routines"},
unknown's avatar
unknown committed
323
  {"File", "File access on server",   "To read and write files on the server"},
324
  {"Grant option",  "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"},
unknown's avatar
unknown committed
325 326 327 328
  {"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"},
329
  {"References", "Databases,Tables", "To have references on tables"},
unknown's avatar
unknown committed
330 331 332 333 334
  {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
  {"Replication client","Server Admin","To ask where the slave or master servers are"},
  {"Replication slave","Server Admin","To read binary log events from the master"},
  {"Select", "Tables",  "To retrieve rows from table"},
  {"Show databases","Server Admin","To see all databases with SHOW DATABASES"},
unknown's avatar
unknown committed
335 336
  {"Show view","Tables","To see views with SHOW CREATE VIEW"},
  {"Shutdown","Server Admin", "To shut down the server"},
unknown's avatar
unknown committed
337
  {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
338
  {"Trigger","Tables", "To use triggers"},
339
  {"Create tablespace", "Server Admin", "To create/alter/drop tablespaces"},
unknown's avatar
unknown committed
340 341
  {"Update", "Tables",  "To update existing rows"},
  {"Usage","Server Admin","No privileges - allow connect only"},
342 343 344
  {NullS, NullS, NullS}
};

unknown's avatar
unknown committed
345
bool mysqld_show_privileges(THD *thd)
unknown's avatar
unknown committed
346 347
{
  List<Item> field_list;
348
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
349 350 351 352
  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));
353
  field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
unknown's avatar
unknown committed
354

355
  if (protocol->send_result_set_metadata(&field_list,
356
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
357
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
358

359 360
  show_privileges_st *privilege= sys_privileges;
  for (privilege= sys_privileges; privilege->privilege ; privilege++)
unknown's avatar
unknown committed
361
  {
362
    protocol->prepare_for_resend();
363 364 365
    protocol->store(privilege->privilege, system_charset_info);
    protocol->store(privilege->context, system_charset_info);
    protocol->store(privilege->comment, system_charset_info);
366
    if (protocol->write())
unknown's avatar
unknown committed
367
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
368
  }
369
  my_eof(thd);
unknown's avatar
unknown committed
370
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
371 372 373
}


374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
/*
  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
395
find_files(THD *thd, List<LEX_STRING> *files, const char *db,
396
           const char *path, const char *wild, bool dir)
unknown's avatar
unknown committed
397 398 399 400 401
{
  uint i;
  char *ext;
  MY_DIR *dirp;
  FILEINFO *file;
402 403
  LEX_STRING *file_name= 0;
  uint file_name_len;
unknown's avatar
unknown committed
404
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
405
  uint col_access=thd->col_access;
unknown's avatar
unknown committed
406
#endif
407
  uint wild_length= 0;
unknown's avatar
unknown committed
408
  TABLE_LIST table_list;
409
  DBUG_ENTER("find_files");
unknown's avatar
unknown committed
410

411 412 413 414 415 416 417 418
  if (wild)
  {
    if (!wild[0])
      wild= 0;
    else
      wild_length= strlen(wild);
  }

419 420


unknown's avatar
unknown committed
421 422
  bzero((char*) &table_list,sizeof(table_list));

423 424 425 426 427 428
  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);
429
    DBUG_RETURN(FIND_FILES_DIR);
430
  }
unknown's avatar
unknown committed
431

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

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

Konstantin Osipov's avatar
Konstantin Osipov committed
517
  (void) ha_find_files(thd, db, path, wild, dir, files);
unknown's avatar
unknown committed
518

519
  DBUG_RETURN(FIND_FILES_OK);
unknown's avatar
unknown committed
520 521
}

522

523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
/**
   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;
  }

586 587 588 589
  bool handle_condition(THD *thd, uint sql_errno, const char */* sqlstate */,
                        MYSQL_ERROR::enum_warning_level level,
                        const char *message, MYSQL_ERROR **/* cond_hdl */)
  {
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 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
    /* 
       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;
    
    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;
  }
};


unknown's avatar
unknown committed
645
bool
unknown's avatar
unknown committed
646 647
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
648 649 650
  Protocol *protocol= thd->protocol;
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
unknown's avatar
unknown committed
651 652
  DBUG_ENTER("mysqld_show_create");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
653
                      table_list->table_name));
unknown's avatar
unknown committed
654

655 656 657
  /* We want to preserve the tree for views. */
  thd->lex->view_prepare_mode= TRUE;

658
  {
659 660
    Show_create_error_handler view_error_suppressor(thd, table_list);
    thd->push_internal_handler(&view_error_suppressor);
661 662 663
    bool error=
      open_normal_and_derived_tables(thd, table_list,
                                     MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL);
664
    thd->pop_internal_handler();
665
    if (error && (thd->killed || thd->is_error()))
666 667
      DBUG_RETURN(TRUE);
  }
668

unknown's avatar
VIEW  
unknown committed
669 670 671
  /* TODO: add environment variables show when it become possible */
  if (thd->lex->only_view && !table_list->view)
  {
672
    my_error(ER_WRONG_OBJECT, MYF(0),
673
             table_list->db, table_list->table_name, "VIEW");
unknown's avatar
unknown committed
674
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
675
  }
unknown's avatar
unknown committed
676

677
  buffer.length(0);
unknown's avatar
unknown committed
678 679 680 681

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

unknown's avatar
VIEW  
unknown committed
682 683
  if ((table_list->view ?
       view_store_create_info(thd, table_list, &buffer) :
684 685
       store_create_info(thd, table_list, &buffer, NULL,
                         FALSE /* show_database */)))
unknown's avatar
unknown committed
686
    DBUG_RETURN(TRUE);
687

unknown's avatar
unknown committed
688
  List<Item> field_list;
unknown's avatar
unknown committed
689 690
  if (table_list->view)
  {
691
    field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN));
unknown's avatar
unknown committed
692 693
    field_list.push_back(new Item_empty_string("Create View",
                                               max(buffer.length(),1024)));
unknown's avatar
unknown committed
694 695 696 697
    field_list.push_back(new Item_empty_string("character_set_client",
                                               MY_CS_NAME_SIZE));
    field_list.push_back(new Item_empty_string("collation_connection",
                                               MY_CS_NAME_SIZE));
unknown's avatar
unknown committed
698 699 700
  }
  else
  {
701
    field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
unknown's avatar
unknown committed
702 703 704 705
    // 1024 is for not to confuse old clients
    field_list.push_back(new Item_empty_string("Create Table",
                                               max(buffer.length(),1024)));
  }
unknown's avatar
unknown committed
706

707
  if (protocol->send_result_set_metadata(&field_list,
708
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
709
    DBUG_RETURN(TRUE);
710
  protocol->prepare_for_resend();
unknown's avatar
VIEW  
unknown committed
711 712 713 714
  if (table_list->view)
    protocol->store(table_list->view_name.str, system_charset_info);
  else
  {
unknown's avatar
unknown committed
715
    if (table_list->schema_table)
716 717
      protocol->store(table_list->schema_table->table_name,
                      system_charset_info);
unknown's avatar
unknown committed
718
    else
719
      protocol->store(table_list->table->alias, system_charset_info);
unknown's avatar
VIEW  
unknown committed
720
  }
unknown's avatar
unknown committed
721 722 723

  if (table_list->view)
  {
724 725
    protocol->store(buffer.ptr(), buffer.length(),
                    table_list->view_creation_ctx->get_client_cs());
unknown's avatar
unknown committed
726 727 728 729 730 731 732 733 734

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

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

736
  if (protocol->write())
unknown's avatar
unknown committed
737
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
738

739
  my_eof(thd);
unknown's avatar
unknown committed
740
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
741 742
}

unknown's avatar
unknown committed
743 744
bool mysqld_show_create_db(THD *thd, char *dbname,
                           HA_CREATE_INFO *create_info)
745 746 747
{
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
unknown's avatar
unknown committed
748
#ifndef NO_EMBEDDED_ACCESS_CHECKS
749
  Security_context *sctx= thd->security_ctx;
750
  uint db_access;
unknown's avatar
unknown committed
751
#endif
752 753 754 755 756 757
  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
758
  if (test_all_bits(sctx->master_access, DB_ACLS))
759 760
    db_access=DB_ACLS;
  else
761 762
    db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
		sctx->master_access);
763
  if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname))
764
  {
765
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
766
             sctx->priv_user, sctx->host_or_ip, dbname);
767 768
    general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
                      sctx->priv_user, sctx->host_or_ip, dbname);
unknown's avatar
unknown committed
769
    DBUG_RETURN(TRUE);
770 771
  }
#endif
772
  if (is_infoschema_db(dbname))
773
  {
774
    dbname= INFORMATION_SCHEMA_NAME.str;
775
    create.default_table_charset= system_charset_info;
776
  }
777
  else
778
  {
779
    if (check_db_dir_existence(dbname))
780 781 782 783
    {
      my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
      DBUG_RETURN(TRUE);
    }
784 785

    load_db_opt_by_name(thd, dbname, &create);
786 787
  }
  List<Item> field_list;
788
  field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
789 790
  field_list.push_back(new Item_empty_string("Create Database",1024));

791
  if (protocol->send_result_set_metadata(&field_list,
792
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
793
    DBUG_RETURN(TRUE);
794 795 796 797

  protocol->prepare_for_resend();
  protocol->store(dbname, strlen(dbname), system_charset_info);
  buffer.length(0);
798
  buffer.append(STRING_WITH_LEN("CREATE DATABASE "));
799
  if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
800
    buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ "));
801 802 803 804
  append_identifier(thd, &buffer, dbname, strlen(dbname));

  if (create.default_table_charset)
  {
805 806
    buffer.append(STRING_WITH_LEN(" /*!40100"));
    buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET "));
807 808 809
    buffer.append(create.default_table_charset->csname);
    if (!(create.default_table_charset->state & MY_CS_PRIMARY))
    {
810
      buffer.append(STRING_WITH_LEN(" COLLATE "));
811 812
      buffer.append(create.default_table_charset->name);
    }
813
    buffer.append(STRING_WITH_LEN(" */"));
814 815 816 817
  }
  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());

  if (protocol->write())
unknown's avatar
unknown committed
818
    DBUG_RETURN(TRUE);
819
  my_eof(thd);
unknown's avatar
unknown committed
820
  DBUG_RETURN(FALSE);
821
}
unknown's avatar
unknown committed
822

unknown's avatar
unknown committed
823 824


unknown's avatar
unknown committed
825
/****************************************************************************
826 827
  Return only fields for API mysql_list_fields
  Use "show table wildcard" in mysql instead of this
unknown's avatar
unknown committed
828 829 830 831 832 833 834
****************************************************************************/

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

837 838
  if (open_normal_and_derived_tables(thd, table_list,
                                     MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
unknown's avatar
unknown committed
839
    DBUG_VOID_RETURN;
840 841
  table= table_list->table;

unknown's avatar
unknown committed
842 843 844 845 846
  List<Item> field_list;

  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
847 848
    if (!wild || !wild[0] || 
        !wild_case_compare(system_charset_info, field->field_name,wild))
849 850 851 852 853 854 855 856
    {
      if (table_list->view)
        field_list.push_back(new Item_ident_for_show(field,
                                                     table_list->view_db.str,
                                                     table_list->view_name.str));
      else
        field_list.push_back(new Item_field(field));
    }
unknown's avatar
unknown committed
857
  }
858
  restore_record(table, s->default_values);              // Get empty record
859
  table->use_all_columns();
860
  if (thd->protocol->send_result_set_metadata(&field_list, Protocol::SEND_DEFAULTS))
unknown's avatar
unknown committed
861
    DBUG_VOID_RETURN;
862
  my_eof(thd);
unknown's avatar
unknown committed
863 864 865
  DBUG_VOID_RETURN;
}

866
/*
867
  Go through all character combinations and ensure that sql_lex.cc can
868
  parse it as an identifier.
869 870

  SYNOPSIS
871 872 873 874 875 876 877
  require_quotes()
  name			attribute name
  name_length		length of name

  RETURN
    #	Pointer to conflicting character
    0	No conflicting character
878 879
*/

880
static const char *require_quotes(const char *name, uint name_length)
881
{
882
  uint length;
883
  bool pure_digit= TRUE;
884 885
  const char *end= name + name_length;

886
  for (; name < end ; name++)
887
  {
888 889 890 891
    uchar chr= (uchar) *name;
    length= my_mbcharlen(system_charset_info, chr);
    if (length == 1 && !system_charset_info->ident_map[chr])
      return name;
892 893
    if (length == 1 && (chr < '0' || chr > '9'))
      pure_digit= FALSE;
894
  }
895 896
  if (pure_digit)
    return name;
897 898
  return 0;
}
899

900

901 902 903 904 905 906 907 908 909 910 911 912
/*
  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
*/

913 914
void
append_identifier(THD *thd, String *packet, const char *name, uint length)
915
{
916 917
  const char *name_end;
  char quote_char;
918
  int q= get_quote_char_for_identifier(thd, name, length);
919

920
  if (q == EOF)
921
  {
unknown's avatar
unknown committed
922
    packet->append(name, length, packet->charset());
923 924 925
    return;
  }

926 927 928 929
  /*
    The identifier must be quoted as it includes a quote character or
   it's a keyword
  */
930

Konstantin Osipov's avatar
Konstantin Osipov committed
931
  (void) packet->reserve(length*2 + 2);
932
  quote_char= (char) q;
933 934 935 936
  packet->append(&quote_char, 1, system_charset_info);

  for (name_end= name+length ; name < name_end ; name+= length)
  {
937
    uchar chr= (uchar) *name;
938
    length= my_mbcharlen(system_charset_info, chr);
939
    /*
unknown's avatar
unknown committed
940
      my_mbcharlen can return 0 on a wrong multibyte
941 942 943 944 945 946 947
      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;
948
    if (length == 1 && chr == (uchar) quote_char)
949
      packet->append(&quote_char, 1, system_charset_info);
unknown's avatar
unknown committed
950
    packet->append(name, length, system_charset_info);
951
  }
952
  packet->append(&quote_char, 1, system_charset_info);
953 954
}

955

956 957 958 959 960 961 962 963 964 965
/*
  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
966 967 968 969 970
    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;
971 972 973 974 975 976 977
    Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE
    is set.

  RETURN
    EOF	  No quote character is needed
    #	  Quote character
*/
978 979 980

int get_quote_char_for_identifier(THD *thd, const char *name, uint length)
{
unknown's avatar
unknown committed
981
  if (length &&
982
      !is_keyword(name,length) &&
983
      !require_quotes(name, length) &&
984
      !(thd->variables.option_bits & OPTION_QUOTE_SHOW_CREATE))
985
    return EOF;
986
  if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
987
    return '"';
988
  return '`';
989 990 991
}


992 993 994 995 996
/* Append directory name (if exists) to CREATE INFO */

static void append_directory(THD *thd, String *packet, const char *dir_type,
			     const char *filename)
{
unknown's avatar
unknown committed
997
  if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
998
  {
999
    uint length= dirname_length(filename);
1000 1001
    packet->append(' ');
    packet->append(dir_type);
1002
    packet->append(STRING_WITH_LEN(" DIRECTORY='"));
1003
#ifdef __WIN__
unknown's avatar
unknown committed
1004 1005 1006 1007 1008 1009 1010 1011 1012
    /* 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;
1013
#endif
unknown's avatar
unknown committed
1014
    packet->append(filename, length);
1015 1016 1017 1018 1019
    packet->append('\'');
  }
}


unknown's avatar
unknown committed
1020
#define LIST_PROCESS_HOST_LEN 64
1021

Sergey Glukhov's avatar
Sergey Glukhov committed
1022
static bool get_field_default_value(THD *thd, Field *timestamp_field,
1023 1024 1025 1026 1027
                                    Field *field, String *def_value,
                                    bool quoted)
{
  bool has_default;
  bool has_now_default;
1028
  enum enum_field_types field_type= field->type();
Sergey Glukhov's avatar
Sergey Glukhov committed
1029 1030

  /*
1031 1032 1033
     We are using CURRENT_TIMESTAMP instead of NOW because it is
     more standard
  */
Sergey Glukhov's avatar
Sergey Glukhov committed
1034 1035 1036
  has_now_default= (timestamp_field == field &&
                    field->unireg_check != Field::TIMESTAMP_UN_FIELD);

1037
  has_default= (field_type != FIELD_TYPE_BLOB &&
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
                !(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());
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
      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);
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
      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
1089

1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
/*
  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.
1104
  
1105 1106 1107
  NOTE
    Currently always return 0, but might return error code in the
    future.
1108
    
1109 1110 1111
  RETURN
    0       OK
 */
1112 1113

int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
1114
                      HA_CREATE_INFO *create_info_arg, bool show_database)
unknown's avatar
unknown committed
1115
{
1116
  List<Item> field_list;
1117
  char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH];
1118
  const char *alias;
1119
  String type(tmp, sizeof(tmp), system_charset_info);
1120
  String def_value(def_value_buf, sizeof(def_value_buf), system_charset_info);
1121 1122 1123
  Field **ptr,*field;
  uint primary_key;
  KEY *key_info;
unknown's avatar
unknown committed
1124
  TABLE *table= table_list->table;
1125
  handler *file= table->file;
1126
  TABLE_SHARE *share= table->s;
1127
  HA_CREATE_INFO create_info;
1128
  bool show_table_options= FALSE;
1129 1130 1131 1132 1133 1134
  bool foreign_db_mode=  (thd->variables.sql_mode & (MODE_POSTGRESQL |
                                                     MODE_ORACLE |
                                                     MODE_MSSQL |
                                                     MODE_DB2 |
                                                     MODE_MAXDB |
                                                     MODE_ANSI)) != 0;
unknown's avatar
unknown committed
1135 1136 1137
  bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS |
                                                       MODE_MYSQL323 |
                                                       MODE_MYSQL40)) != 0;
1138
  my_bitmap_map *old_map;
unknown's avatar
unknown committed
1139
  DBUG_ENTER("store_create_info");
unknown's avatar
unknown committed
1140
  DBUG_PRINT("enter",("table: %s", table->s->table_name.str));
unknown's avatar
unknown committed
1141

1142
  restore_record(table, s->default_values); // Get empty record
1143

1144
  if (share->tmp_table)
1145
    packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
1146
  else
1147
    packet->append(STRING_WITH_LEN("CREATE TABLE "));
1148 1149 1150
  if (create_info_arg &&
      (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS))
    packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
unknown's avatar
unknown committed
1151
  if (table_list->schema_table)
1152
    alias= table_list->schema_table->table_name;
unknown's avatar
unknown committed
1153
  else
1154 1155 1156 1157 1158 1159 1160 1161
  {
    if (lower_case_table_names == 2)
      alias= table->alias;
    else
    {
      alias= share->table_name.str;
    }
  }
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173

  /*
    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;
1174
    if (!thd->db || strcmp(db->str, thd->db))
1175 1176 1177 1178 1179 1180
    {
      append_identifier(thd, packet, db->str, db->length);
      packet->append(STRING_WITH_LEN("."));
    }
  }

unknown's avatar
unknown committed
1181
  append_identifier(thd, packet, alias, strlen(alias));
1182
  packet->append(STRING_WITH_LEN(" (\n"));
1183 1184 1185 1186 1187 1188
  /*
    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);
1189

unknown's avatar
unknown committed
1190 1191
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1192 1193
    uint flags = field->flags;

1194
    if (ptr != table->field)
1195
      packet->append(STRING_WITH_LEN(",\n"));
1196

1197
    packet->append(STRING_WITH_LEN("  "));
1198
    append_identifier(thd,packet,field->field_name, strlen(field->field_name));
unknown's avatar
unknown committed
1199 1200
    packet->append(' ');
    // check for surprises from the previous call to Field::sql_type()
1201
    if (type.ptr() != tmp)
1202
      type.set(tmp, sizeof(tmp), system_charset_info);
unknown's avatar
unknown committed
1203 1204
    else
      type.set_charset(system_charset_info);
1205

unknown's avatar
unknown committed
1206
    field->sql_type(type);
1207
    packet->append(type.ptr(), type.length(), system_charset_info);
1208

1209 1210
    if (field->has_charset() && 
        !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
1211
    {
1212
      if (field->charset() != share->table_charset)
1213
      {
1214
	packet->append(STRING_WITH_LEN(" CHARACTER SET "));
1215 1216 1217 1218 1219 1220 1221 1222
	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))
      {
1223
	packet->append(STRING_WITH_LEN(" COLLATE "));
1224
	packet->append(field->charset()->name);
1225
      }
1226
    }
1227

1228
    if (flags & NOT_NULL_FLAG)
1229
      packet->append(STRING_WITH_LEN(" NOT NULL"));
1230
    else if (field->type() == MYSQL_TYPE_TIMESTAMP)
1231 1232 1233 1234 1235
    {
      /*
        TIMESTAMP field require explicit NULL flag, because unlike
        all other fields they are treated as NOT NULL by default.
      */
1236
      packet->append(STRING_WITH_LEN(" NULL"));
1237
    }
1238

Sergey Glukhov's avatar
Sergey Glukhov committed
1239 1240
    if (get_field_default_value(thd, table->timestamp_field,
                                field, &def_value, 1))
1241
    {
1242
      packet->append(STRING_WITH_LEN(" DEFAULT "));
1243
      packet->append(def_value.ptr(), def_value.length(), system_charset_info);
1244
    }
1245

unknown's avatar
unknown committed
1246
    if (!limited_mysql_mode && table->timestamp_field == field && 
1247
        field->unireg_check != Field::TIMESTAMP_DN_FIELD)
1248
      packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
1249

1250 1251
    if (field->unireg_check == Field::NEXT_NUMBER && 
        !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
1252
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
1253 1254 1255

    if (field->comment.length)
    {
1256
      packet->append(STRING_WITH_LEN(" COMMENT "));
1257 1258
      append_unescaped(packet, field->comment.str, field->comment.length);
    }
unknown's avatar
unknown committed
1259 1260
  }

1261
  key_info= table->key_info;
1262
  bzero((char*) &create_info, sizeof(create_info));
1263 1264
  /* Allow update_create_info to update row type */
  create_info.row_type= share->row_type;
1265
  file->update_create_info(&create_info);
1266
  primary_key= share->primary_key;
1267

1268
  for (uint i=0 ; i < share->keys ; i++,key_info++)
unknown's avatar
unknown committed
1269
  {
1270 1271
    KEY_PART_INFO *key_part= key_info->key_part;
    bool found_primary=0;
1272
    packet->append(STRING_WITH_LEN(",\n  "));
1273

1274
    if (i == primary_key && !strcmp(key_info->name, primary_key_name))
1275 1276
    {
      found_primary=1;
1277 1278 1279 1280 1281
      /*
        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"));
1282
    }
1283
    else if (key_info->flags & HA_NOSAME)
1284
      packet->append(STRING_WITH_LEN("UNIQUE KEY "));
1285
    else if (key_info->flags & HA_FULLTEXT)
1286
      packet->append(STRING_WITH_LEN("FULLTEXT KEY "));
unknown's avatar
unknown committed
1287
    else if (key_info->flags & HA_SPATIAL)
1288 1289 1290
      packet->append(STRING_WITH_LEN("SPATIAL KEY "));
    else
      packet->append(STRING_WITH_LEN("KEY "));
unknown's avatar
unknown committed
1291

1292
    if (!found_primary)
1293
     append_identifier(thd, packet, key_info->name, strlen(key_info->name));
unknown's avatar
unknown committed
1294

1295
    packet->append(STRING_WITH_LEN(" ("));
1296

unknown's avatar
unknown committed
1297 1298
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
1299
      if (j)
1300
        packet->append(',');
1301

1302
      if (key_part->field)
1303 1304
        append_identifier(thd,packet,key_part->field->field_name,
			  strlen(key_part->field->field_name));
1305
      if (key_part->field &&
1306 1307
          (key_part->length !=
           table->field[key_part->fieldnr-1]->key_length() &&
unknown's avatar
unknown committed
1308
           !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))))
unknown's avatar
unknown committed
1309
      {
1310
        char *end;
1311
        buff[0] = '(';
1312 1313 1314
        end= int10_to_str((long) key_part->length /
                          key_part->field->charset()->mbmaxlen,
                          buff + 1,10);
1315 1316
        *end++ = ')';
        packet->append(buff,(uint) (end-buff));
unknown's avatar
unknown committed
1317 1318 1319
      }
    }
    packet->append(')');
1320
    store_key_options(thd, packet, table, key_info);
1321 1322
    if (key_info->parser)
    {
unknown's avatar
unknown committed
1323
      LEX_STRING *parser_name= plugin_name(key_info->parser);
1324
      packet->append(STRING_WITH_LEN(" /*!50100 WITH PARSER "));
unknown's avatar
unknown committed
1325
      append_identifier(thd, packet, parser_name->str, parser_name->length);
1326
      packet->append(STRING_WITH_LEN(" */ "));
1327
    }
unknown's avatar
unknown committed
1328
  }
1329

1330 1331 1332 1333
  /*
    Get possible foreign key definitions stored in InnoDB and append them
    to the CREATE TABLE statement
  */
1334

1335
  if ((for_str= file->get_foreign_key_create_info()))
1336 1337 1338
  {
    packet->append(for_str, strlen(for_str));
    file->free_foreign_key_create_info(for_str);
1339 1340
  }

1341
  packet->append(STRING_WITH_LEN("\n)"));
1342
  if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
1343
  {
1344
    show_table_options= TRUE;
1345 1346 1347 1348 1349
    /*
      Get possible table space definitions and append them
      to the CREATE TABLE statement
    */

1350
    if ((for_str= file->get_tablespace_name(thd,0,0)))
1351
    {
1352
      packet->append(STRING_WITH_LEN(" /*!50100 TABLESPACE "));
1353
      packet->append(for_str, strlen(for_str));
1354
      packet->append(STRING_WITH_LEN(" STORAGE DISK */"));
1355 1356 1357
      my_free(for_str, MYF(0));
    }

1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
    /*
      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="));
1369
#ifdef WITH_PARTITION_STORAGE_ENGINE
unknown's avatar
unknown committed
1370
    if (table->part_info)
unknown's avatar
unknown committed
1371 1372
      packet->append(ha_resolve_storage_engine_name(
                        table->part_info->default_engine_type));
1373
    else
1374
      packet->append(file->table_type());
1375
#else
1376
      packet->append(file->table_type());
1377
#endif
1378
    }
1379

1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
    /*
      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.
    */

1391
    if (create_info.auto_increment_value > 1)
1392
    {
1393
      char *end;
1394
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT="));
1395 1396 1397
      end= longlong10_to_str(create_info.auto_increment_value, buff,10);
      packet->append(buff, (uint) (end - buff));
    }
1398
    
1399
    if (share->table_charset &&
1400 1401
	!(thd->variables.sql_mode & MODE_MYSQL323) &&
	!(thd->variables.sql_mode & MODE_MYSQL40))
1402
    {
1403 1404 1405 1406 1407 1408
      /*
        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))
1409
      {
1410 1411 1412 1413 1414 1415 1416
        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);
        }
1417
      }
1418
    }
1419

1420
    if (share->min_rows)
1421
    {
1422
      char *end;
1423
      packet->append(STRING_WITH_LEN(" MIN_ROWS="));
1424
      end= longlong10_to_str(share->min_rows, buff, 10);
unknown's avatar
unknown committed
1425
      packet->append(buff, (uint) (end- buff));
1426
    }
unknown's avatar
unknown committed
1427

1428
    if (share->max_rows && !table_list->schema_table)
1429
    {
1430
      char *end;
1431
      packet->append(STRING_WITH_LEN(" MAX_ROWS="));
1432
      end= longlong10_to_str(share->max_rows, buff, 10);
unknown's avatar
unknown committed
1433
      packet->append(buff, (uint) (end - buff));
1434
    }
unknown's avatar
unknown committed
1435

1436
    if (share->avg_row_length)
1437
    {
1438
      char *end;
1439
      packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
1440
      end= longlong10_to_str(share->avg_row_length, buff,10);
unknown's avatar
unknown committed
1441
      packet->append(buff, (uint) (end - buff));
1442
    }
1443

1444
    if (share->db_create_options & HA_OPTION_PACK_KEYS)
1445
      packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
1446
    if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
1447
      packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
1448
    /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
1449
    if (share->db_create_options & HA_OPTION_CHECKSUM)
1450
      packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
1451
    if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
1452
      packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1"));
1453
    if (create_info.row_type != ROW_TYPE_DEFAULT)
1454
    {
1455
      packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
1456
      packet->append(ha_row_type[(uint) create_info.row_type]);
1457
    }
1458 1459
    if (table->s->key_block_size)
    {
unknown's avatar
unknown committed
1460
      char *end;
1461 1462 1463 1464
      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));
    }
1465
    table->file->append_create_info(packet);
1466
    if (share->comment.length)
1467
    {
1468
      packet->append(STRING_WITH_LEN(" COMMENT="));
1469
      append_unescaped(packet, share->comment.str, share->comment.length);
1470
    }
1471 1472
    if (share->connect_string.length)
    {
1473
      packet->append(STRING_WITH_LEN(" CONNECTION="));
1474 1475
      append_unescaped(packet, share->connect_string.str, share->connect_string.length);
    }
unknown's avatar
unknown committed
1476 1477
    append_directory(thd, packet, "DATA",  create_info.data_file_name);
    append_directory(thd, packet, "INDEX", create_info.index_file_name);
1478
  }
1479
#ifdef WITH_PARTITION_STORAGE_ENGINE
1480 1481 1482 1483 1484 1485
  {
    /*
      Partition syntax for CREATE TABLE is at the end of the syntax.
    */
    uint part_syntax_len;
    char *part_syntax;
unknown's avatar
unknown committed
1486
    if (table->part_info &&
1487
        (!table->part_info->is_auto_partitioned) &&
unknown's avatar
unknown committed
1488
        ((part_syntax= generate_partition_syntax(table->part_info,
unknown's avatar
unknown committed
1489
                                                  &part_syntax_len,
1490
                                                  FALSE,
1491 1492
                                                  show_table_options,
                                                  NULL, NULL))))
1493
    {
1494
       table->part_info->set_show_version_string(packet);
1495
       packet->append(part_syntax, part_syntax_len);
unknown's avatar
unknown committed
1496
       packet->append(STRING_WITH_LEN(" */"));
1497 1498 1499 1500
       my_free(part_syntax, MYF(0));
    }
  }
#endif
1501
  tmp_restore_column_map(table->read_set, old_map);
unknown's avatar
unknown committed
1502 1503 1504
  DBUG_RETURN(0);
}

1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541

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));
    }
1542 1543 1544 1545 1546 1547 1548 1549
    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);
    }
1550 1551 1552 1553
  }
}


1554 1555
void
view_store_options(THD *thd, TABLE_LIST *table, String *buff)
1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577
{
  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)
1578
{
1579
  buff->append(STRING_WITH_LEN("ALGORITHM="));
1580 1581
  switch ((int8)table->algorithm) {
  case VIEW_ALGORITHM_UNDEFINED:
1582
    buff->append(STRING_WITH_LEN("UNDEFINED "));
1583 1584
    break;
  case VIEW_ALGORITHM_TMPTABLE:
1585
    buff->append(STRING_WITH_LEN("TEMPTABLE "));
1586 1587
    break;
  case VIEW_ALGORITHM_MERGE:
1588
    buff->append(STRING_WITH_LEN("MERGE "));
1589 1590 1591 1592 1593
    break;
  default:
    DBUG_ASSERT(0); // never should happen
  }
}
unknown's avatar
unknown committed
1594

1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
/*
  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(' ');
}


1617
int
unknown's avatar
VIEW  
unknown committed
1618 1619
view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
{
1620
  my_bool compact_view_name= TRUE;
unknown's avatar
VIEW  
unknown committed
1621 1622 1623 1624 1625 1626
  my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
                                                       MODE_ORACLE |
                                                       MODE_MSSQL |
                                                       MODE_DB2 |
                                                       MODE_MAXDB |
                                                       MODE_ANSI)) != 0;
1627

1628
  if (!thd->db || strcmp(thd->db, table->view_db.str))
1629 1630 1631 1632
    /*
      print compact view name if the view belongs to the current database
    */
    compact_view_name= table->compact_view_format= FALSE;
1633 1634
  else
  {
1635 1636 1637 1638
    /*
      Compact output format for view body can be used
      if this view only references table inside it's own db
    */
1639
    TABLE_LIST *tbl;
1640
    table->compact_view_format= TRUE;
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
    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;
      }
    }
  }

1653
  buff->append(STRING_WITH_LEN("CREATE "));
1654
  if (!foreign_db_mode)
unknown's avatar
VIEW  
unknown committed
1655
  {
1656
    view_store_options(thd, table, buff);
unknown's avatar
VIEW  
unknown committed
1657
  }
1658
  buff->append(STRING_WITH_LEN("VIEW "));
1659
  if (!compact_view_name)
1660 1661 1662 1663
  {
    append_identifier(thd, buff, table->view_db.str, table->view_db.length);
    buff->append('.');
  }
1664
  append_identifier(thd, buff, table->view_name.str, table->view_name.length);
1665
  buff->append(STRING_WITH_LEN(" AS "));
1666 1667 1668 1669 1670

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

1673 1674 1675
  if (table->with_check != VIEW_CHECK_NONE)
  {
    if (table->with_check == VIEW_CHECK_LOCAL)
1676
      buff->append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION"));
1677
    else
1678
      buff->append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION"));
1679
  }
unknown's avatar
VIEW  
unknown committed
1680 1681 1682 1683
  return 0;
}


unknown's avatar
unknown committed
1684
/****************************************************************************
1685 1686
  Return info about all processes
  returns for each thread: thread id, user, host, db, command, info
unknown's avatar
unknown committed
1687 1688 1689 1690
****************************************************************************/

class thread_info :public ilink {
public:
unknown's avatar
unknown committed
1691 1692 1693 1694
  static void *operator new(size_t size)
  {
    return (void*) sql_alloc((uint) size);
  }
unknown's avatar
unknown committed
1695
  static void operator delete(void *ptr __attribute__((unused)),
unknown's avatar
unknown committed
1696 1697
                              size_t size __attribute__((unused)))
  { TRASH(ptr, size); }
unknown's avatar
unknown committed
1698

unknown's avatar
unknown committed
1699 1700
  ulong thread_id;
  time_t start_time;
1701
  uint   command;
unknown's avatar
unknown committed
1702 1703 1704 1705
  const char *user,*host,*db,*proc_info,*state_info;
  char *query;
};

1706
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
unknown's avatar
unknown committed
1707 1708 1709
template class I_List<thread_info>;
#endif

1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
static const char *thread_state_info(THD *tmp)
{
#ifndef EMBEDDED_LIBRARY
  if (tmp->net.reading_or_writing)
  {
    if (tmp->net.reading_or_writing == 2)
      return "Writing to net";
    else if (tmp->command == COM_SLEEP)
      return "";
    else
      return "Reading from net";
  }
  else
#endif
  {
    if (tmp->proc_info)
      return tmp->proc_info;
    else if (tmp->mysys_var && tmp->mysys_var->current_cond)
      return "Waiting on cond";
    else
      return NULL;
  }
}

unknown's avatar
unknown committed
1734 1735 1736 1737 1738
void mysqld_list_processes(THD *thd,const char *user, bool verbose)
{
  Item *field;
  List<Item> field_list;
  I_List<thread_info> thread_infos;
unknown's avatar
unknown committed
1739 1740
  ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
			   PROCESS_LIST_WIDTH);
1741
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
1742 1743
  DBUG_ENTER("mysqld_list_processes");

1744
  field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
unknown's avatar
unknown committed
1745
  field_list.push_back(new Item_empty_string("User",16));
1746
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
1747
  field_list.push_back(field=new Item_empty_string("db",NAME_CHAR_LEN));
unknown's avatar
unknown committed
1748 1749
  field->maybe_null=1;
  field_list.push_back(new Item_empty_string("Command",16));
1750
  field_list.push_back(field= new Item_return_int("Time",7, MYSQL_TYPE_LONG));
1751
  field->unsigned_flag= 0;
unknown's avatar
unknown committed
1752 1753 1754 1755
  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;
1756
  if (protocol->send_result_set_metadata(&field_list,
1757
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
1758 1759
    DBUG_VOID_RETURN;

Marc Alff's avatar
Marc Alff committed
1760
  mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
unknown's avatar
unknown committed
1761 1762 1763 1764 1765 1766
  if (!thd->killed)
  {
    I_List_iterator<THD> it(threads);
    THD *tmp;
    while ((tmp=it++))
    {
1767
      Security_context *tmp_sctx= tmp->security_ctx;
1768
      struct st_my_thread_var *mysys_var;
1769
      if ((tmp->vio_ok() || tmp->system_thread) &&
1770
          (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
unknown's avatar
unknown committed
1771
      {
1772
        thread_info *thd_info= new thread_info;
1773 1774

        thd_info->thread_id=tmp->thread_id;
1775 1776 1777 1778 1779
        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])
1780
	{
1781
	  if ((thd_info->host= (char*) thd->alloc(LIST_PROCESS_HOST_LEN+1)))
unknown's avatar
unknown committed
1782
	    my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
1783
			"%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
1784 1785
	}
	else
1786 1787 1788
	  thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ? 
                                      tmp_sctx->host_or_ip : 
                                      tmp_sctx->host ? tmp_sctx->host : "");
1789 1790 1791
        if ((thd_info->db=tmp->db))             // Safe test
          thd_info->db=thd->strdup(thd_info->db);
        thd_info->command=(int) tmp->command;
1792
        if ((mysys_var= tmp->mysys_var))
Marc Alff's avatar
Marc Alff committed
1793
          mysql_mutex_lock(&mysys_var->mutex);
unknown's avatar
SCRUM  
unknown committed
1794
        thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
1795
        thd_info->state_info= thread_state_info(tmp);
1796
        if (mysys_var)
Marc Alff's avatar
Marc Alff committed
1797
          mysql_mutex_unlock(&mysys_var->mutex);
unknown's avatar
unknown committed
1798

1799 1800
        thd_info->start_time= tmp->start_time;
        thd_info->query=0;
1801
        /* Lock THD mutex that protects its data when looking at it. */
Marc Alff's avatar
Marc Alff committed
1802
        mysql_mutex_lock(&tmp->LOCK_thd_data);
1803
        if (tmp->query())
1804
        {
1805 1806
          uint length= min(max_query_length, tmp->query_length());
          thd_info->query= (char*) thd->strmake(tmp->query(),length);
1807
        }
Marc Alff's avatar
Marc Alff committed
1808
        mysql_mutex_unlock(&tmp->LOCK_thd_data);
1809
        thread_infos.append(thd_info);
unknown's avatar
unknown committed
1810 1811 1812
      }
    }
  }
Marc Alff's avatar
Marc Alff committed
1813
  mysql_mutex_unlock(&LOCK_thread_count);
unknown's avatar
unknown committed
1814 1815

  thread_info *thd_info;
1816
  time_t now= my_time(0);
unknown's avatar
unknown committed
1817 1818
  while ((thd_info=thread_infos.get()))
  {
1819 1820
    protocol->prepare_for_resend();
    protocol->store((ulonglong) thd_info->thread_id);
1821 1822 1823
    protocol->store(thd_info->user, system_charset_info);
    protocol->store(thd_info->host, system_charset_info);
    protocol->store(thd_info->db, system_charset_info);
unknown's avatar
unknown committed
1824
    if (thd_info->proc_info)
1825
      protocol->store(thd_info->proc_info, system_charset_info);
unknown's avatar
unknown committed
1826
    else
1827
      protocol->store(command_name[thd_info->command].str, system_charset_info);
unknown's avatar
unknown committed
1828
    if (thd_info->start_time)
1829
      protocol->store_long ((longlong) (now - thd_info->start_time));
unknown's avatar
unknown committed
1830
    else
1831
      protocol->store_null();
1832 1833
    protocol->store(thd_info->state_info, system_charset_info);
    protocol->store(thd_info->query, system_charset_info);
1834
    if (protocol->write())
unknown's avatar
unknown committed
1835 1836
      break; /* purecov: inspected */
  }
1837
  my_eof(thd);
unknown's avatar
unknown committed
1838 1839 1840
  DBUG_VOID_RETURN;
}

1841 1842 1843 1844 1845
int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
{
  TABLE *table= tables->table;
  CHARSET_INFO *cs= system_charset_info;
  char *user;
1846
  time_t now= my_time(0);
1847 1848 1849 1850 1851
  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
1852
  mysql_mutex_lock(&LOCK_thread_count);
1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895

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

      if ((mysys_var= tmp->mysys_var))
Marc Alff's avatar
Marc Alff committed
1896
        mysql_mutex_lock(&mysys_var->mutex);
1897 1898 1899 1900 1901 1902
      /* 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);
1903
      /* MYSQL_TIME */
1904 1905
      table->field[5]->store((longlong)(tmp->start_time ?
                                      now - tmp->start_time : 0), FALSE);
1906
      /* STATE */
1907
      if ((val= thread_state_info(tmp)))
1908 1909 1910 1911 1912 1913
      {
        table->field[6]->store(val, strlen(val), cs);
        table->field[6]->set_notnull();
      }

      if (mysys_var)
Marc Alff's avatar
Marc Alff committed
1914
        mysql_mutex_unlock(&mysys_var->mutex);
1915 1916

      /* INFO */
1917
      if (tmp->query())
1918
      {
1919
        table->field[7]->store(tmp->query(),
1920
                               min(PROCESS_LIST_INFO_WIDTH,
1921
                                   tmp->query_length()), cs);
1922 1923 1924 1925 1926
        table->field[7]->set_notnull();
      }

      if (schema_table_store_record(thd, table))
      {
Marc Alff's avatar
Marc Alff committed
1927
        mysql_mutex_unlock(&LOCK_thread_count);
1928 1929 1930 1931 1932
        DBUG_RETURN(1);
      }
    }
  }

Marc Alff's avatar
Marc Alff committed
1933
  mysql_mutex_unlock(&LOCK_thread_count);
1934 1935 1936
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
1937
/*****************************************************************************
unknown's avatar
unknown committed
1938
  Status functions
unknown's avatar
unknown committed
1939 1940
*****************************************************************************/

1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953
static DYNAMIC_ARRAY all_status_vars;
static bool status_vars_inited= 0;
static int show_var_cmp(const void *var1, const void *var2)
{
  return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
}

/*
  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)
{
1954
  uint a,b;
1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
  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
1992
    mysql_mutex_lock(&LOCK_status);
1993 1994 1995 1996 1997 1998 1999
  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)
2000 2001
    res|= insert_dynamic(&all_status_vars, (uchar*)list++);
  res|= insert_dynamic(&all_status_vars, (uchar*)list); // appending NULL-element
2002 2003 2004 2005 2006
  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
2007
    mysql_mutex_unlock(&LOCK_status);
2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024
  return res;
}

/*
  Make all_status_vars[] usable for SHOW STATUS

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

unknown's avatar
unknown committed
2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036
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;
  }  
}

2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063
/*
  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.
*/
2064

2065 2066 2067 2068
void remove_status_vars(SHOW_VAR *list)
{
  if (status_vars_inited)
  {
Marc Alff's avatar
Marc Alff committed
2069
    mysql_mutex_lock(&LOCK_status);
2070
    SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
2071
    int a= 0, b= all_status_vars.elements, c= (a+b)/2;
2072 2073 2074

    for (; list->name; list++)
    {
2075
      int res= 0;
2076 2077 2078 2079 2080 2081 2082
      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;
2083 2084
        else
          break;
2085 2086 2087 2088 2089
      }
      if (res == 0)
        all[c].type= SHOW_UNDEF;
    }
    shrink_var_array(&all_status_vars);
Marc Alff's avatar
Marc Alff committed
2090
    mysql_mutex_unlock(&LOCK_status);
2091 2092 2093 2094
  }
  else
  {
    SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
2095
    uint i;
2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109
    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);
  }
}

2110 2111 2112 2113 2114 2115
inline void make_upper(char *buf)
{
  for (; *buf; buf++)
    *buf= my_toupper(system_charset_info, *buf);
}

2116
static bool show_status_array(THD *thd, const char *wild,
2117
                              SHOW_VAR *variables,
2118 2119
                              enum enum_var_type value_type,
                              struct system_status_var *status_var,
2120
                              const char *prefix, TABLE *table,
2121 2122
                              bool ucase_names,
                              COND *cond)
unknown's avatar
unknown committed
2123
{
2124 2125 2126
  MY_ALIGNED_BYTE_ARRAY(buff_data, SHOW_VAR_FUNC_BUFF_SIZE, long);
  char * const buff= (char *) &buff_data;
  char *prefix_end;
2127 2128
  /* the variable name should not be longer than 64 characters */
  char name_buffer[64];
2129
  int len;
2130
  LEX_STRING null_lex_str;
2131
  SHOW_VAR tmp, *var;
2132 2133 2134
  COND *partial_cond= 0;
  enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
  bool res= FALSE;
2135
  CHARSET_INFO *charset= system_charset_info;
2136
  DBUG_ENTER("show_status_array");
unknown's avatar
unknown committed
2137

2138
  thd->count_cuted_fields= CHECK_FIELD_WARN;  
2139
  null_lex_str.str= 0;				// For sys_var->value_ptr()
2140
  null_lex_str.length= 0;
unknown's avatar
unknown committed
2141

2142
  prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1);
2143 2144
  if (*prefix)
    *prefix_end++= '_';
2145
  len=name_buffer + sizeof(name_buffer) - prefix_end;
2146
  partial_cond= make_cond_for_info_schema(cond, table->pos_in_table_list);
2147

unknown's avatar
unknown committed
2148
  for (; variables->name; variables++)
unknown's avatar
unknown committed
2149
  {
2150 2151
    strnmov(prefix_end, variables->name, len);
    name_buffer[sizeof(name_buffer)-1]=0;       /* Safety */
2152 2153
    if (ucase_names)
      make_upper(name_buffer);
2154

2155 2156 2157
    restore_record(table, s->default_values);
    table->field[0]->store(name_buffer, strlen(name_buffer),
                           system_charset_info);
2158 2159 2160 2161
    /*
      if var->type is SHOW_FUNC, call the function.
      Repeat as necessary, if new var is again SHOW_FUNC
    */
2162
    for (var=variables; var->type == SHOW_FUNC; var= &tmp)
2163
      ((mysql_show_var_func)(var->value))(thd, &tmp, buff);
2164 2165 2166

    SHOW_TYPE show_type=var->type;
    if (show_type == SHOW_ARRAY)
2167
    {
2168
      show_status_array(thd, wild, (SHOW_VAR *) var->value, value_type,
2169
                        status_var, name_buffer, table, ucase_names, partial_cond);
2170 2171
    }
    else
unknown's avatar
unknown committed
2172
    {
2173
      if (!(wild && wild[0] && wild_case_compare(system_charset_info,
2174 2175
                                                 name_buffer, wild)) &&
          (!partial_cond || partial_cond->val_int()))
unknown's avatar
unknown committed
2176
      {
2177
        char *value=var->value;
unknown's avatar
unknown committed
2178
        const char *pos, *end;                  // We assign a lot of const's
2179

Marc Alff's avatar
Marc Alff committed
2180
        mysql_mutex_lock(&LOCK_global_system_variables);
unknown's avatar
unknown committed
2181

2182 2183
        if (show_type == SHOW_SYS)
        {
2184
          sys_var *var= ((sys_var *) value);
2185 2186 2187
          show_type= var->show_type();
          value= (char*) var->value_ptr(thd, value_type, &null_lex_str);
          charset= var->charset(thd);
2188 2189 2190
        }

        pos= end= buff;
2191 2192 2193 2194
        /*
          note that value may be == buff. All SHOW_xxx code below
          should still work in this case
        */
2195
        switch (show_type) {
2196 2197
        case SHOW_DOUBLE_STATUS:
          value= ((char *) status_var + (ulong) value);
2198 2199
          /* fall through */
        case SHOW_DOUBLE:
2200 2201
          /* 6 is the default precision for '%f' in sprintf() */
          end= buff + my_fcvt(*(double *) value, 6, buff, NULL);
2202
          break;
2203 2204 2205 2206
        case SHOW_LONG_STATUS:
          value= ((char *) status_var + (ulong) value);
          /* fall through */
        case SHOW_LONG:
2207
        case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
2208 2209
          end= int10_to_str(*(long*) value, buff, 10);
          break;
2210 2211
        case SHOW_LONGLONG_STATUS:
          value= ((char *) status_var + (ulonglong) value);
2212
          /* fall through */
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228
        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:
unknown's avatar
unknown committed
2229 2230 2231 2232 2233 2234
        {
          SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
          pos= show_comp_option_name[(int) tmp];
          end= strend(pos);
          break;
        }
2235
        case SHOW_CHAR:
unknown's avatar
unknown committed
2236 2237 2238 2239 2240 2241
        {
          if (!(pos= value))
            pos= "";
          end= strend(pos);
          break;
        }
unknown's avatar
unknown committed
2242
       case SHOW_CHAR_PTR:
unknown's avatar
unknown committed
2243 2244 2245 2246 2247 2248
        {
          if (!(pos= *(char**) value))
            pos= "";
          end= strend(pos);
          break;
        }
2249 2250 2251 2252 2253 2254 2255 2256 2257
        case SHOW_LEX_STRING:
        {
          LEX_STRING *ls=(LEX_STRING*)value;
          if (!(pos= ls->str))
            end= pos= "";
          else
            end= pos + ls->length;
          break;
        }
2258
        case SHOW_KEY_CACHE_LONG:
2259
          value= (char*) dflt_key_cache + (ulong)value;
2260 2261
          end= int10_to_str(*(long*) value, buff, 10);
          break;
2262
        case SHOW_KEY_CACHE_LONGLONG:
2263
          value= (char*) dflt_key_cache + (ulong)value;
2264 2265
	  end= longlong10_to_str(*(longlong*) value, buff, 10);
	  break;
2266
        case SHOW_UNDEF:
2267 2268
          break;                                        // Return empty string
        case SHOW_SYS:                                  // Cannot happen
2269
        default:
2270
          DBUG_ASSERT(0);
2271 2272
          break;
        }
2273
        table->field[1]->store(pos, (uint32) (end - pos), charset);
2274
        thd->count_cuted_fields= CHECK_FIELD_IGNORE;
2275
        table->field[1]->set_notnull();
unknown's avatar
unknown committed
2276

Marc Alff's avatar
Marc Alff committed
2277
        mysql_mutex_unlock(&LOCK_global_system_variables);
unknown's avatar
unknown committed
2278

2279
        if (schema_table_store_record(thd, table))
2280 2281 2282 2283
        {
          res= TRUE;
          goto end;
        }
unknown's avatar
unknown committed
2284 2285 2286
      }
    }
  }
2287 2288 2289
end:
  thd->count_cuted_fields= save_count_cuted_fields;
  DBUG_RETURN(res);
2290 2291 2292
}


2293 2294 2295 2296 2297 2298 2299
/* 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
2300
  mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311

  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
2312
  mysql_mutex_unlock(&LOCK_thread_count);
2313 2314 2315 2316
  DBUG_VOID_RETURN;
}


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

2320
typedef struct st_lookup_field_values
2321
{
2322 2323 2324
  LEX_STRING db_value, table_value;
  bool wild_db_value, wild_table_value;
} LOOKUP_FIELD_VALUES;
2325 2326


2327 2328 2329 2330 2331 2332 2333
/*
  Store record to I_S table, convert HEAP table
  to MyISAM if necessary

  SYNOPSIS
    schema_table_store_record()
    thd                   thread handler
2334 2335
    table                 Information schema table to be updated

2336 2337
  RETURN
    0	                  success
2338
    1	                  error
2339 2340
*/

2341
bool schema_table_store_record(THD *thd, TABLE *table)
2342 2343
{
  int error;
2344
  if ((error= table->file->ha_write_row(table->record[0])))
2345 2346 2347 2348 2349 2350 2351 2352 2353 2354
  {
    if (create_myisam_from_heap(thd, table, 
                                table->pos_in_table_list->schema_table_param,
                                error, 0))
      return 1;
  }
  return 0;
}


2355
int make_table_list(THD *thd, SELECT_LEX *sel,
2356
                    LEX_STRING *db_name, LEX_STRING *table_name)
2357 2358
{
  Table_ident *table_ident;
2359
  table_ident= new Table_ident(thd, *db_name, *table_name, 1);
2360
  sel->init_query();
2361
  if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
2362 2363 2364 2365 2366
    return 1;
  return 0;
}


2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379
/**
  @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 

2380 2381 2382
  @return
    0             success
    1             error, there can be no matching records for the condition
2383 2384
*/

2385
bool get_lookup_value(THD *thd, Item_func *item_func,
2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417
                      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
2418
      return 0;
2419 2420 2421

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

2425 2426 2427 2428
    /* impossible value */
    if (!tmp_str)
      return 1;

2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446
    /* 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);
    }
  }
2447
  return 0;
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462
}


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

2463 2464 2465
  @return
    0             success
    1             error, there can be no matching records for the condition
2466 2467
*/

2468
bool calc_lookup_values_from_cond(THD *thd, COND *cond, TABLE_LIST *table,
2469 2470 2471
                                  LOOKUP_FIELD_VALUES *lookup_field_vals)
{
  if (!cond)
2472
    return 0;
2473 2474 2475 2476 2477 2478 2479 2480 2481 2482

  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)
2483 2484 2485 2486
        {
          if (get_lookup_value(thd, (Item_func*)item, table, lookup_field_vals))
            return 1;
        }
2487
        else
2488 2489 2490 2491
        {
          if (calc_lookup_values_from_cond(thd, item, table, lookup_field_vals))
            return 1;
        }
2492 2493
      }
    }
2494
    return 0;
2495
  }
2496 2497 2498 2499
  else if (cond->type() == Item::FUNC_ITEM &&
           get_lookup_value(thd, (Item_func*) cond, table, lookup_field_vals))
    return 1;
  return 0;
2500 2501 2502
}


2503 2504 2505 2506 2507
bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
{
  if (item->type() == Item::FUNC_ITEM)
  {
    Item_func *item_func= (Item_func*)item;
2508
    for (uint i=0; i<item_func->argument_count(); i++)
2509
    {
2510
      if (!uses_only_table_name_fields(item_func->arguments()[i], table))
2511
        return 0;
2512
    }
2513 2514 2515 2516 2517 2518 2519
  }
  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;
2520 2521 2522 2523
    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 : "";
2524 2525
    if (table->table != item_field->field->table ||
        (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
2526
                               (uchar *) item_field->field_name,
2527 2528
                               strlen(item_field->field_name), 0) &&
         cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2),
2529
                               (uchar *) item_field->field_name,
2530
                               strlen(item_field->field_name), 0)))
2531 2532
      return 0;
  }
2533 2534
  else if (item->type() == Item::REF_ITEM)
    return uses_only_table_name_fields(item->real_item(), table);
2535 2536

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

2539
  return 1;
2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598
}


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


2599 2600 2601 2602 2603 2604 2605 2606 2607 2608
/**
  @brief   Calculate lookup values(database name, table name)

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

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

2612 2613 2614
  @return
    0             success
    1             error, there can be no matching records for the condition
2615 2616
*/

2617
bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables,
2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630
                             LOOKUP_FIELD_VALUES *lookup_field_values)
{
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
  bzero((char*) lookup_field_values, sizeof(LOOKUP_FIELD_VALUES));
  switch (lex->sql_command) {
  case SQLCOM_SHOW_DATABASES:
    if (wild)
    {
      lookup_field_values->db_value.str= (char*) wild;
      lookup_field_values->db_value.length= strlen(wild);
      lookup_field_values->wild_db_value= 1;
    }
2631
    return 0;
2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SHOW_TABLE_STATUS:
  case SQLCOM_SHOW_TRIGGERS:
  case SQLCOM_SHOW_EVENTS:
    lookup_field_values->db_value.str= lex->select_lex.db;
    lookup_field_values->db_value.length=strlen(lex->select_lex.db);
    if (wild)
    {
      lookup_field_values->table_value.str= (char*)wild;
      lookup_field_values->table_value.length= strlen(wild);
      lookup_field_values->wild_table_value= 1;
    }
2644
    return 0;
2645 2646 2647 2648 2649
  default:
    /*
      The "default" is for queries over I_S.
      All previous cases handle SHOW commands.
    */
2650
    return calc_lookup_values_from_cond(thd, cond, tables, lookup_field_values);
2651 2652 2653 2654
  }
}


2655 2656 2657 2658 2659 2660
enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
{
  return (enum enum_schema_tables) (schema_table - &schema_tables[0]);
}


unknown's avatar
unknown committed
2661
/*
2662
  Create db names list. Information schema name always is first in list
unknown's avatar
unknown committed
2663 2664

  SYNOPSIS
2665
    make_db_list()
unknown's avatar
unknown committed
2666 2667 2668
    thd                   thread handler
    files                 list of db names
    wild                  wild string
2669 2670
    idx_field_vals        idx_field_vals->db_name contains db name or
                          wild string
unknown's avatar
unknown committed
2671
    with_i_schema         returns 1 if we added 'IS' name to list
2672
                          otherwise returns 0 
unknown's avatar
unknown committed
2673 2674

  RETURN
2675 2676
    zero                  success
    non-zero              error
unknown's avatar
unknown committed
2677 2678
*/

2679 2680 2681
int make_db_list(THD *thd, List<LEX_STRING> *files,
                 LOOKUP_FIELD_VALUES *lookup_field_vals,
                 bool *with_i_schema)
2682
{
unknown's avatar
unknown committed
2683 2684 2685 2686
  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);
unknown's avatar
unknown committed
2687
  *with_i_schema= 0;
2688
  if (lookup_field_vals->wild_db_value)
unknown's avatar
unknown committed
2689
  {
2690 2691 2692 2693 2694
    /*
      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)
    */
2695
    if (!lookup_field_vals->db_value.str ||
2696
        !wild_case_compare(system_charset_info, 
2697
                           INFORMATION_SCHEMA_NAME.str,
2698
                           lookup_field_vals->db_value.str))
2699 2700
    {
      *with_i_schema= 1;
unknown's avatar
unknown committed
2701
      if (files->push_back(i_s_name_copy))
2702 2703
        return 1;
    }
2704
    return (find_files(thd, files, NullS, mysql_data_home,
2705
                       lookup_field_vals->db_value.str, 1) != FIND_FILES_OK);
unknown's avatar
unknown committed
2706
  }
2707

2708

2709
  /*
2710 2711
    If we have db lookup vaule we just add it to list and
    exit from the function
2712
  */
2713
  if (lookup_field_vals->db_value.str)
2714
  {
2715 2716
    if (is_infoschema_db(lookup_field_vals->db_value.str,
                         lookup_field_vals->db_value.length))
2717 2718
    {
      *with_i_schema= 1;
unknown's avatar
unknown committed
2719
      if (files->push_back(i_s_name_copy))
2720 2721
        return 1;
      return 0;
2722
    }
2723 2724 2725
    if (files->push_back(&lookup_field_vals->db_value))
      return 1;
    return 0;
2726 2727
  }

2728 2729 2730 2731
  /*
    Create list of existing databases. It is used in case
    of select from information schema table
  */
unknown's avatar
unknown committed
2732
  if (files->push_back(i_s_name_copy))
2733 2734
    return 1;
  *with_i_schema= 1;
2735 2736
  return (find_files(thd, files, NullS,
                     mysql_data_home, NullS, 1) != FIND_FILES_OK);
2737 2738
}

2739

unknown's avatar
unknown committed
2740 2741
struct st_add_schema_table 
{
2742
  List<LEX_STRING> *files;
unknown's avatar
unknown committed
2743 2744 2745
  const char *wild;
};

2746

unknown's avatar
unknown committed
2747
static my_bool add_schema_table(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
2748 2749
                                void* p_data)
{
2750
  LEX_STRING *file_name= 0;
unknown's avatar
unknown committed
2751
  st_add_schema_table *data= (st_add_schema_table *)p_data;
2752
  List<LEX_STRING> *file_list= data->files;
unknown's avatar
unknown committed
2753
  const char *wild= data->wild;
unknown's avatar
unknown committed
2754
  ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
unknown's avatar
unknown committed
2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771
  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);
  }

2772 2773 2774 2775 2776 2777
  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);
unknown's avatar
unknown committed
2778
}
2779

2780 2781

int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
2782
{
2783
  LEX_STRING *file_name= 0;
2784
  ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
unknown's avatar
unknown committed
2785 2786 2787
  st_add_schema_table add_data;
  DBUG_ENTER("schema_tables_add");

2788
  for (; tmp_schema_table->table_name; tmp_schema_table++)
2789
  {
2790 2791
    if (tmp_schema_table->hidden)
      continue;
2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
    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;
    }
2804 2805 2806 2807 2808 2809
    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);
2810
  }
unknown's avatar
unknown committed
2811 2812 2813 2814 2815 2816 2817 2818

  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);
2819 2820 2821
}


2822 2823
/**
  @brief          Create table names list
2824

2825 2826
  @details        The function creates the list of table names in
                  database
2827

2828 2829 2830 2831 2832 2833
  @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
2834

2835 2836 2837 2838 2839
  @return         Operation status
    @retval       0           ok
    @retval       1           fatal error
    @retval       2           Not fatal error; Safe to ignore this file list
*/
2840

2841 2842 2843 2844 2845
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)
{
2846 2847
  char path[FN_REFLEN + 1];
  build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0);
2848 2849
  if (!lookup_field_vals->wild_table_value &&
      lookup_field_vals->table_value.str)
2850
  {
2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866
    if (with_i_schema)
    {
      if (find_schema_table(thd, lookup_field_vals->table_value.str))
      {
        if (table_names->push_back(&lookup_field_vals->table_value))
          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
2867
      (void) ha_find_files(thd, db_name->str, path,
2868
                         lookup_field_vals->table_value.str, 0,
Konstantin Osipov's avatar
Konstantin Osipov committed
2869
                         table_names);
2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890
    }
    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.
2891
    */
2892 2893 2894 2895 2896 2897 2898 2899
    if (res == FIND_FILES_DIR)
    {
      if (lex->sql_command != SQLCOM_SELECT)
        return 1;
      thd->clear_error();
      return 2;
    }
    return 1;
2900
  }
2901 2902
  return 0;
}
2903

2904

2905 2906 2907 2908 2909 2910
/**
  @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
2911 2912 2913 2914
  @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.
2915
  @param[in]      open_tables_state_backup pointer to Open_tables_backup object
2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927
                                           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
2928
                              bool can_deadlock,
2929
                              Open_tables_backup *open_tables_state_backup)
2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956
{
  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;
  TABLE_LIST *show_table_list= (TABLE_LIST*) tables->schema_select_lex->
    table_list.first;
  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,
2957
                                      (MYSQL_OPEN_IGNORE_FLUSH |
2958
                                       MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
Konstantin Osipov's avatar
Konstantin Osipov committed
2959 2960
                                       (can_deadlock ?
                                        MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985
  lex->sql_command= save_sql_command;
  /*
    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;
2986 2987
   close_tables_for_reopen(thd, &show_table_list,
                           open_tables_state_backup->mdl_system_tables_svp);
2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017
   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;
3018 3019
    char path[FN_REFLEN + 1];
    (void) build_table_filename(path, sizeof(path) - 1, db_name->str, 
3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036
                                table_name->str, reg_ext, 0);
    switch (mysql_frm_type(thd, path, &not_used)) {
    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
3037
    if (thd->is_error() && thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064
    {
      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
*/

3065
uint get_table_open_method(TABLE_LIST *tables,
3066 3067 3068 3069 3070 3071 3072 3073 3074 3075
                                  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;
3076 3077
    uint star_table_open_method= OPEN_FULL_TABLE;
    bool used_star= true;                  // true if '*' is used in select
3078 3079
    for (ptr=tables->table->field; (field= *ptr) ; ptr++)
    {
3080 3081 3082
      star_table_open_method=
        min(star_table_open_method,
            schema_table->fields_info[field_indx].open_method);
3083
      if (bitmap_is_set(tables->table->read_set, field->field_index))
3084 3085
      {
        used_star= false;
3086
        table_open_method|= schema_table->fields_info[field_indx].open_method;
3087
      }
3088 3089
      field_indx++;
    }
3090 3091
    if (used_star)
      return star_table_open_method;
3092 3093 3094 3095 3096 3097 3098
    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
3099
/**
Konstantin Osipov's avatar
Konstantin Osipov committed
3100 3101
   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
3102 3103

   @param thd            Thread context.
Konstantin Osipov's avatar
Konstantin Osipov committed
3104
   @param mdl_request    Pointer to memory to be used for MDL_request
Konstantin Osipov's avatar
Konstantin Osipov committed
3105 3106
                         object for a lock request.
   @param table          Table list element for the table
Konstantin Osipov's avatar
Konstantin Osipov committed
3107 3108 3109
   @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
3110 3111 3112 3113 3114 3115 3116

   @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
3117 3118
   @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
3119 3120 3121 3122
   @retval TRUE   Some error occured (probably thread was killed).
*/

static bool
Konstantin Osipov's avatar
Konstantin Osipov committed
3123 3124
try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
                                      bool can_deadlock)
Konstantin Osipov's avatar
Konstantin Osipov committed
3125 3126
{
  bool error;
Konstantin Osipov's avatar
Konstantin Osipov committed
3127
  table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
Konstantin Osipov's avatar
Konstantin Osipov committed
3128 3129
                          MDL_SHARED_HIGH_PRIO);
  while (!(error=
3130
           thd->mdl_context.try_acquire_lock(&table->mdl_request)) &&
Konstantin Osipov's avatar
Konstantin Osipov committed
3131
         !table->mdl_request.ticket && !can_deadlock)
Konstantin Osipov's avatar
Konstantin Osipov committed
3132
  {
3133 3134 3135
    if ((error=
         thd->mdl_context.wait_for_lock(&table->mdl_request,
                                        thd->variables.lock_wait_timeout)))
Konstantin Osipov's avatar
Konstantin Osipov committed
3136
      break;
Konstantin Osipov's avatar
Konstantin Osipov committed
3137
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
3138
  return error;
Konstantin Osipov's avatar
Konstantin Osipov committed
3139 3140 3141
}


3142 3143 3144 3145 3146 3147 3148 3149 3150
/**
  @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
3151 3152 3153 3154
  @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.
3155 3156 3157 3158 3159 3160 3161 3162

  @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
3163 3164
static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
                                      ST_SCHEMA_TABLE *schema_table,
3165 3166
                                      LEX_STRING *db_name,
                                      LEX_STRING *table_name,
Konstantin Osipov's avatar
Konstantin Osipov committed
3167 3168
                                      enum enum_schema_tables schema_table_idx,
                                      bool can_deadlock)
3169
{
Sergey Glukhov's avatar
Sergey Glukhov committed
3170
  TABLE *table= tables->table;
3171
  TABLE_SHARE *share;
3172 3173
  TABLE tbl;
  TABLE_LIST table_list;
3174
  uint res= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
3175
  int not_used;
3176
  my_hash_value_type hash_value;
3177 3178
  char key[MAX_DBKEY_LENGTH];
  uint key_length;
3179
  char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1];
3180

3181 3182
  bzero((char*) &table_list, sizeof(TABLE_LIST));
  bzero((char*) &tbl, sizeof(TABLE));
3183

3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203
  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;
  }

3204 3205 3206 3207 3208
  /*
    TODO: investigate if in this particular situation we can get by
          simply obtaining internal lock of data-dictionary (ATM it
          is LOCK_open) instead of obtaning full-blown metadata lock.
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
3209
  if (try_acquire_high_prio_shared_mdl_lock(thd, &table_list, can_deadlock))
3210
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
3211 3212 3213 3214 3215 3216
    /*
      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;
3217 3218
  }

Konstantin Osipov's avatar
Konstantin Osipov committed
3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234
  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
3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249
  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;
  }

3250
  key_length= create_table_def_key(thd, key, &table_list, 0);
3251
  hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
Marc Alff's avatar
Marc Alff committed
3252
  mysql_mutex_lock(&LOCK_open);
3253
  share= get_table_share(thd, &table_list, key,
3254
                         key_length, OPEN_VIEW, &not_used, hash_value);
3255
  if (!share)
3256
  {
3257
    res= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
3258
    goto end_unlock;
3259
  }
Sergey Glukhov's avatar
Sergey Glukhov committed
3260

3261 3262 3263
  if (share->is_view)
  {
    if (schema_table->i_s_requested_object & OPEN_TABLE_ONLY)
3264
    {
3265 3266
      /* skip view processing */
      res= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
3267
      goto end_share;
3268
    }
3269 3270 3271
    else if (schema_table->i_s_requested_object & OPEN_VIEW_FULL)
    {
      /*
Sergey Glukhov's avatar
Sergey Glukhov committed
3272
        tell get_all_tables() to fall back to
3273 3274 3275
        open_normal_and_derived_tables()
      */
      res= 1;
Konstantin Osipov's avatar
Konstantin Osipov committed
3276
      goto end_share;
3277
    }
3278 3279
  }

Sergey Glukhov's avatar
Sergey Glukhov committed
3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294
  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;
  }

3295 3296 3297
  {
    tbl.s= share;
    table_list.table= &tbl;
Konstantin Osipov's avatar
Konstantin Osipov committed
3298
    table_list.view= (LEX*) share->is_view;
3299 3300 3301 3302
    res= schema_table->process_table(thd, &table_list, table,
                                     res, db_name, table_name);
  }

Konstantin Osipov's avatar
Konstantin Osipov committed
3303
end_share:
Konstantin Osipov's avatar
Konstantin Osipov committed
3304
  release_table_share(share);
3305

Konstantin Osipov's avatar
Konstantin Osipov committed
3306
end_unlock:
Marc Alff's avatar
Marc Alff committed
3307
  mysql_mutex_unlock(&LOCK_open);
3308 3309 3310 3311 3312
  /*
    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.
  */
3313

Sergey Glukhov's avatar
Sergey Glukhov committed
3314
end:
3315 3316
  thd->clear_error();
  return res;
3317
}
3318

3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338

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

3339 3340 3341 3342
int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  LEX *lex= thd->lex;
  TABLE *table= tables->table;
3343
  SELECT_LEX *old_all_select_lex= lex->all_selects_list;
unknown's avatar
unknown committed
3344
  SELECT_LEX *lsel= tables->schema_select_lex;
3345
  ST_SCHEMA_TABLE *schema_table= tables->schema_table;
3346
  SELECT_LEX sel;
3347 3348
  LOOKUP_FIELD_VALUES lookup_field_vals;
  LEX_STRING *db_name, *table_name;
3349 3350
  bool with_i_schema;
  enum enum_schema_tables schema_table_idx;
3351 3352
  List<LEX_STRING> db_names;
  List_iterator_fast<LEX_STRING> it(db_names);
3353
  COND *partial_cond= 0;
3354
  uint derived_tables= lex->derived_tables; 
unknown's avatar
unknown committed
3355
  int error= 1;
3356
  Open_tables_backup open_tables_state_backup;
3357
  bool save_view_prepare_mode= lex->view_prepare_mode;
3358
  Query_tables_list query_tables_list_backup;
3359 3360 3361
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  Security_context *sctx= thd->security_ctx;
#endif
3362
  uint table_open_method;
Konstantin Osipov's avatar
Konstantin Osipov committed
3363
  bool can_deadlock;
3364 3365
  DBUG_ENTER("get_all_tables");

Konstantin Osipov's avatar
Konstantin Osipov committed
3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376
  /*
    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();

3377
  lex->view_prepare_mode= TRUE;
3378
  lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
3379 3380 3381 3382 3383 3384
  /*
    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;
3385 3386

  /*
3387 3388
    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
3389 3390
    open and will ignore pending exclusive metadata locks for these
    tables by using high-priority requests for shared metadata locks.
3391
  */
3392 3393
  thd->reset_n_backup_open_tables_state(&open_tables_state_backup);

Sergey Glukhov's avatar
Sergey Glukhov committed
3394 3395 3396 3397
  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));
3398 3399 3400 3401 3402
  /* 
    this branch processes SHOW FIELDS, SHOW INDEXES commands.
    see sql_parse.cc, prepare_schema_table() function where
    this values are initialized
  */
3403
  if (lsel && lsel->table_list.first)
3404
  {
3405
    error= fill_schema_show_cols_or_idxs(thd, tables, schema_table,
Konstantin Osipov's avatar
Konstantin Osipov committed
3406
                                         can_deadlock,
3407
                                         &open_tables_state_backup);
unknown's avatar
unknown committed
3408
    goto err;
3409 3410
  }

3411 3412 3413 3414 3415
  if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
  {
    error= 0;
    goto err;
  }
3416
  DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'",
3417 3418
                             STR_OR_NIL(lookup_field_vals.db_value.str),
                             STR_OR_NIL(lookup_field_vals.table_value.str)));
3419

3420 3421 3422 3423 3424 3425
  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
3426 3427 3428 3429
    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]))
3430 3431 3432 3433 3434 3435 3436 3437
    {
      error= 0;
      goto err;
    }
  }

  if (lookup_field_vals.db_value.length &&
      !lookup_field_vals.wild_db_value)
3438 3439 3440 3441
    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;
3442

3443 3444 3445 3446 3447
  if (tables->has_db_lookup_value && tables->has_table_lookup_value)
    partial_cond= 0;
  else
    partial_cond= make_cond_for_info_schema(cond, tables);

3448 3449 3450 3451
  if (lex->describe)
  {
    /* EXPLAIN SELECT */
    error= 0;
unknown's avatar
unknown committed
3452
    goto err;
3453
  }
3454

3455 3456
  if (make_db_list(thd, &db_names, &lookup_field_vals, &with_i_schema))
    goto err;
unknown's avatar
unknown committed
3457
  it.rewind(); /* To get access to new elements in basis list */
3458
  while ((db_name= it++))
3459 3460
  {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3461 3462
    if (!(check_access(thd, SELECT_ACL, db_name->str,
                       &thd->col_access, NULL, 0, 1) ||
3463
          (!thd->col_access && check_grant_db(thd, db_name->str))) ||
3464
        sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
3465
        acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
3466 3467
#endif
    {
3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479
      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++))
3480
      {
3481 3482 3483 3484 3485 3486 3487
	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())
3488 3489
        {
          /*
3490 3491 3492 3493
            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).
3494
          */
3495 3496 3497
          if (!table_open_method && schema_table_idx == SCH_TABLES &&
              (!lookup_field_vals.table_value.length ||
               lookup_field_vals.wild_table_value))
3498
          {
3499
            table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
3500 3501
            if (schema_table_store_record(thd, table))
              goto err;      /* Out of space in temporary table */
3502 3503
            continue;
          }
3504

3505
          /* SHOW TABLE NAMES command */
3506 3507
          if (schema_table_idx == SCH_TABLE_NAMES)
          {
3508 3509 3510
            if (fill_schema_table_names(thd, tables->table, db_name,
                                        table_name, with_i_schema))
              continue;
3511 3512 3513
          }
          else
          {
Sergey Glukhov's avatar
Sergey Glukhov committed
3514
            if (!(table_open_method & ~OPEN_FRM_ONLY) &&
3515 3516
                !with_i_schema)
            {
Sergey Glukhov's avatar
Sergey Glukhov committed
3517
              if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name,
Konstantin Osipov's avatar
Konstantin Osipov committed
3518 3519
                                              table_name, schema_table_idx,
                                              can_deadlock))
3520 3521 3522
                continue;
            }

3523
            int res;
3524
            LEX_STRING tmp_lex_string, orig_db_name;
unknown's avatar
unknown committed
3525
            /*
3526 3527
              Set the parent lex of 'sel' because it is needed by
              sel.init_query() which is called inside make_table_list.
unknown's avatar
unknown committed
3528
            */
3529
            thd->no_warnings_for_error= 1;
unknown's avatar
unknown committed
3530
            sel.parent_lex= lex;
3531 3532 3533 3534 3535
            /* 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))
unknown's avatar
unknown committed
3536
              goto err;
3537
            TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first;
3538 3539
            lex->all_selects_list= &sel;
            lex->derived_tables= 0;
3540
            lex->sql_command= SQLCOM_SHOW_FIELDS;
3541 3542
            show_table_list->i_s_requested_object=
              schema_table->i_s_requested_object;
3543
            res= open_normal_and_derived_tables(thd, show_table_list,
3544
                   (MYSQL_OPEN_IGNORE_FLUSH |
3545
                    MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
Konstantin Osipov's avatar
Konstantin Osipov committed
3546
                    (can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
3547
            lex->sql_command= query_tables_list_backup.sql_command;
3548 3549 3550 3551 3552 3553
            /*
              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
3554
              for thd->stmt_da->sql_errno().
3555 3556
            */
            if (res && thd->is_error() &&
Marc Alff's avatar
Marc Alff committed
3557
                thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
3558
            {
3559 3560 3561 3562 3563 3564
              /*
                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.
              */
3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576
              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.
              */
3577 3578
              thd->make_lex_string(&tmp_lex_string, show_table_list->alias,
                                   strlen(show_table_list->alias), FALSE);
3579
              res= schema_table->process_table(thd, show_table_list, table,
3580 3581
                                               res, &orig_db_name,
                                               &tmp_lex_string);
3582 3583
              close_tables_for_reopen(thd, &show_table_list,
                                      open_tables_state_backup.mdl_system_tables_svp);
3584
            }
3585
            DBUG_ASSERT(!lex->query_tables_own_last);
3586
            if (res)
unknown's avatar
unknown committed
3587
              goto err;
3588 3589 3590
          }
        }
      }
3591 3592 3593 3594
      /*
        If we have information schema its always the first table and only
        the first table. Reset for other tables.
      */
3595
      with_i_schema= 0;
3596 3597
    }
  }
unknown's avatar
unknown committed
3598 3599 3600

  error= 0;
err:
3601
  thd->restore_backup_open_tables_state(&open_tables_state_backup);
3602
  lex->restore_backup_query_tables_list(&query_tables_list_backup);
3603 3604
  lex->derived_tables= derived_tables;
  lex->all_selects_list= old_all_select_lex;
3605
  lex->view_prepare_mode= save_view_prepare_mode;
unknown's avatar
unknown committed
3606
  DBUG_RETURN(error);
3607 3608 3609
}


3610
bool store_schema_shemata(THD* thd, TABLE *table, LEX_STRING *db_name,
3611
                          CHARSET_INFO *cs)
3612
{
3613
  restore_record(table, s->default_values);
3614
  table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
3615
  table->field[1]->store(db_name->str, db_name->length, system_charset_info);
3616 3617
  table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info);
  table->field[3]->store(cs->name, strlen(cs->name), system_charset_info);
3618
  return schema_table_store_record(thd, table);
3619 3620 3621
}


3622
int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
3623
{
3624 3625 3626 3627 3628
  /*
    TODO: fill_schema_shemata() is called when new client is connected.
    Returning error status in this case leads to client hangup.
  */

3629 3630 3631
  LOOKUP_FIELD_VALUES lookup_field_vals;
  List<LEX_STRING> db_names;
  LEX_STRING *db_name;
unknown's avatar
unknown committed
3632
  bool with_i_schema;
3633 3634
  HA_CREATE_INFO create;
  TABLE *table= tables->table;
3635
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3636
  Security_context *sctx= thd->security_ctx;
3637
#endif
3638
  DBUG_ENTER("fill_schema_shemata");
3639

3640 3641
  if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
    DBUG_RETURN(0);
3642 3643 3644 3645 3646
  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))
3647
    DBUG_RETURN(1);
3648

3649 3650 3651
  /*
    If we have lookup db value we should check that the database exists
  */
3652 3653
  if(lookup_field_vals.db_value.str && !lookup_field_vals.wild_db_value &&
     !with_i_schema)
3654 3655 3656 3657 3658 3659
  {
    char path[FN_REFLEN+16];
    uint path_len;
    MY_STAT stat_info;
    if (!lookup_field_vals.db_value.str[0])
      DBUG_RETURN(0);
3660
    path_len= build_table_filename(path, sizeof(path) - 1,
3661 3662
                                   lookup_field_vals.db_value.str, "", "", 0);
    path[path_len-1]= 0;
Marc Alff's avatar
Marc Alff committed
3663
    if (!mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
3664 3665 3666
      DBUG_RETURN(0);
  }

3667 3668
  List_iterator_fast<LEX_STRING> it(db_names);
  while ((db_name=it++))
3669
  {
3670 3671
    if (with_i_schema)       // information schema name is always first in list
    {
3672
      if (store_schema_shemata(thd, table, db_name,
3673
                               system_charset_info))
3674
        DBUG_RETURN(1);
3675 3676 3677
      with_i_schema= 0;
      continue;
    }
3678
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3679
    if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
3680 3681
	acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
	!check_grant_db(thd, db_name->str))
3682 3683
#endif
    {
3684 3685
      load_db_opt_by_name(thd, db_name->str, &create);
      if (store_schema_shemata(thd, table, db_name,
3686
                               create.default_table_charset))
3687
        DBUG_RETURN(1);
3688 3689
    }
  }
3690
  DBUG_RETURN(0);
3691 3692 3693
}


3694
static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
3695
				    TABLE *table, bool res,
3696 3697
				    LEX_STRING *db_name,
				    LEX_STRING *table_name)
3698 3699
{
  const char *tmp_buff;
3700
  MYSQL_TIME time;
3701 3702
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_schema_tables_record");
3703 3704

  restore_record(table, s->default_values);
3705
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
3706 3707
  table->field[1]->store(db_name->str, db_name->length, cs);
  table->field[2]->store(table_name->str, table_name->length, cs);
unknown's avatar
unknown committed
3708 3709 3710 3711 3712
  if (res)
  {
    /*
      there was errors during opening tables
    */
Marc Alff's avatar
Marc Alff committed
3713
    const char *error= thd->is_error() ? thd->stmt_da->message() : "";
3714 3715 3716 3717 3718 3719
    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);
unknown's avatar
unknown committed
3720 3721 3722 3723
    table->field[20]->store(error, strlen(error), cs);
    thd->clear_error();
  }
  else if (tables->view)
3724
  {
3725 3726
    table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
    table->field[20]->store(STRING_WITH_LEN("VIEW"), cs);
3727 3728 3729
  }
  else
  {
3730
    char option_buff[350],*ptr;
3731
    TABLE *show_table= tables->table;
3732
    TABLE_SHARE *share= show_table->s;
3733
    handler *file= show_table->file;
3734
    handlerton *tmp_db_type= share->db_type();
3735
#ifdef WITH_PARTITION_STORAGE_ENGINE
3736
    bool is_partitioned= FALSE;
3737
#endif
3738
    if (share->tmp_table == SYSTEM_TMP_TABLE)
3739
      table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
3740
    else if (share->tmp_table)
3741
      table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs);
3742
    else
3743
      table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
3744

3745 3746
    for (int i= 4; i < 20; i++)
    {
3747
      if (i == 7 || (i > 12 && i < 17) || i == 18)
3748 3749 3750
        continue;
      table->field[i]->set_notnull();
    }
3751 3752
#ifdef WITH_PARTITION_STORAGE_ENGINE
    if (share->db_type() == partition_hton &&
3753
        share->partition_info_str_len)
3754
    {
3755
      tmp_db_type= share->default_part_db_type;
3756 3757
      is_partitioned= TRUE;
    }
3758 3759
#endif
    tmp_buff= (char *) ha_resolve_storage_engine_name(tmp_db_type);
3760
    table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
3761
    table->field[5]->store((longlong) share->frm_version, TRUE);
3762 3763

    ptr=option_buff;
3764
    if (share->min_rows)
3765 3766
    {
      ptr=strmov(ptr," min_rows=");
3767
      ptr=longlong10_to_str(share->min_rows,ptr,10);
3768
    }
3769
    if (share->max_rows)
3770 3771
    {
      ptr=strmov(ptr," max_rows=");
3772
      ptr=longlong10_to_str(share->max_rows,ptr,10);
3773
    }
3774
    if (share->avg_row_length)
3775 3776
    {
      ptr=strmov(ptr," avg_row_length=");
3777
      ptr=longlong10_to_str(share->avg_row_length,ptr,10);
3778
    }
3779
    if (share->db_create_options & HA_OPTION_PACK_KEYS)
3780
      ptr=strmov(ptr," pack_keys=1");
3781
    if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
3782
      ptr=strmov(ptr," pack_keys=0");
3783
    /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
3784
    if (share->db_create_options & HA_OPTION_CHECKSUM)
3785
      ptr=strmov(ptr," checksum=1");
3786
    if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
3787
      ptr=strmov(ptr," delay_key_write=1");
3788
    if (share->row_type != ROW_TYPE_DEFAULT)
3789
      ptr=strxmov(ptr, " row_format=", 
3790
                  ha_row_type[(uint) share->row_type],
3791
                  NullS);
3792 3793 3794 3795 3796
    if (share->key_block_size)
    {
      ptr= strmov(ptr, " KEY_BLOCK_SIZE=");
      ptr= longlong10_to_str(share->key_block_size, ptr, 10);
    }
3797
#ifdef WITH_PARTITION_STORAGE_ENGINE
3798
    if (is_partitioned)
3799 3800
      ptr= strmov(ptr, " partitioned");
#endif
3801 3802 3803
    table->field[19]->store(option_buff+1,
                            (ptr == option_buff ? 0 : 
                             (uint) (ptr-option_buff)-1), cs);
3804

3805 3806 3807 3808
    tmp_buff= (share->table_charset ?
               share->table_charset->name : "default");
    table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);

3809 3810 3811 3812
    if (share->comment.str)
      table->field[20]->store(share->comment.str, share->comment.length, cs);

    if(file)
3813
    {
3814
      file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO);
3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838
      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;
3839
      case ROW_TYPE_PAGE:
3840 3841 3842 3843 3844
        tmp_buff= "Paged";
        break;
      }
      table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
      if (!tables->schema_table)
3845
      {
3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871
        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)
3872
      {
3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888
        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();
3889 3890
      }
    }
3891
  }
3892
  DBUG_RETURN(schema_table_store_record(thd, table));
3893 3894 3895
}


Sergey Glukhov's avatar
Sergey Glukhov committed
3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 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 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 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
/**
  @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_LONGLONG:
  case MYSQL_TYPE_INT24:
    field_length= field->max_display_length() - 1;
    break;
  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();
  }
}


4018
static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
4019
				    TABLE *table, bool res,
4020 4021
				    LEX_STRING *db_name,
				    LEX_STRING *table_name)
4022
{
4023 4024
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
4025
  CHARSET_INFO *cs= system_charset_info;
4026
  TABLE *show_table;
Sergey Glukhov's avatar
Sergey Glukhov committed
4027 4028
  TABLE_SHARE *show_table_share;
  Field **ptr, *field, *timestamp_field;
4029
  int count;
4030
  DBUG_ENTER("get_schema_column_record");
4031

4032 4033
  if (res)
  {
4034
    if (lex->sql_command != SQLCOM_SHOW_FIELDS)
4035 4036 4037 4038
    {
      /*
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
        rather than in SHOW COLUMNS
Sergey Glukhov's avatar
Sergey Glukhov committed
4039
      */
4040 4041
      if (thd->is_error())
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4042
                     thd->stmt_da->sql_errno(), thd->stmt_da->message());
4043 4044 4045 4046
      thd->clear_error();
      res= 0;
    }
    DBUG_RETURN(res);
4047 4048
  }

4049
  show_table= tables->table;
Sergey Glukhov's avatar
Sergey Glukhov committed
4050
  show_table_share= show_table->s;
4051 4052
  count= 0;

Sergey Glukhov's avatar
Sergey Glukhov committed
4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082
  if (tables->view || tables->schema_table)
  {
    ptr= show_table->field;
    timestamp_field= show_table->timestamp_field;
    show_table->use_all_columns();               // Required for default
  }
  else
  {
    ptr= show_table_share->field;
    timestamp_field= show_table_share->timestamp_field;
    /*
      read_set may be inited in case of
      temporary table
    */
    if (!show_table->read_set)
    {
      /* to satisfy 'field->val_str' ASSERTs */
      uchar *bitmaps;
      uint bitmap_size= show_table_share->column_bitmap_size;
      if (!(bitmaps= (uchar*) alloc_root(thd->mem_root, bitmap_size)))
        DBUG_RETURN(0);
      bitmap_init(&show_table->def_read_set,
                  (my_bitmap_map*) bitmaps, show_table_share->fields, FALSE);
      bitmap_set_all(&show_table->def_read_set);
      show_table->read_set= &show_table->def_read_set;
    }
    bitmap_set_all(show_table->read_set);
  }

  for (; (field= *ptr) ; ptr++)
4083
  {
4084
    uchar *pos;
4085 4086 4087
    char tmp[MAX_FIELD_WIDTH];
    String type(tmp,sizeof(tmp), system_charset_info);
    char *end;
Sergey Glukhov's avatar
Sergey Glukhov committed
4088 4089 4090 4091

    /* to satisfy 'field->val_str' ASSERTs */
    field->table= show_table;
    show_table->in_use= thd;
4092 4093 4094 4095 4096 4097 4098 4099

    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);
4100 4101

#ifndef NO_EMBEDDED_ACCESS_CHECKS
4102
    uint col_access;
Sergey Glukhov's avatar
Sergey Glukhov committed
4103 4104 4105
    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,
4106
                                 db_name->str, table_name->str,
4107
                                 field->field_name) & COL_ACLS;
4108
    if (!tables->schema_table && !col_access)
4109 4110 4111 4112 4113
      continue;
    end= tmp;
    for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
    {
      if (col_access & 1)
4114
      {
4115 4116
        *end++=',';
        end=strmov(end,grant_types.type_names[bitnr]);
4117
      }
4118
    }
4119
    table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
4120

unknown's avatar
unknown committed
4121
#endif
4122
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
4123 4124
    table->field[1]->store(db_name->str, db_name->length, cs);
    table->field[2]->store(table_name->str, table_name->length, cs);
4125 4126
    table->field[3]->store(field->field_name, strlen(field->field_name),
                           cs);
4127
    table->field[4]->store((longlong) count, TRUE);
4128
    field->sql_type(type);
4129
    table->field[14]->store(type.ptr(), type.length(), cs);
4130

Sergey Glukhov's avatar
Sergey Glukhov committed
4131
    if (get_field_default_value(thd, timestamp_field, field, &type, 0))
4132
    {
4133
      table->field[5]->store(type.ptr(), type.length(), cs);
4134 4135
      table->field[5]->set_notnull();
    }
Sergey Glukhov's avatar
Sergey Glukhov committed
4136
    pos=(uchar*) ((field->flags & NOT_NULL_FLAG) ?  "NO" : "YES");
4137 4138
    table->field[6]->store((const char*) pos,
                           strlen((const char*) pos), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4139
    store_column_type(table, field, cs, 7);
4140
    pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
4141 4142 4143 4144 4145 4146 4147
                 (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
                 (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
    table->field[15]->store((const char*) pos,
                            strlen((const char*) pos), cs);

    end= tmp;
    if (field->unireg_check == Field::NEXT_NUMBER)
4148
      table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4149
    if (timestamp_field == field &&
4150 4151 4152
        field->unireg_check != Field::TIMESTAMP_DN_FIELD)
      table->field[16]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
                              cs);
4153 4154 4155 4156

    table->field[18]->store(field->comment.str, field->comment.length, cs);
    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167
  }
  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;
4168

4169 4170 4171
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets) ;
       cs++)
4172 4173 4174 4175
  {
    CHARSET_INFO *tmp_cs= cs[0];
    if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && 
        (tmp_cs->state & MY_CS_AVAILABLE) &&
unknown's avatar
unknown committed
4176
        !(tmp_cs->state & MY_CS_HIDDEN) &&
4177 4178 4179
        !(wild && wild[0] &&
	  wild_case_compare(scs, tmp_cs->csname,wild)))
    {
4180
      const char *comment;
4181
      restore_record(table, s->default_values);
4182
      table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs);
4183
      table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs);
4184 4185
      comment= tmp_cs->comment ? tmp_cs->comment : "";
      table->field[2]->store(comment, strlen(comment), scs);
4186
      table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE);
4187 4188
      if (schema_table_store_record(thd, table))
        return 1;
4189 4190 4191 4192 4193 4194
    }
  }
  return 0;
}


unknown's avatar
unknown committed
4195
static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
4196
                                   void *ptable)
unknown's avatar
unknown committed
4197
{
unknown's avatar
unknown committed
4198
  TABLE *table= (TABLE *) ptable;
unknown's avatar
unknown committed
4199
  handlerton *hton= plugin_data(plugin, handlerton *);
unknown's avatar
unknown committed
4200 4201
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  CHARSET_INFO *scs= system_charset_info;
unknown's avatar
unknown committed
4202
  handlerton *default_type= ha_default_handlerton(thd);
unknown's avatar
unknown committed
4203
  DBUG_ENTER("iter_schema_engines");
unknown's avatar
unknown committed
4204

4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223

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

unknown's avatar
unknown committed
4224
  if (!(hton->flags & HTON_HIDDEN))
unknown's avatar
unknown committed
4225
  {
unknown's avatar
unknown committed
4226
    LEX_STRING *name= plugin_name(plugin);
unknown's avatar
unknown committed
4227
    if (!(wild && wild[0] &&
unknown's avatar
unknown committed
4228
          wild_case_compare(scs, name->str,wild)))
unknown's avatar
unknown committed
4229
    {
unknown's avatar
unknown committed
4230 4231
      LEX_STRING yesno[2]= {{ C_STRING_WITH_LEN("NO") },
                            { C_STRING_WITH_LEN("YES") }};
unknown's avatar
unknown committed
4232
      LEX_STRING *tmp;
4233
      const char *option_name= show_comp_option_name[(int) hton->state];
unknown's avatar
unknown committed
4234 4235
      restore_record(table, s->default_values);

unknown's avatar
unknown committed
4236
      table->field[0]->store(name->str, name->length, scs);
unknown's avatar
unknown committed
4237
      if (hton->state == SHOW_OPTION_YES && default_type == hton)
4238 4239
        option_name= "DEFAULT";
      table->field[1]->store(option_name, strlen(option_name), scs);
unknown's avatar
unknown committed
4240 4241
      table->field[2]->store(plugin_decl(plugin)->descr,
                             strlen(plugin_decl(plugin)->descr), scs);
unknown's avatar
unknown committed
4242 4243
      tmp= &yesno[test(hton->commit)];
      table->field[3]->store(tmp->str, tmp->length, scs);
4244
      table->field[3]->set_notnull();
unknown's avatar
unknown committed
4245 4246
      tmp= &yesno[test(hton->prepare)];
      table->field[4]->store(tmp->str, tmp->length, scs);
4247
      table->field[4]->set_notnull();
unknown's avatar
unknown committed
4248 4249
      tmp= &yesno[test(hton->savepoint_set)];
      table->field[5]->store(tmp->str, tmp->length, scs);
4250
      table->field[5]->set_notnull();
unknown's avatar
unknown committed
4251 4252 4253 4254 4255 4256 4257 4258

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

unknown's avatar
unknown committed
4259 4260
int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond)
{
4261 4262 4263 4264 4265 4266
  DBUG_ENTER("fill_schema_engines");
  if (plugin_foreach_with_mask(thd, iter_schema_engines,
                               MYSQL_STORAGE_ENGINE_PLUGIN,
                               ~PLUGIN_IS_FREED, tables->table))
    DBUG_RETURN(1);
  DBUG_RETURN(0);
unknown's avatar
unknown committed
4267 4268 4269
}


4270 4271 4272 4273 4274 4275
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;
4276 4277 4278
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets)  ;
       cs++ )
4279 4280 4281
  {
    CHARSET_INFO **cl;
    CHARSET_INFO *tmp_cs= cs[0];
unknown's avatar
unknown committed
4282
    if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
unknown's avatar
unknown committed
4283
         (tmp_cs->state & MY_CS_HIDDEN) ||
4284 4285
        !(tmp_cs->state & MY_CS_PRIMARY))
      continue;
4286 4287 4288
    for (cl= all_charsets;
         cl < all_charsets + array_elements(all_charsets)  ;
         cl ++)
4289 4290 4291 4292 4293 4294 4295 4296 4297
    {
      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;
4298
	restore_record(table, s->default_values);
4299 4300
	table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
        table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
4301
        table->field[2]->store((longlong) tmp_cl->number, TRUE);
4302 4303 4304 4305
        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);
4306
        table->field[5]->store((longlong) tmp_cl->strxfrm_multiply, TRUE);
4307 4308
        if (schema_table_store_record(thd, table))
          return 1;
4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320
      }
    }
  }
  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;
4321 4322 4323
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets) ;
       cs++ )
4324 4325 4326 4327 4328 4329
  {
    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;
4330 4331 4332
    for (cl= all_charsets;
         cl < all_charsets + array_elements(all_charsets) ;
         cl ++)
4333 4334
    {
      CHARSET_INFO *tmp_cl= cl[0];
4335 4336
      if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
          (tmp_cl->state & MY_CS_HIDDEN) ||
4337 4338
          !my_charset_same(tmp_cs,tmp_cl))
	continue;
4339
      restore_record(table, s->default_values);
4340 4341
      table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
      table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
4342 4343
      if (schema_table_store_record(thd, table))
        return 1;
4344 4345 4346 4347 4348 4349
    }
  }
  return 0;
}


Sergey Glukhov's avatar
Sergey Glukhov committed
4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 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
/**
  @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);
}


4513
bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
4514
                       const char *wild, bool full_access, const char *sp_user)
4515 4516
{
  String tmp_string;
4517
  String sp_db, sp_name, definer;
4518
  MYSQL_TIME time;
4519 4520
  LEX *lex= thd->lex;
  CHARSET_INFO *cs= system_charset_info;
Sergey Glukhov's avatar
Sergey Glukhov committed
4521 4522 4523
  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);
4524
  if (!full_access)
4525
    full_access= !strcmp(sp_user, definer.ptr());
Sergey Glukhov's avatar
Sergey Glukhov committed
4526 4527 4528 4529
  if (!full_access && 
      check_some_routine_access(thd, sp_db.ptr(), sp_name.ptr(),
                                proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
                                val_int() == TYPE_ENUM_PROCEDURE))
4530
    return 0;
4531

Staale Smedseng's avatar
Staale Smedseng committed
4532
  if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
Sergey Glukhov's avatar
Sergey Glukhov committed
4533 4534
      proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
      TYPE_ENUM_PROCEDURE) ||
Staale Smedseng's avatar
Staale Smedseng committed
4535
      (lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
Sergey Glukhov's avatar
Sergey Glukhov committed
4536 4537
      proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
      TYPE_ENUM_FUNCTION) ||
4538
      (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
4539
  {
4540
    restore_record(table, s->default_values);
4541
    if (!wild || !wild[0] || !wild_compare(sp_name.ptr(), wild, 0))
4542
    {
Sergey Glukhov's avatar
Sergey Glukhov committed
4543
      int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int();
4544
      table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4545 4546
      get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME],
                &tmp_string);
4547
      table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
4548
      table->field[1]->store(STRING_WITH_LEN("def"), cs);
4549
      table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4550 4551
      get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
                &tmp_string);
4552
      table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4553 4554
      if (proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
          TYPE_ENUM_FUNCTION)
4555
      {
Sergey Glukhov's avatar
Sergey Glukhov committed
4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592
        sp_head *sp;
        bool free_sp_head;
        get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS],
                  &tmp_string);

        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,
                                           tmp_string.c_ptr_safe(),
                                           "", &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;
        }
4593
      }
Sergey Glukhov's avatar
Sergey Glukhov committed
4594

4595 4596
      if (full_access)
      {
Sergey Glukhov's avatar
Sergey Glukhov committed
4597 4598 4599 4600
        get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_BODY_UTF8],
                  &tmp_string);
        table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
        table->field[14]->set_notnull();
4601
      }
Sergey Glukhov's avatar
Sergey Glukhov committed
4602 4603 4604 4605 4606 4607 4608 4609
      table->field[13]->store(STRING_WITH_LEN("SQL"), cs);
      table->field[17]->store(STRING_WITH_LEN("SQL"), cs);


      get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DETERMINISTIC],
                &tmp_string);
      table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs);
      table->field[19]->store(sp_data_access_name[enum_idx].str, 
4610
                              sp_data_access_name[enum_idx].length , cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4611 4612 4613 4614

      get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_SECURITY_TYPE],
                &tmp_string);
      table->field[21]->store(tmp_string.ptr(), tmp_string.length(), cs);
4615
      bzero((char *)&time, sizeof(time));
Sergey Glukhov's avatar
Sergey Glukhov committed
4616 4617 4618
      ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_CREATED])->
        get_time(&time);
      table->field[22]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
4619
      bzero((char *)&time, sizeof(time));
Sergey Glukhov's avatar
Sergey Glukhov committed
4620 4621 4622
      ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_MODIFIED])->
        get_time(&time);
      table->field[23]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
unknown's avatar
unknown committed
4623

Sergey Glukhov's avatar
Sergey Glukhov committed
4624 4625 4626
      get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_SQL_MODE],
                &tmp_string);
      table->field[24]->store(tmp_string.ptr(), tmp_string.length(), cs);
unknown's avatar
unknown committed
4627

Sergey Glukhov's avatar
Sergey Glukhov committed
4628 4629 4630 4631
      get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_COMMENT],
                &tmp_string);
      table->field[25]->store(tmp_string.ptr(), tmp_string.length(), cs);
      table->field[26]->store(definer.ptr(), definer.length(), cs);
unknown's avatar
unknown committed
4632

Sergey Glukhov's avatar
Sergey Glukhov committed
4633 4634 4635 4636
      get_field(thd->mem_root,
                proc_table->field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT],
                &tmp_string);
      table->field[27]->store(tmp_string.ptr(), tmp_string.length(), cs);
unknown's avatar
unknown committed
4637

Sergey Glukhov's avatar
Sergey Glukhov committed
4638 4639 4640 4641 4642 4643 4644 4645
      get_field(thd->mem_root,
                proc_table->field[ MYSQL_PROC_FIELD_COLLATION_CONNECTION],
                &tmp_string);
      table->field[28]->store(tmp_string.ptr(), tmp_string.length(), cs);

      get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DB_COLLATION],
                &tmp_string);
      table->field[29]->store(tmp_string.ptr(), tmp_string.length(), cs);
unknown's avatar
unknown committed
4646

4647
      return schema_table_store_record(thd, table);
4648 4649
    }
  }
4650
  return 0;
4651 4652 4653 4654 4655 4656 4657 4658 4659
}


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;
4660
  TABLE *table= tables->table;
4661
  bool full_access;
4662
  char definer[USER_HOST_BUFF_SIZE];
4663
  Open_tables_backup open_tables_state_backup;
Sergey Glukhov's avatar
Sergey Glukhov committed
4664 4665
  enum enum_schema_tables schema_table_idx=
    get_schema_table_idx(tables->schema_table);
4666 4667
  DBUG_ENTER("fill_schema_proc");

4668 4669
  strxmov(definer, thd->security_ctx->priv_user, "@",
          thd->security_ctx->priv_host, NullS);
4670
  /* We use this TABLE_LIST instance only for checking of privileges. */
4671 4672
  bzero((char*) &proc_tables,sizeof(proc_tables));
  proc_tables.db= (char*) "mysql";
4673
  proc_tables.db_length= 5;
4674
  proc_tables.table_name= proc_tables.alias= (char*) "proc";
4675
  proc_tables.table_name_length= 4;
4676
  proc_tables.lock_type= TL_READ;
4677 4678
  full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, FALSE,
                                   1, TRUE);
4679
  if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup)))
4680 4681 4682
  {
    DBUG_RETURN(1);
  }
4683
  proc_table->file->ha_index_init(0, 1);
4684 4685 4686 4687 4688
  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
4689 4690 4691 4692

  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))
4693 4694 4695 4696
  {
    res= 1;
    goto err;
  }
4697
  while (!proc_table->file->index_next(proc_table->record[0]))
4698
  {
Sergey Glukhov's avatar
Sergey Glukhov committed
4699 4700 4701
    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))
4702 4703 4704 4705 4706
    {
      res= 1;
      goto err;
    }
  }
4707 4708 4709

err:
  proc_table->file->ha_index_end();
4710
  close_system_tables(thd, &open_tables_state_backup);
4711 4712 4713 4714
  DBUG_RETURN(res);
}


4715
static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
4716
				  TABLE *table, bool res,
4717 4718
				  LEX_STRING *db_name,
				  LEX_STRING *table_name)
4719 4720 4721
{
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_schema_stat_record");
4722 4723
  if (res)
  {
4724
    if (thd->lex->sql_command != SQLCOM_SHOW_KEYS)
4725 4726 4727 4728
    {
      /*
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
        rather than in SHOW KEYS
4729
      */
4730
      if (thd->is_error())
4731
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4732
                     thd->stmt_da->sql_errno(), thd->stmt_da->message());
4733 4734 4735 4736 4737 4738
      thd->clear_error();
      res= 0;
    }
    DBUG_RETURN(res);
  }
  else if (!tables->view)
4739 4740
  {
    TABLE *show_table= tables->table;
4741 4742 4743 4744 4745
    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);
4746
    for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
4747 4748 4749 4750 4751
    {
      KEY_PART_INFO *key_part= key_info->key_part;
      const char *str;
      for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
      {
4752
        restore_record(table, s->default_values);
4753
        table->field[0]->store(STRING_WITH_LEN("def"), cs);
4754 4755
        table->field[1]->store(db_name->str, db_name->length, cs);
        table->field[2]->store(table_name->str, table_name->length, cs);
4756
        table->field[3]->store((longlong) ((key_info->flags &
4757
                                            HA_NOSAME) ? 0 : 1), TRUE);
4758
        table->field[4]->store(db_name->str, db_name->length, cs);
4759
        table->field[5]->store(key_info->name, strlen(key_info->name), cs);
4760
        table->field[6]->store((longlong) (j+1), TRUE);
4761 4762 4763
        str=(key_part->field ? key_part->field->field_name :
             "?unknown field?");
        table->field[7]->store(str, strlen(str), cs);
4764
        if (show_table->file)
4765
        {
4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782
          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);
4783
        }
4784 4785 4786
        if (!(key_info->flags & HA_FULLTEXT) &&
            (key_part->field &&
             key_part->length !=
4787
             show_table->s->field[key_part->fieldnr-1]->key_length()))
4788
        {
4789
          table->field[10]->store((longlong) key_part->length /
4790
                                  key_part->field->charset()->mbmaxlen, TRUE);
4791 4792 4793 4794 4795
          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);
4796
        if (!show_table->s->keys_in_use.is_set(i))
4797
          table->field[14]->store(STRING_WITH_LEN("disabled"), cs);
4798 4799 4800
        else
          table->field[14]->store("", 0, cs);
        table->field[14]->set_notnull();
4801 4802 4803 4804 4805
        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);
4806 4807
        if (schema_table_store_record(thd, table))
          DBUG_RETURN(1);
4808 4809 4810
      }
    }
  }
unknown's avatar
unknown committed
4811
  DBUG_RETURN(res);
4812 4813 4814
}


4815
static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
4816
				   TABLE *table, bool res,
4817 4818
				   LEX_STRING *db_name,
				   LEX_STRING *table_name)
4819 4820
{
  CHARSET_INFO *cs= system_charset_info;
4821
  char definer[USER_HOST_BUFF_SIZE];
unknown's avatar
unknown committed
4822
  uint definer_len;
4823
  bool updatable_view;
Sergey Glukhov's avatar
Sergey Glukhov committed
4824
  DBUG_ENTER("get_schema_views_record");
unknown's avatar
unknown committed
4825

4826 4827
  if (tables->view)
  {
4828
    Security_context *sctx= thd->security_ctx;
Sergey Glukhov's avatar
Sergey Glukhov committed
4829
    if (!tables->allowed_show)
4830
    {
4831 4832 4833 4834 4835
      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;
4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846
#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
4847 4848
          table_list.db= tables->db;
          table_list.table_name= tables->table_name;
4849 4850
          table_list.grant.privilege= thd->col_access;
          view_access= get_table_grant(thd, &table_list);
Sergey Glukhov's avatar
Sergey Glukhov committed
4851 4852 4853
	  if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
	      (SHOW_VIEW_ACL|SELECT_ACL))
	    tables->allowed_show= TRUE;
4854 4855 4856
        }
      }
#endif
4857
    }
4858
    restore_record(table, s->default_values);
4859
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4860 4861 4862 4863
    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)
4864
    {
Sergey Glukhov's avatar
Sergey Glukhov committed
4865 4866 4867 4868
      table->field[3]->store(tables->view_body_utf8.str,
                             tables->view_body_utf8.length,
                             cs);
    }
4869

Sergey Glukhov's avatar
Sergey Glukhov committed
4870 4871 4872 4873
    if (tables->with_check != VIEW_CHECK_NONE)
    {
      if (tables->with_check == VIEW_CHECK_LOCAL)
        table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs);
unknown's avatar
unknown committed
4874
      else
Sergey Glukhov's avatar
Sergey Glukhov committed
4875 4876 4877 4878
        table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs);
    }
    else
      table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
4879

Sergey Glukhov's avatar
Sergey Glukhov committed
4880 4881 4882
    if (table->pos_in_table_list->table_open_method &
        OPEN_FULL_TABLE)
    {
4883 4884
      updatable_view= 0;
      if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE)
4885
      {
4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900
        /*
          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.
        */
        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++))
4901
        {
4902 4903 4904 4905 4906 4907
          if ((field= item->filed_for_view_update()) && field->field &&
              !field->field->table->pos_in_table_list->schema_table)
          {
            updatable_view= 1;
            break;
          }
4908
        }
4909 4910
        if (updatable_view && !tables->view->can_be_merged())
          updatable_view= 0;
4911
      }
4912 4913
      if (updatable_view)
        table->field[5]->store(STRING_WITH_LEN("YES"), cs);
unknown's avatar
unknown committed
4914
      else
4915
        table->field[5]->store(STRING_WITH_LEN("NO"), cs);
Sergey Glukhov's avatar
Sergey Glukhov committed
4916
    }
unknown's avatar
unknown committed
4917

Sergey Glukhov's avatar
Sergey Glukhov committed
4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933
    definer_len= (strxmov(definer, tables->definer.user.str, "@",
                          tables->definer.host.str, NullS) - definer);
    table->field[6]->store(definer, definer_len, cs);
    if (tables->view_suid)
      table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs);
    else
      table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs);

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

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

4935 4936 4937

    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
4938
    if (res && thd->is_error())
Sergey Glukhov's avatar
Sergey Glukhov committed
4939
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4940
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
4941
  }
Sergey Glukhov's avatar
Sergey Glukhov committed
4942
  if (res)
4943
    thd->clear_error();
4944
  DBUG_RETURN(0);
4945 4946 4947
}


4948 4949
bool store_constraints(THD *thd, TABLE *table, LEX_STRING *db_name,
                       LEX_STRING *table_name, const char *key_name,
4950
                       uint key_len, const char *con_type, uint con_len)
4951 4952
{
  CHARSET_INFO *cs= system_charset_info;
4953
  restore_record(table, s->default_values);
4954
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
4955
  table->field[1]->store(db_name->str, db_name->length, cs);
4956
  table->field[2]->store(key_name, key_len, cs);
4957 4958
  table->field[3]->store(db_name->str, db_name->length, cs);
  table->field[4]->store(table_name->str, table_name->length, cs);
4959
  table->field[5]->store(con_type, con_len, cs);
4960
  return schema_table_store_record(thd, table);
4961 4962 4963
}


4964
static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
4965
					 TABLE *table, bool res,
4966 4967
					 LEX_STRING *db_name,
					 LEX_STRING *table_name)
4968
{
unknown's avatar
unknown committed
4969
  DBUG_ENTER("get_schema_constraints_record");
4970 4971
  if (res)
  {
4972
    if (thd->is_error())
4973
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4974
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
4975 4976 4977 4978
    thd->clear_error();
    DBUG_RETURN(0);
  }
  else if (!tables->view)
4979 4980 4981 4982
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
    KEY *key_info=show_table->key_info;
4983
    uint primary_key= show_table->s->primary_key;
4984 4985 4986
    show_table->file->info(HA_STATUS_VARIABLE | 
                           HA_STATUS_NO_LOCK |
                           HA_STATUS_TIME);
4987
    for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
4988 4989
    {
      if (i != primary_key && !(key_info->flags & HA_NOSAME))
4990 4991
        continue;

4992
      if (i == primary_key && !strcmp(key_info->name, primary_key_name))
4993
      {
4994
        if (store_constraints(thd, table, db_name, table_name, key_info->name,
4995 4996
                              strlen(key_info->name),
                              STRING_WITH_LEN("PRIMARY KEY")))
4997 4998
          DBUG_RETURN(1);
      }
4999
      else if (key_info->flags & HA_NOSAME)
5000
      {
5001
        if (store_constraints(thd, table, db_name, table_name, key_info->name,
5002 5003
                              strlen(key_info->name),
                              STRING_WITH_LEN("UNIQUE")))
5004 5005
          DBUG_RETURN(1);
      }
5006 5007 5008 5009 5010 5011 5012
    }

    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++))
    {
5013
      if (store_constraints(thd, table, db_name, table_name, 
5014 5015 5016 5017
                            f_key_info->forein_id->str,
                            strlen(f_key_info->forein_id->str),
                            "FOREIGN KEY", 11))
        DBUG_RETURN(1);
5018 5019
    }
  }
unknown's avatar
unknown committed
5020
  DBUG_RETURN(res);
5021 5022 5023
}


5024 5025
static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name,
                          LEX_STRING *table_name, LEX_STRING *trigger_name,
5026 5027
                          enum trg_event_type event,
                          enum trg_action_time_type timing,
5028
                          LEX_STRING *trigger_stmt,
5029
                          ulong sql_mode,
unknown's avatar
unknown committed
5030 5031 5032 5033
                          LEX_STRING *definer_buffer,
                          LEX_STRING *client_cs_name,
                          LEX_STRING *connection_cl_name,
                          LEX_STRING *db_cl_name)
5034 5035
{
  CHARSET_INFO *cs= system_charset_info;
5036
  LEX_STRING sql_mode_rep;
5037

5038
  restore_record(table, s->default_values);
5039
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
5040
  table->field[1]->store(db_name->str, db_name->length, cs);
5041 5042 5043
  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);
5044
  table->field[4]->store(STRING_WITH_LEN("def"), cs);
5045 5046
  table->field[5]->store(db_name->str, db_name->length, cs);
  table->field[6]->store(table_name->str, table_name->length, cs);
5047
  table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
5048
  table->field[10]->store(STRING_WITH_LEN("ROW"), cs);
5049 5050
  table->field[11]->store(trg_action_time_type_names[timing].str,
                          trg_action_time_type_names[timing].length, cs);
5051 5052
  table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
  table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
5053

5054
  sql_mode_string_representation(thd, sql_mode, &sql_mode_rep);
5055
  table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs);
unknown's avatar
unknown committed
5056 5057 5058 5059 5060 5061
  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);

5062 5063 5064 5065
  return schema_table_store_record(thd, table);
}


5066
static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables,
5067
				      TABLE *table, bool res,
5068 5069
				      LEX_STRING *db_name,
				      LEX_STRING *table_name)
5070 5071 5072 5073 5074 5075 5076 5077
{
  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)
  {
5078
    if (thd->is_error())
5079
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5080
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5081 5082 5083 5084 5085 5086 5087
    thd->clear_error();
    DBUG_RETURN(0);
  }
  if (!tables->view && tables->table->triggers)
  {
    Table_triggers_list *triggers= tables->table->triggers;
    int event, timing;
5088

5089
    if (check_table_access(thd, TRIGGER_ACL, tables, FALSE, 1, TRUE))
5090 5091
      goto ret;

5092 5093 5094 5095 5096 5097
    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;
5098
        ulong sql_mode;
5099
        char definer_holder[USER_HOST_BUFF_SIZE];
5100
        LEX_STRING definer_buffer;
unknown's avatar
unknown committed
5101 5102 5103 5104
        LEX_STRING client_cs_name;
        LEX_STRING connection_cl_name;
        LEX_STRING db_cl_name;

5105
        definer_buffer.str= definer_holder;
5106 5107
        if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
                                       (enum trg_action_time_type)timing,
5108
                                       &trigger_name, &trigger_stmt,
5109
                                       &sql_mode,
unknown's avatar
unknown committed
5110 5111 5112 5113
                                       &definer_buffer,
                                       &client_cs_name,
                                       &connection_cl_name,
                                       &db_cl_name))
5114
          continue;
5115

5116
        if (store_trigger(thd, table, db_name, table_name, &trigger_name,
5117
                         (enum trg_event_type) event,
5118
                         (enum trg_action_time_type) timing, &trigger_stmt,
5119
                         sql_mode,
unknown's avatar
unknown committed
5120 5121 5122 5123
                         &definer_buffer,
                         &client_cs_name,
                         &connection_cl_name,
                         &db_cl_name))
5124 5125 5126 5127
          DBUG_RETURN(1);
      }
    }
  }
5128
ret:
5129 5130 5131 5132
  DBUG_RETURN(0);
}


5133 5134 5135 5136
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)
5137 5138
{
  CHARSET_INFO *cs= system_charset_info;
5139
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
5140
  table->field[1]->store(db_name->str, db_name->length, cs);
5141
  table->field[2]->store(key_name, key_len, cs);
5142
  table->field[3]->store(STRING_WITH_LEN("def"), cs);
5143 5144
  table->field[4]->store(db_name->str, db_name->length, cs);
  table->field[5]->store(table_name->str, table_name->length, cs);
5145
  table->field[6]->store(con_type, con_len, cs);
5146
  table->field[7]->store((longlong) idx, TRUE);
5147 5148 5149
}


unknown's avatar
unknown committed
5150
static int get_schema_key_column_usage_record(THD *thd,
5151
					      TABLE_LIST *tables,
unknown's avatar
unknown committed
5152
					      TABLE *table, bool res,
5153 5154
					      LEX_STRING *db_name,
					      LEX_STRING *table_name)
5155 5156
{
  DBUG_ENTER("get_schema_key_column_usage_record");
5157 5158
  if (res)
  {
5159
    if (thd->is_error())
5160
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5161
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5162 5163 5164 5165
    thd->clear_error();
    DBUG_RETURN(0);
  }
  else if (!tables->view)
5166 5167 5168 5169
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
    KEY *key_info=show_table->key_info;
5170
    uint primary_key= show_table->s->primary_key;
5171 5172 5173
    show_table->file->info(HA_STATUS_VARIABLE | 
                           HA_STATUS_NO_LOCK |
                           HA_STATUS_TIME);
5174
    for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
5175 5176
    {
      if (i != primary_key && !(key_info->flags & HA_NOSAME))
unknown's avatar
unknown committed
5177
        continue;
5178 5179 5180 5181 5182 5183 5184
      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++;
5185
          restore_record(table, s->default_values);
5186
          store_key_column_usage(table, db_name, table_name,
5187 5188 5189 5190 5191
                                 key_info->name,
                                 strlen(key_info->name), 
                                 key_part->field->field_name, 
                                 strlen(key_part->field->field_name),
                                 (longlong) f_idx);
5192 5193
          if (schema_table_store_record(thd, table))
            DBUG_RETURN(1);
5194 5195 5196 5197 5198 5199
        }
      }
    }

    show_table->file->get_foreign_key_list(thd, &f_key_list);
    FOREIGN_KEY_INFO *f_key_info;
5200 5201
    List_iterator_fast<FOREIGN_KEY_INFO> fkey_it(f_key_list);
    while ((f_key_info= fkey_it++))
5202
    {
5203
      LEX_STRING *f_info;
5204
      LEX_STRING *r_info;
5205 5206 5207 5208 5209
      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++))
      {
5210
        r_info= it1++;
5211
        f_idx++;
5212
        restore_record(table, s->default_values);
5213
        store_key_column_usage(table, db_name, table_name,
5214 5215 5216 5217
                               f_key_info->forein_id->str,
                               f_key_info->forein_id->length,
                               f_info->str, f_info->length,
                               (longlong) f_idx);
5218
        table->field[8]->store((longlong) f_idx, TRUE);
5219
        table->field[8]->set_notnull();
5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230
        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();
5231 5232
        if (schema_table_store_record(thd, table))
          DBUG_RETURN(1);
5233 5234 5235
      }
    }
  }
unknown's avatar
unknown committed
5236
  DBUG_RETURN(res);
5237 5238 5239
}


5240
#ifdef WITH_PARTITION_STORAGE_ENGINE
5241 5242
static void collect_partition_expr(THD *thd, List<char> &field_list,
                                   String *str)
5243 5244 5245 5246 5247 5248 5249
{
  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++))
  {
5250
    append_identifier(thd, str, field_str, strlen(field_str));
5251 5252 5253 5254 5255
    if (--no_fields != 0)
      str->append(",");
  }
  return;
}
5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306


/*
  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;
}
5307
#endif
5308 5309


5310 5311
static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
                                           TABLE *showing_table,
5312 5313 5314
                                           partition_element *part_elem,
                                           handler *file, uint part_id)
{
5315
  TABLE* table= schema_table;
5316
  CHARSET_INFO *cs= system_charset_info;
5317
  PARTITION_STATS stat_info;
5318
  MYSQL_TIME time;
5319
  file->get_dynamic_partition_info(&stat_info, part_id);
5320
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333
  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,
5334
                                              (my_time_t)stat_info.create_time);
5335 5336 5337 5338 5339 5340
    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,
5341
                                              (my_time_t)stat_info.update_time);
5342 5343 5344 5345 5346
    table->field[19]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
    table->field[19]->set_notnull();
  }
  if (stat_info.check_time)
  {
5347 5348
    thd->variables.time_zone->gmt_sec_to_TIME(&time,
                                              (my_time_t)stat_info.check_time);
5349 5350 5351
    table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
    table->field[20]->set_notnull();
  }
5352
  if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
5353 5354 5355 5356 5357 5358 5359 5360 5361 5362
  {
    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
5363
      table->field[22]->store(STRING_WITH_LEN(""), cs);
5364 5365 5366 5367
    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);
5368 5369

    table->field[24]->set_notnull();
5370 5371 5372 5373
    if (part_elem->tablespace_name)
      table->field[24]->store(part_elem->tablespace_name,
                              strlen(part_elem->tablespace_name), cs);
    else
5374
    {
5375
      char *ts= showing_table->file->get_tablespace_name(thd,0,0);
5376
      if(ts)
5377
      {
5378
        table->field[24]->store(ts, strlen(ts), cs);
5379 5380
        my_free(ts, MYF(0));
      }
5381 5382 5383
      else
        table->field[24]->set_null();
    }
5384 5385 5386 5387
  }
  return;
}

Alexander Nozdrin's avatar
Alexander Nozdrin committed
5388
#ifdef WITH_PARTITION_STORAGE_ENGINE
5389
static int
5390 5391
get_partition_column_description(THD *thd,
                                 partition_info *part_info,
5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407
                                 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
    {
5408
      char buffer[MAX_KEY_LENGTH];
5409
      String str(buffer, sizeof(buffer), &my_charset_bin);
5410
      String val_conv;
5411 5412 5413 5414 5415 5416 5417 5418
      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);
5419
      if (get_cs_converted_part_value_from_string(thd, item, res, &val_conv,
5420
                              part_info->part_field_array[i]->charset(),
5421
                              FALSE))
5422 5423 5424
      {
        DBUG_RETURN(1);
      }
5425
      tmp_str.append(val_conv);
5426 5427 5428 5429 5430 5431
    }
    if (i != num_elements - 1)
      tmp_str.append(",");
  }
  DBUG_RETURN(0);
}
Alexander Nozdrin's avatar
Alexander Nozdrin committed
5432
#endif /* WITH_PARTITION_STORAGE_ENGINE */
5433

5434
static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
5435
                                        TABLE *table, bool res,
5436 5437
                                        LEX_STRING *db_name,
                                        LEX_STRING *table_name)
5438 5439 5440 5441 5442 5443
{
  CHARSET_INFO *cs= system_charset_info;
  char buff[61];
  String tmp_res(buff, sizeof(buff), cs);
  String tmp_str;
  TABLE *show_table= tables->table;
5444
  handler *file;
unknown's avatar
unknown committed
5445
#ifdef WITH_PARTITION_STORAGE_ENGINE
5446
  partition_info *part_info;
unknown's avatar
unknown committed
5447
#endif
5448 5449 5450 5451
  DBUG_ENTER("get_schema_partitions_record");

  if (res)
  {
5452
    if (thd->is_error())
5453
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5454
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5455 5456 5457
    thd->clear_error();
    DBUG_RETURN(0);
  }
5458
  file= show_table->file;
unknown's avatar
unknown committed
5459
#ifdef WITH_PARTITION_STORAGE_ENGINE
5460
  part_info= show_table->part_info;
5461 5462 5463 5464 5465 5466 5467
  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);
5468
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
5469 5470
    table->field[1]->store(db_name->str, db_name->length, cs);
    table->field[2]->store(table_name->str, table_name->length, cs);
5471 5472 5473 5474 5475 5476


    /* Partition method*/
    switch (part_info->part_type) {
    case RANGE_PARTITION:
    case LIST_PARTITION:
5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487
      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);
5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503
      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);
5504
      my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516
      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)
    {
5517
      collect_partition_expr(thd, part_info->part_field_list, &tmp_str);
5518 5519
      table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs);
    }
5520
    table->field[9]->set_notnull();
5521

5522
    if (part_info->is_sub_partitioned())
5523 5524
    {
      /* Subpartition method */
5525 5526 5527 5528
      tmp_res.length(0);
      if (part_info->linear_hash_ind)
        tmp_res.append(partition_keywords[PKW_LINEAR].str,
                       partition_keywords[PKW_LINEAR].length);
5529
      if (part_info->list_of_subpart_fields)
5530 5531
        tmp_res.append(partition_keywords[PKW_KEY].str,
                       partition_keywords[PKW_KEY].length);
5532
      else
5533 5534 5535
        tmp_res.append(partition_keywords[PKW_HASH].str, 
                       partition_keywords[PKW_HASH].length);
      table->field[8]->store(tmp_res.ptr(), tmp_res.length(), cs);
5536 5537 5538 5539 5540 5541 5542 5543 5544 5545
      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)
      {
5546
        collect_partition_expr(thd, part_info->subpart_field_list, &tmp_str);
5547 5548
        table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs);
      }
5549
      table->field[10]->set_notnull();
5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563
    }

    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)
      {
5564 5565 5566 5567 5568
        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);
5569 5570
          if (get_partition_column_description(thd,
                                               part_info,
5571 5572 5573 5574 5575 5576 5577
                                               list_value,
                                               tmp_str))
          {
            DBUG_RETURN(1);
          }
          table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
        }
5578
        else
5579 5580 5581 5582 5583
        {
          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,
5584
                                 partition_keywords[PKW_MAXVALUE].length, cs);
5585
        }
5586 5587 5588 5589
        table->field[11]->set_notnull();
      }
      else if (part_info->part_type == LIST_PARTITION)
      {
5590 5591
        List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
        part_elem_value *list_value;
5592
        uint num_items= part_elem->list_val_list.elements;
5593 5594
        tmp_str.length(0);
        tmp_res.length(0);
5595 5596 5597
        if (part_elem->has_null_value)
        {
          tmp_str.append("NULL");
5598
          if (num_items > 0)
5599 5600
            tmp_str.append(",");
        }
5601 5602
        while ((list_value= list_val_it++))
        {
5603 5604 5605 5606
          if (part_info->column_list)
          {
            if (part_info->part_field_list.elements > 1U)
              tmp_str.append("(");
5607 5608
            if (get_partition_column_description(thd,
                                                 part_info,
5609 5610 5611 5612 5613 5614 5615 5616
                                                 list_value,
                                                 tmp_str))
            {
              DBUG_RETURN(1);
            }
            if (part_info->part_field_list.elements > 1U)
              tmp_str.append(")");
          }
5617
          else
5618 5619 5620 5621 5622 5623 5624 5625
          {
            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)
5626
            tmp_str.append(",");
5627
        }
5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646
        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();
          
5647
          store_schema_partitions_record(thd, table, show_table, subpart_elem,
5648 5649 5650 5651 5652 5653 5654 5655
                                         file, part_id);
          part_id++;
          if(schema_table_store_record(thd, table))
            DBUG_RETURN(1);
        }
      }
      else
      {
5656
        store_schema_partitions_record(thd, table, show_table, part_elem,
5657 5658 5659 5660 5661 5662 5663 5664 5665
                                       file, part_id);
        part_id++;
        if(schema_table_store_record(thd, table))
          DBUG_RETURN(1);
      }
    }
    DBUG_RETURN(0);
  }
  else
unknown's avatar
unknown committed
5666
#endif
5667
  {
5668
    store_schema_partitions_record(thd, table, show_table, 0, file, 0);
5669 5670 5671 5672 5673 5674 5675
    if(schema_table_store_record(thd, table))
      DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
5676
#ifdef NOT_USED
5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712
static interval_type get_real_interval_type(interval_type i_type)
{
  switch (i_type) {
  case INTERVAL_YEAR:
    return INTERVAL_YEAR;

  case INTERVAL_QUARTER:
  case INTERVAL_YEAR_MONTH:
  case INTERVAL_MONTH:
    return INTERVAL_MONTH;

  case INTERVAL_WEEK:
  case INTERVAL_DAY:
    return INTERVAL_DAY;

  case INTERVAL_DAY_HOUR:
  case INTERVAL_HOUR:
    return INTERVAL_HOUR;

  case INTERVAL_DAY_MINUTE:
  case INTERVAL_HOUR_MINUTE:
  case INTERVAL_MINUTE:
    return INTERVAL_MINUTE;

  case INTERVAL_DAY_SECOND:
  case INTERVAL_HOUR_SECOND:
  case INTERVAL_MINUTE_SECOND:
  case INTERVAL_SECOND:
    return INTERVAL_SECOND;

  case INTERVAL_DAY_MICROSECOND:
  case INTERVAL_HOUR_MICROSECOND:
  case INTERVAL_MINUTE_MICROSECOND:
  case INTERVAL_SECOND_MICROSECOND:
  case INTERVAL_MICROSECOND:
    return INTERVAL_MICROSECOND;
5713 5714
  case INTERVAL_LAST:
    DBUG_ASSERT(0);
5715 5716 5717 5718 5719
  }
  DBUG_ASSERT(0);
  return INTERVAL_SECOND;
}

unknown's avatar
unknown committed
5720 5721
#endif

5722
#ifdef HAVE_EVENT_SCHEDULER
5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737
/*
  Loads an event from mysql.event and copies it's data to a row of
  I_S.EVENTS

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

  Returns
    0  OK
    1  Error
*/

unknown's avatar
unknown committed
5738
int
5739
copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
5740 5741 5742
{
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  CHARSET_INFO *scs= system_charset_info;
5743
  MYSQL_TIME time;
unknown's avatar
unknown committed
5744
  Event_timed et;
5745
  DBUG_ENTER("copy_event_to_schema_table");
5746 5747 5748

  restore_record(sch_table, s->default_values);

5749
  if (et.load_from_row(thd, event_table))
5750
  {
5751
    my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), event_table->alias);
5752 5753 5754 5755 5756
    DBUG_RETURN(1);
  }

  if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0)))
    DBUG_RETURN(0);
5757 5758 5759 5760 5761 5762

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

5767
  sch_table->field[ISE_EVENT_CATALOG]->store(STRING_WITH_LEN("def"), scs);
5768 5769 5770 5771 5772 5773
  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);
5774 5775 5776
  const String *tz_name= et.time_zone->get_name();
  sch_table->field[ISE_TIME_ZONE]->
                                store(tz_name->ptr(), tz_name->length(), scs);
5777 5778
  sch_table->field[ISE_EVENT_BODY]->
                                store(STRING_WITH_LEN("SQL"), scs);
unknown's avatar
unknown committed
5779 5780
  sch_table->field[ISE_EVENT_DEFINITION]->store(
    et.body_utf8.str, et.body_utf8.length, scs);
5781 5782

  /* SQL_MODE */
5783
  {
5784
    LEX_STRING sql_mode;
5785
    sql_mode_string_representation(thd, et.sql_mode, &sql_mode);
5786
    sch_table->field[ISE_SQL_MODE]->
5787
                                store(sql_mode.str, sql_mode.length, scs);
5788
  }
5789

5790 5791
  int not_used=0;

5792 5793
  if (et.expression)
  {
5794
    String show_str;
5795
    /* type */
5796
    sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("RECURRING"), scs);
5797

5798 5799
    if (Events::reconstruct_interval_expression(&show_str, et.interval,
                                                et.expression))
5800
      DBUG_RETURN(1);
5801

5802 5803 5804
    sch_table->field[ISE_INTERVAL_VALUE]->set_notnull();
    sch_table->field[ISE_INTERVAL_VALUE]->
                                store(show_str.ptr(), show_str.length(), scs);
unknown's avatar
unknown committed
5805 5806

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

5810
    /* starts & ends . STARTS is always set - see sql_yacc.yy */
5811
    et.time_zone->gmt_sec_to_TIME(&time, et.starts);
5812 5813
    sch_table->field[ISE_STARTS]->set_notnull();
    sch_table->field[ISE_STARTS]->
5814
                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5815 5816 5817

    if (!et.ends_null)
    {
5818
      et.time_zone->gmt_sec_to_TIME(&time, et.ends);
5819 5820
      sch_table->field[ISE_ENDS]->set_notnull();
      sch_table->field[ISE_ENDS]->
5821
                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5822
    }
5823 5824 5825
  }
  else
  {
5826 5827
    /* type */
    sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("ONE TIME"), scs);
5828

5829
    et.time_zone->gmt_sec_to_TIME(&time, et.execute_at);
5830 5831
    sch_table->field[ISE_EXECUTE_AT]->set_notnull();
    sch_table->field[ISE_EXECUTE_AT]->
5832
                          store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5833 5834
  }

5835
  /* status */
5836 5837 5838

  switch (et.status)
  {
5839
    case Event_parse_data::ENABLED:
5840 5841
      sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("ENABLED"), scs);
      break;
5842
    case Event_parse_data::SLAVESIDE_DISABLED:
5843 5844 5845
      sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("SLAVESIDE_DISABLED"),
                                          scs);
      break;
5846
    case Event_parse_data::DISABLED:
5847 5848 5849 5850 5851 5852
      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);
5853

5854
  /* on_completion */
5855
  if (et.on_completion == Event_parse_data::ON_COMPLETION_DROP)
5856 5857
    sch_table->field[ISE_ON_COMPLETION]->
                                store(STRING_WITH_LEN("NOT PRESERVE"), scs);
5858
  else
5859 5860
    sch_table->field[ISE_ON_COMPLETION]->
                                store(STRING_WITH_LEN("PRESERVE"), scs);
5861 5862 5863
    
  number_to_datetime(et.created, &time, 0, &not_used);
  DBUG_ASSERT(not_used==0);
5864
  sch_table->field[ISE_CREATED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5865 5866 5867

  number_to_datetime(et.modified, &time, 0, &not_used);
  DBUG_ASSERT(not_used==0);
5868 5869
  sch_table->field[ISE_LAST_ALTERED]->
                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5870

5871
  if (et.last_executed)
5872
  {
5873
    et.time_zone->gmt_sec_to_TIME(&time, et.last_executed);
5874 5875
    sch_table->field[ISE_LAST_EXECUTED]->set_notnull();
    sch_table->field[ISE_LAST_EXECUTED]->
5876
                       store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5877
  }
5878

5879 5880
  sch_table->field[ISE_EVENT_COMMENT]->
                      store(et.comment.str, et.comment.length, scs);
5881

unknown's avatar
unknown committed
5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899
  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);

5900 5901 5902 5903 5904
  if (schema_table_store_record(thd, sch_table))
    DBUG_RETURN(1);

  DBUG_RETURN(0);
}
5905
#endif
5906

5907 5908 5909 5910 5911 5912 5913
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;
5914 5915
  if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild))
            && thd->is_fatal_error)
5916 5917 5918 5919
    DBUG_RETURN(1);

  for (; open_list ; open_list=open_list->next)
  {
5920
    restore_record(table, s->default_values);
5921 5922
    table->field[0]->store(open_list->db, strlen(open_list->db), cs);
    table->field[1]->store(open_list->table, strlen(open_list->table), cs);
5923 5924
    table->field[2]->store((longlong) open_list->in_use, TRUE);
    table->field[3]->store((longlong) open_list->locked, TRUE);
5925 5926
    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
5927 5928 5929 5930 5931 5932 5933 5934
  }
  DBUG_RETURN(0);
}


int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  DBUG_ENTER("fill_variables");
5935
  int res= 0;
5936 5937
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
5938 5939 5940 5941 5942 5943 5944 5945 5946 5947
  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
5948
  mysql_rwlock_rdlock(&LOCK_system_variables_hash);
5949
  res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type),
5950
                         option_type, NULL, "", tables->table, upper_case_names, cond);
Marc Alff's avatar
Marc Alff committed
5951
  mysql_rwlock_unlock(&LOCK_system_variables_hash);
5952 5953 5954 5955 5956 5957 5958 5959 5960 5961
  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;
5962 5963 5964 5965 5966 5967
  STATUS_VAR *tmp1, tmp;
  enum enum_schema_tables schema_table_idx=
    get_schema_table_idx(tables->schema_table);
  enum enum_var_type option_type;
  bool upper_case_names= (schema_table_idx != SCH_STATUS);

unknown's avatar
unknown committed
5968 5969 5970 5971 5972 5973 5974 5975 5976
  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)
5977 5978 5979 5980 5981
  {
    option_type= OPT_GLOBAL;
    tmp1= &tmp;
  }
  else
unknown's avatar
unknown committed
5982
  { 
5983
    option_type= OPT_SESSION;
unknown's avatar
unknown committed
5984
    tmp1= &thd->status_var;
5985 5986
  }

Marc Alff's avatar
Marc Alff committed
5987
  mysql_mutex_lock(&LOCK_status);
5988
  if (option_type == OPT_GLOBAL)
5989
    calc_sum_of_all_status(&tmp);
5990 5991
  res= show_status_array(thd, wild,
                         (SHOW_VAR *)all_status_vars.buffer,
5992
                         option_type, tmp1, "", tables->table,
5993
                         upper_case_names, cond);
Marc Alff's avatar
Marc Alff committed
5994
  mysql_mutex_unlock(&LOCK_status);
5995 5996 5997 5998
  DBUG_RETURN(res);
}


5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017
/*
  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
6018
get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
6019
                                   TABLE *table, bool res,
6020
                                   LEX_STRING *db_name, LEX_STRING *table_name)
6021 6022 6023 6024 6025 6026
{
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_referential_constraints_record");

  if (res)
  {
6027
    if (thd->is_error())
6028
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
6029
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046
    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);
6047
      table->field[0]->store(STRING_WITH_LEN("def"), cs);
6048 6049
      table->field[1]->store(db_name->str, db_name->length, cs);
      table->field[9]->store(table_name->str, table_name->length, cs);
6050 6051
      table->field[2]->store(f_key_info->forein_id->str,
                             f_key_info->forein_id->length, cs);
6052
      table->field[3]->store(STRING_WITH_LEN("def"), cs);
6053 6054
      table->field[4]->store(f_key_info->referenced_db->str, 
                             f_key_info->referenced_db->length, cs);
6055
      table->field[10]->store(f_key_info->referenced_table->str, 
6056
                             f_key_info->referenced_table->length, cs);
6057 6058 6059 6060 6061 6062 6063 6064
      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();
6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076
      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);
}

unknown's avatar
unknown committed
6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096
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
*/
unknown's avatar
unknown committed
6097
static my_bool find_schema_table_in_plugin(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
6098 6099 6100 6101
                                           void* p_table)
{
  schema_table_ref *p_schema_table= (schema_table_ref *)p_table;
  const char* table_name= p_schema_table->table_name;
unknown's avatar
unknown committed
6102
  ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
unknown's avatar
unknown committed
6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114
  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);
}

6115

6116 6117 6118 6119 6120 6121 6122 6123 6124 6125
/*
  Find schema_tables elment by name

  SYNOPSIS
    find_schema_table()
    thd                 thread handler
    table_name          table name

  RETURN
    0	table not found
6126
    #   pointer to 'schema_tables' element
6127 6128 6129 6130
*/

ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
{
unknown's avatar
unknown committed
6131
  schema_table_ref schema_table_a;
6132
  ST_SCHEMA_TABLE *schema_table= schema_tables;
unknown's avatar
unknown committed
6133 6134
  DBUG_ENTER("find_schema_table");

6135
  for (; schema_table->table_name; schema_table++)
6136 6137 6138 6139
  {
    if (!my_strcasecmp(system_charset_info,
                       schema_table->table_name,
                       table_name))
unknown's avatar
unknown committed
6140
      DBUG_RETURN(schema_table);
6141
  }
unknown's avatar
unknown committed
6142 6143 6144 6145 6146 6147 6148

  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);
6149 6150 6151 6152 6153 6154 6155 6156 6157
}


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


6158 6159
/**
  Create information_schema table using schema_table data.
6160

6161 6162 6163 6164 6165 6166 6167 6168 6169
  @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
6170
    thd	       	          thread handler
6171 6172 6173

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

6175 6176
  @retval  \#             Pointer to created table
  @retval  NULL           Can't create table
6177 6178
*/

6179
TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
6180 6181 6182 6183 6184
{
  int field_count= 0;
  Item *item;
  TABLE *table;
  List<Item> field_list;
6185
  ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
6186
  ST_FIELD_INFO *fields_info= schema_table->fields_info;
unknown's avatar
unknown committed
6187
  CHARSET_INFO *cs= system_charset_info;
6188 6189
  DBUG_ENTER("create_schema_table");

6190
  for (; fields_info->field_name; fields_info++)
6191 6192
  {
    switch (fields_info->field_type) {
6193
    case MYSQL_TYPE_TINY:
6194
    case MYSQL_TYPE_LONG:
6195 6196 6197 6198 6199 6200 6201
    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)))
6202 6203 6204
      {
        DBUG_RETURN(0);
      }
6205
      item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
6206
      break;
6207 6208
    case MYSQL_TYPE_DATE:
    case MYSQL_TYPE_TIME:
6209
    case MYSQL_TYPE_TIMESTAMP:
6210 6211 6212
    case MYSQL_TYPE_DATETIME:
      if (!(item=new Item_return_date_time(fields_info->field_name,
                                           fields_info->field_type)))
6213 6214 6215 6216
      {
        DBUG_RETURN(0);
      }
      break;
6217 6218 6219 6220 6221 6222
    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;
6223
    case MYSQL_TYPE_DECIMAL:
6224
    case MYSQL_TYPE_NEWDECIMAL:
6225 6226 6227 6228
      if (!(item= new Item_decimal((longlong) fields_info->value, false)))
      {
        DBUG_RETURN(0);
      }
6229
      item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
6230 6231 6232 6233 6234 6235 6236 6237 6238
      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;
6239 6240 6241 6242 6243 6244 6245 6246 6247 6248
    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;
6249
    default:
6250 6251 6252
      /* Don't let unimplemented types pass through. Could be a grave error. */
      DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING);

6253
      if (!(item= new Item_empty_string("", fields_info->field_length, cs)))
6254 6255 6256
      {
        DBUG_RETURN(0);
      }
unknown's avatar
unknown committed
6257 6258
      item->set_name(fields_info->field_name,
                     strlen(fields_info->field_name), cs);
6259 6260 6261
      break;
    }
    field_list.push_back(item);
6262
    item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL);
6263 6264 6265
    field_count++;
  }
  TMP_TABLE_PARAM *tmp_table_param =
6266
    (TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM)));
6267
  tmp_table_param->init();
unknown's avatar
unknown committed
6268
  tmp_table_param->table_charset= cs;
6269
  tmp_table_param->field_count= field_count;
6270
  tmp_table_param->schema_table= 1;
6271 6272 6273
  SELECT_LEX *select_lex= thd->lex->current_select;
  if (!(table= create_tmp_table(thd, tmp_table_param,
                                field_list, (ORDER*) 0, 0, 0, 
6274
                                (select_lex->options | thd->variables.option_bits |
6275
                                 TMP_TABLE_ALL_COLUMNS),
unknown's avatar
unknown committed
6276
                                HA_POS_ERROR, table_list->alias)))
6277
    DBUG_RETURN(0);
6278 6279 6280 6281 6282 6283
  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);
6284
  table_list->schema_table_param= tmp_table_param;
6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299
  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
6300 6301
   1	error
   0	success
6302 6303 6304 6305 6306
*/

int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
  ST_FIELD_INFO *field_info= schema_table->fields_info;
6307
  Name_resolution_context *context= &thd->lex->select_lex.context;
6308
  for (; field_info->field_name; field_info++)
6309 6310 6311
  {
    if (field_info->old_name)
    {
6312 6313
      Item_field *field= new Item_field(context,
                                        NullS, NullS, field_info->field_name);
6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332
      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;
6333
  Name_resolution_context *context= &sel->context;
6334 6335 6336 6337 6338

  if (!sel->item_list.elements)
  {
    ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
    String buffer(tmp,sizeof(tmp), system_charset_info);
6339 6340
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
6341 6342 6343 6344 6345 6346
    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())
    {
6347
      buffer.append(STRING_WITH_LEN(" ("));
6348
      buffer.append(lex->wild->ptr());
6349
      buffer.append(')');
6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361
    }
    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;
6362
  Name_resolution_context *context= &lex->select_lex.context;
6363 6364 6365 6366 6367 6368 6369

  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())
  {
6370
    buffer.append(STRING_WITH_LEN(" ("));
6371
    buffer.append(lex->wild->ptr());
6372
    buffer.append(')');
6373
  }
6374 6375
  Item_field *field= new Item_field(context,
                                    NullS, NullS, field_info->field_name);
6376 6377 6378 6379 6380 6381 6382
  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];
6383
    field= new Item_field(context, NullS, NullS, field_info->field_name);
6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394
    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)
{
6395 6396 6397
  int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1};
  int *field_num= fields_arr;
  ST_FIELD_INFO *field_info;
6398 6399
  Name_resolution_context *context= &thd->lex->select_lex.context;

6400
  for (; *field_num >= 0; field_num++)
6401
  {
6402 6403 6404 6405 6406
    field_info= &schema_table->fields_info[*field_num];
    if (!thd->lex->verbose && (*field_num == 13 ||
                               *field_num == 17 ||
                               *field_num == 18))
      continue;
6407 6408
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
6409
    if (field)
6410
    {
6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421
      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;
}


6422 6423 6424 6425 6426
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;
6427 6428
  Name_resolution_context *context= &thd->lex->select_lex.context;

6429 6430 6431
  for (; *field_num >= 0; field_num++)
  {
    field_info= &schema_table->fields_info[*field_num];
6432 6433
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446
    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;
}


6447 6448
int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
Sergey Glukhov's avatar
Sergey Glukhov committed
6449
  int fields_arr[]= {2, 3, 4, 26, 23, 22, 21, 25, 27, 28, 29, -1};
6450 6451
  int *field_num= fields_arr;
  ST_FIELD_INFO *field_info;
6452 6453
  Name_resolution_context *context= &thd->lex->select_lex.context;

6454 6455 6456
  for (; *field_num >= 0; field_num++)
  {
    field_info= &schema_table->fields_info[*field_num];
6457 6458
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
6459 6460 6461 6462 6463 6464 6465
    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;
6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489
    }
  }
  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");
6490
  if (!(table= table_list->schema_table->create_table(thd, table_list)))
6491
    DBUG_RETURN(1);
6492
  table->s->tmp_table= SYSTEM_TMP_TABLE;
6493
  table->grant.privilege= SELECT_ACL;
6494 6495 6496 6497 6498 6499 6500
  /*
    This test is necessary to make
    case insensitive file systems +
    upper case table names(information schema tables) +
    views
    working correctly
  */
6501 6502 6503 6504
  if (table_list->schema_table_name)
    table->alias_name_used= my_strcasecmp(table_alias_charset,
                                          table_list->schema_table_name,
                                          table_list->alias);
unknown's avatar
unknown committed
6505 6506
  table_list->table_name= table->s->table_name.str;
  table_list->table_name_length= table->s->table_name.length;
6507 6508 6509 6510
  table_list->table= table;
  table->next= thd->derived_tables;
  thd->derived_tables= table;
  table_list->select_lex->options |= OPTION_SCHEMA_TABLE;
6511
  lex->safe_to_cache_query= 0;
6512 6513 6514 6515 6516

  if (table_list->schema_table_reformed) // show command
  {
    SELECT_LEX *sel= lex->current_select;
    Item *item;
unknown's avatar
unknown committed
6517
    Field_translator *transl, *org_transl;
6518 6519 6520

    if (table_list->field_translation)
    {
6521
      Field_translator *end= table_list->field_translation_end;
6522 6523 6524
      for (transl= table_list->field_translation; transl < end; transl++)
      {
        if (!transl->item->fixed &&
6525
            transl->item->fix_fields(thd, &transl->item))
6526 6527 6528 6529 6530 6531
          DBUG_RETURN(1);
      }
      DBUG_RETURN(0);
    }
    List_iterator_fast<Item> it(sel->item_list);
    if (!(transl=
unknown's avatar
unknown committed
6532
          (Field_translator*)(thd->stmt_arena->
6533 6534 6535 6536 6537
                              alloc(sel->item_list.elements *
                                    sizeof(Field_translator)))))
    {
      DBUG_RETURN(1);
    }
unknown's avatar
unknown committed
6538
    for (org_transl= transl; (item= it++); transl++)
6539
    {
unknown's avatar
unknown committed
6540 6541 6542 6543
      transl->item= item;
      transl->name= item->name;
      if (!item->fixed && item->fix_fields(thd, &transl->item))
      {
6544
        DBUG_RETURN(1);
unknown's avatar
unknown committed
6545
      }
6546
    }
unknown's avatar
unknown committed
6547 6548
    table_list->field_translation= org_transl;
    table_list->field_translation_end= transl;
6549 6550
  }

6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573
  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;
6574
  DBUG_ENTER("make_schema_select");
unknown's avatar
unknown committed
6575
  DBUG_PRINT("enter", ("mysql_schema_select: %s", schema_table->table_name));
6576
  /*
6577 6578 6579
     We have to make non const db_name & table_name
     because of lower_case_table_names
  */
6580 6581 6582 6583
  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);
6584
  if (schema_table->old_format(thd, schema_table) ||   /* Handle old syntax */
6585
      !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
6586
                              0, 0, TL_READ))
6587 6588 6589 6590 6591 6592 6593 6594
  {
    DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


/*
6595
  Fill temporary schema tables before SELECT
6596 6597 6598 6599

  SYNOPSIS
    get_schema_tables_result()
    join  join which use schema tables
6600
    executed_place place where I_S table processed
6601 6602

  RETURN
unknown's avatar
unknown committed
6603 6604
    FALSE success
    TRUE  error
6605 6606
*/

6607 6608
bool get_schema_tables_result(JOIN *join,
                              enum enum_schema_table_state executed_place)
6609 6610 6611
{
  JOIN_TAB *tmp_join_tab= join->join_tab+join->tables;
  THD *thd= join->thd;
unknown's avatar
unknown committed
6612 6613
  LEX *lex= thd->lex;
  bool result= 0;
6614 6615 6616
  DBUG_ENTER("get_schema_tables_result");

  thd->no_warnings_for_error= 1;
6617 6618 6619 6620
  for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
  {  
    if (!tab->table || !tab->table->pos_in_table_list)
      break;
unknown's avatar
unknown committed
6621

unknown's avatar
unknown committed
6622
    TABLE_LIST *table_list= tab->table->pos_in_table_list;
6623
    if (table_list->schema_table && thd->fill_information_schema_tables())
6624
    {
6625 6626
      bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
                          lex->current_select->master_unit()->item);
6627

6628 6629 6630
      /* A value of 0 indicates a dummy implementation */
      if (table_list->schema_table->fill_table == 0)
        continue;
6631 6632 6633 6634 6635 6636

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

6637
      /*
6638 6639 6640 6641 6642 6643 6644
        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.
6645
      */
6646 6647
      if (table_list->schema_table_state &&
          (!is_subselect || table_list->schema_table_state != executed_place))
6648 6649
        continue;

6650 6651 6652 6653 6654 6655
      /*
        if table is used in a subselect and
        table has been processed earlier with the same
        'executed_place' value then we should refresh the table.
      */
      if (table_list->schema_table_state && is_subselect)
unknown's avatar
unknown committed
6656
      {
6657
        table_list->table->file->extra(HA_EXTRA_NO_CACHE);
unknown's avatar
unknown committed
6658
        table_list->table->file->extra(HA_EXTRA_RESET_STATE);
6659
        table_list->table->file->ha_delete_all_rows();
unknown's avatar
unknown committed
6660
        free_io_cache(table_list->table);
unknown's avatar
unknown committed
6661
        filesort_free_buffers(table_list->table,1);
6662
        table_list->table->null_row= 0;
unknown's avatar
unknown committed
6663 6664
      }
      else
6665
        table_list->table->file->stats.records= 0;
unknown's avatar
unknown committed
6666

6667 6668
      if (table_list->schema_table->fill_table(thd, table_list,
                                               tab->select_cond))
6669
      {
unknown's avatar
unknown committed
6670
        result= 1;
6671
        join->error= 1;
6672
        tab->read_record.file= table_list->table->file;
6673
        table_list->schema_table_state= executed_place;
6674 6675
        break;
      }
6676
      tab->read_record.file= table_list->table->file;
6677
      table_list->schema_table_state= executed_place;
6678 6679
    }
  }
6680
  thd->no_warnings_for_error= 0;
unknown's avatar
unknown committed
6681
  DBUG_RETURN(result);
6682 6683
}

6684
struct run_hton_fill_schema_table_args
6685 6686 6687 6688 6689
{
  TABLE_LIST *tables;
  COND *cond;
};

6690
static my_bool run_hton_fill_schema_table(THD *thd, plugin_ref plugin,
6691 6692
                                          void *arg)
{
6693 6694
  struct run_hton_fill_schema_table_args *args=
    (run_hton_fill_schema_table_args *) arg;
unknown's avatar
unknown committed
6695
  handlerton *hton= plugin_data(plugin, handlerton *);
6696 6697 6698
  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));
6699 6700 6701
  return false;
}

6702
int hton_fill_schema_table(THD *thd, TABLE_LIST *tables, COND *cond)
6703
{
6704
  DBUG_ENTER("hton_fill_schema_table");
6705

6706
  struct run_hton_fill_schema_table_args args;
6707 6708 6709
  args.tables= tables;
  args.cond= cond;

6710
  plugin_foreach(thd, run_hton_fill_schema_table,
6711 6712 6713 6714
                 MYSQL_STORAGE_ENGINE_PLUGIN, &args);

  DBUG_RETURN(0);
}
6715

6716

6717 6718
ST_FIELD_INFO schema_fields_info[]=
{
6719
  {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6720 6721
  {"SCHEMA_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
   SKIP_OPEN_TABLE},
6722 6723 6724
  {"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,
6725 6726 6727
   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}
6728 6729 6730 6731 6732
};


ST_FIELD_INFO tables_fields_info[]=
{
6733
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6734 6735 6736 6737 6738
  {"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},
6739
  {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6740 6741
   (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},
6742
  {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6743
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", OPEN_FULL_TABLE},
6744
  {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 
6745
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", OPEN_FULL_TABLE},
6746
  {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 
6747
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", OPEN_FULL_TABLE},
6748
  {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6749
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", OPEN_FULL_TABLE},
6750
  {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 
6751
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", OPEN_FULL_TABLE},
6752
  {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6753
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", OPEN_FULL_TABLE},
6754
  {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0, 
6755 6756 6757 6758
   (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},
6759 6760
  {"TABLE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
   OPEN_FRM_ONLY},
6761
  {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6762 6763 6764
   (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},
6765 6766
  {"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 
   "Comment", OPEN_FRM_ONLY},
6767
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6768 6769 6770 6771 6772
};


ST_FIELD_INFO columns_fields_info[]=
{
6773
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6774 6775 6776 6777
  {"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},
6778
  {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6779
   MY_I_S_UNSIGNED, 0, OPEN_FRM_ONLY},
6780
  {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0,
6781 6782 6783
   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},
6784
  {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
6785
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6786
  {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
6787
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6788
  {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
6789
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6790
  {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
6791
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6792 6793 6794 6795
  {"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},
6796 6797
  {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type", OPEN_FRM_ONLY},
  {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY},
6798
  {"EXTRA", 27, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
6799
  {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY},
6800 6801
  {"COLUMN_COMMENT", COLUMN_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 
   "Comment", OPEN_FRM_ONLY},
6802
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6803 6804 6805 6806 6807
};


ST_FIELD_INFO charsets_fields_info[]=
{
6808
  {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
6809
   SKIP_OPEN_TABLE},
6810 6811
  {"DEFAULT_COLLATE_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
   "Default collation", SKIP_OPEN_TABLE},
6812 6813 6814 6815
  {"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}
6816 6817 6818 6819 6820
};


ST_FIELD_INFO collation_fields_info[]=
{
6821 6822 6823
  {"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",
6824 6825 6826 6827 6828 6829 6830
   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}
6831 6832 6833
};


unknown's avatar
unknown committed
6834 6835
ST_FIELD_INFO engines_fields_info[]=
{
6836 6837 6838
  {"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},
6839 6840 6841
  {"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},
6842
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
unknown's avatar
unknown committed
6843 6844 6845
};


6846 6847
ST_FIELD_INFO events_fields_info[]=
{
6848
  {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862
  {"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},
6863
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6864 6865 6866 6867 6868 6869 6870 6871 6872
  {"STARTS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Starts", SKIP_OPEN_TABLE},
  {"ENDS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Ends", SKIP_OPEN_TABLE},
  {"STATUS", 18, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
  {"ON_COMPLETION", 12, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
  {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
  {"LAST_EXECUTED", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
  {"EVENT_COMMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
  {"ORIGINATOR", 10, MYSQL_TYPE_LONGLONG, 0, 0, "Originator", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6873
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6874
   "character_set_client", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6875
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6876
   "collation_connection", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6877
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6878 6879
   "Database Collation", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6880 6881 6882 6883
};



6884 6885
ST_FIELD_INFO coll_charset_app_fields_info[]=
{
6886 6887 6888 6889
  {"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},
6890
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6891 6892 6893 6894 6895
};


ST_FIELD_INFO proc_fields_info[]=
{
6896
  {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6897
  {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6898 6899 6900 6901 6902
  {"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
6903 6904 6905 6906 6907 6908 6909 6910
  {"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},
6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924
  {"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},
6925
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6926
  {"ROUTINE_COMMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Comment",
6927 6928
   SKIP_OPEN_TABLE},
  {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6929
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6930
   "character_set_client", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6931
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6932
   "collation_connection", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6933
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6934 6935
   "Database Collation", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6936 6937 6938 6939 6940
};


ST_FIELD_INFO stat_fields_info[]=
{
6941
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6942 6943 6944 6945 6946 6947 6948 6949 6950 6951
  {"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},
6952
  {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 1,
6953 6954 6955 6956 6957 6958
   "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},
6959 6960
  {"INDEX_COMMENT", INDEX_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 
   "Index_comment", OPEN_FRM_ONLY},
6961
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6962 6963 6964 6965 6966
};


ST_FIELD_INFO view_fields_info[]=
{
6967
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6968 6969
  {"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
6970 6971
  {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6972
  {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
Sergey Glukhov's avatar
Sergey Glukhov committed
6973 6974
  {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
  {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6975
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
6976
   OPEN_FRM_ONLY},
6977
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
6978
   OPEN_FRM_ONLY},
6979
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6980 6981 6982 6983 6984
};


ST_FIELD_INFO user_privileges_fields_info[]=
{
6985
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6986
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6987 6988 6989
  {"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}
6990 6991 6992 6993 6994
};


ST_FIELD_INFO schema_privileges_fields_info[]=
{
6995
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6996
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6997 6998 6999 7000
  {"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}
7001 7002 7003 7004 7005
};


ST_FIELD_INFO table_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 7011 7012
  {"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}
7013 7014 7015 7016 7017
};


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


ST_FIELD_INFO table_constraints_fields_info[]=
{
7031
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7032 7033 7034 7035 7036 7037 7038 7039 7040
  {"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}
7041 7042 7043 7044 7045
};


ST_FIELD_INFO key_column_usage_fields_info[]=
{
7046
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7047 7048 7049 7050
  {"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},
7051
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064
  {"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}
7065 7066 7067 7068 7069
};


ST_FIELD_INFO table_names_fields_info[]=
{
7070
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7071 7072 7073 7074 7075 7076
  {"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}
7077 7078 7079
};


7080 7081
ST_FIELD_INFO open_tables_fields_info[]=
{
7082 7083 7084 7085 7086 7087
  {"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}
7088 7089 7090
};


7091 7092
ST_FIELD_INFO triggers_fields_info[]=
{
Sergey Glukhov's avatar
Sergey Glukhov committed
7093 7094
  {"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},
7095
  {"TRIGGER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger",
Sergey Glukhov's avatar
Sergey Glukhov committed
7096 7097
   OPEN_FRM_ONLY},
  {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FRM_ONLY},
7098
  {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7099
   OPEN_FRM_ONLY},
7100
  {"EVENT_OBJECT_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7101
   OPEN_FRM_ONLY},
7102
  {"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table",
Sergey Glukhov's avatar
Sergey Glukhov committed
7103 7104 7105
   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},
7106
  {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement",
Sergey Glukhov's avatar
Sergey Glukhov committed
7107 7108 7109
   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},
7110
  {"ACTION_REFERENCE_OLD_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7111
   OPEN_FRM_ONLY},
7112
  {"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7113 7114 7115 7116 7117 7118
   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},
unknown's avatar
unknown committed
7119
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7120
   "character_set_client", OPEN_FRM_ONLY},
unknown's avatar
unknown committed
7121
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7122
   "collation_connection", OPEN_FRM_ONLY},
unknown's avatar
unknown committed
7123
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
Sergey Glukhov's avatar
Sergey Glukhov committed
7124
   "Database Collation", OPEN_FRM_ONLY},
7125
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
7126 7127 7128
};


7129 7130
ST_FIELD_INFO partitions_fields_info[]=
{
7131
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7132 7133 7134 7135 7136
  {"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},
7137
  {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
7138
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
7139
  {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
7140
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
7141
  {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152
  {"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},
7153
  {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
7154 7155 7156 7157 7158 7159 7160 7161
   (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},
7162
  {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
7163 7164 7165 7166 7167 7168
   (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}
7169 7170 7171
};


7172 7173
ST_FIELD_INFO variables_fields_info[]=
{
7174 7175
  {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name",
   SKIP_OPEN_TABLE},
7176
  {"VARIABLE_VALUE", 1024, MYSQL_TYPE_STRING, 0, 1, "Value", SKIP_OPEN_TABLE},
7177
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
7178 7179 7180
};


7181 7182
ST_FIELD_INFO processlist_fields_info[]=
{
7183 7184 7185 7186 7187 7188
  {"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},
7189
  {"TIME", 7, MYSQL_TYPE_LONG, 0, 0, "Time", SKIP_OPEN_TABLE},
7190 7191 7192 7193
  {"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}
7194 7195 7196
};


unknown's avatar
unknown committed
7197 7198
ST_FIELD_INFO plugin_fields_info[]=
{
7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211
  {"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},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
unknown's avatar
unknown committed
7212 7213
};

7214 7215
ST_FIELD_INFO files_fields_info[]=
{
7216 7217 7218 7219 7220
  {"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},
7221
  {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233
  {"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},
7234
  {"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
7235
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
7236
  {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, 
7237
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
7238
  {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, 
7239 7240 7241 7242 7243 7244
   (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},
7245
  {"VERSION", 21 , MYSQL_TYPE_LONGLONG, 0,
7246 7247
   (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},
7248
  {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0,
7249
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", SKIP_OPEN_TABLE},
7250
  {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
7251
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", SKIP_OPEN_TABLE},
7252
  {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
7253
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", SKIP_OPEN_TABLE},
7254
  {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
7255
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", SKIP_OPEN_TABLE},
7256
  {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
7257
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", SKIP_OPEN_TABLE},
7258
  {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, 
7259 7260 7261 7262
   (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},
7263
  {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0, 
7264 7265 7266 7267
   (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}
7268
};
unknown's avatar
unknown committed
7269

7270 7271 7272 7273 7274 7275 7276 7277 7278 7279
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);
}

7280 7281
ST_FIELD_INFO referential_constraints_fields_info[]=
{
7282
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
7283 7284 7285 7286
  {"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},
7287
  {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
7288 7289 7290
   OPEN_FULL_TABLE},
  {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
7291 7292
  {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0,
   MY_I_S_MAYBE_NULL, 0, OPEN_FULL_TABLE},
7293 7294 7295 7296 7297 7298 7299
  {"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}
7300 7301 7302
};


Sergey Glukhov's avatar
Sergey Glukhov committed
7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324
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}
};


7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347
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}
};


7348 7349
/*
  Description of ST_FIELD_INFO in table.h
unknown's avatar
unknown committed
7350 7351 7352

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

7353 7354 7355 7356 7357
*/

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


7444
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
unknown's avatar
unknown committed
7445
template class List_iterator_fast<char>;
unknown's avatar
unknown committed
7446 7447
template class List<char>;
#endif
unknown's avatar
unknown committed
7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465

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; 

7466
    /* Make the name available to the init() function. */
7467
    schema_table->table_name= plugin->name.str;
unknown's avatar
unknown committed
7468 7469 7470 7471 7472

    if (plugin->plugin->init(schema_table))
    {
      sql_print_error("Plugin '%s' init function returned error.",
                      plugin->name.str);
7473 7474 7475
      plugin->data= NULL;
      my_free(schema_table, MYF(0));
      DBUG_RETURN(1);
unknown's avatar
unknown committed
7476
    }
7477 7478
    
    /* Make sure the plugin name is not set inside the init() function. */
unknown's avatar
unknown committed
7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496
    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");

  if (schema_table && plugin->plugin->deinit)
  {
    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));
    }
7497
    my_free(schema_table, MYF(0));
unknown's avatar
unknown committed
7498 7499 7500
  }
  DBUG_RETURN(0);
}
unknown's avatar
unknown committed
7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531


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

7532 7533
  CHARSET_INFO *trg_client_cs;

unknown's avatar
unknown committed
7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554
  /*
    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);

7555
  sql_mode_string_representation(thd, trg_sql_mode, &trg_sql_mode_str);
unknown's avatar
unknown committed
7556

7557 7558 7559 7560 7561
  /* Resolve trigger client character set. */

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

unknown's avatar
unknown committed
7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590
  /* 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));

7591
  if (p->send_result_set_metadata(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607
    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,
7608
           trg_client_cs);
unknown's avatar
unknown committed
7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624

  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)
7625
    my_eof(thd);
unknown's avatar
unknown committed
7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654

  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
7655 7656
static
TABLE_LIST *get_trigger_table_impl(THD *thd, const sp_name *trg_name)
unknown's avatar
unknown committed
7657 7658 7659
{
  char trn_path_buff[FN_REFLEN];
  LEX_STRING trn_path= { trn_path_buff, 0 };
Konstantin Osipov's avatar
Konstantin Osipov committed
7660
  LEX_STRING db;
unknown's avatar
unknown committed
7661
  LEX_STRING tbl_name;
Konstantin Osipov's avatar
Konstantin Osipov committed
7662
  TABLE_LIST *table;
unknown's avatar
unknown committed
7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675

  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
7676
  if (!(table= (TABLE_LIST*) thd->alloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
7677 7678
    return NULL;

Konstantin Osipov's avatar
Konstantin Osipov committed
7679
  db= trg_name->m_db;
unknown's avatar
unknown committed
7680

Konstantin Osipov's avatar
Konstantin Osipov committed
7681 7682
  db.str= thd->strmake(db.str, db.length);
  tbl_name.str= thd->strmake(tbl_name.str, tbl_name.length);
unknown's avatar
unknown committed
7683

Konstantin Osipov's avatar
Konstantin Osipov committed
7684 7685
  if (db.str == NULL || tbl_name.str == NULL)
    return NULL;
unknown's avatar
unknown committed
7686

Konstantin Osipov's avatar
Konstantin Osipov committed
7687 7688
  table->init_one_table(db.str, db.length, tbl_name.str, tbl_name.length,
                        tbl_name.str, TL_IGNORE);
unknown's avatar
unknown committed
7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703

  return table;
}

/**
  Read TRN and TRG files to obtain base table name for the specified
  trigger name and construct TABE_LIST object for the base table. Acquire
  LOCK_open when doing this.

  @param thd      Thread context.
  @param trg_name Trigger name.

  @return TABLE_LIST object corresponding to the base table.
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
7704 7705
static
TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
unknown's avatar
unknown committed
7706 7707 7708
{
  /* Acquire LOCK_open (stop the server). */

Marc Alff's avatar
Marc Alff committed
7709
  mysql_mutex_lock(&LOCK_open);
unknown's avatar
unknown committed
7710 7711 7712 7713 7714 7715 7716 7717 7718

  /*
    Load base table name from the TRN-file and create TABLE_LIST object.
  */

  TABLE_LIST *lst= get_trigger_table_impl(thd, trg_name);

  /* Release LOCK_open (continue the server). */

Marc Alff's avatar
Marc Alff committed
7719
  mysql_mutex_unlock(&LOCK_open);
unknown's avatar
unknown committed
7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741

  /* That's it. */

  return lst;
}


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

7742 7743 7744
  if (!lst)
    return TRUE;

7745
  if (check_table_access(thd, TRIGGER_ACL, lst, FALSE, 1, TRUE))
7746 7747 7748 7749 7750
  {
    my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "TRIGGER");
    return TRUE;
  }

unknown's avatar
unknown committed
7751 7752 7753 7754
  /*
    Open the table by name in order to load Table_triggers_list object.

    NOTE: there is race condition here -- the table can be dropped after
Konstantin Osipov's avatar
Konstantin Osipov committed
7755 7756
    LOCK_open is released. It will be fixed later by acquiring shared
    metadata lock on trigger or table name.
unknown's avatar
unknown committed
7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798
  */

  uint num_tables; /* NOTE: unused, only to pass to open_tables(). */

  if (open_tables(thd, &lst, &num_tables, 0))
  {
    my_error(ER_TRG_CANT_OPEN_TABLE, MYF(0),
             (const char *) trg_name->m_db.str,
             (const char *) lst->table_name);

    return TRUE;

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

  Table_triggers_list *triggers= lst->table->triggers;

  if (!triggers)
  {
    my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
    return TRUE;
  }

  int trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name);

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

    return TRUE;
  }

  return show_create_trigger_impl(thd, triggers, trigger_idx);

  /*
    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.
  */
}
7799

Marc Alff's avatar
Marc Alff committed
7800 7801 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
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);
}

7850 7851 7852 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
/*
  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;
}