sql_show.cc 246 KB
Newer Older
1
/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
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 14 15 16 17 18 19
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


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

#include "mysql_priv.h"
20
#include "sql_select.h"                         // For select_describe
21
#include "sql_show.h"
22
#include "repl_failsafe.h"
23
#include "sp.h"
24
#include "sp_head.h"
25
#include "sql_trigger.h"
unknown's avatar
unknown committed
26
#include "authors.h"
27
#include "contributors.h"
28
#include "sql_partition.h"
29
#ifdef HAVE_EVENT_SCHEDULER
30
#include "events.h"
31
#include "event_data_objects.h"
32
#endif
unknown's avatar
unknown committed
33
#include <my_dir.h>
unknown's avatar
unknown committed
34

35 36
#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")

37 38 39
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
40 41 42 43 44 45
enum enum_i_s_events_fields
{
  ISE_EVENT_CATALOG= 0,
  ISE_EVENT_SCHEMA,
  ISE_EVENT_NAME,
  ISE_DEFINER,
46
  ISE_TIME_ZONE,
47 48 49 50 51 52 53 54 55 56 57 58 59 60
  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,
61
  ISE_EVENT_COMMENT,
unknown's avatar
unknown committed
62 63 64 65
  ISE_ORIGINATOR,
  ISE_CLIENT_CS,
  ISE_CONNECTION_CL,
  ISE_DB_CL
66 67
};

68
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
69 70 71 72 73
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 **),
74
                               "grant_types",
75
                               grant_names, NULL};
unknown's avatar
unknown committed
76
#endif
unknown's avatar
unknown committed
77

78 79 80
static void store_key_options(THD *thd, String *packet, TABLE *table,
                              KEY *key_info);

81 82 83 84 85 86
static void get_cs_converted_string_value(THD *thd,
                                          String *input_str,
                                          String *output_str,
                                          CHARSET_INFO *cs,
                                          bool use_hex);

87 88
static void
append_algorithm(TABLE_LIST *table, String *buff);
89

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

unknown's avatar
unknown committed
92
/***************************************************************************
unknown's avatar
unknown committed
93
** List all table types supported
unknown's avatar
unknown committed
94 95
***************************************************************************/

unknown's avatar
unknown committed
96 97
static int make_version_string(char *buf, int buf_length, uint version)
{
unknown's avatar
unknown committed
98
  return my_snprintf(buf, buf_length, "%d.%d", version>>8,version&0xff);
unknown's avatar
unknown committed
99 100
}

unknown's avatar
unknown committed
101
static my_bool show_plugins(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
102 103 104
                            void *arg)
{
  TABLE *table= (TABLE*) arg;
unknown's avatar
unknown committed
105 106
  struct st_mysql_plugin *plug= plugin_decl(plugin);
  struct st_plugin_dl *plugin_dl= plugin_dlib(plugin);
unknown's avatar
unknown committed
107 108 109 110 111
  CHARSET_INFO *cs= system_charset_info;
  char version_buf[20];

  restore_record(table, s->default_values);

unknown's avatar
unknown committed
112 113
  table->field[0]->store(plugin_name(plugin)->str,
                         plugin_name(plugin)->length, cs);
unknown's avatar
unknown committed
114 115 116 117 118

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

unknown's avatar
fixes  
unknown committed
119

unknown's avatar
unknown committed
120
  switch (plugin_state(plugin)) {
unknown's avatar
unknown committed
121 122
  /* case PLUGIN_IS_FREED: does not happen */
  case PLUGIN_IS_DELETED:
unknown's avatar
unknown committed
123
    table->field[2]->store(STRING_WITH_LEN("DELETED"), cs);
unknown's avatar
unknown committed
124 125
    break;
  case PLUGIN_IS_UNINITIALIZED:
unknown's avatar
unknown committed
126
    table->field[2]->store(STRING_WITH_LEN("INACTIVE"), cs);
unknown's avatar
unknown committed
127 128
    break;
  case PLUGIN_IS_READY:
unknown's avatar
unknown committed
129
    table->field[2]->store(STRING_WITH_LEN("ACTIVE"), cs);
unknown's avatar
unknown committed
130
    break;
131 132 133
  case PLUGIN_IS_DISABLED:
    table->field[2]->store(STRING_WITH_LEN("DISABLED"), cs);
    break;
unknown's avatar
unknown committed
134 135 136 137
  default:
    DBUG_ASSERT(0);
  }

unknown's avatar
unknown committed
138 139 140
  table->field[3]->store(plugin_type_names[plug->type].str,
                         plugin_type_names[plug->type].length,
                         cs);
unknown's avatar
unknown committed
141
  table->field[4]->store(version_buf,
unknown's avatar
unknown committed
142
        make_version_string(version_buf, sizeof(version_buf),
unknown's avatar
unknown committed
143
                            *(uint *)plug->info), cs);
unknown's avatar
unknown committed
144

unknown's avatar
unknown committed
145
  if (plugin_dl)
unknown's avatar
unknown committed
146
  {
unknown's avatar
unknown committed
147
    table->field[5]->store(plugin_dl->dl.str, plugin_dl->dl.length, cs);
unknown's avatar
unknown committed
148
    table->field[5]->set_notnull();
unknown's avatar
unknown committed
149
    table->field[6]->store(version_buf,
unknown's avatar
unknown committed
150
          make_version_string(version_buf, sizeof(version_buf),
unknown's avatar
unknown committed
151
                              plugin_dl->version),
unknown's avatar
unknown committed
152 153
          cs);
    table->field[6]->set_notnull();
unknown's avatar
unknown committed
154 155
  }
  else
unknown's avatar
unknown committed
156
  {
unknown's avatar
unknown committed
157
    table->field[5]->set_null();
unknown's avatar
unknown committed
158 159 160 161
    table->field[6]->set_null();
  }


unknown's avatar
unknown committed
162 163
  if (plug->author)
  {
unknown's avatar
unknown committed
164 165
    table->field[7]->store(plug->author, strlen(plug->author), cs);
    table->field[7]->set_notnull();
unknown's avatar
unknown committed
166 167
  }
  else
unknown's avatar
unknown committed
168
    table->field[7]->set_null();
unknown's avatar
unknown committed
169 170 171

  if (plug->descr)
  {
unknown's avatar
unknown committed
172 173
    table->field[8]->store(plug->descr, strlen(plug->descr), cs);
    table->field[8]->set_notnull();
unknown's avatar
unknown committed
174 175
  }
  else
unknown's avatar
unknown committed
176
    table->field[8]->set_null();
unknown's avatar
unknown committed
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
  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
194 195 196 197 198 199 200 201 202
  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;

203 204
  if (plugin_foreach_with_mask(thd, show_plugins, MYSQL_ANY_PLUGIN,
                               ~PLUGIN_IS_FREED, table))
unknown's avatar
unknown committed
205
    DBUG_RETURN(1);
206

unknown's avatar
unknown committed
207 208 209 210
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
/***************************************************************************
** 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));

  if (protocol->send_fields(&field_list,
                            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);
  }
240
  my_eof(thd);
unknown's avatar
unknown committed
241 242
  DBUG_RETURN(FALSE);
}
243

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273

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

  if (protocol->send_fields(&field_list,
                            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);
  }
274
  my_eof(thd);
275 276 277 278
  DBUG_RETURN(FALSE);
}


unknown's avatar
unknown committed
279
/***************************************************************************
280
 List all privileges supported
unknown's avatar
unknown committed
281 282
***************************************************************************/

283 284 285 286
struct show_privileges_st {
  const char *privilege;
  const char *context;
  const char *comment;
unknown's avatar
unknown committed
287 288
};

289 290
static struct show_privileges_st sys_privileges[]=
{
unknown's avatar
unknown committed
291
  {"Alter", "Tables",  "To alter the table"},
292
  {"Alter routine", "Functions,Procedures",  "To alter or drop stored functions/procedures"},
293
  {"Create", "Databases,Tables,Indexes",  "To create new databases and tables"},
294
  {"Create routine","Databases","To use CREATE FUNCTION/PROCEDURE"},
unknown's avatar
unknown committed
295 296
  {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
  {"Create view", "Tables",  "To create new views"},
297
  {"Create user", "Server Admin",  "To create new users"},
unknown's avatar
unknown committed
298
  {"Delete", "Tables",  "To delete existing rows"},
unknown's avatar
unknown committed
299
  {"Drop", "Databases,Tables", "To drop databases, tables, and views"},
300
#ifdef HAVE_EVENT_SCHEDULER
301
  {"Event","Server Admin","To create, alter, drop and execute events"},
302
#endif
303
  {"Execute", "Functions,Procedures", "To execute stored routines"},
unknown's avatar
unknown committed
304
  {"File", "File access on server",   "To read and write files on the server"},
305
  {"Grant option",  "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"},
unknown's avatar
unknown committed
306 307 308 309
  {"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"},
310
  {"References", "Databases,Tables", "To have references on tables"},
unknown's avatar
unknown committed
311 312 313 314 315
  {"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
316 317
  {"Show view","Tables","To see views with SHOW CREATE VIEW"},
  {"Shutdown","Server Admin", "To shut down the server"},
unknown's avatar
unknown committed
318
  {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
319
  {"Trigger","Tables", "To use triggers"},
unknown's avatar
unknown committed
320 321
  {"Update", "Tables",  "To update existing rows"},
  {"Usage","Server Admin","No privileges - allow connect only"},
322 323 324
  {NullS, NullS, NullS}
};

unknown's avatar
unknown committed
325
bool mysqld_show_privileges(THD *thd)
unknown's avatar
unknown committed
326 327
{
  List<Item> field_list;
328
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
329 330 331 332
  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));
333
  field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
unknown's avatar
unknown committed
334

335 336
  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
337
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
338

339 340
  show_privileges_st *privilege= sys_privileges;
  for (privilege= sys_privileges; privilege->privilege ; privilege++)
unknown's avatar
unknown committed
341
  {
342
    protocol->prepare_for_resend();
343 344 345
    protocol->store(privilege->privilege, system_charset_info);
    protocol->store(privilege->context, system_charset_info);
    protocol->store(privilege->comment, system_charset_info);
346
    if (protocol->write())
unknown's avatar
unknown committed
347
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
348
  }
349
  my_eof(thd);
unknown's avatar
unknown committed
350
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
351 352 353
}


354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
/*
  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
375
find_files(THD *thd, List<LEX_STRING> *files, const char *db,
376
           const char *path, const char *wild, bool dir)
unknown's avatar
unknown committed
377 378 379 380 381
{
  uint i;
  char *ext;
  MY_DIR *dirp;
  FILEINFO *file;
382 383
  LEX_STRING *file_name= 0;
  uint file_name_len;
unknown's avatar
unknown committed
384
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
385
  uint col_access=thd->col_access;
unknown's avatar
unknown committed
386
#endif
387
  uint wild_length= 0;
unknown's avatar
unknown committed
388
  TABLE_LIST table_list;
389
  DBUG_ENTER("find_files");
unknown's avatar
unknown committed
390

391 392 393 394 395 396 397 398
  if (wild)
  {
    if (!wild[0])
      wild= 0;
    else
      wild_length= strlen(wild);
  }

399 400


unknown's avatar
unknown committed
401 402
  bzero((char*) &table_list,sizeof(table_list));

403 404 405 406 407 408
  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);
409
    DBUG_RETURN(FIND_FILES_DIR);
410
  }
unknown's avatar
unknown committed
411

412
  for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
unknown's avatar
unknown committed
413
  {
414
    char uname[NAME_LEN + 1];                   /* Unencoded name */
unknown's avatar
unknown committed
415 416
    file=dirp->dir_entry+i;
    if (dir)
417
    {                                           /* Return databases */
418 419 420 421
      if ((file->name[0] == '.' && 
          ((file->name[1] == '.' && file->name[2] == '\0') ||
            file->name[1] == '\0')))
        continue;                               /* . or .. */
unknown's avatar
unknown committed
422 423
#ifdef USE_SYMDIR
      char *ext;
424
      char buff[FN_REFLEN];
unknown's avatar
unknown committed
425
      if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
426 427
      {
	/* Only show the sym file if it points to a directory */
428
	char *end;
429
        *ext=0;                                 /* Remove extension */
430 431 432 433
	unpack_dirname(buff, file->name);
	end= strend(buff);
	if (end != buff && end[-1] == FN_LIBCHAR)
	  end[-1]= 0;				// Remove end FN_LIBCHAR
434 435 436
        if (!my_stat(buff, file->mystat, MYF(0)))
               continue;
       }
unknown's avatar
unknown committed
437
#endif
438 439
      if (!MY_S_ISDIR(file->mystat->st_mode))
        continue;
440 441

      file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
442
      if (wild && wild_compare(uname, wild, 0))
443
        continue;
444 445 446 447 448 449
      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
450 451 452
    }
    else
    {
453
        // Return only .frm files which aren't temp files.
454
      if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),reg_ext) ||
455
          is_prefix(file->name, tmp_file_prefix))
456
        continue;
unknown's avatar
unknown committed
457
      *ext=0;
458
      file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
459 460 461 462
      if (wild)
      {
	if (lower_case_table_names)
	{
463
          if (my_wildcmp(files_charset_info,
464
                         uname, uname + file_name_len,
465 466 467
                         wild, wild + wild_length,
                         wild_prefix, wild_one,wild_many))
            continue;
468
	}
469
	else if (wild_compare(uname, wild, 0))
470 471
	  continue;
      }
unknown's avatar
unknown committed
472
    }
unknown's avatar
unknown committed
473
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
474 475 476 477
    /* Don't show tables where we don't have any privileges */
    if (db && !(col_access & TABLE_ACLS))
    {
      table_list.db= (char*) db;
478
      table_list.db_length= strlen(db);
479 480
      table_list.table_name= uname;
      table_list.table_name_length= file_name_len;
unknown's avatar
unknown committed
481
      table_list.grant.privilege=col_access;
482
      if (check_grant(thd, TABLE_ACLS, &table_list, 1, 1, 1))
483
        continue;
unknown's avatar
unknown committed
484
    }
unknown's avatar
unknown committed
485
#endif
486 487 488
    if (!(file_name= 
          thd->make_lex_string(file_name, uname, file_name_len, TRUE)) ||
        files->push_back(file_name))
unknown's avatar
unknown committed
489 490
    {
      my_dirend(dirp);
491
      DBUG_RETURN(FIND_FILES_OOM);
unknown's avatar
unknown committed
492 493 494 495
    }
  }
  DBUG_PRINT("info",("found: %d files", files->elements));
  my_dirend(dirp);
unknown's avatar
unknown committed
496

497
  VOID(ha_find_files(thd, db, path, wild, dir, files));
unknown's avatar
unknown committed
498

499
  DBUG_RETURN(FIND_FILES_OK);
unknown's avatar
unknown committed
500 501
}

502

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 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
/**
   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;
  }

566 567 568 569
  bool handle_condition(THD *thd, uint sql_errno, const char */* sqlstate */,
                        MYSQL_ERROR::enum_warning_level level,
                        const char *message, MYSQL_ERROR **/* cond_hdl */)
  {
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
    /* 
       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
625
bool
unknown's avatar
unknown committed
626 627
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
628 629 630
  Protocol *protocol= thd->protocol;
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
unknown's avatar
unknown committed
631 632
  DBUG_ENTER("mysqld_show_create");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
633
                      table_list->table_name));
unknown's avatar
unknown committed
634

635 636 637
  /* We want to preserve the tree for views. */
  thd->lex->view_prepare_mode= TRUE;

638
  {
639 640 641 642
    Show_create_error_handler view_error_suppressor(thd, table_list);
    thd->push_internal_handler(&view_error_suppressor);
    bool error= open_normal_and_derived_tables(thd, table_list, 0);
    thd->pop_internal_handler();
643
    if (error && thd->is_error())
644 645
      DBUG_RETURN(TRUE);
  }
646

unknown's avatar
VIEW  
unknown committed
647 648 649
  /* TODO: add environment variables show when it become possible */
  if (thd->lex->only_view && !table_list->view)
  {
650
    my_error(ER_WRONG_OBJECT, MYF(0),
651
             table_list->db, table_list->table_name, "VIEW");
unknown's avatar
unknown committed
652
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
653
  }
unknown's avatar
unknown committed
654

655
  buffer.length(0);
unknown's avatar
unknown committed
656 657 658 659

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

unknown's avatar
VIEW  
unknown committed
660 661
  if ((table_list->view ?
       view_store_create_info(thd, table_list, &buffer) :
662 663
       store_create_info(thd, table_list, &buffer, NULL,
                         FALSE /* show_database */)))
unknown's avatar
unknown committed
664
    DBUG_RETURN(TRUE);
665

unknown's avatar
unknown committed
666
  List<Item> field_list;
unknown's avatar
unknown committed
667 668
  if (table_list->view)
  {
669
    field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN));
unknown's avatar
unknown committed
670 671
    field_list.push_back(new Item_empty_string("Create View",
                                               max(buffer.length(),1024)));
unknown's avatar
unknown committed
672 673 674 675
    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
676 677 678
  }
  else
  {
679
    field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
unknown's avatar
unknown committed
680 681 682 683
    // 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
684

685 686
  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
687
    DBUG_RETURN(TRUE);
688
  protocol->prepare_for_resend();
unknown's avatar
VIEW  
unknown committed
689 690 691 692
  if (table_list->view)
    protocol->store(table_list->view_name.str, system_charset_info);
  else
  {
unknown's avatar
unknown committed
693
    if (table_list->schema_table)
694 695
      protocol->store(table_list->schema_table->table_name,
                      system_charset_info);
unknown's avatar
unknown committed
696
    else
697
      protocol->store(table_list->table->alias, system_charset_info);
unknown's avatar
VIEW  
unknown committed
698
  }
unknown's avatar
unknown committed
699 700 701

  if (table_list->view)
  {
702 703
    protocol->store(buffer.ptr(), buffer.length(),
                    table_list->view_creation_ctx->get_client_cs());
unknown's avatar
unknown committed
704 705 706 707 708 709 710 711 712

    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
713

714
  if (protocol->write())
unknown's avatar
unknown committed
715
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
716

717
  my_eof(thd);
unknown's avatar
unknown committed
718
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
719 720
}

unknown's avatar
unknown committed
721 722
bool mysqld_show_create_db(THD *thd, char *dbname,
                           HA_CREATE_INFO *create_info)
723 724 725
{
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
unknown's avatar
unknown committed
726
#ifndef NO_EMBEDDED_ACCESS_CHECKS
727
  Security_context *sctx= thd->security_ctx;
728
  uint db_access;
unknown's avatar
unknown committed
729
#endif
730 731 732 733 734 735
  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
736
  if (test_all_bits(sctx->master_access, DB_ACLS))
737 738
    db_access=DB_ACLS;
  else
739 740
    db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
		sctx->master_access);
741
  if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname))
742
  {
743
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
744
             sctx->priv_user, sctx->host_or_ip, dbname);
745 746
    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
747
    DBUG_RETURN(TRUE);
748 749
  }
#endif
750
  if (!my_strcasecmp(system_charset_info, dbname,
751
                     INFORMATION_SCHEMA_NAME.str))
752
  {
753
    dbname= INFORMATION_SCHEMA_NAME.str;
754
    create.default_table_charset= system_charset_info;
755
  }
756
  else
757
  {
758
    if (check_db_dir_existence(dbname))
759 760 761 762
    {
      my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
      DBUG_RETURN(TRUE);
    }
763 764

    load_db_opt_by_name(thd, dbname, &create);
765 766
  }
  List<Item> field_list;
767
  field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
768 769
  field_list.push_back(new Item_empty_string("Create Database",1024));

770 771
  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
772
    DBUG_RETURN(TRUE);
773 774 775 776

  protocol->prepare_for_resend();
  protocol->store(dbname, strlen(dbname), system_charset_info);
  buffer.length(0);
777
  buffer.append(STRING_WITH_LEN("CREATE DATABASE "));
778
  if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
779
    buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ "));
780 781 782 783
  append_identifier(thd, &buffer, dbname, strlen(dbname));

  if (create.default_table_charset)
  {
784 785
    buffer.append(STRING_WITH_LEN(" /*!40100"));
    buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET "));
786 787 788
    buffer.append(create.default_table_charset->csname);
    if (!(create.default_table_charset->state & MY_CS_PRIMARY))
    {
789
      buffer.append(STRING_WITH_LEN(" COLLATE "));
790 791
      buffer.append(create.default_table_charset->name);
    }
792
    buffer.append(STRING_WITH_LEN(" */"));
793 794 795 796
  }
  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());

  if (protocol->write())
unknown's avatar
unknown committed
797
    DBUG_RETURN(TRUE);
798
  my_eof(thd);
unknown's avatar
unknown committed
799
  DBUG_RETURN(FALSE);
800
}
unknown's avatar
unknown committed
801

unknown's avatar
unknown committed
802 803


unknown's avatar
unknown committed
804
/****************************************************************************
805 806
  Return only fields for API mysql_list_fields
  Use "show table wildcard" in mysql instead of this
unknown's avatar
unknown committed
807 808 809 810 811 812 813
****************************************************************************/

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

816
  if (open_normal_and_derived_tables(thd, table_list, 0))
unknown's avatar
unknown committed
817
    DBUG_VOID_RETURN;
818 819
  table= table_list->table;

unknown's avatar
unknown committed
820 821 822 823 824
  List<Item> field_list;

  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
825 826
    if (!wild || !wild[0] || 
        !wild_case_compare(system_charset_info, field->field_name,wild))
827 828 829 830 831 832 833 834
    {
      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
835
  }
836
  restore_record(table, s->default_values);              // Get empty record
837
  table->use_all_columns();
838
  if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS))
unknown's avatar
unknown committed
839
    DBUG_VOID_RETURN;
840
  my_eof(thd);
unknown's avatar
unknown committed
841 842 843
  DBUG_VOID_RETURN;
}

844

unknown's avatar
unknown committed
845
int
unknown's avatar
unknown committed
846
mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd)
unknown's avatar
unknown committed
847
{
848 849
  Protocol *protocol= thd->protocol;
  String *packet= protocol->storage_packet();
unknown's avatar
unknown committed
850
  DBUG_ENTER("mysqld_dump_create_info");
unknown's avatar
unknown committed
851
  DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name.str));
852

853
  protocol->prepare_for_resend();
854 855
  if (store_create_info(thd, table_list, packet, NULL,
                        FALSE /* show_database */))
unknown's avatar
unknown committed
856
    DBUG_RETURN(-1);
857

858
  if (fd < 0)
859
  {
860
    if (protocol->write())
861
      DBUG_RETURN(-1);
862
    protocol->flush();
863
  }
unknown's avatar
unknown committed
864
  else
865
  {
866
    if (my_write(fd, (const uchar*) packet->ptr(), packet->length(),
867
		 MYF(MY_WME)))
868 869
      DBUG_RETURN(-1);
  }
unknown's avatar
unknown committed
870 871
  DBUG_RETURN(0);
}
872

873
/*
874
  Go through all character combinations and ensure that sql_lex.cc can
875
  parse it as an identifier.
876 877

  SYNOPSIS
878 879 880 881 882 883 884
  require_quotes()
  name			attribute name
  name_length		length of name

  RETURN
    #	Pointer to conflicting character
    0	No conflicting character
885 886
*/

887
static const char *require_quotes(const char *name, uint name_length)
888
{
889
  uint length;
890
  bool pure_digit= TRUE;
891 892
  const char *end= name + name_length;

893
  for (; name < end ; name++)
894
  {
895 896 897 898
    uchar chr= (uchar) *name;
    length= my_mbcharlen(system_charset_info, chr);
    if (length == 1 && !system_charset_info->ident_map[chr])
      return name;
899 900
    if (length == 1 && (chr < '0' || chr > '9'))
      pure_digit= FALSE;
901
  }
902 903
  if (pure_digit)
    return name;
904 905
  return 0;
}
906

907

908 909 910 911 912 913 914 915 916 917 918 919
/*
  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
*/

920 921
void
append_identifier(THD *thd, String *packet, const char *name, uint length)
922
{
923 924
  const char *name_end;
  char quote_char;
925
  int q= get_quote_char_for_identifier(thd, name, length);
926

927
  if (q == EOF)
928
  {
unknown's avatar
unknown committed
929
    packet->append(name, length, packet->charset());
930 931 932
    return;
  }

933 934 935 936
  /*
    The identifier must be quoted as it includes a quote character or
   it's a keyword
  */
937

938
  VOID(packet->reserve(length*2 + 2));
939
  quote_char= (char) q;
940 941 942 943
  packet->append(&quote_char, 1, system_charset_info);

  for (name_end= name+length ; name < name_end ; name+= length)
  {
944
    uchar chr= (uchar) *name;
945
    length= my_mbcharlen(system_charset_info, chr);
946
    /*
unknown's avatar
unknown committed
947
      my_mbcharlen can return 0 on a wrong multibyte
948 949 950 951 952 953 954
      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;
955
    if (length == 1 && chr == (uchar) quote_char)
956
      packet->append(&quote_char, 1, system_charset_info);
unknown's avatar
unknown committed
957
    packet->append(name, length, system_charset_info);
958
  }
959
  packet->append(&quote_char, 1, system_charset_info);
960 961
}

962

963 964 965 966 967 968 969 970 971 972
/*
  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
973 974 975 976 977
    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;
978 979 980 981 982 983 984
    Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE
    is set.

  RETURN
    EOF	  No quote character is needed
    #	  Quote character
*/
985 986 987

int get_quote_char_for_identifier(THD *thd, const char *name, uint length)
{
unknown's avatar
unknown committed
988
  if (length &&
989
      !is_keyword(name,length) &&
990 991 992
      !require_quotes(name, length) &&
      !(thd->options & OPTION_QUOTE_SHOW_CREATE))
    return EOF;
993
  if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
994
    return '"';
995
  return '`';
996 997 998
}


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


unknown's avatar
unknown committed
1027
#define LIST_PROCESS_HOST_LEN 64
1028

1029 1030 1031 1032 1033 1034
static bool get_field_default_value(THD *thd, TABLE *table,
                                    Field *field, String *def_value,
                                    bool quoted)
{
  bool has_default;
  bool has_now_default;
1035
  enum enum_field_types field_type= field->type();
1036 1037 1038 1039 1040 1041 1042
  /* 
     We are using CURRENT_TIMESTAMP instead of NOW because it is
     more standard
  */
  has_now_default= table->timestamp_field == field && 
    field->unireg_check != Field::TIMESTAMP_UN_FIELD;
    
1043
  has_default= (field_type != FIELD_TYPE_BLOB &&
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
                !(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());
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
      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);
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
      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;
}

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

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

1147
  restore_record(table, s->default_values); // Get empty record
1148

1149
  if (share->tmp_table)
1150
    packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
1151
  else
1152
    packet->append(STRING_WITH_LEN("CREATE TABLE "));
1153 1154 1155
  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
1156
  if (table_list->schema_table)
1157
    alias= table_list->schema_table->table_name;
unknown's avatar
unknown committed
1158
  else
1159 1160 1161 1162 1163 1164 1165 1166
  {
    if (lower_case_table_names == 2)
      alias= table->alias;
    else
    {
      alias= share->table_name.str;
    }
  }
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178

  /*
    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;
1179
    if (!thd->db || strcmp(db->str, thd->db))
1180 1181 1182 1183 1184 1185
    {
      append_identifier(thd, packet, db->str, db->length);
      packet->append(STRING_WITH_LEN("."));
    }
  }

unknown's avatar
unknown committed
1186
  append_identifier(thd, packet, alias, strlen(alias));
1187
  packet->append(STRING_WITH_LEN(" (\n"));
1188 1189 1190 1191 1192 1193
  /*
    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);
1194

unknown's avatar
unknown committed
1195 1196
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1197 1198
    uint flags = field->flags;

1199
    if (ptr != table->field)
1200
      packet->append(STRING_WITH_LEN(",\n"));
1201

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

unknown's avatar
unknown committed
1211
    field->sql_type(type);
1212
    packet->append(type.ptr(), type.length(), system_charset_info);
1213

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

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

1244
    if (get_field_default_value(thd, table, field, &def_value, 1))
1245
    {
1246
      packet->append(STRING_WITH_LEN(" DEFAULT "));
1247
      packet->append(def_value.ptr(), def_value.length(), system_charset_info);
1248
    }
1249

unknown's avatar
unknown committed
1250
    if (!limited_mysql_mode && table->timestamp_field == field && 
1251
        field->unireg_check != Field::TIMESTAMP_DN_FIELD)
1252
      packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
1253

1254 1255
    if (field->unireg_check == Field::NEXT_NUMBER && 
        !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
1256
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
1257 1258 1259

    if (field->comment.length)
    {
1260
      packet->append(STRING_WITH_LEN(" COMMENT "));
1261 1262
      append_unescaped(packet, field->comment.str, field->comment.length);
    }
unknown's avatar
unknown committed
1263 1264
  }

1265
  key_info= table->key_info;
1266
  bzero((char*) &create_info, sizeof(create_info));
1267 1268
  /* Allow update_create_info to update row type */
  create_info.row_type= share->row_type;
1269
  file->update_create_info(&create_info);
1270
  primary_key= share->primary_key;
1271

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

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

1296
    if (!found_primary)
1297
     append_identifier(thd, packet, key_info->name, strlen(key_info->name));
unknown's avatar
unknown committed
1298

1299
    packet->append(STRING_WITH_LEN(" ("));
1300

unknown's avatar
unknown committed
1301 1302
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
1303
      if (j)
1304
        packet->append(',');
1305

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

1334 1335 1336 1337
  /*
    Get possible foreign key definitions stored in InnoDB and append them
    to the CREATE TABLE statement
  */
1338

1339
  if ((for_str= file->get_foreign_key_create_info()))
1340 1341 1342
  {
    packet->append(for_str, strlen(for_str));
    file->free_foreign_key_create_info(for_str);
1343 1344
  }

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

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

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

1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394
    /*
      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.
    */

1395
    if (create_info.auto_increment_value > 1)
1396
    {
1397
      char *end;
1398
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT="));
1399 1400 1401
      end= longlong10_to_str(create_info.auto_increment_value, buff,10);
      packet->append(buff, (uint) (end - buff));
    }
1402

1403
    
1404
    if (share->table_charset &&
1405 1406
	!(thd->variables.sql_mode & MODE_MYSQL323) &&
	!(thd->variables.sql_mode & MODE_MYSQL40))
1407
    {
1408 1409 1410 1411 1412 1413
      /*
        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))
1414
      {
1415 1416 1417 1418 1419 1420 1421
        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);
        }
1422
      }
1423
    }
1424

1425
    if (share->min_rows)
1426
    {
1427
      char *end;
1428
      packet->append(STRING_WITH_LEN(" MIN_ROWS="));
1429
      end= longlong10_to_str(share->min_rows, buff, 10);
unknown's avatar
unknown committed
1430
      packet->append(buff, (uint) (end- buff));
1431
    }
unknown's avatar
unknown committed
1432

1433
    if (share->max_rows && !table_list->schema_table)
1434
    {
1435
      char *end;
1436
      packet->append(STRING_WITH_LEN(" MAX_ROWS="));
1437
      end= longlong10_to_str(share->max_rows, buff, 10);
unknown's avatar
unknown committed
1438
      packet->append(buff, (uint) (end - buff));
1439
    }
unknown's avatar
unknown committed
1440

1441
    if (share->avg_row_length)
1442
    {
1443
      char *end;
1444
      packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
1445
      end= longlong10_to_str(share->avg_row_length, buff,10);
unknown's avatar
unknown committed
1446
      packet->append(buff, (uint) (end - buff));
1447
    }
1448

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

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 1542 1543 1544 1545 1546 1547 1548 1549 1550

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


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

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


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

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

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

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

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


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

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

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

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

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
1712 1713
  ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
			   PROCESS_LIST_WIDTH);
1714
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
1715 1716
  DBUG_ENTER("mysqld_list_processes");

1717
  field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
unknown's avatar
unknown committed
1718
  field_list.push_back(new Item_empty_string("User",16));
1719
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
1720
  field_list.push_back(field=new Item_empty_string("db",NAME_CHAR_LEN));
unknown's avatar
unknown committed
1721 1722
  field->maybe_null=1;
  field_list.push_back(new Item_empty_string("Command",16));
1723
  field_list.push_back(field= new Item_return_int("Time",7, MYSQL_TYPE_LONG));
1724
  field->unsigned_flag= 0;
unknown's avatar
unknown committed
1725 1726 1727 1728
  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;
1729 1730
  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
1731 1732 1733 1734 1735 1736 1737 1738 1739
    DBUG_VOID_RETURN;

  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  if (!thd->killed)
  {
    I_List_iterator<THD> it(threads);
    THD *tmp;
    while ((tmp=it++))
    {
1740
      Security_context *tmp_sctx= tmp->security_ctx;
1741
      struct st_my_thread_var *mysys_var;
1742
      if ((tmp->vio_ok() || tmp->system_thread) &&
1743
          (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
unknown's avatar
unknown committed
1744
      {
1745
        thread_info *thd_info= new thread_info;
1746 1747

        thd_info->thread_id=tmp->thread_id;
1748 1749 1750 1751 1752
        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])
1753
	{
1754
	  if ((thd_info->host= (char*) thd->alloc(LIST_PROCESS_HOST_LEN+1)))
unknown's avatar
unknown committed
1755
	    my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
1756
			"%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
1757 1758
	}
	else
1759 1760 1761
	  thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ? 
                                      tmp_sctx->host_or_ip : 
                                      tmp_sctx->host ? tmp_sctx->host : "");
1762 1763 1764
        if ((thd_info->db=tmp->db))             // Safe test
          thd_info->db=thd->strdup(thd_info->db);
        thd_info->command=(int) tmp->command;
1765 1766
        if ((mysys_var= tmp->mysys_var))
          pthread_mutex_lock(&mysys_var->mutex);
unknown's avatar
SCRUM  
unknown committed
1767
        thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
unknown's avatar
SCRUM  
unknown committed
1768
#ifndef EMBEDDED_LIBRARY
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
        thd_info->state_info= (char*) (tmp->locked ? "Locked" :
                                       tmp->net.reading_or_writing ?
                                       (tmp->net.reading_or_writing == 2 ?
                                        "Writing to net" :
                                        thd_info->command == COM_SLEEP ? "" :
                                        "Reading from net") :
                                       tmp->proc_info ? tmp->proc_info :
                                       tmp->mysys_var &&
                                       tmp->mysys_var->current_cond ?
                                       "Waiting on cond" : NullS);
unknown's avatar
SCRUM  
unknown committed
1779 1780 1781
#else
        thd_info->state_info= (char*)"Writing to net";
#endif
1782 1783
        if (mysys_var)
          pthread_mutex_unlock(&mysys_var->mutex);
unknown's avatar
unknown committed
1784

1785 1786
        thd_info->start_time= tmp->start_time;
        thd_info->query=0;
1787 1788
        /* Lock THD mutex that protects its data when looking at it. */
        pthread_mutex_lock(&tmp->LOCK_thd_data);
1789 1790
        if (tmp->query)
        {
unknown's avatar
unknown committed
1791
          uint length= min(max_query_length, tmp->query_length);
1792
          thd_info->query=(char*) thd->strmake(tmp->query,length);
1793
        }
1794
        pthread_mutex_unlock(&tmp->LOCK_thd_data);
1795
        thread_infos.append(thd_info);
unknown's avatar
unknown committed
1796 1797 1798 1799 1800 1801
      }
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));

  thread_info *thd_info;
1802
  time_t now= my_time(0);
unknown's avatar
unknown committed
1803 1804
  while ((thd_info=thread_infos.get()))
  {
1805 1806
    protocol->prepare_for_resend();
    protocol->store((ulonglong) thd_info->thread_id);
1807 1808 1809
    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
1810
    if (thd_info->proc_info)
1811
      protocol->store(thd_info->proc_info, system_charset_info);
unknown's avatar
unknown committed
1812
    else
1813
      protocol->store(command_name[thd_info->command].str, system_charset_info);
unknown's avatar
unknown committed
1814
    if (thd_info->start_time)
1815
      protocol->store_long ((longlong) (now - thd_info->start_time));
unknown's avatar
unknown committed
1816
    else
1817
      protocol->store_null();
1818 1819
    protocol->store(thd_info->state_info, system_charset_info);
    protocol->store(thd_info->query, system_charset_info);
1820
    if (protocol->write())
unknown's avatar
unknown committed
1821 1822
      break; /* purecov: inspected */
  }
1823
  my_eof(thd);
unknown's avatar
unknown committed
1824 1825 1826
  DBUG_VOID_RETURN;
}

1827 1828 1829 1830 1831
int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
{
  TABLE *table= tables->table;
  CHARSET_INFO *cs= system_charset_info;
  char *user;
1832
  time_t now= my_time(0);
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 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
  DBUG_ENTER("fill_process_list");

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

  VOID(pthread_mutex_lock(&LOCK_thread_count));

  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))
        pthread_mutex_lock(&mysys_var->mutex);
      /* 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);
1889
      /* MYSQL_TIME */
1890 1891
      table->field[5]->store((longlong)(tmp->start_time ?
                                      now - tmp->start_time : 0), FALSE);
1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904
      /* STATE */
#ifndef EMBEDDED_LIBRARY
      val= (char*) (tmp->locked ? "Locked" :
                    tmp->net.reading_or_writing ?
                    (tmp->net.reading_or_writing == 2 ?
                     "Writing to net" :
                     tmp->command == COM_SLEEP ? "" :
                     "Reading from net") :
                    tmp->proc_info ? tmp->proc_info :
                    tmp->mysys_var &&
                    tmp->mysys_var->current_cond ?
                    "Waiting on cond" : NullS);
#else
1905
      val= (char *) (tmp->proc_info ? tmp->proc_info : NullS);
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919
#endif
      if (val)
      {
        table->field[6]->store(val, strlen(val), cs);
        table->field[6]->set_notnull();
      }

      if (mysys_var)
        pthread_mutex_unlock(&mysys_var->mutex);

      /* INFO */
      if (tmp->query)
      {
        table->field[7]->store(tmp->query,
1920 1921
                               min(PROCESS_LIST_INFO_WIDTH,
                                   tmp->query_length), cs);
1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936
        table->field[7]->set_notnull();
      }

      if (schema_table_store_record(thd, table))
      {
        VOID(pthread_mutex_unlock(&LOCK_thread_count));
        DBUG_RETURN(1);
      }
    }
  }

  VOID(pthread_mutex_unlock(&LOCK_thread_count));
  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 1992 1993 1994 1995 1996 1997 1998 1999
  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)
    pthread_mutex_lock(&LOCK_status);
  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 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024
  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)
    pthread_mutex_unlock(&LOCK_status);
  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 2069 2070
void remove_status_vars(SHOW_VAR *list)
{
  if (status_vars_inited)
  {
    pthread_mutex_lock(&LOCK_status);
    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 2090 2091 2092 2093 2094
      }
      if (res == 0)
        all[c].type= SHOW_UNDEF;
    }
    shrink_var_array(&all_status_vars);
    pthread_mutex_unlock(&LOCK_status);
  }
  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

unknown's avatar
unknown committed
2180 2181
        pthread_mutex_lock(&LOCK_global_system_variables);

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 2200
          /* fall through */
        case SHOW_DOUBLE:
          end= buff + my_sprintf(buff, (buff, "%f", *(double*) value));
2201
          break;
2202 2203 2204 2205
        case SHOW_LONG_STATUS:
          value= ((char *) status_var + (ulong) value);
          /* fall through */
        case SHOW_LONG:
2206
        case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
2207 2208
          end= int10_to_str(*(long*) value, buff, 10);
          break;
2209 2210
        case SHOW_LONGLONG_STATUS:
          value= ((char *) status_var + (ulonglong) value);
2211
          /* fall through */
2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227
        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
2228 2229 2230 2231 2232 2233
        {
          SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
          pos= show_comp_option_name[(int) tmp];
          end= strend(pos);
          break;
        }
2234
        case SHOW_CHAR:
unknown's avatar
unknown committed
2235 2236 2237 2238 2239 2240
        {
          if (!(pos= value))
            pos= "";
          end= strend(pos);
          break;
        }
unknown's avatar
unknown committed
2241
       case SHOW_CHAR_PTR:
unknown's avatar
unknown committed
2242 2243 2244 2245 2246 2247
        {
          if (!(pos= *(char**) value))
            pos= "";
          end= strend(pos);
          break;
        }
2248
        case SHOW_KEY_CACHE_LONG:
2249
          value= (char*) dflt_key_cache + (ulong)value;
2250 2251
          end= int10_to_str(*(long*) value, buff, 10);
          break;
2252
        case SHOW_KEY_CACHE_LONGLONG:
2253
          value= (char*) dflt_key_cache + (ulong)value;
2254 2255
	  end= longlong10_to_str(*(longlong*) value, buff, 10);
	  break;
2256
        case SHOW_UNDEF:
2257 2258
          break;                                        // Return empty string
        case SHOW_SYS:                                  // Cannot happen
2259
        default:
2260
          DBUG_ASSERT(0);
2261 2262
          break;
        }
2263
        table->field[1]->store(pos, (uint32) (end - pos), charset);
2264
        thd->count_cuted_fields= CHECK_FIELD_IGNORE;
2265
        table->field[1]->set_notnull();
unknown's avatar
unknown committed
2266 2267 2268

        pthread_mutex_unlock(&LOCK_global_system_variables);

2269
        if (schema_table_store_record(thd, table))
2270 2271 2272 2273
        {
          res= TRUE;
          goto end;
        }
unknown's avatar
unknown committed
2274 2275 2276
      }
    }
  }
2277 2278 2279
end:
  thd->count_cuted_fields= save_count_cuted_fields;
  DBUG_RETURN(res);
2280 2281 2282
}


2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306
/* 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 */
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list

  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);
  
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
  DBUG_VOID_RETURN;
}


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

2310
typedef struct st_lookup_field_values
2311
{
2312 2313 2314
  LEX_STRING db_value, table_value;
  bool wild_db_value, wild_table_value;
} LOOKUP_FIELD_VALUES;
2315 2316


2317 2318 2319 2320 2321 2322 2323
/*
  Store record to I_S table, convert HEAP table
  to MyISAM if necessary

  SYNOPSIS
    schema_table_store_record()
    thd                   thread handler
2324 2325
    table                 Information schema table to be updated

2326 2327
  RETURN
    0	                  success
2328
    1	                  error
2329 2330
*/

2331
bool schema_table_store_record(THD *thd, TABLE *table)
2332 2333
{
  int error;
2334
  if ((error= table->file->ha_write_row(table->record[0])))
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344
  {
    if (create_myisam_from_heap(thd, table, 
                                table->pos_in_table_list->schema_table_param,
                                error, 0))
      return 1;
  }
  return 0;
}


2345
int make_table_list(THD *thd, SELECT_LEX *sel,
2346
                    LEX_STRING *db_name, LEX_STRING *table_name)
2347 2348
{
  Table_ident *table_ident;
2349
  table_ident= new Table_ident(thd, *db_name, *table_name, 1);
2350
  sel->init_query();
2351
  if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
2352 2353 2354 2355 2356
    return 1;
  return 0;
}


2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369
/**
  @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 

2370 2371 2372
  @return
    0             success
    1             error, there can be no matching records for the condition
2373 2374
*/

2375
bool get_lookup_value(THD *thd, Item_func *item_func,
2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407
                      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
2408
      return 0;
2409 2410 2411

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

2415 2416 2417 2418
    /* impossible value */
    if (!tmp_str)
      return 1;

2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436
    /* 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);
    }
  }
2437
  return 0;
2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452
}


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

2453 2454 2455
  @return
    0             success
    1             error, there can be no matching records for the condition
2456 2457
*/

2458
bool calc_lookup_values_from_cond(THD *thd, COND *cond, TABLE_LIST *table,
2459 2460 2461
                                  LOOKUP_FIELD_VALUES *lookup_field_vals)
{
  if (!cond)
2462
    return 0;
2463 2464 2465 2466 2467 2468 2469 2470 2471 2472

  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)
2473 2474 2475 2476
        {
          if (get_lookup_value(thd, (Item_func*)item, table, lookup_field_vals))
            return 1;
        }
2477
        else
2478 2479 2480 2481
        {
          if (calc_lookup_values_from_cond(thd, item, table, lookup_field_vals))
            return 1;
        }
2482 2483
      }
    }
2484
    return 0;
2485
  }
2486 2487 2488 2489
  else if (cond->type() == Item::FUNC_ITEM &&
           get_lookup_value(thd, (Item_func*) cond, table, lookup_field_vals))
    return 1;
  return 0;
2490 2491 2492
}


2493 2494 2495 2496 2497
bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
{
  if (item->type() == Item::FUNC_ITEM)
  {
    Item_func *item_func= (Item_func*)item;
2498
    for (uint i=0; i<item_func->argument_count(); i++)
2499
    {
2500
      if (!uses_only_table_name_fields(item_func->arguments()[i], table))
2501
        return 0;
2502
    }
2503 2504 2505 2506 2507 2508 2509
  }
  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;
2510 2511 2512 2513
    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 : "";
2514 2515
    if (table->table != item_field->field->table ||
        (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
2516
                               (uchar *) item_field->field_name,
2517 2518
                               strlen(item_field->field_name), 0) &&
         cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2),
2519
                               (uchar *) item_field->field_name,
2520
                               strlen(item_field->field_name), 0)))
2521 2522
      return 0;
  }
2523 2524
  else if (item->type() == Item::REF_ITEM)
    return uses_only_table_name_fields(item->real_item(), table);
2525 2526

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

2529
  return 1;
2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 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
}


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


2589 2590 2591 2592 2593 2594 2595 2596 2597 2598
/**
  @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
2599 2600
  @param[in]      tables                I_S table
  @param[in, out] lookup_field_values   Struct which holds lookup values 
2601

2602 2603 2604
  @return
    0             success
    1             error, there can be no matching records for the condition
2605 2606
*/

2607
bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables,
2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620
                             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;
    }
2621
    return 0;
2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633
  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;
    }
2634
    return 0;
2635 2636 2637 2638 2639
  default:
    /*
      The "default" is for queries over I_S.
      All previous cases handle SHOW commands.
    */
2640
    return calc_lookup_values_from_cond(thd, cond, tables, lookup_field_values);
2641 2642 2643 2644
  }
}


2645 2646 2647 2648 2649 2650
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
2651
/*
2652
  Create db names list. Information schema name always is first in list
unknown's avatar
unknown committed
2653 2654

  SYNOPSIS
2655
    make_db_list()
unknown's avatar
unknown committed
2656 2657 2658
    thd                   thread handler
    files                 list of db names
    wild                  wild string
2659 2660
    idx_field_vals        idx_field_vals->db_name contains db name or
                          wild string
unknown's avatar
unknown committed
2661
    with_i_schema         returns 1 if we added 'IS' name to list
2662
                          otherwise returns 0 
unknown's avatar
unknown committed
2663 2664

  RETURN
2665 2666
    zero                  success
    non-zero              error
unknown's avatar
unknown committed
2667 2668
*/

2669 2670 2671
int make_db_list(THD *thd, List<LEX_STRING> *files,
                 LOOKUP_FIELD_VALUES *lookup_field_vals,
                 bool *with_i_schema)
2672
{
unknown's avatar
unknown committed
2673 2674 2675 2676
  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
2677
  *with_i_schema= 0;
2678
  if (lookup_field_vals->wild_db_value)
unknown's avatar
unknown committed
2679
  {
2680 2681 2682 2683 2684
    /*
      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)
    */
2685
    if (!lookup_field_vals->db_value.str ||
2686
        !wild_case_compare(system_charset_info, 
2687
                           INFORMATION_SCHEMA_NAME.str,
2688
                           lookup_field_vals->db_value.str))
2689 2690
    {
      *with_i_schema= 1;
unknown's avatar
unknown committed
2691
      if (files->push_back(i_s_name_copy))
2692 2693
        return 1;
    }
2694
    return (find_files(thd, files, NullS, mysql_data_home,
2695
                       lookup_field_vals->db_value.str, 1) != FIND_FILES_OK);
unknown's avatar
unknown committed
2696
  }
2697

2698

2699
  /*
2700 2701
    If we have db lookup vaule we just add it to list and
    exit from the function
2702
  */
2703
  if (lookup_field_vals->db_value.str)
2704
  {
2705
    if (!my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str,
2706
                       lookup_field_vals->db_value.str))
2707 2708
    {
      *with_i_schema= 1;
unknown's avatar
unknown committed
2709
      if (files->push_back(i_s_name_copy))
2710 2711
        return 1;
      return 0;
2712
    }
2713 2714 2715
    if (files->push_back(&lookup_field_vals->db_value))
      return 1;
    return 0;
2716 2717
  }

2718 2719 2720 2721
  /*
    Create list of existing databases. It is used in case
    of select from information schema table
  */
unknown's avatar
unknown committed
2722
  if (files->push_back(i_s_name_copy))
2723 2724
    return 1;
  *with_i_schema= 1;
2725 2726
  return (find_files(thd, files, NullS,
                     mysql_data_home, NullS, 1) != FIND_FILES_OK);
2727 2728
}

2729

unknown's avatar
unknown committed
2730 2731
struct st_add_schema_table 
{
2732
  List<LEX_STRING> *files;
unknown's avatar
unknown committed
2733 2734 2735
  const char *wild;
};

2736

unknown's avatar
unknown committed
2737
static my_bool add_schema_table(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
2738 2739
                                void* p_data)
{
2740
  LEX_STRING *file_name= 0;
unknown's avatar
unknown committed
2741
  st_add_schema_table *data= (st_add_schema_table *)p_data;
2742
  List<LEX_STRING> *file_list= data->files;
unknown's avatar
unknown committed
2743
  const char *wild= data->wild;
unknown's avatar
unknown committed
2744
  ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
unknown's avatar
unknown committed
2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761
  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);
  }

2762 2763 2764 2765 2766 2767
  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
2768
}
2769

2770 2771

int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
2772
{
2773
  LEX_STRING *file_name= 0;
2774
  ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
unknown's avatar
unknown committed
2775 2776 2777
  st_add_schema_table add_data;
  DBUG_ENTER("schema_tables_add");

2778
  for (; tmp_schema_table->table_name; tmp_schema_table++)
2779
  {
2780 2781
    if (tmp_schema_table->hidden)
      continue;
2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793
    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;
    }
2794 2795 2796 2797 2798 2799
    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);
2800
  }
unknown's avatar
unknown committed
2801 2802 2803 2804 2805 2806 2807 2808

  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);
2809 2810 2811
}


2812 2813
/**
  @brief          Create table names list
2814

2815 2816
  @details        The function creates the list of table names in
                  database
2817

2818 2819 2820 2821 2822 2823
  @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
2824

2825 2826 2827 2828 2829
  @return         Operation status
    @retval       0           ok
    @retval       1           fatal error
    @retval       2           Not fatal error; Safe to ignore this file list
*/
2830

2831 2832 2833 2834 2835
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)
{
2836 2837
  char path[FN_REFLEN + 1];
  build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0);
2838 2839
  if (!lookup_field_vals->wild_table_value &&
      lookup_field_vals->table_value.str)
2840
  {
2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880
    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)
      */
      VOID(ha_find_files(thd, db_name->str, path,
                         lookup_field_vals->table_value.str, 0,
                         table_names));
    }
    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.
2881
    */
2882 2883 2884 2885 2886 2887 2888 2889
    if (res == FIND_FILES_DIR)
    {
      if (lex->sql_command != SQLCOM_SELECT)
        return 1;
      thd->clear_error();
      return 2;
    }
    return 1;
2890
  }
2891 2892
  return 0;
}
2893

2894

2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 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 2957 2958 2959 2960 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 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998
/**
  @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
  @param[in]      open_tables_state_backup pointer to Open_tables_state object
                                           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,
                              Open_tables_state *open_tables_state_backup)
{
  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,
                                      MYSQL_LOCK_IGNORE_FLUSH);
  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;
   close_tables_for_reopen(thd, &show_table_list);
   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;
2999 3000
    char path[FN_REFLEN + 1];
    (void) build_table_filename(path, sizeof(path) - 1, db_name->str, 
3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017
                                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
3018
    if (thd->is_error() && thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045
    {
      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
*/

3046
uint get_table_open_method(TABLE_LIST *tables,
3047 3048 3049 3050 3051 3052 3053 3054 3055 3056
                                  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;
3057 3058
    uint star_table_open_method= OPEN_FULL_TABLE;
    bool used_star= true;                  // true if '*' is used in select
3059 3060
    for (ptr=tables->table->field; (field= *ptr) ; ptr++)
    {
3061 3062 3063
      star_table_open_method=
        min(star_table_open_method,
            schema_table->fields_info[field_indx].open_method);
3064
      if (bitmap_is_set(tables->table->read_set, field->field_index))
3065 3066
      {
        used_star= false;
3067
        table_open_method|= schema_table->fields_info[field_indx].open_method;
3068
      }
3069 3070
      field_indx++;
    }
3071 3072
    if (used_star)
      return star_table_open_method;
3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102
    return table_open_method;
  }
  /* I_S tables which use get_all_tables but can not be optimized */
  return (uint) OPEN_FULL_TABLE;
}


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

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

static int fill_schema_table_from_frm(THD *thd,TABLE *table,
                                      ST_SCHEMA_TABLE *schema_table, 
                                      LEX_STRING *db_name,
                                      LEX_STRING *table_name,
                                      enum enum_schema_tables schema_table_idx)
{
3103
  TABLE_SHARE *share;
3104 3105
  TABLE tbl;
  TABLE_LIST table_list;
3106 3107 3108 3109 3110
  uint res= 0;
  int error;
  char key[MAX_DBKEY_LENGTH];
  uint key_length;

3111 3112
  bzero((char*) &table_list, sizeof(TABLE_LIST));
  bzero((char*) &tbl, sizeof(TABLE));
3113 3114 3115 3116 3117 3118 3119 3120

  table_list.table_name= table_name->str;
  table_list.db= db_name->str;
  key_length= create_table_def_key(thd, key, &table_list, 0);
  pthread_mutex_lock(&LOCK_open);
  share= get_table_share(thd, &table_list, key,
                         key_length, OPEN_VIEW, &error);
  if (!share)
3121
  {
3122
    res= 0;
unknown's avatar
unknown committed
3123
    goto err;
3124 3125 3126 3127 3128
  }
 
  if (share->is_view)
  {
    if (schema_table->i_s_requested_object & OPEN_TABLE_ONLY)
3129
    {
3130 3131 3132
      /* skip view processing */
      res= 0;
      goto err1;
3133
    }
3134 3135 3136 3137 3138 3139 3140 3141
    else if (schema_table->i_s_requested_object & OPEN_VIEW_FULL)
    {
      /*
        tell get_all_tables() to fall back to 
        open_normal_and_derived_tables()
      */
      res= 1;
      goto err1;
3142
    }
3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
  }

  if (share->is_view ||
      !open_table_from_share(thd, share, table_name->str, 0,
                             (READ_KEYINFO | COMPUTE_TYPES |
                              EXTRA_RECORD | OPEN_FRM_FILE_ONLY),
                             thd->open_options, &tbl, FALSE))
  {
    tbl.s= share;
    table_list.table= &tbl;
    table_list.view= (st_lex*) share->is_view;
3154 3155
    res= schema_table->process_table(thd, &table_list, table,
                                     res, db_name, table_name);
3156 3157
    closefrm(&tbl, true);
    goto err;
3158 3159
  }

3160 3161 3162 3163 3164 3165 3166
err1:
  release_table_share(share, RELEASE_NORMAL);

err:
  pthread_mutex_unlock(&LOCK_open);
  thd->clear_error();
  return res;
3167
}
3168

3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189


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

3190 3191 3192 3193
int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  LEX *lex= thd->lex;
  TABLE *table= tables->table;
3194
  SELECT_LEX *old_all_select_lex= lex->all_selects_list;
3195
  enum_sql_command save_sql_command= lex->sql_command;
unknown's avatar
unknown committed
3196
  SELECT_LEX *lsel= tables->schema_select_lex;
3197
  ST_SCHEMA_TABLE *schema_table= tables->schema_table;
3198
  SELECT_LEX sel;
3199 3200
  LOOKUP_FIELD_VALUES lookup_field_vals;
  LEX_STRING *db_name, *table_name;
3201 3202
  bool with_i_schema;
  enum enum_schema_tables schema_table_idx;
3203 3204
  List<LEX_STRING> db_names;
  List_iterator_fast<LEX_STRING> it(db_names);
3205
  COND *partial_cond= 0;
3206
  uint derived_tables= lex->derived_tables; 
unknown's avatar
unknown committed
3207
  int error= 1;
3208
  Open_tables_state open_tables_state_backup;
3209
  bool save_view_prepare_mode= lex->view_prepare_mode;
3210
  Query_tables_list query_tables_list_backup;
3211 3212 3213
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  Security_context *sctx= thd->security_ctx;
#endif
3214
  uint table_open_method;
3215 3216
  DBUG_ENTER("get_all_tables");

3217
  lex->view_prepare_mode= TRUE;
3218
  lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
3219 3220

  /*
3221 3222 3223
    We should not introduce deadlocks even if we already have some
    tables open and locked, since we won't lock tables which we will
    open and will ignore possible name-locks for these tables.
3224
  */
3225 3226
  thd->reset_n_backup_open_tables_state(&open_tables_state_backup);

3227 3228 3229 3230 3231
  /* 
    this branch processes SHOW FIELDS, SHOW INDEXES commands.
    see sql_parse.cc, prepare_schema_table() function where
    this values are initialized
  */
3232
  if (lsel && lsel->table_list.first)
3233
  {
3234 3235
    error= fill_schema_show_cols_or_idxs(thd, tables, schema_table,
                                         &open_tables_state_backup);
unknown's avatar
unknown committed
3236
    goto err;
3237 3238
  }

3239
  schema_table_idx= get_schema_table_idx(schema_table);
3240 3241 3242 3243 3244
  if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
  {
    error= 0;
    goto err;
  }
3245
  DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'",
3246 3247
                             STR_OR_NIL(lookup_field_vals.db_value.str),
                             STR_OR_NIL(lookup_field_vals.table_value.str)));
3248

3249 3250 3251 3252 3253 3254
  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
3255 3256 3257 3258
    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]))
3259 3260 3261 3262 3263 3264 3265 3266
    {
      error= 0;
      goto err;
    }
  }

  if (lookup_field_vals.db_value.length &&
      !lookup_field_vals.wild_db_value)
3267 3268 3269 3270
    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;
3271

3272 3273 3274 3275 3276
  if (tables->has_db_lookup_value && tables->has_table_lookup_value)
    partial_cond= 0;
  else
    partial_cond= make_cond_for_info_schema(cond, tables);

3277 3278 3279 3280 3281 3282 3283
  tables->table_open_method= table_open_method=
    get_table_open_method(tables, schema_table, schema_table_idx);

  if (lex->describe)
  {
    /* EXPLAIN SELECT */
    error= 0;
unknown's avatar
unknown committed
3284
    goto err;
3285
  }
3286

3287 3288
  if (make_db_list(thd, &db_names, &lookup_field_vals, &with_i_schema))
    goto err;
unknown's avatar
unknown committed
3289
  it.rewind(); /* To get access to new elements in basis list */
3290
  while ((db_name= it++))
3291 3292
  {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3293
    if (!check_access(thd,SELECT_ACL, db_name->str, 
3294
                      &thd->col_access, 0, 1, with_i_schema) ||
3295
        sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
3296 3297
	acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
	!check_grant_db(thd, db_name->str))
3298 3299
#endif
    {
3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311
      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++))
3312
      {
3313 3314 3315 3316 3317 3318 3319
	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())
3320 3321
        {
          /*
3322 3323 3324 3325
            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).
3326
          */
3327 3328 3329
          if (!table_open_method && schema_table_idx == SCH_TABLES &&
              (!lookup_field_vals.table_value.length ||
               lookup_field_vals.wild_table_value))
3330
          {
3331
            table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
3332 3333
            if (schema_table_store_record(thd, table))
              goto err;      /* Out of space in temporary table */
3334 3335
            continue;
          }
3336

3337
          /* SHOW TABLE NAMES command */
3338 3339
          if (schema_table_idx == SCH_TABLE_NAMES)
          {
3340 3341 3342
            if (fill_schema_table_names(thd, tables->table, db_name,
                                        table_name, with_i_schema))
              continue;
3343 3344 3345
          }
          else
          {
3346 3347 3348 3349 3350 3351 3352 3353
            if (!(table_open_method & ~OPEN_FRM_ONLY) && 
                !with_i_schema)
            {
              if (!fill_schema_table_from_frm(thd, table, schema_table, db_name,
                                              table_name, schema_table_idx))
                continue;
            }

3354
            int res;
3355
            LEX_STRING tmp_lex_string, orig_db_name;
unknown's avatar
unknown committed
3356
            /*
3357 3358
              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
3359
            */
3360
            thd->no_warnings_for_error= 1;
unknown's avatar
unknown committed
3361
            sel.parent_lex= lex;
3362 3363 3364 3365 3366
            /* 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
3367
              goto err;
3368
            TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first;
3369 3370
            lex->all_selects_list= &sel;
            lex->derived_tables= 0;
3371
            lex->sql_command= SQLCOM_SHOW_FIELDS;
3372 3373
            show_table_list->i_s_requested_object=
              schema_table->i_s_requested_object;
3374 3375
            res= open_normal_and_derived_tables(thd, show_table_list,
                                                MYSQL_LOCK_IGNORE_FLUSH);
3376
            lex->sql_command= save_sql_command;
3377 3378 3379 3380 3381 3382
            /*
              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
3383
              for thd->stmt_da->sql_errno().
3384 3385
            */
            if (res && thd->is_error() &&
Marc Alff's avatar
Marc Alff committed
3386
                thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
3387
            {
3388 3389 3390 3391 3392 3393
              /*
                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.
              */
3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405
              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.
              */
3406 3407
              thd->make_lex_string(&tmp_lex_string, show_table_list->alias,
                                   strlen(show_table_list->alias), FALSE);
3408
              res= schema_table->process_table(thd, show_table_list, table,
3409 3410
                                               res, &orig_db_name,
                                               &tmp_lex_string);
3411 3412
              close_tables_for_reopen(thd, &show_table_list);
            }
3413
            DBUG_ASSERT(!lex->query_tables_own_last);
3414
            if (res)
unknown's avatar
unknown committed
3415
              goto err;
3416 3417 3418
          }
        }
      }
3419 3420 3421 3422
      /*
        If we have information schema its always the first table and only
        the first table. Reset for other tables.
      */
3423
      with_i_schema= 0;
3424 3425
    }
  }
unknown's avatar
unknown committed
3426 3427 3428

  error= 0;
err:
3429
  thd->restore_backup_open_tables_state(&open_tables_state_backup);
3430
  lex->restore_backup_query_tables_list(&query_tables_list_backup);
3431 3432
  lex->derived_tables= derived_tables;
  lex->all_selects_list= old_all_select_lex;
3433
  lex->view_prepare_mode= save_view_prepare_mode;
3434
  lex->sql_command= save_sql_command;
unknown's avatar
unknown committed
3435
  DBUG_RETURN(error);
3436 3437 3438
}


3439
bool store_schema_shemata(THD* thd, TABLE *table, LEX_STRING *db_name,
3440
                          CHARSET_INFO *cs)
3441
{
3442
  restore_record(table, s->default_values);
3443
  table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
3444
  table->field[1]->store(db_name->str, db_name->length, system_charset_info);
3445 3446
  table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info);
  table->field[3]->store(cs->name, strlen(cs->name), system_charset_info);
3447
  return schema_table_store_record(thd, table);
3448 3449 3450
}


3451
int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
3452
{
3453 3454 3455 3456 3457
  /*
    TODO: fill_schema_shemata() is called when new client is connected.
    Returning error status in this case leads to client hangup.
  */

3458 3459 3460
  LOOKUP_FIELD_VALUES lookup_field_vals;
  List<LEX_STRING> db_names;
  LEX_STRING *db_name;
unknown's avatar
unknown committed
3461
  bool with_i_schema;
3462 3463
  HA_CREATE_INFO create;
  TABLE *table= tables->table;
3464
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3465
  Security_context *sctx= thd->security_ctx;
3466
#endif
3467
  DBUG_ENTER("fill_schema_shemata");
3468

3469 3470
  if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
    DBUG_RETURN(0);
3471 3472 3473 3474 3475
  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))
3476
    DBUG_RETURN(1);
3477

3478 3479 3480
  /*
    If we have lookup db value we should check that the database exists
  */
3481 3482
  if(lookup_field_vals.db_value.str && !lookup_field_vals.wild_db_value &&
     !with_i_schema)
3483 3484 3485 3486 3487 3488
  {
    char path[FN_REFLEN+16];
    uint path_len;
    MY_STAT stat_info;
    if (!lookup_field_vals.db_value.str[0])
      DBUG_RETURN(0);
3489
    path_len= build_table_filename(path, sizeof(path) - 1,
3490 3491 3492 3493 3494 3495
                                   lookup_field_vals.db_value.str, "", "", 0);
    path[path_len-1]= 0;
    if (!my_stat(path,&stat_info,MYF(0)))
      DBUG_RETURN(0);
  }

3496 3497
  List_iterator_fast<LEX_STRING> it(db_names);
  while ((db_name=it++))
3498
  {
3499 3500
    if (with_i_schema)       // information schema name is always first in list
    {
3501
      if (store_schema_shemata(thd, table, db_name,
3502
                               system_charset_info))
3503
        DBUG_RETURN(1);
3504 3505 3506
      with_i_schema= 0;
      continue;
    }
3507
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3508
    if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
3509 3510
	acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
	!check_grant_db(thd, db_name->str))
3511 3512
#endif
    {
3513 3514
      load_db_opt_by_name(thd, db_name->str, &create);
      if (store_schema_shemata(thd, table, db_name,
3515
                               create.default_table_charset))
3516
        DBUG_RETURN(1);
3517 3518
    }
  }
3519
  DBUG_RETURN(0);
3520 3521 3522
}


3523
static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
3524
				    TABLE *table, bool res,
3525 3526
				    LEX_STRING *db_name,
				    LEX_STRING *table_name)
3527 3528
{
  const char *tmp_buff;
3529
  MYSQL_TIME time;
3530 3531
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_schema_tables_record");
3532 3533

  restore_record(table, s->default_values);
3534
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
3535 3536
  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
3537 3538 3539 3540 3541
  if (res)
  {
    /*
      there was errors during opening tables
    */
Marc Alff's avatar
Marc Alff committed
3542
    const char *error= thd->is_error() ? thd->stmt_da->message() : "";
3543 3544 3545 3546 3547 3548
    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
3549 3550 3551 3552
    table->field[20]->store(error, strlen(error), cs);
    thd->clear_error();
  }
  else if (tables->view)
3553
  {
3554 3555
    table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
    table->field[20]->store(STRING_WITH_LEN("VIEW"), cs);
3556 3557 3558
  }
  else
  {
3559
    char option_buff[350],*ptr;
3560
    TABLE *show_table= tables->table;
3561
    TABLE_SHARE *share= show_table->s;
3562
    handler *file= show_table->file;
3563
    handlerton *tmp_db_type= share->db_type();
3564
#ifdef WITH_PARTITION_STORAGE_ENGINE
3565
    bool is_partitioned= FALSE;
3566
#endif
3567
    if (share->tmp_table == SYSTEM_TMP_TABLE)
3568
      table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
3569
    else if (share->tmp_table)
3570
      table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs);
3571
    else
3572
      table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
3573

3574 3575
    for (int i= 4; i < 20; i++)
    {
3576
      if (i == 7 || (i > 12 && i < 17) || i == 18)
3577 3578 3579
        continue;
      table->field[i]->set_notnull();
    }
3580 3581 3582
#ifdef WITH_PARTITION_STORAGE_ENGINE
    if (share->db_type() == partition_hton &&
        share->partition_info_len)
3583
    {
3584
      tmp_db_type= share->default_part_db_type;
3585 3586
      is_partitioned= TRUE;
    }
3587 3588
#endif
    tmp_buff= (char *) ha_resolve_storage_engine_name(tmp_db_type);
3589
    table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
3590
    table->field[5]->store((longlong) share->frm_version, TRUE);
3591 3592

    ptr=option_buff;
3593
    if (share->min_rows)
3594 3595
    {
      ptr=strmov(ptr," min_rows=");
3596
      ptr=longlong10_to_str(share->min_rows,ptr,10);
3597
    }
3598
    if (share->max_rows)
3599 3600
    {
      ptr=strmov(ptr," max_rows=");
3601
      ptr=longlong10_to_str(share->max_rows,ptr,10);
3602
    }
3603
    if (share->avg_row_length)
3604 3605
    {
      ptr=strmov(ptr," avg_row_length=");
3606
      ptr=longlong10_to_str(share->avg_row_length,ptr,10);
3607
    }
3608
    if (share->db_create_options & HA_OPTION_PACK_KEYS)
3609
      ptr=strmov(ptr," pack_keys=1");
3610
    if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
3611
      ptr=strmov(ptr," pack_keys=0");
3612
    /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
3613
    if (share->db_create_options & HA_OPTION_CHECKSUM)
3614
      ptr=strmov(ptr," checksum=1");
3615
    if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
3616
      ptr=strmov(ptr," delay_key_write=1");
3617
    if (share->row_type != ROW_TYPE_DEFAULT)
3618
      ptr=strxmov(ptr, " row_format=", 
3619
                  ha_row_type[(uint) share->row_type],
3620
                  NullS);
3621 3622 3623 3624 3625
    if (share->key_block_size)
    {
      ptr= strmov(ptr, " KEY_BLOCK_SIZE=");
      ptr= longlong10_to_str(share->key_block_size, ptr, 10);
    }
3626
#ifdef WITH_PARTITION_STORAGE_ENGINE
3627
    if (is_partitioned)
3628 3629
      ptr= strmov(ptr, " partitioned");
#endif
3630 3631 3632
    table->field[19]->store(option_buff+1,
                            (ptr == option_buff ? 0 : 
                             (uint) (ptr-option_buff)-1), cs);
3633

3634 3635 3636 3637
    tmp_buff= (share->table_charset ?
               share->table_charset->name : "default");
    table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);

3638 3639 3640 3641
    if (share->comment.str)
      table->field[20]->store(share->comment.str, share->comment.length, cs);

    if(file)
3642
    {
3643
      file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO);
3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667
      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;
3668
      case ROW_TYPE_PAGE:
3669 3670 3671 3672 3673
        tmp_buff= "Paged";
        break;
      }
      table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
      if (!tables->schema_table)
3674
      {
3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700
        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)
3701
      {
3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717
        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();
3718 3719
      }
    }
3720
  }
3721
  DBUG_RETURN(schema_table_store_record(thd, table));
3722 3723 3724
}


3725
static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
3726
				    TABLE *table, bool res,
3727 3728
				    LEX_STRING *db_name,
				    LEX_STRING *table_name)
3729
{
3730 3731
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
3732
  CHARSET_INFO *cs= system_charset_info;
3733 3734 3735
  TABLE *show_table;
  Field **ptr,*field;
  int count;
3736
  DBUG_ENTER("get_schema_column_record");
3737

3738 3739
  if (res)
  {
3740
    if (lex->sql_command != SQLCOM_SHOW_FIELDS)
3741 3742 3743 3744 3745
    {
      /*
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
        rather than in SHOW COLUMNS
      */ 
3746 3747
      if (thd->is_error())
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
3748
                     thd->stmt_da->sql_errno(), thd->stmt_da->message());
3749 3750 3751 3752
      thd->clear_error();
      res= 0;
    }
    DBUG_RETURN(res);
3753 3754
  }

3755 3756
  show_table= tables->table;
  count= 0;
3757
  restore_record(show_table, s->default_values);
3758
  show_table->use_all_columns();               // Required for default
3759

3760
  for (ptr= show_table->field; (field= *ptr) ; ptr++)
3761
  {
3762
    const char *tmp_buff;
3763
    uchar *pos;
3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778
    bool is_blob;
    uint flags=field->flags;
    char tmp[MAX_FIELD_WIDTH];
    String type(tmp,sizeof(tmp), system_charset_info);
    char *end;
    int decimals, field_length;

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

    flags= field->flags;
    count++;
    /* Get default row, with all NULL fields set to NULL */
    restore_record(table, s->default_values);
3779 3780

#ifndef NO_EMBEDDED_ACCESS_CHECKS
3781
    uint col_access;
3782
    check_access(thd,SELECT_ACL | EXTRA_ACL, db_name->str,
3783
                 &tables->grant.privilege, 0, 0, test(tables->schema_table));
3784
    col_access= get_column_grant(thd, &tables->grant, 
3785
                                 db_name->str, table_name->str,
3786
                                 field->field_name) & COL_ACLS;
3787
    if (!tables->schema_table && !col_access)
3788 3789 3790 3791 3792
      continue;
    end= tmp;
    for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
    {
      if (col_access & 1)
3793
      {
3794 3795
        *end++=',';
        end=strmov(end,grant_types.type_names[bitnr]);
3796
      }
3797
    }
3798
    table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
3799

unknown's avatar
unknown committed
3800
#endif
3801
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
3802 3803
    table->field[1]->store(db_name->str, db_name->length, cs);
    table->field[2]->store(table_name->str, table_name->length, cs);
3804 3805
    table->field[3]->store(field->field_name, strlen(field->field_name),
                           cs);
3806
    table->field[4]->store((longlong) count, TRUE);
3807
    field->sql_type(type);
3808 3809 3810 3811 3812 3813
    table->field[14]->store(type.ptr(), type.length(), cs);
    /*
      MySQL column type has the following format:
      base_type [(dimension)] [unsigned] [zerofill].
      For DATA_TYPE column we extract only base type.
    */
3814
    tmp_buff= strchr(type.ptr(), '(');
3815 3816 3817 3818 3819 3820
    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(type.ptr(), ' ');
3821 3822 3823
    table->field[7]->store(type.ptr(),
                           (tmp_buff ? tmp_buff - type.ptr() :
                            type.length()), cs);
3824 3825

    if (get_field_default_value(thd, show_table, field, &type, 0))
3826
    {
3827
      table->field[5]->store(type.ptr(), type.length(), cs);
3828 3829
      table->field[5]->set_notnull();
    }
3830
    pos=(uchar*) ((flags & NOT_NULL_FLAG) ?  "NO" : "YES");
3831 3832
    table->field[6]->store((const char*) pos,
                           strlen((const char*) pos), cs);
3833
    is_blob= (field->type() == MYSQL_TYPE_BLOB);
3834 3835 3836
    if (field->has_charset() || is_blob ||
        field->real_type() == MYSQL_TYPE_VARCHAR ||  // For varbinary type
        field->real_type() == MYSQL_TYPE_STRING)     // For binary type
3837
    {
3838
      uint32 octet_max_length= field->max_display_length();
3839
      if (is_blob && octet_max_length != (uint32) 4294967295U)
unknown's avatar
unknown committed
3840
        octet_max_length /= field->charset()->mbmaxlen;
3841
      longlong char_max_len= is_blob ? 
unknown's avatar
unknown committed
3842 3843
        (longlong) octet_max_length / field->charset()->mbminlen :
        (longlong) octet_max_length / field->charset()->mbmaxlen;
3844
      table->field[8]->store(char_max_len, TRUE);
3845
      table->field[8]->set_notnull();
unknown's avatar
unknown committed
3846
      table->field[9]->store((longlong) octet_max_length, TRUE);
3847 3848
      table->field[9]->set_notnull();
    }
3849

3850 3851 3852 3853
    /*
      Calculate field_length and decimals.
      They are set to -1 if they should not be set (we should return NULL)
    */
unknown's avatar
unknown committed
3854

3855 3856
    decimals= field->decimals();
    switch (field->type()) {
3857
    case MYSQL_TYPE_NEWDECIMAL:
3858 3859
      field_length= ((Field_new_decimal*) field)->precision;
      break;
3860
    case MYSQL_TYPE_DECIMAL:
3861 3862
      field_length= field->field_length - (decimals  ? 2 : 1);
      break;
3863 3864 3865 3866 3867
    case MYSQL_TYPE_TINY:
    case MYSQL_TYPE_SHORT:
    case MYSQL_TYPE_LONG:
    case MYSQL_TYPE_LONGLONG:
    case MYSQL_TYPE_INT24:
3868
      field_length= field->max_display_length() - 1;
3869
      break;
3870
    case MYSQL_TYPE_BIT:
3871
      field_length= field->max_display_length();
3872 3873
      decimals= -1;                             // return NULL
      break;
3874 3875
    case MYSQL_TYPE_FLOAT:  
    case MYSQL_TYPE_DOUBLE:
3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886
      field_length= field->field_length;
      if (decimals == NOT_FIXED_DEC)
        decimals= -1;                           // return NULL
    break;
    default:
      field_length= decimals= -1;
      break;
    }

    if (field_length >= 0)
    {
3887
      table->field[10]->store((longlong) field_length, TRUE);
3888
      table->field[10]->set_notnull();
3889
    }
3890 3891
    if (decimals >= 0)
    {
3892
      table->field[11]->store((longlong) decimals, TRUE);
3893 3894 3895 3896 3897
      table->field[11]->set_notnull();
    }

    if (field->has_charset())
    {
3898
      pos=(uchar*) field->charset()->csname;
3899 3900 3901
      table->field[12]->store((const char*) pos,
                              strlen((const char*) pos), cs);
      table->field[12]->set_notnull();
3902
      pos=(uchar*) field->charset()->name;
3903 3904 3905 3906
      table->field[13]->store((const char*) pos,
                              strlen((const char*) pos), cs);
      table->field[13]->set_notnull();
    }
3907
    pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
3908 3909 3910 3911 3912 3913 3914
                 (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)
3915 3916 3917 3918 3919
      table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs);
    if (show_table->timestamp_field == field &&
        field->unireg_check != Field::TIMESTAMP_DN_FIELD)
      table->field[16]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
                              cs);
3920 3921 3922 3923

    table->field[18]->store(field->comment.str, field->comment.length, cs);
    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935
  }
  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;
3936

3937 3938 3939
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets) ;
       cs++)
3940 3941 3942 3943
  {
    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
3944
        !(tmp_cs->state & MY_CS_HIDDEN) &&
3945 3946 3947
        !(wild && wild[0] &&
	  wild_case_compare(scs, tmp_cs->csname,wild)))
    {
3948
      const char *comment;
3949
      restore_record(table, s->default_values);
3950
      table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs);
3951
      table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs);
3952 3953
      comment= tmp_cs->comment ? tmp_cs->comment : "";
      table->field[2]->store(comment, strlen(comment), scs);
3954
      table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE);
3955 3956
      if (schema_table_store_record(thd, table))
        return 1;
3957 3958 3959 3960 3961 3962
    }
  }
  return 0;
}


unknown's avatar
unknown committed
3963
static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
3964
                                   void *ptable)
unknown's avatar
unknown committed
3965
{
unknown's avatar
unknown committed
3966
  TABLE *table= (TABLE *) ptable;
unknown's avatar
unknown committed
3967
  handlerton *hton= plugin_data(plugin, handlerton *);
unknown's avatar
unknown committed
3968 3969
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  CHARSET_INFO *scs= system_charset_info;
unknown's avatar
unknown committed
3970
  handlerton *default_type= ha_default_handlerton(thd);
unknown's avatar
unknown committed
3971
  DBUG_ENTER("iter_schema_engines");
unknown's avatar
unknown committed
3972

3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991

  /* 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
3992
  if (!(hton->flags & HTON_HIDDEN))
unknown's avatar
unknown committed
3993
  {
unknown's avatar
unknown committed
3994
    LEX_STRING *name= plugin_name(plugin);
unknown's avatar
unknown committed
3995
    if (!(wild && wild[0] &&
unknown's avatar
unknown committed
3996
          wild_case_compare(scs, name->str,wild)))
unknown's avatar
unknown committed
3997
    {
unknown's avatar
unknown committed
3998 3999
      LEX_STRING yesno[2]= {{ C_STRING_WITH_LEN("NO") },
                            { C_STRING_WITH_LEN("YES") }};
unknown's avatar
unknown committed
4000
      LEX_STRING *tmp;
4001
      const char *option_name= show_comp_option_name[(int) hton->state];
unknown's avatar
unknown committed
4002 4003
      restore_record(table, s->default_values);

unknown's avatar
unknown committed
4004
      table->field[0]->store(name->str, name->length, scs);
unknown's avatar
unknown committed
4005
      if (hton->state == SHOW_OPTION_YES && default_type == hton)
4006 4007
        option_name= "DEFAULT";
      table->field[1]->store(option_name, strlen(option_name), scs);
unknown's avatar
unknown committed
4008 4009
      table->field[2]->store(plugin_decl(plugin)->descr,
                             strlen(plugin_decl(plugin)->descr), scs);
unknown's avatar
unknown committed
4010 4011
      tmp= &yesno[test(hton->commit)];
      table->field[3]->store(tmp->str, tmp->length, scs);
4012
      table->field[3]->set_notnull();
unknown's avatar
unknown committed
4013 4014
      tmp= &yesno[test(hton->prepare)];
      table->field[4]->store(tmp->str, tmp->length, scs);
4015
      table->field[4]->set_notnull();
unknown's avatar
unknown committed
4016 4017
      tmp= &yesno[test(hton->savepoint_set)];
      table->field[5]->store(tmp->str, tmp->length, scs);
4018
      table->field[5]->set_notnull();
unknown's avatar
unknown committed
4019 4020 4021 4022 4023 4024 4025 4026

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

unknown's avatar
unknown committed
4027 4028
int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond)
{
4029 4030 4031 4032 4033 4034
  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
4035 4036 4037
}


4038 4039 4040 4041 4042 4043
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;
4044 4045 4046
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets)  ;
       cs++ )
4047 4048 4049
  {
    CHARSET_INFO **cl;
    CHARSET_INFO *tmp_cs= cs[0];
unknown's avatar
unknown committed
4050
    if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
unknown's avatar
unknown committed
4051
         (tmp_cs->state & MY_CS_HIDDEN) ||
4052 4053
        !(tmp_cs->state & MY_CS_PRIMARY))
      continue;
4054 4055 4056
    for (cl= all_charsets;
         cl < all_charsets + array_elements(all_charsets)  ;
         cl ++)
4057 4058 4059 4060 4061 4062 4063 4064 4065
    {
      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;
4066
	restore_record(table, s->default_values);
4067 4068
	table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
        table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
4069
        table->field[2]->store((longlong) tmp_cl->number, TRUE);
4070 4071 4072 4073
        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);
4074
        table->field[5]->store((longlong) tmp_cl->strxfrm_multiply, TRUE);
4075 4076
        if (schema_table_store_record(thd, table))
          return 1;
4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088
      }
    }
  }
  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;
4089 4090 4091
  for (cs= all_charsets ;
       cs < all_charsets + array_elements(all_charsets) ;
       cs++ )
4092 4093 4094 4095 4096 4097
  {
    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;
4098 4099 4100
    for (cl= all_charsets;
         cl < all_charsets + array_elements(all_charsets) ;
         cl ++)
4101 4102
    {
      CHARSET_INFO *tmp_cl= cl[0];
4103 4104
      if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
          (tmp_cl->state & MY_CS_HIDDEN) ||
4105 4106
          !my_charset_same(tmp_cs,tmp_cl))
	continue;
4107
      restore_record(table, s->default_values);
4108 4109
      table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
      table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
4110 4111
      if (schema_table_store_record(thd, table))
        return 1;
4112 4113 4114 4115 4116 4117
    }
  }
  return 0;
}


4118
bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
4119
                       const char *wild, bool full_access, const char *sp_user)
4120 4121
{
  String tmp_string;
4122
  String sp_db, sp_name, definer;
4123
  MYSQL_TIME time;
4124 4125
  LEX *lex= thd->lex;
  CHARSET_INFO *cs= system_charset_info;
4126 4127 4128
  get_field(thd->mem_root, proc_table->field[0], &sp_db);
  get_field(thd->mem_root, proc_table->field[1], &sp_name);
  get_field(thd->mem_root, proc_table->field[11], &definer);
4129
  if (!full_access)
4130
    full_access= !strcmp(sp_user, definer.ptr());
4131 4132 4133 4134
  if (!full_access && check_some_routine_access(thd, sp_db.ptr(),
                                                sp_name.ptr(),
                                                proc_table->field[2]->
                                                val_int() ==
4135
                                                TYPE_ENUM_PROCEDURE))
4136
    return 0;
4137

Staale Smedseng's avatar
Staale Smedseng committed
4138
  if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
4139
      proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE) ||
Staale Smedseng's avatar
Staale Smedseng committed
4140
      (lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
4141
      proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION) ||
4142
      (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
4143
  {
4144
    restore_record(table, s->default_values);
4145
    if (!wild || !wild[0] || !wild_compare(sp_name.ptr(), wild, 0))
4146
    {
4147
      int enum_idx= (int) proc_table->field[5]->val_int();
4148
      table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
4149 4150
      get_field(thd->mem_root, proc_table->field[3], &tmp_string);
      table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
4151
      table->field[1]->store(STRING_WITH_LEN("def"), cs);
4152
      table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
4153 4154
      get_field(thd->mem_root, proc_table->field[2], &tmp_string);
      table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs);
4155 4156 4157 4158 4159 4160
      if (proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION)
      {
        get_field(thd->mem_root, proc_table->field[9], &tmp_string);
        table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs);
        table->field[5]->set_notnull();
      }
4161 4162
      if (full_access)
      {
unknown's avatar
unknown committed
4163
        get_field(thd->mem_root, proc_table->field[19], &tmp_string);
4164
        table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
4165
        table->field[7]->set_notnull();
4166
      }
4167 4168
      table->field[6]->store(STRING_WITH_LEN("SQL"), cs);
      table->field[10]->store(STRING_WITH_LEN("SQL"), cs);
4169
      get_field(thd->mem_root, proc_table->field[6], &tmp_string);
4170
      table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs);
4171 4172
      table->field[12]->store(sp_data_access_name[enum_idx].str, 
                              sp_data_access_name[enum_idx].length , cs);
4173 4174
      get_field(thd->mem_root, proc_table->field[7], &tmp_string);
      table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
4175 4176
      bzero((char *)&time, sizeof(time));
      ((Field_timestamp *) proc_table->field[12])->get_time(&time);
4177
      table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
4178 4179
      bzero((char *)&time, sizeof(time));
      ((Field_timestamp *) proc_table->field[13])->get_time(&time);
4180
      table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
4181
      get_field(thd->mem_root, proc_table->field[14], &tmp_string);
4182
      table->field[17]->store(tmp_string.ptr(), tmp_string.length(), cs);
4183
      get_field(thd->mem_root, proc_table->field[15], &tmp_string);
4184
      table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs);
4185
      table->field[19]->store(definer.ptr(), definer.length(), cs);
unknown's avatar
unknown committed
4186 4187 4188 4189 4190 4191 4192 4193 4194 4195

      get_field(thd->mem_root, proc_table->field[16], &tmp_string);
      table->field[20]->store(tmp_string.ptr(), tmp_string.length(), cs);

      get_field(thd->mem_root, proc_table->field[17], &tmp_string);
      table->field[21]->store(tmp_string.ptr(), tmp_string.length(), cs);

      get_field(thd->mem_root, proc_table->field[18], &tmp_string);
      table->field[22]->store(tmp_string.ptr(), tmp_string.length(), cs);

4196
      return schema_table_store_record(thd, table);
4197 4198
    }
  }
4199
  return 0;
4200 4201 4202 4203 4204 4205 4206 4207 4208
}


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;
4209
  TABLE *table= tables->table;
4210
  bool full_access;
4211
  char definer[USER_HOST_BUFF_SIZE];
4212
  Open_tables_state open_tables_state_backup;
4213 4214
  DBUG_ENTER("fill_schema_proc");

4215 4216
  strxmov(definer, thd->security_ctx->priv_user, "@",
          thd->security_ctx->priv_host, NullS);
4217
  /* We use this TABLE_LIST instance only for checking of privileges. */
4218 4219
  bzero((char*) &proc_tables,sizeof(proc_tables));
  proc_tables.db= (char*) "mysql";
4220
  proc_tables.db_length= 5;
4221
  proc_tables.table_name= proc_tables.alias= (char*) "proc";
4222
  proc_tables.table_name_length= 4;
4223
  proc_tables.lock_type= TL_READ;
4224
  full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1, TRUE);
4225
  if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup)))
4226 4227 4228
  {
    DBUG_RETURN(1);
  }
4229
  proc_table->file->ha_index_init(0, 1);
4230 4231 4232 4233 4234
  if ((res= proc_table->file->index_first(proc_table->record[0])))
  {
    res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
    goto err;
  }
4235 4236 4237 4238 4239
  if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
  {
    res= 1;
    goto err;
  }
4240
  while (!proc_table->file->index_next(proc_table->record[0]))
4241 4242 4243 4244 4245 4246 4247
  {
    if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
    {
      res= 1;
      goto err;
    }
  }
4248 4249 4250

err:
  proc_table->file->ha_index_end();
4251
  close_system_tables(thd, &open_tables_state_backup);
4252 4253 4254 4255
  DBUG_RETURN(res);
}


4256
static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
4257
				  TABLE *table, bool res,
4258 4259
				  LEX_STRING *db_name,
				  LEX_STRING *table_name)
4260 4261 4262
{
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_schema_stat_record");
4263 4264
  if (res)
  {
4265
    if (thd->lex->sql_command != SQLCOM_SHOW_KEYS)
4266 4267 4268 4269
    {
      /*
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
        rather than in SHOW KEYS
4270
      */
4271
      if (thd->is_error())
4272
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4273
                     thd->stmt_da->sql_errno(), thd->stmt_da->message());
4274 4275 4276 4277 4278 4279
      thd->clear_error();
      res= 0;
    }
    DBUG_RETURN(res);
  }
  else if (!tables->view)
4280 4281
  {
    TABLE *show_table= tables->table;
4282 4283 4284 4285 4286
    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);
4287
    for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
4288 4289 4290 4291 4292
    {
      KEY_PART_INFO *key_part= key_info->key_part;
      const char *str;
      for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
      {
4293
        restore_record(table, s->default_values);
4294
        table->field[0]->store(STRING_WITH_LEN("def"), cs);
4295 4296
        table->field[1]->store(db_name->str, db_name->length, cs);
        table->field[2]->store(table_name->str, table_name->length, cs);
4297
        table->field[3]->store((longlong) ((key_info->flags &
4298
                                            HA_NOSAME) ? 0 : 1), TRUE);
4299
        table->field[4]->store(db_name->str, db_name->length, cs);
4300
        table->field[5]->store(key_info->name, strlen(key_info->name), cs);
4301
        table->field[6]->store((longlong) (j+1), TRUE);
4302 4303 4304
        str=(key_part->field ? key_part->field->field_name :
             "?unknown field?");
        table->field[7]->store(str, strlen(str), cs);
4305
        if (show_table->file)
4306
        {
4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323
          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);
4324
        }
4325 4326 4327
        if (!(key_info->flags & HA_FULLTEXT) &&
            (key_part->field &&
             key_part->length !=
4328
             show_table->s->field[key_part->fieldnr-1]->key_length()))
4329
        {
4330
          table->field[10]->store((longlong) key_part->length /
4331
                                  key_part->field->charset()->mbmaxlen, TRUE);
4332 4333 4334 4335 4336
          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);
4337
        if (!show_table->s->keys_in_use.is_set(i))
4338
          table->field[14]->store(STRING_WITH_LEN("disabled"), cs);
4339 4340 4341
        else
          table->field[14]->store("", 0, cs);
        table->field[14]->set_notnull();
4342 4343
        if (schema_table_store_record(thd, table))
          DBUG_RETURN(1);
4344 4345 4346
      }
    }
  }
unknown's avatar
unknown committed
4347
  DBUG_RETURN(res);
4348 4349 4350
}


4351
static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
4352
				   TABLE *table, bool res,
4353 4354
				   LEX_STRING *db_name,
				   LEX_STRING *table_name)
4355 4356 4357
{
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_schema_views_record");
4358
  LEX_STRING *tmp_db_name, *tmp_table_name;
4359
  char definer[USER_HOST_BUFF_SIZE];
unknown's avatar
unknown committed
4360
  uint definer_len;
4361
  bool updatable_view;
4362 4363 4364 4365 4366 4367 4368 4369
  /*
    if SELECT FROM I_S.VIEWS uses only fields
    which have OPEN_FRM_ONLY flag then 'tables'
    structure is zeroed and only tables->view is set.
    (see fill_schema_table_from_frm() function).
    So we should disable other fields filling.
  */
  bool only_share= !tables->definer.user.str;
unknown's avatar
unknown committed
4370

4371 4372
  if (tables->view)
  {
4373
    Security_context *sctx= thd->security_ctx;
4374
    if (!only_share && !tables->allowed_show)
4375
    {
4376 4377 4378 4379 4380
      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;
4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401
#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));
          table_list.db= tables->view_db.str;
          table_list.table_name= tables->view_name.str;
          table_list.grant.privilege= thd->col_access;
          view_access= get_table_grant(thd, &table_list);
          if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
              (SHOW_VIEW_ACL|SELECT_ACL))
            tables->allowed_show= TRUE;
        }
      }
#endif
4402
    }
4403
    restore_record(table, s->default_values);
4404 4405 4406
    tmp_db_name= &tables->view_db;
    tmp_table_name= &tables->view_name;
    if (only_share)
4407
    {
4408 4409
      tmp_db_name= db_name;
      tmp_table_name= table_name;
4410
    }
4411
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
4412 4413 4414
    table->field[1]->store(tmp_db_name->str, tmp_db_name->length, cs);
    table->field[2]->store(tmp_table_name->str, tmp_table_name->length, cs);
    if (!only_share)
4415
    {
4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429
      if (tables->allowed_show)
      {
        table->field[3]->store(tables->view_body_utf8.str,
                               tables->view_body_utf8.length,
                               cs);
      }

      if (tables->with_check != VIEW_CHECK_NONE)
      {
        if (tables->with_check == VIEW_CHECK_LOCAL)
          table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs);
        else
          table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs);
      }
unknown's avatar
unknown committed
4430
      else
4431
        table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
4432

4433 4434
      updatable_view= 0;
      if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE)
4435
      {
4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450
        /*
          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++))
4451
        {
4452 4453 4454 4455 4456 4457
          if ((field= item->filed_for_view_update()) && field->field &&
              !field->field->table->pos_in_table_list->schema_table)
          {
            updatable_view= 1;
            break;
          }
4458
        }
4459 4460
        if (updatable_view && !tables->view->can_be_merged())
          updatable_view= 0;
4461
      }
4462 4463
      if (updatable_view)
        table->field[5]->store(STRING_WITH_LEN("YES"), cs);
unknown's avatar
unknown committed
4464
      else
4465 4466 4467 4468 4469 4470 4471 4472
        table->field[5]->store(STRING_WITH_LEN("NO"), cs);
      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);
unknown's avatar
unknown committed
4473

4474 4475 4476
      table->field[8]->store(tables->view_creation_ctx->get_client_cs()->csname,
                             strlen(tables->view_creation_ctx->
                                    get_client_cs()->csname), cs);
unknown's avatar
unknown committed
4477

4478 4479 4480 4481
      table->field[9]->store(tables->view_creation_ctx->
                             get_connection_cl()->name,
                             strlen(tables->view_creation_ctx->
                                    get_connection_cl()->name), cs);
4482
    }
4483 4484 4485

    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
4486
    if (res && thd->is_error())
4487
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
Marc Alff's avatar
Marc Alff committed
4488
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
4489
  }
4490 4491
  if (res) 
    thd->clear_error();
4492
  DBUG_RETURN(0);
4493 4494 4495
}


4496 4497
bool store_constraints(THD *thd, TABLE *table, LEX_STRING *db_name,
                       LEX_STRING *table_name, const char *key_name,
4498
                       uint key_len, const char *con_type, uint con_len)
4499 4500
{
  CHARSET_INFO *cs= system_charset_info;
4501
  restore_record(table, s->default_values);
4502
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
4503
  table->field[1]->store(db_name->str, db_name->length, cs);
4504
  table->field[2]->store(key_name, key_len, cs);
4505 4506
  table->field[3]->store(db_name->str, db_name->length, cs);
  table->field[4]->store(table_name->str, table_name->length, cs);
4507
  table->field[5]->store(con_type, con_len, cs);
4508
  return schema_table_store_record(thd, table);
4509 4510 4511
}


4512
static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
unknown's avatar
unknown committed
4513
					 TABLE *table, bool res,
4514 4515
					 LEX_STRING *db_name,
					 LEX_STRING *table_name)
4516
{
unknown's avatar
unknown committed
4517
  DBUG_ENTER("get_schema_constraints_record");
4518 4519
  if (res)
  {
4520
    if (thd->is_error())
4521
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4522
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
4523 4524 4525 4526
    thd->clear_error();
    DBUG_RETURN(0);
  }
  else if (!tables->view)
4527 4528 4529 4530
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
    KEY *key_info=show_table->key_info;
4531
    uint primary_key= show_table->s->primary_key;
4532 4533 4534
    show_table->file->info(HA_STATUS_VARIABLE | 
                           HA_STATUS_NO_LOCK |
                           HA_STATUS_TIME);
4535
    for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
4536 4537
    {
      if (i != primary_key && !(key_info->flags & HA_NOSAME))
4538 4539
        continue;

4540
      if (i == primary_key && !strcmp(key_info->name, primary_key_name))
4541
      {
4542
        if (store_constraints(thd, table, db_name, table_name, key_info->name,
4543 4544
                              strlen(key_info->name),
                              STRING_WITH_LEN("PRIMARY KEY")))
4545 4546
          DBUG_RETURN(1);
      }
4547
      else if (key_info->flags & HA_NOSAME)
4548
      {
4549
        if (store_constraints(thd, table, db_name, table_name, key_info->name,
4550 4551
                              strlen(key_info->name),
                              STRING_WITH_LEN("UNIQUE")))
4552 4553
          DBUG_RETURN(1);
      }
4554 4555 4556 4557 4558 4559 4560
    }

    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++))
    {
4561
      if (store_constraints(thd, table, db_name, table_name, 
4562 4563 4564 4565
                            f_key_info->forein_id->str,
                            strlen(f_key_info->forein_id->str),
                            "FOREIGN KEY", 11))
        DBUG_RETURN(1);
4566 4567
    }
  }
unknown's avatar
unknown committed
4568
  DBUG_RETURN(res);
4569 4570 4571
}


4572 4573
static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name,
                          LEX_STRING *table_name, LEX_STRING *trigger_name,
4574 4575
                          enum trg_event_type event,
                          enum trg_action_time_type timing,
4576
                          LEX_STRING *trigger_stmt,
4577
                          ulong sql_mode,
unknown's avatar
unknown committed
4578 4579 4580 4581
                          LEX_STRING *definer_buffer,
                          LEX_STRING *client_cs_name,
                          LEX_STRING *connection_cl_name,
                          LEX_STRING *db_cl_name)
4582 4583
{
  CHARSET_INFO *cs= system_charset_info;
4584
  LEX_STRING sql_mode_rep;
4585

4586
  restore_record(table, s->default_values);
4587
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
4588
  table->field[1]->store(db_name->str, db_name->length, cs);
4589 4590 4591
  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);
4592
  table->field[4]->store(STRING_WITH_LEN("def"), cs);
4593 4594
  table->field[5]->store(db_name->str, db_name->length, cs);
  table->field[6]->store(table_name->str, table_name->length, cs);
4595
  table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
4596
  table->field[10]->store(STRING_WITH_LEN("ROW"), cs);
4597 4598
  table->field[11]->store(trg_action_time_type_names[timing].str,
                          trg_action_time_type_names[timing].length, cs);
4599 4600
  table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
  table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
4601

4602 4603 4604
  sys_var_thd_sql_mode::symbolic_mode_representation(thd, sql_mode,
                                                     &sql_mode_rep);
  table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs);
unknown's avatar
unknown committed
4605 4606 4607 4608 4609 4610
  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);

4611 4612 4613 4614
  return schema_table_store_record(thd, table);
}


4615
static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables,
4616
				      TABLE *table, bool res,
4617 4618
				      LEX_STRING *db_name,
				      LEX_STRING *table_name)
4619 4620 4621 4622 4623 4624 4625 4626
{
  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)
  {
4627
    if (thd->is_error())
4628
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4629
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
4630 4631 4632 4633 4634 4635 4636
    thd->clear_error();
    DBUG_RETURN(0);
  }
  if (!tables->view && tables->table->triggers)
  {
    Table_triggers_list *triggers= tables->table->triggers;
    int event, timing;
4637

4638
    if (check_table_access(thd, TRIGGER_ACL, tables, 1, TRUE))
4639 4640
      goto ret;

4641 4642 4643 4644 4645 4646
    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;
4647
        ulong sql_mode;
4648
        char definer_holder[USER_HOST_BUFF_SIZE];
4649
        LEX_STRING definer_buffer;
unknown's avatar
unknown committed
4650 4651 4652 4653
        LEX_STRING client_cs_name;
        LEX_STRING connection_cl_name;
        LEX_STRING db_cl_name;

4654
        definer_buffer.str= definer_holder;
4655 4656
        if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
                                       (enum trg_action_time_type)timing,
4657
                                       &trigger_name, &trigger_stmt,
4658
                                       &sql_mode,
unknown's avatar
unknown committed
4659 4660 4661 4662
                                       &definer_buffer,
                                       &client_cs_name,
                                       &connection_cl_name,
                                       &db_cl_name))
4663
          continue;
4664

4665
        if (store_trigger(thd, table, db_name, table_name, &trigger_name,
4666
                         (enum trg_event_type) event,
4667
                         (enum trg_action_time_type) timing, &trigger_stmt,
4668
                         sql_mode,
unknown's avatar
unknown committed
4669 4670 4671 4672
                         &definer_buffer,
                         &client_cs_name,
                         &connection_cl_name,
                         &db_cl_name))
4673 4674 4675 4676
          DBUG_RETURN(1);
      }
    }
  }
4677
ret:
4678 4679 4680 4681
  DBUG_RETURN(0);
}


4682 4683 4684 4685
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)
4686 4687
{
  CHARSET_INFO *cs= system_charset_info;
4688
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
4689
  table->field[1]->store(db_name->str, db_name->length, cs);
4690
  table->field[2]->store(key_name, key_len, cs);
4691
  table->field[3]->store(STRING_WITH_LEN("def"), cs);
4692 4693
  table->field[4]->store(db_name->str, db_name->length, cs);
  table->field[5]->store(table_name->str, table_name->length, cs);
4694
  table->field[6]->store(con_type, con_len, cs);
4695
  table->field[7]->store((longlong) idx, TRUE);
4696 4697 4698
}


unknown's avatar
unknown committed
4699
static int get_schema_key_column_usage_record(THD *thd,
4700
					      TABLE_LIST *tables,
unknown's avatar
unknown committed
4701
					      TABLE *table, bool res,
4702 4703
					      LEX_STRING *db_name,
					      LEX_STRING *table_name)
4704 4705
{
  DBUG_ENTER("get_schema_key_column_usage_record");
4706 4707
  if (res)
  {
4708
    if (thd->is_error())
4709
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
4710
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
4711 4712 4713 4714
    thd->clear_error();
    DBUG_RETURN(0);
  }
  else if (!tables->view)
4715 4716 4717 4718
  {
    List<FOREIGN_KEY_INFO> f_key_list;
    TABLE *show_table= tables->table;
    KEY *key_info=show_table->key_info;
4719
    uint primary_key= show_table->s->primary_key;
4720 4721 4722
    show_table->file->info(HA_STATUS_VARIABLE | 
                           HA_STATUS_NO_LOCK |
                           HA_STATUS_TIME);
4723
    for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
4724 4725
    {
      if (i != primary_key && !(key_info->flags & HA_NOSAME))
unknown's avatar
unknown committed
4726
        continue;
4727 4728 4729 4730 4731 4732 4733
      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++;
4734
          restore_record(table, s->default_values);
4735
          store_key_column_usage(table, db_name, table_name,
4736 4737 4738 4739 4740
                                 key_info->name,
                                 strlen(key_info->name), 
                                 key_part->field->field_name, 
                                 strlen(key_part->field->field_name),
                                 (longlong) f_idx);
4741 4742
          if (schema_table_store_record(thd, table))
            DBUG_RETURN(1);
4743 4744 4745 4746 4747 4748
        }
      }
    }

    show_table->file->get_foreign_key_list(thd, &f_key_list);
    FOREIGN_KEY_INFO *f_key_info;
4749 4750
    List_iterator_fast<FOREIGN_KEY_INFO> fkey_it(f_key_list);
    while ((f_key_info= fkey_it++))
4751
    {
4752
      LEX_STRING *f_info;
4753
      LEX_STRING *r_info;
4754 4755 4756 4757 4758
      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++))
      {
4759
        r_info= it1++;
4760
        f_idx++;
4761
        restore_record(table, s->default_values);
4762
        store_key_column_usage(table, db_name, table_name,
4763 4764 4765 4766
                               f_key_info->forein_id->str,
                               f_key_info->forein_id->length,
                               f_info->str, f_info->length,
                               (longlong) f_idx);
4767
        table->field[8]->store((longlong) f_idx, TRUE);
4768
        table->field[8]->set_notnull();
4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779
        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();
4780 4781
        if (schema_table_store_record(thd, table))
          DBUG_RETURN(1);
4782 4783 4784
      }
    }
  }
unknown's avatar
unknown committed
4785
  DBUG_RETURN(res);
4786 4787 4788
}


4789
#ifdef WITH_PARTITION_STORAGE_ENGINE
4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803
static void collect_partition_expr(List<char> &field_list, String *str)
{
  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++))
  {
    str->append(field_str);
    if (--no_fields != 0)
      str->append(",");
  }
  return;
}
4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854


/*
  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;
}
4855
#endif
4856 4857


4858 4859
static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
                                           TABLE *showing_table,
4860 4861 4862
                                           partition_element *part_elem,
                                           handler *file, uint part_id)
{
4863
  TABLE* table= schema_table;
4864 4865
  CHARSET_INFO *cs= system_charset_info;
  PARTITION_INFO stat_info;
4866
  MYSQL_TIME time;
4867
  file->get_dynamic_partition_info(&stat_info, part_id);
4868
  table->field[0]->store(STRING_WITH_LEN("def"), cs);
4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881
  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,
4882
                                              (my_time_t)stat_info.create_time);
4883 4884 4885 4886 4887 4888
    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,
4889
                                              (my_time_t)stat_info.update_time);
4890 4891 4892 4893 4894
    table->field[19]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
    table->field[19]->set_notnull();
  }
  if (stat_info.check_time)
  {
4895 4896
    thd->variables.time_zone->gmt_sec_to_TIME(&time,
                                              (my_time_t)stat_info.check_time);
4897 4898 4899
    table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
    table->field[20]->set_notnull();
  }
4900
  if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
4901 4902 4903 4904 4905 4906 4907 4908 4909 4910
  {
    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
4911
      table->field[22]->store(STRING_WITH_LEN(""), cs);
4912 4913 4914 4915
    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);
4916 4917

    table->field[24]->set_notnull();
4918 4919 4920 4921
    if (part_elem->tablespace_name)
      table->field[24]->store(part_elem->tablespace_name,
                              strlen(part_elem->tablespace_name), cs);
    else
4922
    {
4923
      char *ts= showing_table->file->get_tablespace_name(thd,0,0);
4924
      if(ts)
4925
      {
4926
        table->field[24]->store(ts, strlen(ts), cs);
4927 4928
        my_free(ts, MYF(0));
      }
4929 4930 4931
      else
        table->field[24]->set_null();
    }
4932 4933 4934 4935
  }
  return;
}

4936
static int
4937 4938
get_partition_column_description(THD *thd,
                                 partition_info *part_info,
4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954
                                 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
    {
4955
      char buffer[MAX_KEY_LENGTH];
4956
      String str(buffer, sizeof(buffer), &my_charset_bin);
4957
      String val_conv;
4958 4959 4960 4961 4962 4963 4964 4965
      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);
4966
      if (get_cs_converted_part_value_from_string(thd, item, res, &val_conv,
4967
                              part_info->part_field_array[i]->charset(),
4968
                              FALSE))
4969 4970 4971
      {
        DBUG_RETURN(1);
      }
4972
      tmp_str.append(val_conv);
4973 4974 4975 4976 4977 4978
    }
    if (i != num_elements - 1)
      tmp_str.append(",");
  }
  DBUG_RETURN(0);
}
4979

4980
static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
4981
                                        TABLE *table, bool res,
4982 4983
                                        LEX_STRING *db_name,
                                        LEX_STRING *table_name)
4984 4985 4986 4987 4988 4989
{
  CHARSET_INFO *cs= system_charset_info;
  char buff[61];
  String tmp_res(buff, sizeof(buff), cs);
  String tmp_str;
  TABLE *show_table= tables->table;
4990
  handler *file;
unknown's avatar
unknown committed
4991
#ifdef WITH_PARTITION_STORAGE_ENGINE
4992
  partition_info *part_info;
unknown's avatar
unknown committed
4993
#endif
4994 4995 4996 4997
  DBUG_ENTER("get_schema_partitions_record");

  if (res)
  {
4998
    if (thd->is_error())
4999
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5000
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5001 5002 5003
    thd->clear_error();
    DBUG_RETURN(0);
  }
5004
  file= show_table->file;
unknown's avatar
unknown committed
5005
#ifdef WITH_PARTITION_STORAGE_ENGINE
5006
  part_info= show_table->part_info;
5007 5008 5009 5010 5011 5012 5013
  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);
5014
    table->field[0]->store(STRING_WITH_LEN("def"), cs);
5015 5016
    table->field[1]->store(db_name->str, db_name->length, cs);
    table->field[2]->store(table_name->str, table_name->length, cs);
5017 5018 5019 5020 5021 5022


    /* Partition method*/
    switch (part_info->part_type) {
    case RANGE_PARTITION:
    case LIST_PARTITION:
5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033
      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);
5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049
      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);
5050
      my_error(ER_OUT_OF_RESOURCES, MYF(0));
5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066
      current_thd->fatal_error();
      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)
    {
      collect_partition_expr(part_info->part_field_list, &tmp_str);
      table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs);
    }
5067
    table->field[9]->set_notnull();
5068

5069
    if (part_info->is_sub_partitioned())
5070 5071
    {
      /* Subpartition method */
5072 5073 5074 5075
      tmp_res.length(0);
      if (part_info->linear_hash_ind)
        tmp_res.append(partition_keywords[PKW_LINEAR].str,
                       partition_keywords[PKW_LINEAR].length);
5076
      if (part_info->list_of_subpart_fields)
5077 5078
        tmp_res.append(partition_keywords[PKW_KEY].str,
                       partition_keywords[PKW_KEY].length);
5079
      else
5080 5081 5082
        tmp_res.append(partition_keywords[PKW_HASH].str, 
                       partition_keywords[PKW_HASH].length);
      table->field[8]->store(tmp_res.ptr(), tmp_res.length(), cs);
5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095
      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)
      {
        collect_partition_expr(part_info->subpart_field_list, &tmp_str);
        table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs);
      }
5096
      table->field[10]->set_notnull();
5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110
    }

    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)
      {
5111 5112 5113 5114 5115
        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);
5116 5117
          if (get_partition_column_description(thd,
                                               part_info,
5118 5119 5120 5121 5122 5123 5124
                                               list_value,
                                               tmp_str))
          {
            DBUG_RETURN(1);
          }
          table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
        }
5125
        else
5126 5127 5128 5129 5130
        {
          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,
5131
                                 partition_keywords[PKW_MAXVALUE].length, cs);
5132
        }
5133 5134 5135 5136
        table->field[11]->set_notnull();
      }
      else if (part_info->part_type == LIST_PARTITION)
      {
5137 5138
        List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
        part_elem_value *list_value;
5139
        uint num_items= part_elem->list_val_list.elements;
5140 5141
        tmp_str.length(0);
        tmp_res.length(0);
5142 5143 5144
        if (part_elem->has_null_value)
        {
          tmp_str.append("NULL");
5145
          if (num_items > 0)
5146 5147
            tmp_str.append(",");
        }
5148 5149
        while ((list_value= list_val_it++))
        {
5150 5151 5152 5153
          if (part_info->column_list)
          {
            if (part_info->part_field_list.elements > 1U)
              tmp_str.append("(");
5154 5155
            if (get_partition_column_description(thd,
                                                 part_info,
5156 5157 5158 5159 5160 5161 5162 5163
                                                 list_value,
                                                 tmp_str))
            {
              DBUG_RETURN(1);
            }
            if (part_info->part_field_list.elements > 1U)
              tmp_str.append(")");
          }
5164
          else
5165 5166 5167 5168 5169 5170 5171 5172
          {
            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)
5173
            tmp_str.append(",");
5174
        }
5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193
        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();
          
5194
          store_schema_partitions_record(thd, table, show_table, subpart_elem,
5195 5196 5197 5198 5199 5200 5201 5202
                                         file, part_id);
          part_id++;
          if(schema_table_store_record(thd, table))
            DBUG_RETURN(1);
        }
      }
      else
      {
5203
        store_schema_partitions_record(thd, table, show_table, part_elem,
5204 5205 5206 5207 5208 5209 5210 5211 5212
                                       file, part_id);
        part_id++;
        if(schema_table_store_record(thd, table))
          DBUG_RETURN(1);
      }
    }
    DBUG_RETURN(0);
  }
  else
unknown's avatar
unknown committed
5213
#endif
5214
  {
5215
    store_schema_partitions_record(thd, table, show_table, 0, file, 0);
5216 5217 5218 5219 5220 5221 5222
    if(schema_table_store_record(thd, table))
      DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
5223
#ifdef NOT_USED
5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259
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;
5260 5261
  case INTERVAL_LAST:
    DBUG_ASSERT(0);
5262 5263 5264 5265 5266
  }
  DBUG_ASSERT(0);
  return INTERVAL_SECOND;
}

unknown's avatar
unknown committed
5267 5268
#endif

5269
#ifdef HAVE_EVENT_SCHEDULER
5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284
/*
  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
5285
int
5286
copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
5287 5288 5289
{
  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
  CHARSET_INFO *scs= system_charset_info;
5290
  MYSQL_TIME time;
unknown's avatar
unknown committed
5291
  Event_timed et;
5292
  DBUG_ENTER("copy_event_to_schema_table");
5293 5294 5295

  restore_record(sch_table, s->default_values);

5296
  if (et.load_from_row(thd, event_table))
5297
  {
5298
    my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), event_table->alias);
5299 5300 5301 5302 5303
    DBUG_RETURN(1);
  }

  if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0)))
    DBUG_RETURN(0);
5304 5305 5306 5307 5308 5309

  /*
    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.
  */
5310
  if (thd->lex->sql_command != SQLCOM_SHOW_EVENTS &&
5311 5312 5313 5314
      check_access(thd, EVENT_ACL, et.dbname.str, 0, 0, 1,
                   is_schema_db(et.dbname.str)))
    DBUG_RETURN(0);

5315
  sch_table->field[ISE_EVENT_CATALOG]->store(STRING_WITH_LEN("def"), scs);
5316 5317 5318 5319 5320 5321
  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);
5322 5323 5324
  const String *tz_name= et.time_zone->get_name();
  sch_table->field[ISE_TIME_ZONE]->
                                store(tz_name->ptr(), tz_name->length(), scs);
5325 5326
  sch_table->field[ISE_EVENT_BODY]->
                                store(STRING_WITH_LEN("SQL"), scs);
unknown's avatar
unknown committed
5327 5328
  sch_table->field[ISE_EVENT_DEFINITION]->store(
    et.body_utf8.str, et.body_utf8.length, scs);
5329 5330

  /* SQL_MODE */
5331
  {
5332 5333 5334
    LEX_STRING sql_mode;
    sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode,
                                                       &sql_mode);
5335
    sch_table->field[ISE_SQL_MODE]->
5336
                                store(sql_mode.str, sql_mode.length, scs);
5337
  }
5338

5339 5340
  int not_used=0;

5341 5342
  if (et.expression)
  {
5343
    String show_str;
5344
    /* type */
5345
    sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("RECURRING"), scs);
5346

5347 5348
    if (Events::reconstruct_interval_expression(&show_str, et.interval,
                                                et.expression))
5349
      DBUG_RETURN(1);
5350

5351 5352 5353
    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
5354 5355

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

5359
    /* starts & ends . STARTS is always set - see sql_yacc.yy */
5360
    et.time_zone->gmt_sec_to_TIME(&time, et.starts);
5361 5362
    sch_table->field[ISE_STARTS]->set_notnull();
    sch_table->field[ISE_STARTS]->
5363
                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5364 5365 5366

    if (!et.ends_null)
    {
5367
      et.time_zone->gmt_sec_to_TIME(&time, et.ends);
5368 5369
      sch_table->field[ISE_ENDS]->set_notnull();
      sch_table->field[ISE_ENDS]->
5370
                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5371
    }
5372 5373 5374
  }
  else
  {
5375 5376
    /* type */
    sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("ONE TIME"), scs);
5377

5378
    et.time_zone->gmt_sec_to_TIME(&time, et.execute_at);
5379 5380
    sch_table->field[ISE_EXECUTE_AT]->set_notnull();
    sch_table->field[ISE_EXECUTE_AT]->
5381
                          store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5382 5383
  }

5384
  /* status */
5385 5386 5387

  switch (et.status)
  {
5388
    case Event_parse_data::ENABLED:
5389 5390
      sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("ENABLED"), scs);
      break;
5391
    case Event_parse_data::SLAVESIDE_DISABLED:
5392 5393 5394
      sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("SLAVESIDE_DISABLED"),
                                          scs);
      break;
5395
    case Event_parse_data::DISABLED:
5396 5397 5398 5399 5400 5401
      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);
5402

5403
  /* on_completion */
5404
  if (et.on_completion == Event_parse_data::ON_COMPLETION_DROP)
5405 5406
    sch_table->field[ISE_ON_COMPLETION]->
                                store(STRING_WITH_LEN("NOT PRESERVE"), scs);
5407
  else
5408 5409
    sch_table->field[ISE_ON_COMPLETION]->
                                store(STRING_WITH_LEN("PRESERVE"), scs);
5410 5411 5412
    
  number_to_datetime(et.created, &time, 0, &not_used);
  DBUG_ASSERT(not_used==0);
5413
  sch_table->field[ISE_CREATED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5414 5415 5416

  number_to_datetime(et.modified, &time, 0, &not_used);
  DBUG_ASSERT(not_used==0);
5417 5418
  sch_table->field[ISE_LAST_ALTERED]->
                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5419

5420
  if (et.last_executed)
5421
  {
5422
    et.time_zone->gmt_sec_to_TIME(&time, et.last_executed);
5423 5424
    sch_table->field[ISE_LAST_EXECUTED]->set_notnull();
    sch_table->field[ISE_LAST_EXECUTED]->
5425
                       store_time(&time, MYSQL_TIMESTAMP_DATETIME);
5426
  }
5427

5428 5429
  sch_table->field[ISE_EVENT_COMMENT]->
                      store(et.comment.str, et.comment.length, scs);
5430

unknown's avatar
unknown committed
5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448
  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);

5449 5450 5451 5452 5453
  if (schema_table_store_record(thd, sch_table))
    DBUG_RETURN(1);

  DBUG_RETURN(0);
}
5454
#endif
5455

5456 5457 5458 5459 5460 5461 5462
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;
5463 5464
  if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild))
            && thd->is_fatal_error)
5465 5466 5467 5468
    DBUG_RETURN(1);

  for (; open_list ; open_list=open_list->next)
  {
5469
    restore_record(table, s->default_values);
5470 5471
    table->field[0]->store(open_list->db, strlen(open_list->db), cs);
    table->field[1]->store(open_list->table, strlen(open_list->table), cs);
5472 5473
    table->field[2]->store((longlong) open_list->in_use, TRUE);
    table->field[3]->store((longlong) open_list->locked, TRUE);
5474 5475
    if (schema_table_store_record(thd, table))
      DBUG_RETURN(1);
5476 5477 5478 5479 5480 5481 5482 5483
  }
  DBUG_RETURN(0);
}


int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
{
  DBUG_ENTER("fill_variables");
5484
  int res= 0;
5485 5486
  LEX *lex= thd->lex;
  const char *wild= lex->wild ? lex->wild->ptr() : NullS;
5487 5488 5489 5490 5491 5492 5493 5494 5495 5496
  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;

unknown's avatar
unknown committed
5497
  rw_rdlock(&LOCK_system_variables_hash);
5498
  res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars),
5499
                         option_type, NULL, "", tables->table, upper_case_names, cond);
unknown's avatar
unknown committed
5500
  rw_unlock(&LOCK_system_variables_hash);
5501 5502 5503 5504 5505 5506 5507 5508 5509 5510
  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;
5511 5512 5513 5514 5515 5516
  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
5517 5518 5519 5520 5521 5522 5523 5524 5525
  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)
5526 5527 5528 5529 5530
  {
    option_type= OPT_GLOBAL;
    tmp1= &tmp;
  }
  else
unknown's avatar
unknown committed
5531
  { 
5532
    option_type= OPT_SESSION;
unknown's avatar
unknown committed
5533
    tmp1= &thd->status_var;
5534 5535
  }

5536
  pthread_mutex_lock(&LOCK_status);
5537
  if (option_type == OPT_GLOBAL)
5538
    calc_sum_of_all_status(&tmp);
5539 5540
  res= show_status_array(thd, wild,
                         (SHOW_VAR *)all_status_vars.buffer,
5541
                         option_type, tmp1, "", tables->table,
5542
                         upper_case_names, cond);
5543
  pthread_mutex_unlock(&LOCK_status);
5544 5545 5546 5547
  DBUG_RETURN(res);
}


5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566
/*
  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
5567
get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
5568
                                   TABLE *table, bool res,
5569
                                   LEX_STRING *db_name, LEX_STRING *table_name)
5570 5571 5572 5573 5574 5575
{
  CHARSET_INFO *cs= system_charset_info;
  DBUG_ENTER("get_referential_constraints_record");

  if (res)
  {
5576
    if (thd->is_error())
5577
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
Marc Alff's avatar
Marc Alff committed
5578
                   thd->stmt_da->sql_errno(), thd->stmt_da->message());
5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595
    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);
5596
      table->field[0]->store(STRING_WITH_LEN("def"), cs);
5597 5598
      table->field[1]->store(db_name->str, db_name->length, cs);
      table->field[9]->store(table_name->str, table_name->length, cs);
5599 5600
      table->field[2]->store(f_key_info->forein_id->str,
                             f_key_info->forein_id->length, cs);
5601
      table->field[3]->store(STRING_WITH_LEN("def"), cs);
5602 5603
      table->field[4]->store(f_key_info->referenced_db->str, 
                             f_key_info->referenced_db->length, cs);
5604
      table->field[10]->store(f_key_info->referenced_table->str, 
5605
                             f_key_info->referenced_table->length, cs);
5606 5607 5608 5609 5610 5611 5612 5613
      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();
5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625
      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
5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645
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
5646
static my_bool find_schema_table_in_plugin(THD *thd, plugin_ref plugin,
unknown's avatar
unknown committed
5647 5648 5649 5650
                                           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
5651
  ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
unknown's avatar
unknown committed
5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663
  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);
}

5664

5665 5666 5667 5668 5669 5670 5671 5672 5673 5674
/*
  Find schema_tables elment by name

  SYNOPSIS
    find_schema_table()
    thd                 thread handler
    table_name          table name

  RETURN
    0	table not found
5675
    #   pointer to 'schema_tables' element
5676 5677 5678 5679
*/

ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
{
unknown's avatar
unknown committed
5680
  schema_table_ref schema_table_a;
5681
  ST_SCHEMA_TABLE *schema_table= schema_tables;
unknown's avatar
unknown committed
5682 5683
  DBUG_ENTER("find_schema_table");

5684
  for (; schema_table->table_name; schema_table++)
5685 5686 5687 5688
  {
    if (!my_strcasecmp(system_charset_info,
                       schema_table->table_name,
                       table_name))
unknown's avatar
unknown committed
5689
      DBUG_RETURN(schema_table);
5690
  }
unknown's avatar
unknown committed
5691 5692 5693 5694 5695 5696 5697

  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);
5698 5699 5700 5701 5702 5703 5704 5705 5706
}


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


5707 5708
/**
  Create information_schema table using schema_table data.
5709

5710 5711 5712 5713 5714 5715 5716 5717 5718
  @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
5719
    thd	       	          thread handler
5720 5721 5722

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

5724 5725
  @retval  \#             Pointer to created table
  @retval  NULL           Can't create table
5726 5727
*/

5728
TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
5729 5730 5731 5732 5733
{
  int field_count= 0;
  Item *item;
  TABLE *table;
  List<Item> field_list;
5734
  ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
5735
  ST_FIELD_INFO *fields_info= schema_table->fields_info;
unknown's avatar
unknown committed
5736
  CHARSET_INFO *cs= system_charset_info;
5737 5738
  DBUG_ENTER("create_schema_table");

5739
  for (; fields_info->field_name; fields_info++)
5740 5741
  {
    switch (fields_info->field_type) {
5742
    case MYSQL_TYPE_TINY:
5743
    case MYSQL_TYPE_LONG:
5744 5745 5746 5747 5748 5749 5750
    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)))
5751 5752 5753
      {
        DBUG_RETURN(0);
      }
5754
      item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
5755
      break;
5756 5757
    case MYSQL_TYPE_DATE:
    case MYSQL_TYPE_TIME:
5758
    case MYSQL_TYPE_TIMESTAMP:
5759 5760 5761
    case MYSQL_TYPE_DATETIME:
      if (!(item=new Item_return_date_time(fields_info->field_name,
                                           fields_info->field_type)))
5762 5763 5764 5765
      {
        DBUG_RETURN(0);
      }
      break;
5766 5767 5768 5769 5770 5771
    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;
5772
    case MYSQL_TYPE_DECIMAL:
5773
    case MYSQL_TYPE_NEWDECIMAL:
5774 5775 5776 5777
      if (!(item= new Item_decimal((longlong) fields_info->value, false)))
      {
        DBUG_RETURN(0);
      }
5778
      item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
5779 5780 5781 5782 5783 5784 5785 5786 5787
      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;
5788 5789 5790 5791 5792 5793 5794 5795 5796 5797
    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;
5798
    default:
5799 5800 5801
      /* Don't let unimplemented types pass through. Could be a grave error. */
      DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING);

5802
      if (!(item= new Item_empty_string("", fields_info->field_length, cs)))
5803 5804 5805
      {
        DBUG_RETURN(0);
      }
unknown's avatar
unknown committed
5806 5807
      item->set_name(fields_info->field_name,
                     strlen(fields_info->field_name), cs);
5808 5809 5810
      break;
    }
    field_list.push_back(item);
5811
    item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL);
5812 5813 5814
    field_count++;
  }
  TMP_TABLE_PARAM *tmp_table_param =
5815
    (TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM)));
5816
  tmp_table_param->init();
unknown's avatar
unknown committed
5817
  tmp_table_param->table_charset= cs;
5818
  tmp_table_param->field_count= field_count;
5819
  tmp_table_param->schema_table= 1;
5820 5821 5822 5823 5824
  SELECT_LEX *select_lex= thd->lex->current_select;
  if (!(table= create_tmp_table(thd, tmp_table_param,
                                field_list, (ORDER*) 0, 0, 0, 
                                (select_lex->options | thd->options |
                                 TMP_TABLE_ALL_COLUMNS),
unknown's avatar
unknown committed
5825
                                HA_POS_ERROR, table_list->alias)))
5826
    DBUG_RETURN(0);
5827 5828 5829 5830 5831 5832
  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);
5833
  table_list->schema_table_param= tmp_table_param;
5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848
  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
5849 5850
   1	error
   0	success
5851 5852 5853 5854 5855
*/

int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
  ST_FIELD_INFO *field_info= schema_table->fields_info;
5856
  Name_resolution_context *context= &thd->lex->select_lex.context;
5857
  for (; field_info->field_name; field_info++)
5858 5859 5860
  {
    if (field_info->old_name)
    {
5861 5862
      Item_field *field= new Item_field(context,
                                        NullS, NullS, field_info->field_name);
5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881
      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;
5882
  Name_resolution_context *context= &sel->context;
5883 5884 5885 5886 5887

  if (!sel->item_list.elements)
  {
    ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
    String buffer(tmp,sizeof(tmp), system_charset_info);
5888 5889
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
5890 5891 5892 5893 5894 5895
    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())
    {
5896
      buffer.append(STRING_WITH_LEN(" ("));
5897
      buffer.append(lex->wild->ptr());
5898
      buffer.append(')');
5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910
    }
    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;
5911
  Name_resolution_context *context= &lex->select_lex.context;
5912 5913 5914 5915 5916 5917 5918

  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())
  {
5919
    buffer.append(STRING_WITH_LEN(" ("));
5920
    buffer.append(lex->wild->ptr());
5921
    buffer.append(')');
5922
  }
5923 5924
  Item_field *field= new Item_field(context,
                                    NullS, NullS, field_info->field_name);
5925 5926 5927 5928 5929 5930 5931
  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];
5932
    field= new Item_field(context, NullS, NullS, field_info->field_name);
5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943
    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)
{
5944 5945 5946
  int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1};
  int *field_num= fields_arr;
  ST_FIELD_INFO *field_info;
5947 5948
  Name_resolution_context *context= &thd->lex->select_lex.context;

5949
  for (; *field_num >= 0; field_num++)
5950
  {
5951 5952 5953 5954 5955
    field_info= &schema_table->fields_info[*field_num];
    if (!thd->lex->verbose && (*field_num == 13 ||
                               *field_num == 17 ||
                               *field_num == 18))
      continue;
5956 5957
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
5958
    if (field)
5959
    {
5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970
      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;
}


5971 5972 5973 5974 5975
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;
5976 5977
  Name_resolution_context *context= &thd->lex->select_lex.context;

5978 5979 5980
  for (; *field_num >= 0; field_num++)
  {
    field_info= &schema_table->fields_info[*field_num];
5981 5982
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995
    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;
}


5996 5997
int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
unknown's avatar
unknown committed
5998
  int fields_arr[]= {2, 3, 4, 19, 16, 15, 14, 18, 20, 21, 22, -1};
5999 6000
  int *field_num= fields_arr;
  ST_FIELD_INFO *field_info;
6001 6002
  Name_resolution_context *context= &thd->lex->select_lex.context;

6003 6004 6005
  for (; *field_num >= 0; field_num++)
  {
    field_info= &schema_table->fields_info[*field_num];
6006 6007
    Item_field *field= new Item_field(context,
                                      NullS, NullS, field_info->field_name);
6008 6009 6010 6011 6012 6013 6014
    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;
6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038
    }
  }
  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");
6039
  if (!(table= table_list->schema_table->create_table(thd, table_list)))
6040
    DBUG_RETURN(1);
6041
  table->s->tmp_table= SYSTEM_TMP_TABLE;
6042
  table->grant.privilege= SELECT_ACL;
6043 6044 6045 6046 6047 6048 6049
  /*
    This test is necessary to make
    case insensitive file systems +
    upper case table names(information schema tables) +
    views
    working correctly
  */
6050 6051 6052 6053
  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
6054 6055
  table_list->table_name= table->s->table_name.str;
  table_list->table_name_length= table->s->table_name.length;
6056 6057 6058 6059
  table_list->table= table;
  table->next= thd->derived_tables;
  thd->derived_tables= table;
  table_list->select_lex->options |= OPTION_SCHEMA_TABLE;
6060
  lex->safe_to_cache_query= 0;
6061 6062 6063 6064 6065

  if (table_list->schema_table_reformed) // show command
  {
    SELECT_LEX *sel= lex->current_select;
    Item *item;
unknown's avatar
unknown committed
6066
    Field_translator *transl, *org_transl;
6067 6068 6069

    if (table_list->field_translation)
    {
6070
      Field_translator *end= table_list->field_translation_end;
6071 6072 6073
      for (transl= table_list->field_translation; transl < end; transl++)
      {
        if (!transl->item->fixed &&
6074
            transl->item->fix_fields(thd, &transl->item))
6075 6076 6077 6078 6079 6080
          DBUG_RETURN(1);
      }
      DBUG_RETURN(0);
    }
    List_iterator_fast<Item> it(sel->item_list);
    if (!(transl=
unknown's avatar
unknown committed
6081
          (Field_translator*)(thd->stmt_arena->
6082 6083 6084 6085 6086
                              alloc(sel->item_list.elements *
                                    sizeof(Field_translator)))))
    {
      DBUG_RETURN(1);
    }
unknown's avatar
unknown committed
6087
    for (org_transl= transl; (item= it++); transl++)
6088
    {
unknown's avatar
unknown committed
6089 6090 6091 6092
      transl->item= item;
      transl->name= item->name;
      if (!item->fixed && item->fix_fields(thd, &transl->item))
      {
6093
        DBUG_RETURN(1);
unknown's avatar
unknown committed
6094
      }
6095
    }
unknown's avatar
unknown committed
6096 6097
    table_list->field_translation= org_transl;
    table_list->field_translation_end= transl;
6098 6099
  }

6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122
  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;
6123
  DBUG_ENTER("make_schema_select");
unknown's avatar
unknown committed
6124
  DBUG_PRINT("enter", ("mysql_schema_select: %s", schema_table->table_name));
6125
  /*
6126 6127 6128
     We have to make non const db_name & table_name
     because of lower_case_table_names
  */
6129 6130 6131 6132
  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);
6133
  if (schema_table->old_format(thd, schema_table) ||   /* Handle old syntax */
6134
      !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
6135
                              0, 0, TL_READ))
6136 6137 6138 6139 6140 6141 6142 6143
  {
    DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


/*
6144
  Fill temporary schema tables before SELECT
6145 6146 6147 6148

  SYNOPSIS
    get_schema_tables_result()
    join  join which use schema tables
6149
    executed_place place where I_S table processed
6150 6151

  RETURN
unknown's avatar
unknown committed
6152 6153
    FALSE success
    TRUE  error
6154 6155
*/

6156 6157
bool get_schema_tables_result(JOIN *join,
                              enum enum_schema_table_state executed_place)
6158 6159 6160
{
  JOIN_TAB *tmp_join_tab= join->join_tab+join->tables;
  THD *thd= join->thd;
unknown's avatar
unknown committed
6161 6162
  LEX *lex= thd->lex;
  bool result= 0;
6163 6164 6165
  DBUG_ENTER("get_schema_tables_result");

  thd->no_warnings_for_error= 1;
6166 6167 6168 6169
  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
6170

unknown's avatar
unknown committed
6171
    TABLE_LIST *table_list= tab->table->pos_in_table_list;
6172
    if (table_list->schema_table && thd->fill_information_schema_tables())
6173
    {
6174 6175
      bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
                          lex->current_select->master_unit()->item);
6176

6177 6178 6179
      /* A value of 0 indicates a dummy implementation */
      if (table_list->schema_table->fill_table == 0)
        continue;
6180 6181 6182 6183 6184 6185

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

6186
      /*
6187 6188 6189 6190 6191 6192 6193
        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.
6194
      */
6195 6196
      if (table_list->schema_table_state &&
          (!is_subselect || table_list->schema_table_state != executed_place))
6197 6198
        continue;

6199 6200 6201 6202 6203 6204
      /*
        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
6205
      {
6206
        table_list->table->file->extra(HA_EXTRA_NO_CACHE);
unknown's avatar
unknown committed
6207
        table_list->table->file->extra(HA_EXTRA_RESET_STATE);
6208
        table_list->table->file->ha_delete_all_rows();
unknown's avatar
unknown committed
6209
        free_io_cache(table_list->table);
unknown's avatar
unknown committed
6210
        filesort_free_buffers(table_list->table,1);
6211
        table_list->table->null_row= 0;
unknown's avatar
unknown committed
6212 6213
      }
      else
6214
        table_list->table->file->stats.records= 0;
unknown's avatar
unknown committed
6215

6216 6217
      if (table_list->schema_table->fill_table(thd, table_list,
                                               tab->select_cond))
6218
      {
unknown's avatar
unknown committed
6219
        result= 1;
6220
        join->error= 1;
6221
        tab->read_record.file= table_list->table->file;
6222
        table_list->schema_table_state= executed_place;
6223 6224
        break;
      }
6225
      tab->read_record.file= table_list->table->file;
6226
      table_list->schema_table_state= executed_place;
6227 6228
    }
  }
6229
  thd->no_warnings_for_error= 0;
unknown's avatar
unknown committed
6230
  DBUG_RETURN(result);
6231 6232
}

6233 6234 6235 6236 6237 6238
struct run_hton_fill_schema_files_args
{
  TABLE_LIST *tables;
  COND *cond;
};

unknown's avatar
unknown committed
6239
static my_bool run_hton_fill_schema_files(THD *thd, plugin_ref plugin,
6240 6241 6242 6243
                                          void *arg)
{
  struct run_hton_fill_schema_files_args *args=
    (run_hton_fill_schema_files_args *) arg;
unknown's avatar
unknown committed
6244
  handlerton *hton= plugin_data(plugin, handlerton *);
6245
  if(hton->fill_files_table && hton->state == SHOW_OPTION_YES)
6246
    hton->fill_files_table(hton, thd, args->tables, args->cond);
6247 6248 6249 6250 6251
  return false;
}

int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond)
{
unknown's avatar
unknown committed
6252
  DBUG_ENTER("fill_schema_files");
6253 6254 6255 6256 6257 6258 6259 6260 6261 6262

  struct run_hton_fill_schema_files_args args;
  args.tables= tables;
  args.cond= cond;

  plugin_foreach(thd, run_hton_fill_schema_files,
                 MYSQL_STORAGE_ENGINE_PLUGIN, &args);

  DBUG_RETURN(0);
}
6263

6264

6265 6266
ST_FIELD_INFO schema_fields_info[]=
{
6267
  {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6268 6269
  {"SCHEMA_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
   SKIP_OPEN_TABLE},
6270 6271 6272
  {"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,
6273 6274 6275
   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}
6276 6277 6278 6279 6280
};


ST_FIELD_INFO tables_fields_info[]=
{
6281
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6282 6283 6284 6285 6286
  {"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},
6287
  {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6288 6289
   (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},
6290
  {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6291
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", OPEN_FULL_TABLE},
6292
  {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 
6293
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", OPEN_FULL_TABLE},
6294
  {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 
6295
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", OPEN_FULL_TABLE},
6296
  {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6297
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", OPEN_FULL_TABLE},
6298
  {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 
6299
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", OPEN_FULL_TABLE},
6300
  {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6301
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", OPEN_FULL_TABLE},
6302
  {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0, 
6303 6304 6305 6306
   (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},
6307 6308
  {"TABLE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
   OPEN_FRM_ONLY},
6309
  {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6310 6311 6312 6313 6314
   (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},
  {"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment", OPEN_FRM_ONLY},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6315 6316 6317 6318 6319
};


ST_FIELD_INFO columns_fields_info[]=
{
6320
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6321 6322 6323 6324
  {"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},
6325
  {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
6326
   MY_I_S_UNSIGNED, 0, OPEN_FRM_ONLY},
6327
  {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0,
6328 6329 6330
   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},
6331
  {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
6332
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6333
  {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
6334
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6335
  {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
6336
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6337
  {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
6338
   0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
6339 6340 6341 6342
  {"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},
6343 6344
  {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type", OPEN_FRM_ONLY},
  {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY},
6345
  {"EXTRA", 27, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
6346 6347 6348
  {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY},
  {"COLUMN_COMMENT", 255, MYSQL_TYPE_STRING, 0, 0, "Comment", OPEN_FRM_ONLY},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6349 6350 6351 6352 6353
};


ST_FIELD_INFO charsets_fields_info[]=
{
6354
  {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
6355
   SKIP_OPEN_TABLE},
6356 6357
  {"DEFAULT_COLLATE_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
   "Default collation", SKIP_OPEN_TABLE},
6358 6359 6360 6361
  {"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}
6362 6363 6364 6365 6366
};


ST_FIELD_INFO collation_fields_info[]=
{
6367 6368 6369
  {"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",
6370 6371 6372 6373 6374 6375 6376
   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}
6377 6378 6379
};


unknown's avatar
unknown committed
6380 6381
ST_FIELD_INFO engines_fields_info[]=
{
6382 6383 6384
  {"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},
6385 6386 6387
  {"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},
6388
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
unknown's avatar
unknown committed
6389 6390 6391
};


6392 6393
ST_FIELD_INFO events_fields_info[]=
{
6394
  {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408
  {"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},
6409
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6410 6411 6412 6413 6414 6415 6416 6417 6418
  {"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
6419
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6420
   "character_set_client", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6421
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6422
   "collation_connection", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6423
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6424 6425
   "Database Collation", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6426 6427 6428 6429
};



6430 6431
ST_FIELD_INFO coll_charset_app_fields_info[]=
{
6432 6433 6434 6435
  {"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},
6436
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6437 6438 6439 6440 6441
};


ST_FIELD_INFO proc_fields_info[]=
{
6442
  {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6443
  {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463
  {"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},
  {"DTD_IDENTIFIER", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
  {"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},
6464
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6465 6466 6467
  {"ROUTINE_COMMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Comment",
   SKIP_OPEN_TABLE},
  {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6468
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6469
   "character_set_client", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6470
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6471
   "collation_connection", SKIP_OPEN_TABLE},
unknown's avatar
unknown committed
6472
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6473 6474
   "Database Collation", SKIP_OPEN_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6475 6476 6477 6478 6479
};


ST_FIELD_INFO stat_fields_info[]=
{
6480
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6481 6482 6483 6484 6485 6486 6487 6488 6489 6490
  {"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},
6491
  {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 1,
6492 6493 6494 6495 6496 6497 6498
   "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},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6499 6500 6501 6502 6503
};


ST_FIELD_INFO view_fields_info[]=
{
6504
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516
  {"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},
  {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6517 6518 6519 6520 6521
};


ST_FIELD_INFO user_privileges_fields_info[]=
{
6522
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6523
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6524 6525 6526
  {"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}
6527 6528 6529 6530 6531
};


ST_FIELD_INFO schema_privileges_fields_info[]=
{
6532
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6533
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6534 6535 6536 6537
  {"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}
6538 6539 6540 6541 6542
};


ST_FIELD_INFO table_privileges_fields_info[]=
{
6543
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6544
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6545 6546 6547 6548 6549
  {"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}
6550 6551 6552 6553 6554
};


ST_FIELD_INFO column_privileges_fields_info[]=
{
6555
  {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6556
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6557 6558 6559 6560 6561 6562
  {"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}
6563 6564 6565 6566 6567
};


ST_FIELD_INFO table_constraints_fields_info[]=
{
6568
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
6569 6570 6571 6572 6573 6574 6575 6576 6577
  {"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}
6578 6579 6580 6581 6582
};


ST_FIELD_INFO key_column_usage_fields_info[]=
{
6583
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
6584 6585 6586 6587
  {"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},
6588
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601
  {"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}
6602 6603 6604 6605 6606
};


ST_FIELD_INFO table_names_fields_info[]=
{
6607
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6608 6609 6610 6611 6612 6613
  {"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}
6614 6615 6616
};


6617 6618
ST_FIELD_INFO open_tables_fields_info[]=
{
6619 6620 6621 6622 6623 6624
  {"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}
6625 6626 6627
};


6628 6629
ST_FIELD_INFO triggers_fields_info[]=
{
6630
  {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
6631 6632 6633 6634
  {"TRIGGER_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"TRIGGER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger",
   OPEN_FULL_TABLE},
  {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FULL_TABLE},
6635
  {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653
   OPEN_FULL_TABLE},
  {"EVENT_OBJECT_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
  {"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table",
   OPEN_FULL_TABLE},
  {"ACTION_ORDER", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FULL_TABLE},
  {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
  {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement",
   OPEN_FULL_TABLE},
  {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing", OPEN_FULL_TABLE},
  {"ACTION_REFERENCE_OLD_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   OPEN_FULL_TABLE},
  {"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
   OPEN_FULL_TABLE},
  {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
  {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FULL_TABLE},
6654 6655
  {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FULL_TABLE},
  {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FULL_TABLE},
unknown's avatar
unknown committed
6656
  {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6657
   "character_set_client", OPEN_FULL_TABLE},
unknown's avatar
unknown committed
6658
  {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6659
   "collation_connection", OPEN_FULL_TABLE},
unknown's avatar
unknown committed
6660
  {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
6661 6662
   "Database Collation", OPEN_FULL_TABLE},
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6663 6664 6665
};


6666 6667
ST_FIELD_INFO partitions_fields_info[]=
{
6668
  {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
6669 6670 6671 6672 6673
  {"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},
6674
  {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
6675
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
6676
  {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
6677
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
6678
  {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689
  {"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},
6690
  {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
6691 6692 6693 6694 6695 6696 6697 6698
   (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},
6699
  {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
6700 6701 6702 6703 6704 6705
   (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}
6706 6707 6708
};


6709 6710
ST_FIELD_INFO variables_fields_info[]=
{
6711 6712
  {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name",
   SKIP_OPEN_TABLE},
6713
  {"VARIABLE_VALUE", 1024, MYSQL_TYPE_STRING, 0, 1, "Value", SKIP_OPEN_TABLE},
6714
  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
6715 6716 6717
};


6718 6719
ST_FIELD_INFO processlist_fields_info[]=
{
6720 6721 6722 6723 6724 6725
  {"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},
6726
  {"TIME", 7, MYSQL_TYPE_LONG, 0, 0, "Time", SKIP_OPEN_TABLE},
6727 6728 6729 6730
  {"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}
6731 6732 6733
};


unknown's avatar
unknown committed
6734 6735
ST_FIELD_INFO plugin_fields_info[]=
{
6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748
  {"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
6749 6750
};

6751 6752
ST_FIELD_INFO files_fields_info[]=
{
6753 6754 6755 6756 6757
  {"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},
6758
  {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770
  {"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},
6771
  {"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
6772
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
6773
  {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, 
6774
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
6775
  {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, 
6776 6777 6778 6779 6780 6781
   (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},
6782
  {"VERSION", 21 , MYSQL_TYPE_LONGLONG, 0,
6783 6784
   (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},
6785
  {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0,
6786
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", SKIP_OPEN_TABLE},
6787
  {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
6788
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", SKIP_OPEN_TABLE},
6789
  {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
6790
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", SKIP_OPEN_TABLE},
6791
  {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
6792
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", SKIP_OPEN_TABLE},
6793
  {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, 
6794
   (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", SKIP_OPEN_TABLE},
6795
  {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, 
6796 6797 6798 6799
   (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},
6800
  {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0, 
6801 6802 6803 6804
   (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}
6805
};
unknown's avatar
unknown committed
6806

6807 6808 6809 6810 6811 6812 6813 6814 6815 6816
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);
}

6817 6818
ST_FIELD_INFO referential_constraints_fields_info[]=
{
6819
  {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
6820 6821 6822 6823
  {"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},
6824
  {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
6825 6826 6827
   OPEN_FULL_TABLE},
  {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
   OPEN_FULL_TABLE},
6828 6829
  {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0,
   MY_I_S_MAYBE_NULL, 0, OPEN_FULL_TABLE},
6830 6831 6832 6833 6834 6835 6836
  {"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}
6837 6838 6839
};


6840 6841
/*
  Description of ST_FIELD_INFO in table.h
unknown's avatar
unknown committed
6842 6843 6844

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

6845 6846 6847 6848 6849
*/

ST_SCHEMA_TABLE schema_tables[]=
{
  {"CHARACTER_SETS", charsets_fields_info, create_schema_table, 
6850
   fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0},
6851
  {"COLLATIONS", collation_fields_info, create_schema_table, 
6852
   fill_schema_collation, make_old_format, 0, -1, -1, 0, 0},
6853
  {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
6854
   create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0, 0},
6855
  {"COLUMNS", columns_fields_info, create_schema_table, 
6856
   get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0,
6857
   OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
6858
  {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
6859
   fill_schema_column_privileges, 0, 0, -1, -1, 0, 0},
unknown's avatar
unknown committed
6860
  {"ENGINES", engines_fields_info, create_schema_table,
6861
   fill_schema_engines, make_old_format, 0, -1, -1, 0, 0},
6862
#ifdef HAVE_EVENT_SCHEDULER
6863
  {"EVENTS", events_fields_info, create_schema_table,
6864
   Events::fill_schema_events, make_old_format, 0, -1, -1, 0, 0},
6865 6866 6867
#else
  {"EVENTS", events_fields_info, create_schema_table,
   0, make_old_format, 0, -1, -1, 0, 0},
6868
#endif
6869
  {"FILES", files_fields_info, create_schema_table,
6870
   fill_schema_files, 0, 0, -1, -1, 0, 0},
6871
  {"GLOBAL_STATUS", variables_fields_info, create_schema_table,
6872
   fill_status, make_old_format, 0, 0, -1, 0, 0},
6873
  {"GLOBAL_VARIABLES", variables_fields_info, create_schema_table,
6874
   fill_variables, make_old_format, 0, 0, -1, 0, 0},
6875
  {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
6876
   get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0,
6877
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
6878
  {"OPEN_TABLES", open_tables_fields_info, create_schema_table,
6879
   fill_open_tables, make_old_format, 0, -1, -1, 1, 0},
6880
  {"PARTITIONS", partitions_fields_info, create_schema_table,
6881 6882
   get_all_tables, 0, get_schema_partitions_record, 1, 2, 0,
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
unknown's avatar
unknown committed
6883
  {"PLUGINS", plugin_fields_info, create_schema_table,
6884
   fill_plugins, make_old_format, 0, -1, -1, 0, 0},
6885
  {"PROCESSLIST", processlist_fields_info, create_schema_table,
6886
   fill_schema_processlist, make_old_format, 0, -1, -1, 0, 0},
6887
  {"PROFILING", query_profile_statistics_info, create_schema_table,
6888 6889
    fill_query_profile_statistics_info, make_profile_table_for_show, 
    NULL, -1, -1, false, 0},
6890 6891
  {"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info,
   create_schema_table, get_all_tables, 0, get_referential_constraints_record,
6892
   1, 9, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
6893
  {"ROUTINES", proc_fields_info, create_schema_table, 
6894
   fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0},
6895
  {"SCHEMATA", schema_fields_info, create_schema_table,
6896
   fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0},
6897
  {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table,
6898
   fill_schema_schema_privileges, 0, 0, -1, -1, 0, 0},
6899
  {"SESSION_STATUS", variables_fields_info, create_schema_table,
6900
   fill_status, make_old_format, 0, 0, -1, 0, 0},
6901
  {"SESSION_VARIABLES", variables_fields_info, create_schema_table,
6902
   fill_variables, make_old_format, 0, 0, -1, 0, 0},
6903
  {"STATISTICS", stat_fields_info, create_schema_table, 
6904
   get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0,
6905
   OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
6906
  {"STATUS", variables_fields_info, create_schema_table, fill_status, 
6907
   make_old_format, 0, 0, -1, 1, 0},
6908
  {"TABLES", tables_fields_info, create_schema_table, 
6909 6910
   get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0,
   OPTIMIZE_I_S_TABLE},
6911
  {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table,
6912 6913
   get_all_tables, 0, get_schema_constraints_record, 3, 4, 0,
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
6914
  {"TABLE_NAMES", table_names_fields_info, create_schema_table,
6915
   get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0},
6916
  {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
6917
   fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
6918
  {"TRIGGERS", triggers_fields_info, create_schema_table,
6919
   get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
6920
   OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
6921
  {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, 
6922
   fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
6923
  {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
6924
   make_old_format, 0, 0, -1, 1, 0},
6925
  {"VIEWS", view_fields_info, create_schema_table, 
6926 6927 6928
   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}
6929 6930 6931
};


6932
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
unknown's avatar
unknown committed
6933
template class List_iterator_fast<char>;
unknown's avatar
unknown committed
6934 6935
template class List<char>;
#endif
unknown's avatar
unknown committed
6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953

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; 

6954
    /* Make the name available to the init() function. */
6955
    schema_table->table_name= plugin->name.str;
unknown's avatar
unknown committed
6956 6957 6958 6959 6960

    if (plugin->plugin->init(schema_table))
    {
      sql_print_error("Plugin '%s' init function returned error.",
                      plugin->name.str);
6961 6962 6963
      plugin->data= NULL;
      my_free(schema_table, MYF(0));
      DBUG_RETURN(1);
unknown's avatar
unknown committed
6964
    }
6965 6966
    
    /* Make sure the plugin name is not set inside the init() function. */
unknown's avatar
unknown committed
6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984
    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));
    }
6985
    my_free(schema_table, MYF(0));
unknown's avatar
unknown committed
6986 6987 6988
  }
  DBUG_RETURN(0);
}
unknown's avatar
unknown committed
6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019


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

7020 7021
  CHARSET_INFO *trg_client_cs;

unknown's avatar
unknown committed
7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046
  /*
    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);

  sys_var_thd_sql_mode::symbolic_mode_representation(thd,
                                                     trg_sql_mode,
                                                     &trg_sql_mode_str);

7047 7048 7049 7050 7051
  /* Resolve trigger client character set. */

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

unknown's avatar
unknown committed
7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097
  /* 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));

  if (p->send_fields(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
    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,
7098
           trg_client_cs);
unknown's avatar
unknown committed
7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114

  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)
7115
    my_eof(thd);
unknown's avatar
unknown committed
7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236

  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().
*/

static TABLE_LIST *get_trigger_table_impl(
  THD *thd,
  const sp_name *trg_name)
{
  char trn_path_buff[FN_REFLEN];

  LEX_STRING trn_path= { trn_path_buff, 0 };
  LEX_STRING tbl_name;

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

  TABLE_LIST *table;

  if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
  {
    my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST));
    return NULL;
  }

  table->db_length= trg_name->m_db.length;
  table->db= thd->strmake(trg_name->m_db.str, trg_name->m_db.length);

  table->table_name_length= tbl_name.length;
  table->table_name= thd->strmake(tbl_name.str, tbl_name.length);

  table->alias= thd->strmake(tbl_name.str, tbl_name.length);

  table->lock_type= TL_IGNORE;
  table->cacheable_table= 0;

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

static TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
{
  /* Acquire LOCK_open (stop the server). */

  pthread_mutex_lock(&LOCK_open);

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

  pthread_mutex_unlock(&LOCK_open);

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

7237 7238 7239
  if (!lst)
    return TRUE;

7240 7241 7242 7243 7244 7245
  if (check_table_access(thd, TRIGGER_ACL, lst, 1, TRUE))
  {
    my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "TRIGGER");
    return TRUE;
  }

unknown's avatar
unknown committed
7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293
  /*
    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
    LOCK_open is released. It will be fixed later by introducing
    acquire-shared-table-name-lock functionality.
  */

  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.
  */
}
7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385

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