1 /* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 
24 /* Function with list databases, tables or fields */
25 
26 #include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
27 #include "sql_priv.h"
28 #include "unireg.h"
29 #include "sql_acl.h"                        // fill_schema_*_privileges
30 #include "sql_select.h"
31 #include "sql_base.h"                       // close_tables_for_reopen
32 #include "sql_show.h"
33 #include "sql_table.h"                        // filename_to_tablename,
34                                               // primary_key_name,
35                                               // build_table_filename
36 #include "sql_view.h"                           // mysql_frm_type
37 #include "sql_parse.h"             // check_access, check_table_access
38 #include "sql_partition.h"         // partition_element
39 #include "sql_derived.h"           // mysql_derived_prepare,
40                                    // mysql_handle_derived,
41 #include "sql_db.h"     // check_db_dir_existence, load_db_opt_by_name
42 #include "sql_time.h"   // interval_type_to_name
43 #include "tztime.h"                             // struct Time_zone
44 #include "sql_acl.h"     // TABLE_ACLS, check_grant, DB_ACLS, acl_get,
45                          // check_grant_db
46 #include "filesort.h"    // filesort_free_buffers
47 #include "sp.h"
48 #include "sp_head.h"
49 #include "sp_pcontext.h"
50 #include "set_var.h"
51 #include "sql_trigger.h"
52 #include "sql_derived.h"
53 #include "sql_partition.h"
54 #ifdef HAVE_EVENT_SCHEDULER
55 #include "events.h"
56 #include "event_data_objects.h"
57 #endif
58 #include <my_dir.h>
59 #include "lock.h"                           // MYSQL_OPEN_IGNORE_FLUSH
60 #include "debug_sync.h"
61 #include "datadict.h"   // dd_frm_type()
62 #include "opt_trace.h"     // Optimizer trace information schema tables
63 #include "sql_tmp_table.h" // Tmp tables
64 #include "sql_optimizer.h" // JOIN
65 #include "global_threads.h"
66 #include "my_default.h"
67 
68 #include <algorithm>
69 using std::max;
70 using std::min;
71 
72 #define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
73 
74 #ifdef WITH_PARTITION_STORAGE_ENGINE
75 #include "ha_partition.h"
76 #endif
77 enum enum_i_s_events_fields
78 {
79   ISE_EVENT_CATALOG= 0,
80   ISE_EVENT_SCHEMA,
81   ISE_EVENT_NAME,
82   ISE_DEFINER,
83   ISE_TIME_ZONE,
84   ISE_EVENT_BODY,
85   ISE_EVENT_DEFINITION,
86   ISE_EVENT_TYPE,
87   ISE_EXECUTE_AT,
88   ISE_INTERVAL_VALUE,
89   ISE_INTERVAL_FIELD,
90   ISE_SQL_MODE,
91   ISE_STARTS,
92   ISE_ENDS,
93   ISE_STATUS,
94   ISE_ON_COMPLETION,
95   ISE_CREATED,
96   ISE_LAST_ALTERED,
97   ISE_LAST_EXECUTED,
98   ISE_EVENT_COMMENT,
99   ISE_ORIGINATOR,
100   ISE_CLIENT_CS,
101   ISE_CONNECTION_CL,
102   ISE_DB_CL
103 };
104 
105 #ifndef NO_EMBEDDED_ACCESS_CHECKS
106 static const char *grant_names[]={
107   "select","insert","update","delete","create","drop","reload","shutdown",
108   "process","file","grant","references","index","alter"};
109 
110 static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
111                                "grant_types",
112                                grant_names, NULL};
113 #endif
114 
115 static void store_key_options(THD *thd, String *packet, TABLE *table,
116                               KEY *key_info);
117 
118 #ifdef WITH_PARTITION_STORAGE_ENGINE
119 static void get_cs_converted_string_value(THD *thd,
120                                           String *input_str,
121                                           String *output_str,
122                                           const CHARSET_INFO *cs,
123                                           bool use_hex);
124 #endif
125 
126 static void
127 append_algorithm(TABLE_LIST *table, String *buff);
128 
129 static Item * make_cond_for_info_schema(Item *cond, TABLE_LIST *table);
130 
131 /***************************************************************************
132 ** List all table types supported
133 ***************************************************************************/
134 
make_version_string(char * buf,int buf_length,uint version)135 static int make_version_string(char *buf, int buf_length, uint version)
136 {
137   return my_snprintf(buf, buf_length, "%d.%d", version>>8,version&0xff);
138 }
139 
show_plugins(THD * thd,plugin_ref plugin,void * arg)140 static my_bool show_plugins(THD *thd, plugin_ref plugin,
141                             void *arg)
142 {
143   TABLE *table= (TABLE*) arg;
144   struct st_mysql_plugin *plug= plugin_decl(plugin);
145   struct st_plugin_dl *plugin_dl= plugin_dlib(plugin);
146   CHARSET_INFO *cs= system_charset_info;
147   char version_buf[20];
148 
149   restore_record(table, s->default_values);
150 
151   table->field[0]->store(plugin_name(plugin)->str,
152                          plugin_name(plugin)->length, cs);
153 
154   table->field[1]->store(version_buf,
155         make_version_string(version_buf, sizeof(version_buf), plug->version),
156         cs);
157 
158 
159   switch (plugin_state(plugin)) {
160   /* case PLUGIN_IS_FREED: does not happen */
161   case PLUGIN_IS_DELETED:
162     table->field[2]->store(STRING_WITH_LEN("DELETED"), cs);
163     break;
164   case PLUGIN_IS_UNINITIALIZED:
165     table->field[2]->store(STRING_WITH_LEN("INACTIVE"), cs);
166     break;
167   case PLUGIN_IS_READY:
168     table->field[2]->store(STRING_WITH_LEN("ACTIVE"), cs);
169     break;
170   case PLUGIN_IS_DISABLED:
171     table->field[2]->store(STRING_WITH_LEN("DISABLED"), cs);
172     break;
173   default:
174     DBUG_ASSERT(0);
175   }
176 
177   table->field[3]->store(plugin_type_names[plug->type].str,
178                          plugin_type_names[plug->type].length,
179                          cs);
180   table->field[4]->store(version_buf,
181         make_version_string(version_buf, sizeof(version_buf),
182                             *(uint *)plug->info), cs);
183 
184   if (plugin_dl)
185   {
186     table->field[5]->store(plugin_dl->dl.str, plugin_dl->dl.length, cs);
187     table->field[5]->set_notnull();
188     table->field[6]->store(version_buf,
189           make_version_string(version_buf, sizeof(version_buf),
190                               plugin_dl->version),
191           cs);
192     table->field[6]->set_notnull();
193   }
194   else
195   {
196     table->field[5]->set_null();
197     table->field[6]->set_null();
198   }
199 
200 
201   if (plug->author)
202   {
203     table->field[7]->store(plug->author, strlen(plug->author), cs);
204     table->field[7]->set_notnull();
205   }
206   else
207     table->field[7]->set_null();
208 
209   if (plug->descr)
210   {
211     table->field[8]->store(plug->descr, strlen(plug->descr), cs);
212     table->field[8]->set_notnull();
213   }
214   else
215     table->field[8]->set_null();
216 
217   switch (plug->license) {
218   case PLUGIN_LICENSE_GPL:
219     table->field[9]->store(PLUGIN_LICENSE_GPL_STRING,
220                            strlen(PLUGIN_LICENSE_GPL_STRING), cs);
221     break;
222   case PLUGIN_LICENSE_BSD:
223     table->field[9]->store(PLUGIN_LICENSE_BSD_STRING,
224                            strlen(PLUGIN_LICENSE_BSD_STRING), cs);
225     break;
226   default:
227     table->field[9]->store(PLUGIN_LICENSE_PROPRIETARY_STRING,
228                            strlen(PLUGIN_LICENSE_PROPRIETARY_STRING), cs);
229     break;
230   }
231   table->field[9]->set_notnull();
232 
233   table->field[10]->store(
234     global_plugin_typelib_names[plugin_load_option(plugin)],
235     strlen(global_plugin_typelib_names[plugin_load_option(plugin)]),
236     cs);
237 
238   return schema_table_store_record(thd, table);
239 }
240 
241 
fill_plugins(THD * thd,TABLE_LIST * tables,Item * cond)242 int fill_plugins(THD *thd, TABLE_LIST *tables, Item *cond)
243 {
244   DBUG_ENTER("fill_plugins");
245   TABLE *table= tables->table;
246 
247   if (plugin_foreach_with_mask(thd, show_plugins, MYSQL_ANY_PLUGIN,
248                                ~PLUGIN_IS_FREED, table))
249     DBUG_RETURN(1);
250 
251   DBUG_RETURN(0);
252 }
253 
254 
255 /***************************************************************************
256  List all privileges supported
257 ***************************************************************************/
258 
259 struct show_privileges_st {
260   const char *privilege;
261   const char *context;
262   const char *comment;
263 };
264 
265 static struct show_privileges_st sys_privileges[]=
266 {
267   {"Alter", "Tables",  "To alter the table"},
268   {"Alter routine", "Functions,Procedures",  "To alter or drop stored functions/procedures"},
269   {"Create", "Databases,Tables,Indexes",  "To create new databases and tables"},
270   {"Create routine","Databases","To use CREATE FUNCTION/PROCEDURE"},
271   {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
272   {"Create view", "Tables",  "To create new views"},
273   {"Create user", "Server Admin",  "To create new users"},
274   {"Delete", "Tables",  "To delete existing rows"},
275   {"Drop", "Databases,Tables", "To drop databases, tables, and views"},
276 #ifdef HAVE_EVENT_SCHEDULER
277   {"Event","Server Admin","To create, alter, drop and execute events"},
278 #endif
279   {"Execute", "Functions,Procedures", "To execute stored routines"},
280   {"File", "File access on server",   "To read and write files on the server"},
281   {"Grant option",  "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"},
282   {"Index", "Tables",  "To create or drop indexes"},
283   {"Insert", "Tables",  "To insert data into tables"},
284   {"Lock tables","Databases","To use LOCK TABLES (together with SELECT privilege)"},
285   {"Process", "Server Admin", "To view the plain text of currently executing queries"},
286   {"Proxy", "Server Admin", "To make proxy user possible"},
287   {"References", "Databases,Tables", "To have references on tables"},
288   {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
289   {"Replication client","Server Admin","To ask where the slave or master servers are"},
290   {"Replication slave","Server Admin","To read binary log events from the master"},
291   {"Select", "Tables",  "To retrieve rows from table"},
292   {"Show databases","Server Admin","To see all databases with SHOW DATABASES"},
293   {"Show view","Tables","To see views with SHOW CREATE VIEW"},
294   {"Shutdown","Server Admin", "To shut down the server"},
295   {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
296   {"Trigger","Tables", "To use triggers"},
297   {"Create tablespace", "Server Admin", "To create/alter/drop tablespaces"},
298   {"Update", "Tables",  "To update existing rows"},
299   {"Usage","Server Admin","No privileges - allow connect only"},
300   {NullS, NullS, NullS}
301 };
302 
mysqld_show_privileges(THD * thd)303 bool mysqld_show_privileges(THD *thd)
304 {
305   List<Item> field_list;
306   Protocol *protocol= thd->protocol;
307   DBUG_ENTER("mysqld_show_privileges");
308 
309   field_list.push_back(new Item_empty_string("Privilege",10));
310   field_list.push_back(new Item_empty_string("Context",15));
311   field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
312 
313   if (protocol->send_result_set_metadata(&field_list,
314                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
315     DBUG_RETURN(TRUE);
316 
317   show_privileges_st *privilege= sys_privileges;
318   for (privilege= sys_privileges; privilege->privilege ; privilege++)
319   {
320     protocol->prepare_for_resend();
321     protocol->store(privilege->privilege, system_charset_info);
322     protocol->store(privilege->context, system_charset_info);
323     protocol->store(privilege->comment, system_charset_info);
324     if (protocol->write())
325       DBUG_RETURN(TRUE);
326   }
327   my_eof(thd);
328   DBUG_RETURN(FALSE);
329 }
330 
331 
332 /** Hash of LEX_STRINGs used to search for ignored db directories. */
333 static HASH ignore_db_dirs_hash;
334 
335 /**
336   An array of LEX_STRING pointers to collect the options at
337   option parsing time.
338 */
339 static DYNAMIC_ARRAY ignore_db_dirs_array;
340 
341 /**
342   A value for the read only system variable to show a list of
343   ignored directories.
344 */
345 char *opt_ignore_db_dirs= NULL;
346 
347 
348 /**
349   Sets up the data structures for collection of directories at option
350   processing time.
351   We need to collect the directories in an array first, because
352   we need the character sets initialized before setting up the hash.
353 
354   @return state
355   @retval TRUE  failed
356   @retval FALSE success
357 */
358 
359 bool
ignore_db_dirs_init()360 ignore_db_dirs_init()
361 {
362   return my_init_dynamic_array(&ignore_db_dirs_array, sizeof(LEX_STRING *),
363                                0, 0);
364 }
365 
366 
367 /**
368   Retrieves the key (the string itself) from the LEX_STRING hash members.
369 
370   Needed by hash_init().
371 
372   @param     data         the data element from the hash
373   @param out len_ret      Placeholder to return the length of the key
374   @param                  unused
375   @return                 a pointer to the key
376 */
377 
378 static uchar *
db_dirs_hash_get_key(const uchar * data,size_t * len_ret,my_bool MY_ATTRIBUTE ((unused)))379 db_dirs_hash_get_key(const uchar *data, size_t *len_ret,
380                      my_bool MY_ATTRIBUTE((unused)))
381 {
382   LEX_STRING *e= (LEX_STRING *) data;
383 
384   *len_ret= e->length;
385   return (uchar *) e->str;
386 }
387 
388 
389 /**
390   Wrap a directory name into a LEX_STRING and push it to the array.
391 
392   Called at option processing time for each --ignore-db-dir option.
393 
394   @param    path  the name of the directory to push
395   @return state
396   @retval TRUE  failed
397   @retval FALSE success
398 */
399 
400 bool
push_ignored_db_dir(char * path)401 push_ignored_db_dir(char *path)
402 {
403   LEX_STRING *new_elt;
404   char *new_elt_buffer;
405   size_t path_len= strlen(path);
406 
407   if (!path_len || path_len >= FN_REFLEN)
408     return true;
409 
410   // No need to normalize, it's only a directory name, not a path.
411   if (!my_multi_malloc(0,
412                        &new_elt, sizeof(LEX_STRING),
413                        &new_elt_buffer, path_len + 1,
414                        NullS))
415     return true;
416   new_elt->str= new_elt_buffer;
417   memcpy(new_elt_buffer, path, path_len);
418   new_elt_buffer[path_len]= 0;
419   new_elt->length= path_len;
420   return insert_dynamic(&ignore_db_dirs_array, &new_elt);
421 }
422 
423 
424 /**
425   Clean up the directory ignore options accumulated so far.
426 
427   Called at option processing time for each --ignore-db-dir option
428   with an empty argument.
429 */
430 
431 void
ignore_db_dirs_reset()432 ignore_db_dirs_reset()
433 {
434   LEX_STRING **elt;
435   while (NULL!= (elt= (LEX_STRING **) pop_dynamic(&ignore_db_dirs_array)))
436     if (elt && *elt)
437       my_free(*elt);
438 }
439 
440 
441 /**
442   Free the directory ignore option variables.
443 
444   Called at server shutdown.
445 */
446 
447 void
ignore_db_dirs_free()448 ignore_db_dirs_free()
449 {
450   if (opt_ignore_db_dirs)
451   {
452     my_free(opt_ignore_db_dirs);
453     opt_ignore_db_dirs= NULL;
454   }
455   ignore_db_dirs_reset();
456   delete_dynamic(&ignore_db_dirs_array);
457   my_hash_free(&ignore_db_dirs_hash);
458 }
459 
460 
461 /**
462   Initialize the ignore db directories hash and status variable from
463   the options collected in the array.
464 
465   Called when option processing is over and the server's in-memory
466   structures are fully initialized.
467 
468   @return state
469   @retval TRUE  failed
470   @retval FALSE success
471 */
472 
473 bool
ignore_db_dirs_process_additions()474 ignore_db_dirs_process_additions()
475 {
476   ulong i;
477   size_t len;
478   char *ptr;
479   LEX_STRING *dir;
480 
481   DBUG_ASSERT(opt_ignore_db_dirs == NULL);
482 
483   if (my_hash_init(&ignore_db_dirs_hash,
484                    lower_case_table_names ?
485                      character_set_filesystem : &my_charset_bin,
486                    0, 0, 0, db_dirs_hash_get_key,
487                    my_free,
488                    HASH_UNIQUE))
489     return true;
490 
491   /* len starts from 1 because of the terminating zero. */
492   len= 1;
493   for (i= 0; i < ignore_db_dirs_array.elements; i++)
494   {
495     get_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i);
496     len+= dir->length + 1;                      // +1 for the comma
497   }
498 
499   /* No delimiter for the last directory. */
500   if (len > 1)
501     len--;
502 
503   /* +1 the terminating zero */
504   ptr= opt_ignore_db_dirs= (char *) my_malloc(len + 1, MYF(0));
505   if (!ptr)
506     return true;
507 
508   /* Make sure we have an empty string to start with. */
509   *ptr= 0;
510 
511   for (i= 0; i < ignore_db_dirs_array.elements; i++)
512   {
513     get_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i);
514     if (my_hash_insert(&ignore_db_dirs_hash, (uchar *) dir))
515       return true;
516     ptr= strnmov(ptr, dir->str, dir->length);
517     if (i + 1 < ignore_db_dirs_array.elements)
518       ptr= strmov(ptr, ",");
519 
520     /*
521       Set the transferred array element to NULL to avoid double free
522       in case of error.
523     */
524     dir= NULL;
525     set_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i);
526   }
527 
528   /* make sure the string is terminated */
529   DBUG_ASSERT(ptr - opt_ignore_db_dirs <= (ptrdiff_t) len);
530   *ptr= 0;
531 
532   /*
533     It's OK to empty the array here as the allocated elements are
534     referenced through the hash now.
535   */
536   reset_dynamic(&ignore_db_dirs_array);
537 
538   return false;
539 }
540 
541 
542 /**
543   Check if a directory name is in the hash of ignored directories.
544 
545   @return search result
546   @retval TRUE  found
547   @retval FALSE not found
548 */
549 
550 static inline bool
is_in_ignore_db_dirs_list(const char * directory)551 is_in_ignore_db_dirs_list(const char *directory)
552 {
553   return ignore_db_dirs_hash.records &&
554     NULL != my_hash_search(&ignore_db_dirs_hash, (const uchar *) directory,
555                            strlen(directory));
556 }
557 
558 
559 /*
560   find_files() - find files in a given directory.
561 
562   SYNOPSIS
563     find_files()
564     thd                 thread handler
565     files               put found files in this list
566     db                  database name to set in TABLE_LIST structure
567     path                path to database
568     wild                filter for found files
569     dir                 read databases in path if TRUE, read .frm files in
570                         database otherwise
571 
572   RETURN
573     FIND_FILES_OK       success
574     FIND_FILES_OOM      out of memory error
575     FIND_FILES_DIR      no such directory, or directory can't be read
576 */
577 
578 
579 find_files_result
find_files(THD * thd,List<LEX_STRING> * files,const char * db,const char * path,const char * wild,bool dir,MEM_ROOT * tmp_mem_root)580 find_files(THD *thd, List<LEX_STRING> *files, const char *db,
581            const char *path, const char *wild, bool dir, MEM_ROOT *tmp_mem_root)
582 {
583   uint i;
584   MY_DIR *dirp;
585   MEM_ROOT **root_ptr= NULL, *old_root= NULL;
586 #ifndef NO_EMBEDDED_ACCESS_CHECKS
587   uint col_access=thd->col_access;
588 #endif
589   uint wild_length= 0;
590   TABLE_LIST table_list;
591   DBUG_ENTER("find_files");
592 
593   if (wild)
594   {
595     if (!wild[0])
596       wild= 0;
597     else
598       wild_length= strlen(wild);
599   }
600 
601 
602 
603   memset(static_cast<void*>(&table_list), 0, sizeof(table_list));
604 
605   if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0))))
606   {
607     if (my_errno == ENOENT)
608       my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db);
609     else
610     {
611       char errbuf[MYSYS_STRERROR_SIZE];
612       my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path,
613                my_errno, my_strerror(errbuf, sizeof(errbuf), my_errno));
614     }
615     DBUG_RETURN(FIND_FILES_DIR);
616   }
617 
618   if (tmp_mem_root)
619   {
620     root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
621     old_root= *root_ptr;
622     *root_ptr= tmp_mem_root;
623   }
624 
625   for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
626   {
627     char uname[NAME_LEN + 1];                   /* Unencoded name */
628     FILEINFO *file;
629     LEX_STRING *file_name= 0;
630     uint file_name_len;
631     char *ext;
632 
633     file=dirp->dir_entry+i;
634     if (dir)
635     {                                           /* Return databases */
636       /*
637         Ignore all the directories having names that start with a  dot (.).
638         This covers '.' and '..' and other cases like e.g. '.mysqlgui'.
639         Note that since 5.1 database directory names can't start with a
640         dot (.) thanks to table name encoding.
641       */
642       if (file->name[0]  == '.')
643         continue;
644 #ifdef USE_SYMDIR
645       char buff[FN_REFLEN];
646       if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
647       {
648 	/* Only show the sym file if it points to a directory */
649 	char *end;
650         my_bool not_used;
651         *ext=0;                                 /* Remove extension */
652 	unpack_dirname(buff, file->name, &not_used);
653 	end= strend(buff);
654 	if (end != buff && end[-1] == FN_LIBCHAR)
655 	  end[-1]= 0;				// Remove end FN_LIBCHAR
656         if (!mysql_file_stat(key_file_misc, buff, file->mystat, MYF(0)))
657                continue;
658        }
659 #endif
660       if (!MY_S_ISDIR(file->mystat->st_mode))
661         continue;
662 
663       if (is_in_ignore_db_dirs_list(file->name))
664         continue;
665 
666     }
667     else
668     {
669         // Return only .frm files which aren't temp files.
670       if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),reg_ext) ||
671           is_prefix(file->name, tmp_file_prefix))
672         continue;
673       *ext=0;
674     }
675 
676     file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
677 
678     if (wild)
679     {
680       if (lower_case_table_names)
681       {
682         if (my_wildcmp(files_charset_info,
683                        uname, uname + file_name_len,
684                        wild, wild + wild_length,
685                        wild_prefix, wild_one,wild_many))
686           continue;
687       }
688       else if (wild_compare(uname, wild, 0))
689         continue;
690     }
691 
692 #ifndef NO_EMBEDDED_ACCESS_CHECKS
693     /* Don't show tables where we don't have any privileges */
694     if (db && !(col_access & TABLE_ACLS))
695     {
696       table_list.db= (char*) db;
697       table_list.db_length= strlen(db);
698       table_list.table_name= uname;
699       table_list.table_name_length= file_name_len;
700       table_list.grant.privilege=col_access;
701       if (check_grant(thd, TABLE_ACLS, &table_list, TRUE, 1, TRUE))
702         continue;
703     }
704 #endif
705     if (!(file_name= tmp_mem_root ?
706                      make_lex_string_root(tmp_mem_root, file_name, uname,
707                                           file_name_len, TRUE) :
708                      thd->make_lex_string(file_name, uname,
709                                           file_name_len, TRUE)) ||
710         files->push_back(file_name))
711     {
712       my_dirend(dirp);
713       DBUG_RETURN(FIND_FILES_OOM);
714     }
715   }
716   DBUG_PRINT("info",("found: %d files", files->elements));
717   my_dirend(dirp);
718 
719   (void) ha_find_files(thd, db, path, wild, dir, files);
720 
721   if (tmp_mem_root)
722     *root_ptr= old_root;
723 
724   DBUG_RETURN(FIND_FILES_OK);
725 }
726 
727 
728 /**
729    An Internal_error_handler that suppresses errors regarding views'
730    underlying tables that occur during privilege checking within SHOW CREATE
731    VIEW commands. This happens in the cases when
732 
733    - A view's underlying table (e.g. referenced in its SELECT list) does not
734      exist. There should not be an error as no attempt was made to access it
735      per se.
736 
737    - Access is denied for some table, column, function or stored procedure
738      such as mentioned above. This error gets raised automatically, since we
739      can't untangle its access checking from that of the view itself.
740  */
741 class Show_create_error_handler : public Internal_error_handler {
742 
743   TABLE_LIST *m_top_view;
744   bool m_handling;
745   Security_context *m_sctx;
746 
747   char m_view_access_denied_message[MYSQL_ERRMSG_SIZE];
748   char *m_view_access_denied_message_ptr;
749 
750 public:
751 
752   /**
753      Creates a new Show_create_error_handler for the particular security
754      context and view.
755 
756      @thd Thread context, used for security context information if needed.
757      @top_view The view. We do not verify at this point that top_view is in
758      fact a view since, alas, these things do not stay constant.
759   */
Show_create_error_handler(THD * thd,TABLE_LIST * top_view)760   explicit Show_create_error_handler(THD *thd, TABLE_LIST *top_view) :
761     m_top_view(top_view), m_handling(FALSE),
762     m_view_access_denied_message_ptr(NULL)
763   {
764 
765     m_sctx = MY_TEST(m_top_view->security_ctx) ?
766       m_top_view->security_ctx : thd->security_ctx;
767   }
768 
769   /**
770      Lazy instantiation of 'view access denied' message. The purpose of the
771      Show_create_error_handler is to hide details of underlying tables for
772      which we have no privileges behind ER_VIEW_INVALID messages. But this
773      obviously does not apply if we lack privileges on the view itself.
774      Unfortunately the information about for which table privilege checking
775      failed is not available at this point. The only way for us to check is by
776      reconstructing the actual error message and see if it's the same.
777   */
get_view_access_denied_message()778   char* get_view_access_denied_message()
779   {
780     if (!m_view_access_denied_message_ptr)
781     {
782       m_view_access_denied_message_ptr= m_view_access_denied_message;
783       my_snprintf(m_view_access_denied_message, MYSQL_ERRMSG_SIZE,
784                   ER(ER_TABLEACCESS_DENIED_ERROR), "SHOW VIEW",
785                   m_sctx->priv_user,
786                   m_sctx->host_or_ip, m_top_view->get_table_name());
787     }
788     return m_view_access_denied_message_ptr;
789   }
790 
handle_condition(THD * thd,uint sql_errno,const char *,Sql_condition::enum_warning_level level,const char * message,Sql_condition **)791   bool handle_condition(THD *thd, uint sql_errno, const char * /* sqlstate */,
792                         Sql_condition::enum_warning_level level,
793                         const char *message, Sql_condition ** /* cond_hdl */)
794   {
795     /*
796        The handler does not handle the errors raised by itself.
797        At this point we know if top_view is really a view.
798     */
799     if (m_handling || !m_top_view->view)
800       return FALSE;
801 
802     m_handling= TRUE;
803 
804     bool is_handled;
805 
806     switch (sql_errno)
807     {
808     case ER_TABLEACCESS_DENIED_ERROR:
809       if (!strcmp(get_view_access_denied_message(), message))
810       {
811         /* Access to top view is not granted, don't interfere. */
812         is_handled= FALSE;
813         break;
814       }
815       // fallthrough
816     case ER_COLUMNACCESS_DENIED_ERROR:
817     case ER_VIEW_NO_EXPLAIN: /* Error was anonymized, ignore all the same. */
818     case ER_PROCACCESS_DENIED_ERROR:
819       is_handled= TRUE;
820       break;
821 
822     case ER_NO_SUCH_TABLE:
823       /* Established behavior: warn if underlying tables are missing. */
824       push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
825                           ER_VIEW_INVALID,
826                           ER(ER_VIEW_INVALID),
827                           m_top_view->get_db_name(),
828                           m_top_view->get_table_name());
829       is_handled= TRUE;
830       break;
831 
832     case ER_SP_DOES_NOT_EXIST:
833       /* Established behavior: warn if underlying functions are missing. */
834       push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
835                           ER_VIEW_INVALID,
836                           ER(ER_VIEW_INVALID),
837                           m_top_view->get_db_name(),
838                           m_top_view->get_table_name());
839       is_handled= TRUE;
840       break;
841     default:
842       is_handled= FALSE;
843     }
844 
845     m_handling= FALSE;
846     return is_handled;
847   }
848 };
849 
850 
851 bool
mysqld_show_create(THD * thd,TABLE_LIST * table_list)852 mysqld_show_create(THD *thd, TABLE_LIST *table_list)
853 {
854   Protocol *protocol= thd->protocol;
855   char buff[2048];
856   String buffer(buff, sizeof(buff), system_charset_info);
857   List<Item> field_list;
858   bool error= TRUE;
859   DBUG_ENTER("mysqld_show_create");
860   DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
861                       table_list->table_name));
862 
863   /*
864     Metadata locks taken during SHOW CREATE should be released when
865     the statmement completes as it is an information statement.
866   */
867   MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
868 
869   /* We want to preserve the tree for views. */
870   thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
871 
872   {
873     /*
874       Use open_tables() directly rather than open_normal_and_derived_tables().
875       This ensures that close_thread_tables() is not called if open tables fails
876       and the error is ignored. This allows us to handle broken views nicely.
877     */
878     uint counter;
879     Show_create_error_handler view_error_suppressor(thd, table_list);
880     thd->push_internal_handler(&view_error_suppressor);
881     bool open_error=
882       open_tables(thd, &table_list, &counter,
883                   MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) ||
884                   mysql_handle_derived(thd->lex, &mysql_derived_prepare);
885     thd->pop_internal_handler();
886     if (open_error && (thd->killed || thd->is_error()))
887       goto exit;
888   }
889 
890   /* TODO: add environment variables show when it become possible */
891   if (thd->lex->only_view && !table_list->view)
892   {
893     my_error(ER_WRONG_OBJECT, MYF(0),
894              table_list->db, table_list->table_name, "VIEW");
895     goto exit;
896   }
897 
898   buffer.length(0);
899 
900   if (table_list->view)
901     buffer.set_charset(table_list->view_creation_ctx->get_client_cs());
902 
903   if ((table_list->view ?
904        view_store_create_info(thd, table_list, &buffer) :
905        store_create_info(thd, table_list, &buffer, NULL,
906                          FALSE /* show_database */)))
907     goto exit;
908 
909   if (table_list->view)
910   {
911     field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN));
912     field_list.push_back(new Item_empty_string("Create View",
913                                                max(buffer.length(), 1024U)));
914     field_list.push_back(new Item_empty_string("character_set_client",
915                                                MY_CS_NAME_SIZE));
916     field_list.push_back(new Item_empty_string("collation_connection",
917                                                MY_CS_NAME_SIZE));
918   }
919   else
920   {
921     field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
922     // 1024 is for not to confuse old clients
923     field_list.push_back(new Item_empty_string("Create Table",
924                                                max(buffer.length(), 1024U)));
925   }
926 
927   if (protocol->send_result_set_metadata(&field_list,
928                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
929     goto exit;
930 
931   protocol->prepare_for_resend();
932   if (table_list->view)
933     protocol->store(table_list->view_name.str, system_charset_info);
934   else
935   {
936     if (table_list->schema_table)
937       protocol->store(table_list->schema_table->table_name,
938                       system_charset_info);
939     else
940       protocol->store(table_list->table->alias, system_charset_info);
941   }
942 
943   if (table_list->view)
944   {
945     protocol->store(buffer.ptr(), buffer.length(),
946                     table_list->view_creation_ctx->get_client_cs());
947 
948     protocol->store(table_list->view_creation_ctx->get_client_cs()->csname,
949                     system_charset_info);
950 
951     protocol->store(table_list->view_creation_ctx->get_connection_cl()->name,
952                     system_charset_info);
953   }
954   else
955     protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
956 
957   if (protocol->write())
958     goto exit;
959 
960   error= FALSE;
961   my_eof(thd);
962 
963 exit:
964   close_thread_tables(thd);
965   /* Release any metadata locks taken during SHOW CREATE. */
966   thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
967   DBUG_RETURN(error);
968 }
969 
mysqld_show_create_db(THD * thd,char * dbname,HA_CREATE_INFO * create_info)970 bool mysqld_show_create_db(THD *thd, char *dbname,
971                            HA_CREATE_INFO *create_info)
972 {
973   char buff[2048], orig_dbname[NAME_LEN];
974   String buffer(buff, sizeof(buff), system_charset_info);
975 #ifndef NO_EMBEDDED_ACCESS_CHECKS
976   Security_context *sctx= thd->security_ctx;
977   uint db_access;
978 #endif
979   HA_CREATE_INFO create;
980   uint create_options = create_info ? create_info->options : 0;
981   Protocol *protocol=thd->protocol;
982   DBUG_ENTER("mysql_show_create_db");
983 
984   strcpy(orig_dbname, dbname);
985   if (lower_case_table_names && dbname != any_db)
986     my_casedn_str(files_charset_info, dbname);
987 
988 #ifndef NO_EMBEDDED_ACCESS_CHECKS
989   if (test_all_bits(sctx->master_access, DB_ACLS))
990     db_access=DB_ACLS;
991   else
992     db_access= (acl_get(sctx->get_host()->ptr(), sctx->get_ip()->ptr(),
993                         sctx->priv_user, dbname, 0) | sctx->master_access);
994   if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname))
995   {
996     thd->diff_access_denied_errors++;
997     my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
998              sctx->priv_user, sctx->host_or_ip, dbname);
999     general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
1000                       sctx->priv_user, sctx->host_or_ip, dbname);
1001     DBUG_RETURN(TRUE);
1002   }
1003 #endif
1004   if (is_infoschema_db(dbname))
1005   {
1006     dbname= INFORMATION_SCHEMA_NAME.str;
1007     create.default_table_charset= system_charset_info;
1008   }
1009   else
1010   {
1011     if (check_db_dir_existence(dbname))
1012     {
1013       my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
1014       DBUG_RETURN(TRUE);
1015     }
1016 
1017     load_db_opt_by_name(thd, dbname, &create);
1018   }
1019   List<Item> field_list;
1020   field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
1021   field_list.push_back(new Item_empty_string("Create Database",1024));
1022 
1023   if (protocol->send_result_set_metadata(&field_list,
1024                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
1025     DBUG_RETURN(TRUE);
1026 
1027   protocol->prepare_for_resend();
1028   protocol->store(orig_dbname, strlen(orig_dbname), system_charset_info);
1029   buffer.length(0);
1030   buffer.append(STRING_WITH_LEN("CREATE DATABASE "));
1031   if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
1032     buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ "));
1033   append_identifier(thd, &buffer, orig_dbname, strlen(orig_dbname));
1034 
1035   if (create.default_table_charset)
1036   {
1037     buffer.append(STRING_WITH_LEN(" /*!40100"));
1038     buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET "));
1039     buffer.append(create.default_table_charset->csname);
1040     if (!(create.default_table_charset->state & MY_CS_PRIMARY))
1041     {
1042       buffer.append(STRING_WITH_LEN(" COLLATE "));
1043       buffer.append(create.default_table_charset->name);
1044     }
1045     buffer.append(STRING_WITH_LEN(" */"));
1046   }
1047   protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
1048 
1049   if (protocol->write())
1050     DBUG_RETURN(TRUE);
1051   my_eof(thd);
1052   DBUG_RETURN(FALSE);
1053 }
1054 
1055 
1056 
1057 /****************************************************************************
1058   Return only fields for API mysql_list_fields
1059   Use "show table wildcard" in mysql instead of this
1060 ****************************************************************************/
1061 
1062 void
mysqld_list_fields(THD * thd,TABLE_LIST * table_list,const char * wild)1063 mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
1064 {
1065   TABLE *table;
1066   DBUG_ENTER("mysqld_list_fields");
1067   DBUG_PRINT("enter",("table: %s",table_list->table_name));
1068 
1069   if (open_normal_and_derived_tables(thd, table_list,
1070                                      MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
1071     DBUG_VOID_RETURN;
1072   table= table_list->table;
1073   /* Create derived tables result table prior to reading it's fields list. */
1074   mysql_handle_single_derived(thd->lex, table_list, &mysql_derived_create);
1075   List<Item> field_list;
1076 
1077   Field **ptr,*field;
1078   for (ptr=table->field ; (field= *ptr); ptr++)
1079   {
1080     if (!wild || !wild[0] ||
1081         !wild_case_compare(system_charset_info, field->field_name,wild))
1082     {
1083       if (table_list->view)
1084         field_list.push_back(new Item_ident_for_show(field,
1085                                                      table_list->view_db.str,
1086                                                      table_list->view_name.str));
1087       else
1088         field_list.push_back(new Item_field(field));
1089     }
1090   }
1091   restore_record(table, s->default_values);              // Get empty record
1092   table->use_all_columns();
1093   if (thd->protocol->send_result_set_metadata(&field_list, Protocol::SEND_DEFAULTS))
1094     DBUG_VOID_RETURN;
1095   my_eof(thd);
1096   DBUG_VOID_RETURN;
1097 }
1098 
1099 /*
1100   Go through all character combinations and ensure that sql_lex.cc can
1101   parse it as an identifier.
1102 
1103   SYNOPSIS
1104   require_quotes()
1105   name			attribute name
1106   name_length		length of name
1107 
1108   RETURN
1109     #	Pointer to conflicting character
1110     0	No conflicting character
1111 */
1112 
require_quotes(const char * name,uint name_length)1113 static const char *require_quotes(const char *name, uint name_length)
1114 {
1115   bool pure_digit= TRUE;
1116   const char *end= name + name_length;
1117 
1118   for (; name < end ; name++)
1119   {
1120     uchar chr= (uchar) *name;
1121     uint length= my_mbcharlen(system_charset_info, chr);
1122     if (length == 0 || (length == 1 && !system_charset_info->ident_map[chr]))
1123       return name;
1124     if (length == 1 && (chr < '0' || chr > '9'))
1125       pure_digit= FALSE;
1126   }
1127   if (pure_digit)
1128     return name;
1129   return 0;
1130 }
1131 
1132 
1133 /**
1134   Convert and quote the given identifier if needed and append it to the
1135   target string. If the given identifier is empty, it will be quoted.
1136   @thd                         thread handler
1137   @packet                      target string
1138   @name                        the identifier to be appended
1139   @length                      length of the appending identifier
1140   @param from_cs               Charset information about the input string
1141   @param to_cs                 Charset information about the target string
1142 */
1143 
1144 void
append_identifier(THD * thd,String * packet,const char * name,uint length,const CHARSET_INFO * from_cs,const CHARSET_INFO * to_cs)1145 append_identifier(THD *thd, String *packet, const char *name, uint length,
1146                   const CHARSET_INFO *from_cs, const CHARSET_INFO *to_cs)
1147 {
1148   const char *name_end;
1149   char quote_char;
1150   int q;
1151 
1152   const CHARSET_INFO *cs_info= system_charset_info;
1153   const char *to_name= name;
1154   size_t to_length= length;
1155   String to_string(name,length, from_cs);
1156 
1157   if (from_cs != NULL && to_cs != NULL && from_cs != to_cs)
1158     thd->convert_string(&to_string, from_cs, to_cs);
1159 
1160   if (to_cs != NULL)
1161   {
1162     to_name= to_string.c_ptr();
1163     to_length= to_string.length();
1164     cs_info= to_cs;
1165   }
1166 
1167   q= thd ? get_quote_char_for_identifier(thd, to_name, to_length) : '`';
1168   if (q == EOF)
1169   {
1170     packet->append(to_name, to_length, packet->charset());
1171     return;
1172   }
1173 
1174   /*
1175     The identifier must be quoted as it includes a quote character or
1176    it's a keyword
1177   */
1178 
1179   (void) packet->reserve(to_length*2 + 2);
1180   quote_char= (char) q;
1181   packet->append(&quote_char, 1, system_charset_info);
1182 
1183   for (name_end= to_name+to_length ; to_name < name_end ; to_name+= to_length)
1184   {
1185     uchar chr= (uchar) *to_name;
1186     to_length= my_mbcharlen(cs_info, chr);
1187     /*
1188       my_mbcharlen can return 0 on a wrong multibyte
1189       sequence. It is possible when upgrading from 4.0,
1190       and identifier contains some accented characters.
1191       The manual says it does not work. So we'll just
1192       change length to 1 not to hang in the endless loop.
1193     */
1194     if (!to_length)
1195       to_length= 1;
1196     if (to_length == 1 && chr == (uchar) quote_char)
1197       packet->append(&quote_char, 1, system_charset_info);
1198     packet->append(to_name, to_length, system_charset_info);
1199   }
1200   packet->append(&quote_char, 1, system_charset_info);
1201 }
1202 
1203 
1204 /*
1205   Get the quote character for displaying an identifier.
1206 
1207   SYNOPSIS
1208     get_quote_char_for_identifier()
1209     thd		Thread handler
1210     name	name to quote
1211     length	length of name
1212 
1213   IMPLEMENTATION
1214     Force quoting in the following cases:
1215       - name is empty (for one, it is possible when we use this function for
1216         quoting user and host names for DEFINER clause);
1217       - name is a keyword;
1218       - name includes a special character;
1219     Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE
1220     is set.
1221 
1222   RETURN
1223     EOF	  No quote character is needed
1224     #	  Quote character
1225 */
1226 
get_quote_char_for_identifier(THD * thd,const char * name,uint length)1227 int get_quote_char_for_identifier(THD *thd, const char *name, uint length)
1228 {
1229   if (length &&
1230       !is_keyword(name,length) &&
1231       !require_quotes(name, length) &&
1232       !(thd->variables.option_bits & OPTION_QUOTE_SHOW_CREATE))
1233     return EOF;
1234   if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
1235     return '"';
1236   return '`';
1237 }
1238 
1239 
1240 /* Append directory name (if exists) to CREATE INFO */
1241 
append_directory(THD * thd,String * packet,const char * dir_type,const char * filename)1242 static void append_directory(THD *thd, String *packet, const char *dir_type,
1243 			     const char *filename)
1244 {
1245   if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
1246   {
1247     uint length= dirname_length(filename);
1248     packet->append(' ');
1249     packet->append(dir_type);
1250     packet->append(STRING_WITH_LEN(" DIRECTORY='"));
1251 #ifdef __WIN__
1252     /* Convert \ to / to be able to create table on unix */
1253     char *winfilename= (char*) thd->memdup(filename, length);
1254     char *pos, *end;
1255     for (pos= winfilename, end= pos+length ; pos < end ; pos++)
1256     {
1257       if (*pos == '\\')
1258         *pos = '/';
1259     }
1260     filename= winfilename;
1261 #endif
1262     packet->append(filename, length);
1263     packet->append('\'');
1264   }
1265 }
1266 
1267 
1268 /**
1269   Print "ON UPDATE" clause of a field into a string.
1270 
1271   @param timestamp_field   Pointer to timestamp field of a table.
1272   @param field             The field to generate ON UPDATE clause for.
1273   @bool  lcase             Whether to print in lower case.
1274   @return                  false on success, true on error.
1275 */
print_on_update_clause(Field * field,String * val,bool lcase)1276 static bool print_on_update_clause(Field *field, String *val, bool lcase)
1277 {
1278   DBUG_ASSERT(val->charset()->mbminlen == 1);
1279   val->length(0);
1280   if (field->has_update_default_function())
1281   {
1282     if (lcase)
1283       val->copy(STRING_WITH_LEN("on update "), val->charset());
1284     else
1285       val->copy(STRING_WITH_LEN("ON UPDATE "), val->charset());
1286     val->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
1287     if (field->decimals() > 0)
1288       val->append_parenthesized(field->decimals());
1289     return true;
1290   }
1291   return false;
1292 }
1293 
1294 
print_default_clause(THD * thd,Field * field,String * def_value,bool quoted)1295 static bool print_default_clause(THD *thd, Field *field, String *def_value,
1296                                  bool quoted)
1297 {
1298   enum enum_field_types field_type= field->type();
1299 
1300   const bool has_now_default= field->has_insert_default_function();
1301   const bool has_default=
1302     (field_type != FIELD_TYPE_BLOB &&
1303      !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
1304      field->unireg_check != Field::NEXT_NUMBER &&
1305      !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
1306        && has_now_default));
1307 
1308   def_value->length(0);
1309   if (has_default)
1310   {
1311     if (has_now_default)
1312       /*
1313         We are using CURRENT_TIMESTAMP instead of NOW because it is the SQL
1314         standard.
1315       */
1316     {
1317       def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
1318       if (field->decimals() > 0)
1319         def_value->append_parenthesized(field->decimals());
1320     }
1321     else if (!field->is_null())
1322     {                                             // Not null by default
1323       char tmp[MAX_FIELD_WIDTH];
1324       String type(tmp, sizeof(tmp), field->charset());
1325       if (field_type == MYSQL_TYPE_BIT)
1326       {
1327         longlong dec= field->val_int();
1328         char *ptr= longlong2str(dec, tmp + 2, 2);
1329         uint32 length= (uint32) (ptr - tmp);
1330         tmp[0]= 'b';
1331         tmp[1]= '\'';
1332         tmp[length]= '\'';
1333         type.length(length + 1);
1334         quoted= 0;
1335       }
1336       else
1337         field->val_str(&type);
1338       if (type.length())
1339       {
1340         String def_val;
1341         uint dummy_errors;
1342         /* convert to system_charset_info == utf8 */
1343         def_val.copy(type.ptr(), type.length(), field->charset(),
1344                      system_charset_info, &dummy_errors);
1345         if (quoted)
1346           append_unescaped(def_value, def_val.ptr(), def_val.length());
1347         else
1348           def_value->append(def_val.ptr(), def_val.length());
1349       }
1350       else if (quoted)
1351         def_value->append(STRING_WITH_LEN("''"));
1352     }
1353     else if (field->maybe_null() && quoted)
1354       def_value->append(STRING_WITH_LEN("NULL"));    // Null as default
1355     else
1356       return 0;
1357 
1358   }
1359   return has_default;
1360 }
1361 
1362 
1363 /*
1364   Build a CREATE TABLE statement for a table.
1365 
1366   SYNOPSIS
1367     store_create_info()
1368     thd               The thread
1369     table_list        A list containing one table to write statement
1370                       for.
1371     packet            Pointer to a string where statement will be
1372                       written.
1373     create_info_arg   Pointer to create information that can be used
1374                       to tailor the format of the statement.  Can be
1375                       NULL, in which case only SQL_MODE is considered
1376                       when building the statement.
1377     show_database     If true, then print the database before the table
1378                       name. The database name is only printed in the event
1379                       that it is different from the current database.
1380                       If false, then do not print the database before
1381                       the table name.
1382 
1383   NOTE
1384     Currently always return 0, but might return error code in the
1385     future.
1386 
1387   RETURN
1388     0       OK
1389  */
1390 
store_create_info(THD * thd,TABLE_LIST * table_list,String * packet,HA_CREATE_INFO * create_info_arg,bool show_database)1391 int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
1392                       HA_CREATE_INFO *create_info_arg, bool show_database)
1393 {
1394   List<Item> field_list;
1395   char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH];
1396   const char *alias;
1397   String type(tmp, sizeof(tmp), system_charset_info);
1398   String def_value(def_value_buf, sizeof(def_value_buf), system_charset_info);
1399   Field **ptr,*field;
1400   uint primary_key;
1401   KEY *key_info;
1402   TABLE *table= table_list->table;
1403   handler *file= table->file;
1404   TABLE_SHARE *share= table->s;
1405   HA_CREATE_INFO create_info;
1406 #ifdef WITH_PARTITION_STORAGE_ENGINE
1407   bool show_table_options= FALSE;
1408 #endif /* WITH_PARTITION_STORAGE_ENGINE */
1409   bool foreign_db_mode=  (thd->variables.sql_mode & (MODE_POSTGRESQL |
1410                                                      MODE_ORACLE |
1411                                                      MODE_MSSQL |
1412                                                      MODE_DB2 |
1413                                                      MODE_MAXDB |
1414                                                      MODE_ANSI)) != 0;
1415   bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS |
1416                                                        MODE_MYSQL323 |
1417                                                        MODE_MYSQL40)) != 0;
1418   my_bitmap_map *old_map;
1419   int error= 0;
1420   bool omit_compressed_columns_extensions= false;
1421   DBUG_ENTER("store_create_info");
1422   DBUG_PRINT("enter",("table: %s", table->s->table_name.str));
1423 
1424   restore_record(table, s->default_values); // Get empty record
1425 
1426   if (share->tmp_table)
1427     packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
1428   else
1429     packet->append(STRING_WITH_LEN("CREATE TABLE "));
1430   if (create_info_arg &&
1431       (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS))
1432     packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
1433   if (table_list->schema_table)
1434     alias= table_list->schema_table->table_name;
1435   else
1436   {
1437     if (lower_case_table_names == 2)
1438       alias= table->alias;
1439     else
1440     {
1441       alias= share->table_name.str;
1442     }
1443   }
1444 
1445   /*
1446     Print the database before the table name if told to do that. The
1447     database name is only printed in the event that it is different
1448     from the current database.  The main reason for doing this is to
1449     avoid having to update gazillions of tests and result files, but
1450     it also saves a few bytes of the binary log.
1451    */
1452   if (show_database)
1453   {
1454     const LEX_STRING *const db=
1455       table_list->schema_table ? &INFORMATION_SCHEMA_NAME : &table->s->db;
1456     if (!thd->db || strcmp(db->str, thd->db))
1457     {
1458       append_identifier(thd, packet, db->str, db->length);
1459       packet->append(STRING_WITH_LEN("."));
1460     }
1461   }
1462 
1463   append_identifier(thd, packet, alias, strlen(alias));
1464   packet->append(STRING_WITH_LEN(" (\n"));
1465   /*
1466     We need this to get default values from the table
1467     We have to restore the read_set if we are called from insert in case
1468     of row based replication.
1469   */
1470   old_map= tmp_use_all_columns(table, table->read_set);
1471 
1472   for (ptr=table->field ; (field= *ptr); ptr++)
1473   {
1474     uint flags = field->flags;
1475     enum_field_types field_type= field->real_type();
1476 
1477     if (ptr != table->field)
1478       packet->append(STRING_WITH_LEN(",\n"));
1479 
1480     packet->append(STRING_WITH_LEN("  "));
1481     append_identifier(thd,packet,field->field_name, strlen(field->field_name));
1482     packet->append(' ');
1483     // check for surprises from the previous call to Field::sql_type()
1484     if (type.ptr() != tmp)
1485       type.set(tmp, sizeof(tmp), system_charset_info);
1486     else
1487       type.set_charset(system_charset_info);
1488 
1489     field->sql_type(type);
1490     /*
1491       If the session variable 'show_old_temporals' is enabled and the field
1492       is a temporal type of old format, add a comment to indicate the same.
1493     */
1494     if (thd->variables.show_old_temporals &&
1495         (field_type == MYSQL_TYPE_TIME || field_type == MYSQL_TYPE_DATETIME ||
1496          field_type == MYSQL_TYPE_TIMESTAMP))
1497       type.append(" /* 5.5 binary format */");
1498     packet->append(type.ptr(), type.length(), system_charset_info);
1499 
1500     if (field->has_charset() &&
1501         !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
1502     {
1503       if (field->charset() != share->table_charset)
1504       {
1505 	packet->append(STRING_WITH_LEN(" CHARACTER SET "));
1506 	packet->append(field->charset()->csname);
1507       }
1508       /*
1509 	For string types dump collation name only if
1510 	collation is not primary for the given charset
1511       */
1512       if (!(field->charset()->state & MY_CS_PRIMARY))
1513       {
1514 	packet->append(STRING_WITH_LEN(" COLLATE "));
1515 	packet->append(field->charset()->name);
1516       }
1517     }
1518 
1519     if (flags & NOT_NULL_FLAG)
1520       packet->append(STRING_WITH_LEN(" NOT NULL"));
1521     else if (field->type() == MYSQL_TYPE_TIMESTAMP)
1522     {
1523       /*
1524         TIMESTAMP field require explicit NULL flag, because unlike
1525         all other fields they are treated as NOT NULL by default.
1526       */
1527       packet->append(STRING_WITH_LEN(" NULL"));
1528     }
1529 
1530     switch(field->field_storage_type()){
1531     case HA_SM_DEFAULT:
1532       break;
1533     case HA_SM_DISK:
1534       packet->append(STRING_WITH_LEN(" /*!50606 STORAGE DISK */"));
1535       break;
1536     case HA_SM_MEMORY:
1537       packet->append(STRING_WITH_LEN(" /*!50606 STORAGE MEMORY */"));
1538       break;
1539     default:
1540       DBUG_ASSERT(0);
1541       break;
1542     }
1543 
1544     switch(field->column_format()){
1545     case COLUMN_FORMAT_TYPE_DEFAULT:
1546       break;
1547     case COLUMN_FORMAT_TYPE_FIXED:
1548       packet->append(STRING_WITH_LEN(" /*!50606 COLUMN_FORMAT FIXED */"));
1549       break;
1550     case COLUMN_FORMAT_TYPE_DYNAMIC:
1551       packet->append(STRING_WITH_LEN(" /*!50606 COLUMN_FORMAT DYNAMIC */"));
1552       break;
1553     case COLUMN_FORMAT_TYPE_COMPRESSED:
1554       DBUG_EXECUTE_IF("omit_compressed_columns_show_extensions",
1555                       omit_compressed_columns_extensions= true; );
1556       if (!omit_compressed_columns_extensions)
1557       {
1558         packet->append(STRING_WITH_LEN(" /*!"
1559           STRINGIFY_ARG(FIRST_SUPPORTED_COMPRESSED_COLUMNS_VERSION)
1560           " COLUMN_FORMAT COMPRESSED"));
1561         if (field->has_associated_compression_dictionary())
1562         {
1563           packet->append(STRING_WITH_LEN(" WITH COMPRESSION_DICTIONARY "));
1564           append_identifier(thd, packet, field->zip_dict_name.str,
1565                             field->zip_dict_name.length);
1566         }
1567         packet->append(STRING_WITH_LEN(" */"));
1568       }
1569       break;
1570     default:
1571       DBUG_ASSERT(0);
1572       break;
1573     }
1574 
1575     if (print_default_clause(thd, field, &def_value, true))
1576     {
1577       packet->append(STRING_WITH_LEN(" DEFAULT "));
1578       packet->append(def_value.ptr(), def_value.length(), system_charset_info);
1579     }
1580 
1581     if (!limited_mysql_mode &&
1582         print_on_update_clause(field, &def_value, false))
1583     {
1584       packet->append(STRING_WITH_LEN(" "));
1585       packet->append(def_value);
1586     }
1587 
1588     if (field->unireg_check == Field::NEXT_NUMBER &&
1589         !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
1590       packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
1591 
1592     if (field->comment.length)
1593     {
1594       packet->append(STRING_WITH_LEN(" COMMENT "));
1595       append_unescaped(packet, field->comment.str, field->comment.length);
1596     }
1597   }
1598 
1599   key_info= table->key_info;
1600   memset(static_cast<void*>(&create_info), 0, sizeof(create_info));
1601   /* Allow update_create_info to update row type */
1602   create_info.row_type= share->row_type;
1603   file->update_create_info(&create_info);
1604   primary_key= share->primary_key;
1605 
1606   for (uint i=0 ; i < share->keys ; i++,key_info++)
1607   {
1608     KEY_PART_INFO *key_part= key_info->key_part;
1609     bool found_primary=0;
1610     packet->append(STRING_WITH_LEN(",\n  "));
1611 
1612     if (i == primary_key && !strcmp(key_info->name, primary_key_name))
1613     {
1614       found_primary=1;
1615       /*
1616         No space at end, because a space will be added after where the
1617         identifier would go, but that is not added for primary key.
1618       */
1619       packet->append(STRING_WITH_LEN("PRIMARY KEY"));
1620     }
1621     else if (key_info->flags & HA_NOSAME)
1622       packet->append(STRING_WITH_LEN("UNIQUE KEY "));
1623     else if (key_info->flags & HA_FULLTEXT)
1624       packet->append(STRING_WITH_LEN("FULLTEXT KEY "));
1625     else if (key_info->flags & HA_SPATIAL)
1626       packet->append(STRING_WITH_LEN("SPATIAL KEY "));
1627     else if (key_info->flags & HA_CLUSTERING)
1628       packet->append(STRING_WITH_LEN("CLUSTERING KEY "));
1629     else
1630       packet->append(STRING_WITH_LEN("KEY "));
1631 
1632     if (!found_primary)
1633      append_identifier(thd, packet, key_info->name, strlen(key_info->name));
1634 
1635     packet->append(STRING_WITH_LEN(" ("));
1636 
1637     for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++)
1638     {
1639       if (j)
1640         packet->append(',');
1641 
1642       if (key_part->field)
1643         append_identifier(thd,packet,key_part->field->field_name,
1644 			  strlen(key_part->field->field_name));
1645       if (key_part->field &&
1646           (key_part->length !=
1647            table->field[key_part->fieldnr-1]->key_length() &&
1648            !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))))
1649       {
1650         packet->append_parenthesized((long) key_part->length /
1651                                       key_part->field->charset()->mbmaxlen);
1652       }
1653     }
1654     packet->append(')');
1655     store_key_options(thd, packet, table, key_info);
1656     if (key_info->parser)
1657     {
1658       LEX_STRING *parser_name= plugin_name(key_info->parser);
1659       packet->append(STRING_WITH_LEN(" /*!50100 WITH PARSER "));
1660       append_identifier(thd, packet, parser_name->str, parser_name->length);
1661       packet->append(STRING_WITH_LEN(" */ "));
1662     }
1663   }
1664 
1665   /*
1666     Get possible foreign key definitions stored in InnoDB and append them
1667     to the CREATE TABLE statement
1668   */
1669 
1670   if ((for_str= file->get_foreign_key_create_info()))
1671   {
1672     packet->append(for_str, strlen(for_str));
1673     file->free_foreign_key_create_info(for_str);
1674   }
1675 
1676   packet->append(STRING_WITH_LEN("\n)"));
1677   if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
1678   {
1679 #ifdef WITH_PARTITION_STORAGE_ENGINE
1680     show_table_options= TRUE;
1681 #endif /* WITH_PARTITION_STORAGE_ENGINE */
1682 
1683     /* TABLESPACE and STORAGE */
1684     if (share->tablespace ||
1685         share->default_storage_media != HA_SM_DEFAULT)
1686     {
1687       packet->append(STRING_WITH_LEN(" /*!50100"));
1688       if (share->tablespace)
1689       {
1690         packet->append(STRING_WITH_LEN(" TABLESPACE "));
1691         packet->append(share->tablespace, strlen(share->tablespace));
1692       }
1693 
1694       if (share->default_storage_media == HA_SM_DISK)
1695         packet->append(STRING_WITH_LEN(" STORAGE DISK"));
1696       if (share->default_storage_media == HA_SM_MEMORY)
1697         packet->append(STRING_WITH_LEN(" STORAGE MEMORY"));
1698 
1699       packet->append(STRING_WITH_LEN(" */"));
1700     }
1701 
1702     /*
1703       IF   check_create_info
1704       THEN add ENGINE only if it was used when creating the table
1705     */
1706     if (!create_info_arg ||
1707         (create_info_arg->used_fields & HA_CREATE_USED_ENGINE))
1708     {
1709       if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
1710         packet->append(STRING_WITH_LEN(" TYPE="));
1711       else
1712         packet->append(STRING_WITH_LEN(" ENGINE="));
1713 #ifdef WITH_PARTITION_STORAGE_ENGINE
1714     if (table->part_info)
1715       packet->append(ha_resolve_storage_engine_name(
1716                         table->part_info->default_engine_type));
1717     else
1718       packet->append(file->table_type());
1719 #else
1720       packet->append(file->table_type());
1721 #endif
1722     }
1723 
1724     /*
1725       Add AUTO_INCREMENT=... if there is an AUTO_INCREMENT column,
1726       and NEXT_ID > 1 (the default).  We must not print the clause
1727       for engines that do not support this as it would break the
1728       import of dumps, but as of this writing, the test for whether
1729       AUTO_INCREMENT columns are allowed and wether AUTO_INCREMENT=...
1730       is supported is identical, !(file->table_flags() & HA_NO_AUTO_INCREMENT))
1731       Because of that, we do not explicitly test for the feature,
1732       but may extrapolate its existence from that of an AUTO_INCREMENT column.
1733     */
1734 
1735     if (create_info.auto_increment_value > 1)
1736     {
1737       char *end;
1738       packet->append(STRING_WITH_LEN(" AUTO_INCREMENT="));
1739       end= longlong10_to_str(create_info.auto_increment_value, buff,10);
1740       packet->append(buff, (uint) (end - buff));
1741     }
1742 
1743     if (share->table_charset &&
1744 	!(thd->variables.sql_mode & MODE_MYSQL323) &&
1745 	!(thd->variables.sql_mode & MODE_MYSQL40))
1746     {
1747       /*
1748         IF   check_create_info
1749         THEN add DEFAULT CHARSET only if it was used when creating the table
1750       */
1751       if (!create_info_arg ||
1752           (create_info_arg->used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
1753       {
1754         packet->append(STRING_WITH_LEN(" DEFAULT CHARSET="));
1755         packet->append(share->table_charset->csname);
1756         if (!(share->table_charset->state & MY_CS_PRIMARY))
1757         {
1758           packet->append(STRING_WITH_LEN(" COLLATE="));
1759           packet->append(table->s->table_charset->name);
1760         }
1761       }
1762     }
1763 
1764     if (share->min_rows)
1765     {
1766       char *end;
1767       packet->append(STRING_WITH_LEN(" MIN_ROWS="));
1768       end= longlong10_to_str(share->min_rows, buff, 10);
1769       packet->append(buff, (uint) (end- buff));
1770     }
1771 
1772     if (share->max_rows && !table_list->schema_table)
1773     {
1774       char *end;
1775       packet->append(STRING_WITH_LEN(" MAX_ROWS="));
1776       end= longlong10_to_str(share->max_rows, buff, 10);
1777       packet->append(buff, (uint) (end - buff));
1778     }
1779 
1780     if (share->avg_row_length)
1781     {
1782       char *end;
1783       packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
1784       end= longlong10_to_str(share->avg_row_length, buff,10);
1785       packet->append(buff, (uint) (end - buff));
1786     }
1787 
1788     if (share->db_create_options & HA_OPTION_PACK_KEYS)
1789       packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
1790     if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
1791       packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
1792     if (share->db_create_options & HA_OPTION_STATS_PERSISTENT)
1793       packet->append(STRING_WITH_LEN(" STATS_PERSISTENT=1"));
1794     if (share->db_create_options & HA_OPTION_NO_STATS_PERSISTENT)
1795       packet->append(STRING_WITH_LEN(" STATS_PERSISTENT=0"));
1796     if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON)
1797       packet->append(STRING_WITH_LEN(" STATS_AUTO_RECALC=1"));
1798     else if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF)
1799       packet->append(STRING_WITH_LEN(" STATS_AUTO_RECALC=0"));
1800     if (share->stats_sample_pages != 0)
1801     {
1802       char *end;
1803       packet->append(STRING_WITH_LEN(" STATS_SAMPLE_PAGES="));
1804       end= longlong10_to_str(share->stats_sample_pages, buff, 10);
1805       packet->append(buff, (uint) (end - buff));
1806     }
1807     /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
1808     if (share->db_create_options & HA_OPTION_CHECKSUM)
1809       packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
1810     if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
1811       packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1"));
1812     if (create_info.row_type != ROW_TYPE_DEFAULT)
1813     {
1814       packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
1815       packet->append(ha_row_type[(uint) create_info.row_type]);
1816     }
1817     if (table->s->key_block_size)
1818     {
1819       char *end;
1820       packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
1821       end= longlong10_to_str(table->s->key_block_size, buff, 10);
1822       packet->append(buff, (uint) (end - buff));
1823     }
1824     table->file->append_create_info(packet);
1825     if (share->comment.length)
1826     {
1827       packet->append(STRING_WITH_LEN(" COMMENT="));
1828       append_unescaped(packet, share->comment.str, share->comment.length);
1829     }
1830     if (share->connect_string.length)
1831     {
1832       packet->append(STRING_WITH_LEN(" CONNECTION="));
1833       append_unescaped(packet, share->connect_string.str, share->connect_string.length);
1834     }
1835     append_directory(thd, packet, "DATA",  create_info.data_file_name);
1836     append_directory(thd, packet, "INDEX", create_info.index_file_name);
1837   }
1838 #ifdef WITH_PARTITION_STORAGE_ENGINE
1839   {
1840     if (table->part_info &&
1841         !((table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) &&
1842           table->part_info->is_auto_partitioned))
1843     {
1844       /*
1845         Partition syntax for CREATE TABLE is at the end of the syntax.
1846       */
1847       uint part_syntax_len;
1848       char *part_syntax;
1849       String comment_start;
1850       table->part_info->set_show_version_string(&comment_start);
1851       if ((part_syntax= generate_partition_syntax(table->part_info,
1852                                                   &part_syntax_len,
1853                                                   FALSE,
1854                                                   show_table_options,
1855                                                   NULL, NULL,
1856                                                   comment_start.c_ptr())))
1857       {
1858          packet->append(comment_start);
1859          if (packet->append(part_syntax, part_syntax_len) ||
1860              packet->append(STRING_WITH_LEN(" */")))
1861           error= 1;
1862          my_free(part_syntax);
1863       }
1864     }
1865   }
1866 #endif
1867   tmp_restore_column_map(table->read_set, old_map);
1868   DBUG_RETURN(error);
1869 }
1870 
1871 
store_key_options(THD * thd,String * packet,TABLE * table,KEY * key_info)1872 static void store_key_options(THD *thd, String *packet, TABLE *table,
1873                               KEY *key_info)
1874 {
1875   bool limited_mysql_mode= (thd->variables.sql_mode &
1876                             (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
1877                              MODE_MYSQL40)) != 0;
1878   bool foreign_db_mode=  (thd->variables.sql_mode & (MODE_POSTGRESQL |
1879                                                      MODE_ORACLE |
1880                                                      MODE_MSSQL |
1881                                                      MODE_DB2 |
1882                                                      MODE_MAXDB |
1883                                                      MODE_ANSI)) != 0;
1884   char *end, buff[32];
1885 
1886   if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) &&
1887       !limited_mysql_mode && !foreign_db_mode)
1888   {
1889 
1890     if (key_info->algorithm == HA_KEY_ALG_BTREE)
1891       packet->append(STRING_WITH_LEN(" USING BTREE"));
1892 
1893     if (key_info->algorithm == HA_KEY_ALG_HASH)
1894       packet->append(STRING_WITH_LEN(" USING HASH"));
1895 
1896     /* send USING only in non-default case: non-spatial rtree */
1897     if ((key_info->algorithm == HA_KEY_ALG_RTREE) &&
1898         !(key_info->flags & HA_SPATIAL))
1899       packet->append(STRING_WITH_LEN(" USING RTREE"));
1900 
1901     if ((key_info->flags & HA_USES_BLOCK_SIZE) &&
1902         table->s->key_block_size != key_info->block_size)
1903     {
1904       packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
1905       end= longlong10_to_str(key_info->block_size, buff, 10);
1906       packet->append(buff, (uint) (end - buff));
1907     }
1908     DBUG_ASSERT(MY_TEST(key_info->flags & HA_USES_COMMENT) ==
1909                (key_info->comment.length > 0));
1910     if (key_info->flags & HA_USES_COMMENT)
1911     {
1912       packet->append(STRING_WITH_LEN(" COMMENT "));
1913       append_unescaped(packet, key_info->comment.str,
1914                        key_info->comment.length);
1915     }
1916   }
1917 }
1918 
1919 
1920 void
view_store_options(THD * thd,TABLE_LIST * table,String * buff)1921 view_store_options(THD *thd, TABLE_LIST *table, String *buff)
1922 {
1923   append_algorithm(table, buff);
1924   append_definer(thd, buff, &table->definer.user, &table->definer.host);
1925   if (table->view_suid)
1926     buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER "));
1927   else
1928     buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER "));
1929 }
1930 
1931 
1932 /*
1933   Append DEFINER clause to the given buffer.
1934 
1935   SYNOPSIS
1936     append_definer()
1937     thd           [in] thread handle
1938     buffer        [inout] buffer to hold DEFINER clause
1939     definer_user  [in] user name part of definer
1940     definer_host  [in] host name part of definer
1941 */
1942 
append_algorithm(TABLE_LIST * table,String * buff)1943 static void append_algorithm(TABLE_LIST *table, String *buff)
1944 {
1945   buff->append(STRING_WITH_LEN("ALGORITHM="));
1946   switch ((int8)table->algorithm) {
1947   case VIEW_ALGORITHM_UNDEFINED:
1948     buff->append(STRING_WITH_LEN("UNDEFINED "));
1949     break;
1950   case VIEW_ALGORITHM_TMPTABLE:
1951     buff->append(STRING_WITH_LEN("TEMPTABLE "));
1952     break;
1953   case VIEW_ALGORITHM_MERGE:
1954     buff->append(STRING_WITH_LEN("MERGE "));
1955     break;
1956   default:
1957     DBUG_ASSERT(0); // never should happen
1958   }
1959 }
1960 
1961 /*
1962   Append DEFINER clause to the given buffer.
1963 
1964   SYNOPSIS
1965     append_definer()
1966     thd           [in] thread handle
1967     buffer        [inout] buffer to hold DEFINER clause
1968     definer_user  [in] user name part of definer
1969     definer_host  [in] host name part of definer
1970 */
1971 
append_definer(THD * thd,String * buffer,const LEX_STRING * definer_user,const LEX_STRING * definer_host)1972 void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
1973                     const LEX_STRING *definer_host)
1974 {
1975   buffer->append(STRING_WITH_LEN("DEFINER="));
1976   append_identifier(thd, buffer, definer_user->str, definer_user->length);
1977   buffer->append('@');
1978   append_identifier(thd, buffer, definer_host->str, definer_host->length);
1979   buffer->append(' ');
1980 }
1981 
1982 
1983 int
view_store_create_info(THD * thd,TABLE_LIST * table,String * buff)1984 view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
1985 {
1986   my_bool compact_view_name= TRUE;
1987   my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
1988                                                        MODE_ORACLE |
1989                                                        MODE_MSSQL |
1990                                                        MODE_DB2 |
1991                                                        MODE_MAXDB |
1992                                                        MODE_ANSI)) != 0;
1993 
1994   if (!thd->db || strcmp(thd->db, table->view_db.str))
1995     /*
1996       print compact view name if the view belongs to the current database
1997     */
1998     compact_view_name= table->compact_view_format= FALSE;
1999   else
2000   {
2001     /*
2002       Compact output format for view body can be used
2003       if this view only references table inside it's own db
2004     */
2005     TABLE_LIST *tbl;
2006     table->compact_view_format= TRUE;
2007     for (tbl= thd->lex->query_tables;
2008          tbl;
2009          tbl= tbl->next_global)
2010     {
2011       if (strcmp(table->view_db.str, tbl->view ? tbl->view_db.str :tbl->db)!= 0)
2012       {
2013         table->compact_view_format= FALSE;
2014         break;
2015       }
2016     }
2017   }
2018 
2019   buff->append(STRING_WITH_LEN("CREATE "));
2020   if (!foreign_db_mode)
2021   {
2022     view_store_options(thd, table, buff);
2023   }
2024   buff->append(STRING_WITH_LEN("VIEW "));
2025   if (!compact_view_name)
2026   {
2027     append_identifier(thd, buff, table->view_db.str, table->view_db.length);
2028     buff->append('.');
2029   }
2030   append_identifier(thd, buff, table->view_name.str, table->view_name.length);
2031   buff->append(STRING_WITH_LEN(" AS "));
2032 
2033   /*
2034     We can't just use table->query, because our SQL_MODE may trigger
2035     a different syntax, like when ANSI_QUOTES is defined.
2036   */
2037   table->view->unit.print(buff, QT_ORDINARY);
2038 
2039   if (table->with_check != VIEW_CHECK_NONE)
2040   {
2041     if (table->with_check == VIEW_CHECK_LOCAL)
2042       buff->append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION"));
2043     else
2044       buff->append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION"));
2045   }
2046   return 0;
2047 }
2048 
2049 
2050 /****************************************************************************
2051   Return info about all processes
2052   returns for each thread: thread id, user, host, db, command, info,
2053   rows_sent, rows_examined
2054 ****************************************************************************/
2055 
2056 class thread_info
2057 {
2058 public:
operator new(size_t size)2059   static void *operator new(size_t size)
2060   {
2061     return (void*) sql_alloc((uint) size);
2062   }
operator delete(void * ptr MY_ATTRIBUTE ((unused)),size_t size MY_ATTRIBUTE ((unused)))2063   static void operator delete(void *ptr MY_ATTRIBUTE((unused)),
2064                               size_t size MY_ATTRIBUTE((unused)))
2065   { TRASH(ptr, size); }
2066 
2067   ulong thread_id;
2068   time_t start_time;
2069   uint   command;
2070   const char *user,*host,*db,*proc_info,*state_info;
2071   CSET_STRING query_string;
2072   ulonglong rows_sent, rows_examined;
2073 };
2074 
2075 // For sorting by thread_id.
2076 class thread_info_compare :
2077   public std::binary_function<const thread_info*, const thread_info*, bool>
2078 {
2079 public:
operator ()(const thread_info * p1,const thread_info * p2)2080   bool operator() (const thread_info* p1, const thread_info* p2)
2081   {
2082     return p1->thread_id < p2->thread_id;
2083   }
2084 };
2085 
thread_state_info(THD * tmp)2086 static const char *thread_state_info(THD *tmp)
2087 {
2088 #ifndef EMBEDDED_LIBRARY
2089   if (tmp->net.reading_or_writing)
2090   {
2091     if (tmp->net.reading_or_writing == 2)
2092       return "Writing to net";
2093     else if (tmp->get_command() == COM_SLEEP)
2094       return "";
2095     else
2096       return "Reading from net";
2097   }
2098   else
2099 #endif
2100   {
2101     if (tmp->proc_info)
2102       return tmp->proc_info;
2103     else if (tmp->mysys_var && tmp->mysys_var->current_cond)
2104       return "Waiting on cond";
2105     else
2106       return NULL;
2107   }
2108 }
2109 
mysqld_list_processes(THD * thd,const char * user,bool verbose)2110 void mysqld_list_processes(THD *thd,const char *user, bool verbose)
2111 {
2112   Item *field;
2113   List<Item> field_list;
2114   Mem_root_array<thread_info*, true> thread_infos(thd->mem_root);
2115   ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
2116 			   PROCESS_LIST_WIDTH);
2117   Protocol *protocol= thd->protocol;
2118   DBUG_ENTER("mysqld_list_processes");
2119 
2120   field_list.push_back(new Item_int(NAME_STRING("Id"), 0, MY_INT64_NUM_DECIMAL_DIGITS));
2121   field_list.push_back(new Item_empty_string("User",16));
2122   field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
2123   field_list.push_back(field=new Item_empty_string("db",NAME_CHAR_LEN));
2124   field->maybe_null=1;
2125   field_list.push_back(new Item_empty_string("Command",16));
2126   field_list.push_back(field= new Item_return_int("Time",7, MYSQL_TYPE_LONG));
2127   field->unsigned_flag= 0;
2128   field_list.push_back(field=new Item_empty_string("State",30));
2129   field->maybe_null=1;
2130   field_list.push_back(field=new Item_empty_string("Info",max_query_length));
2131   field->maybe_null=1;
2132   field_list.push_back(field= new Item_return_int("Rows_sent",
2133                                                   MY_INT64_NUM_DECIMAL_DIGITS,
2134                                                   MYSQL_TYPE_LONGLONG));
2135   field_list.push_back(field= new Item_return_int("Rows_examined",
2136                                                   MY_INT64_NUM_DECIMAL_DIGITS,
2137                                                   MYSQL_TYPE_LONGLONG));
2138   if (protocol->send_result_set_metadata(&field_list,
2139                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
2140     DBUG_VOID_RETURN;
2141 
2142   if (!thd->killed)
2143   {
2144     /* take copy of global_thread_list */
2145     std::set<THD*> global_thread_list_copy;
2146     DEBUG_SYNC(thd,"before_copying_threads");
2147     /*
2148       Allow inserts to global_thread_list. Newly added thd
2149       will not be accounted for `show processlist` and
2150       removal from global_thread_list is blocked as LOCK_thd_remove
2151       mutex is not released yet
2152      */
2153     mysql_mutex_lock(&LOCK_thd_remove);
2154     copy_global_thread_list(&global_thread_list_copy);
2155 
2156     DEBUG_SYNC(thd,"after_copying_threads");
2157     thread_infos.reserve(get_thread_count());
2158     Thread_iterator it= global_thread_list_copy.begin();
2159     Thread_iterator end= global_thread_list_copy.end();
2160     for (; it != end; ++it)
2161     {
2162       THD *tmp= *it;
2163       Security_context *tmp_sctx= tmp->security_ctx;
2164       struct st_my_thread_var *mysys_var;
2165       if ((tmp->vio_ok() || tmp->system_thread) &&
2166           (!user || (!tmp->system_thread && tmp_sctx->user &&
2167                      !strcmp(tmp_sctx->user, user)))
2168           && !acl_is_utility_user(tmp_sctx->user, tmp_sctx->get_host()->ptr(),
2169                                   tmp_sctx->get_ip()->ptr()))
2170       {
2171         thread_info *thd_info= new thread_info;
2172 
2173         thd_info->thread_id=tmp->thread_id;
2174         thd_info->user= thd->strdup(tmp_sctx->user ? tmp_sctx->user :
2175                                     (tmp->system_thread ?
2176                                      "system user" : "unauthenticated user"));
2177 	if (tmp->peer_port && (tmp_sctx->get_host()->length() ||
2178             tmp_sctx->get_ip()->length()) && thd->security_ctx->host_or_ip[0])
2179 	{
2180 	  if ((thd_info->host= (char*) thd->alloc(LIST_PROCESS_HOST_LEN+1)))
2181 	    my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
2182 			"%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
2183 	}
2184 	else
2185 	  thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ?
2186                                       tmp_sctx->host_or_ip :
2187                                       tmp_sctx->get_host()->length() ?
2188                                       tmp_sctx->get_host()->ptr() : "");
2189         thd_info->command=(int) tmp->get_command();
2190         DBUG_EXECUTE_IF("processlist_acquiring_dump_threads_LOCK_thd_data",
2191                         {
2192                          if (thd_info->command == COM_BINLOG_DUMP ||
2193                              thd_info->command == COM_BINLOG_DUMP_GTID)
2194                            DEBUG_SYNC(thd, "processlist_after_LOCK_thd_count_before_LOCK_thd_data");
2195                         });
2196         mysql_mutex_lock(&tmp->LOCK_thd_data);
2197         if ((thd_info->db= tmp->db))             // Safe test
2198           thd_info->db= thd->strdup(thd_info->db);
2199         if ((mysys_var= tmp->mysys_var))
2200           mysql_mutex_lock(&mysys_var->mutex);
2201         thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
2202         thd_info->state_info= thread_state_info(tmp);
2203         if (mysys_var)
2204           mysql_mutex_unlock(&mysys_var->mutex);
2205 
2206         /* Lock THD mutex that protects its data when looking at it. */
2207         if (tmp->query())
2208         {
2209           const char *query_str;
2210           size_t query_length;
2211           if ((query_length = tmp->rewritten_query.length()) > 0) {
2212             query_str = tmp->rewritten_query.c_ptr();
2213           } else {
2214             query_length = tmp->query_length();
2215             query_str = tmp->query();
2216           }
2217 
2218           uint length= min<uint>(max_query_length, query_length);
2219           char *q= thd->strmake(query_str, length);
2220           /* Safety: in case strmake failed, we set length to 0. */
2221           thd_info->query_string=
2222             CSET_STRING(q, q ? length : 0, tmp->query_charset());
2223         }
2224         thd_info->rows_sent= tmp->get_sent_row_count();
2225         thd_info->rows_examined= tmp->get_examined_row_count();
2226         mysql_mutex_unlock(&tmp->LOCK_thd_data);
2227         thd_info->start_time= tmp->start_time.tv_sec;
2228         thread_infos.push_back(thd_info);
2229       }
2230     }
2231     mysql_mutex_unlock(&LOCK_thd_remove);
2232   }
2233 
2234   // Return list sorted by thread_id.
2235   std::sort(thread_infos.begin(), thread_infos.end(), thread_info_compare());
2236 
2237   time_t now= my_time(0);
2238   for (size_t ix= 0; ix < thread_infos.size(); ++ix)
2239   {
2240     thread_info *thd_info= thread_infos.at(ix);
2241     protocol->prepare_for_resend();
2242     protocol->store((ulonglong) thd_info->thread_id);
2243     protocol->store(thd_info->user, system_charset_info);
2244     protocol->store(thd_info->host, system_charset_info);
2245     protocol->store(thd_info->db, system_charset_info);
2246     if (thd_info->proc_info)
2247       protocol->store(thd_info->proc_info, system_charset_info);
2248     else
2249       protocol->store(command_name[thd_info->command].str, system_charset_info);
2250     if (thd_info->start_time)
2251     {
2252       protocol->store_long ((thd_info->start_time > now) ? 0
2253         : (longlong) (now - thd_info->start_time));
2254     }
2255     else
2256       protocol->store_null();
2257     protocol->store(thd_info->state_info, system_charset_info);
2258     protocol->store(thd_info->query_string.str(),
2259                     thd_info->query_string.charset());
2260     protocol->store(thd_info->rows_sent);
2261     protocol->store(thd_info->rows_examined);
2262     if (protocol->write())
2263       break; /* purecov: inspected */
2264   }
2265   my_eof(thd);
2266   DBUG_VOID_RETURN;
2267 }
2268 
fill_schema_processlist(THD * thd,TABLE_LIST * tables,Item * cond)2269 int fill_schema_processlist(THD* thd, TABLE_LIST* tables, Item* cond)
2270 {
2271   TABLE *table= tables->table;
2272   CHARSET_INFO *cs= system_charset_info;
2273   char *user;
2274   time_t now;
2275   ulonglong now_utime= my_micro_time_and_time(&now);
2276   DBUG_ENTER("fill_process_list");
2277 
2278   DEBUG_SYNC(thd, "before_fill_schema_processlist");
2279 
2280   user= thd->security_ctx->master_access & PROCESS_ACL ?
2281         NullS : thd->security_ctx->priv_user;
2282 
2283   if (!thd->killed)
2284   {
2285     /* take copy of global_thread_list */
2286     std::set<THD*> global_thread_list_copy;
2287     /*
2288       Allow inserts to global_thread_list. Newly added thd
2289       will not be accounted for `fill schema processlist` and
2290       removal from global_thread_list is blocked as LOCK_thd_remove
2291       mutex is not released yet
2292      */
2293     mysql_mutex_lock(&LOCK_thd_remove);
2294     copy_global_thread_list(&global_thread_list_copy);
2295 
2296     DEBUG_SYNC(thd,"fill_schema_processlist_after_copying_threads");
2297 
2298     Thread_iterator it= global_thread_list_copy.begin();
2299     Thread_iterator end= global_thread_list_copy.end();
2300     for (; it != end; ++it)
2301     {
2302       THD* tmp= *it;
2303       Security_context *tmp_sctx= tmp->security_ctx;
2304       struct st_my_thread_var *mysys_var;
2305       const char *val, *db;
2306 
2307       if ((!tmp->vio_ok() && !tmp->system_thread) ||
2308           (user && (tmp->system_thread || !tmp_sctx->user ||
2309                     strcmp(tmp_sctx->user, user)))
2310           || acl_is_utility_user(tmp_sctx->user, tmp_sctx->get_host()->ptr(),
2311                                  tmp_sctx->get_ip()->ptr()))
2312         continue;
2313 
2314       restore_record(table, s->default_values);
2315       /* ID */
2316 
2317       table->field[0]->store((ulonglong) tmp->thread_id, TRUE);
2318       /* USER */
2319       val= tmp_sctx->user ? tmp_sctx->user :
2320             (tmp->system_thread ? "system user" : "unauthenticated user");
2321       table->field[1]->store(val, strlen(val), cs);
2322       /* HOST */
2323       if (tmp->peer_port && (tmp_sctx->get_host()->length() ||
2324           tmp_sctx->get_ip()->length()) && thd->security_ctx->host_or_ip[0])
2325       {
2326         char host[LIST_PROCESS_HOST_LEN + 1];
2327         my_snprintf(host, LIST_PROCESS_HOST_LEN, "%s:%u",
2328                     tmp_sctx->host_or_ip, tmp->peer_port);
2329         table->field[2]->store(host, strlen(host), cs);
2330       }
2331       else
2332         table->field[2]->store(tmp_sctx->host_or_ip,
2333                                strlen(tmp_sctx->host_or_ip), cs);
2334       DBUG_EXECUTE_IF("processlist_acquiring_dump_threads_LOCK_thd_data",
2335                       {
2336                       if (tmp->get_command() == COM_BINLOG_DUMP ||
2337                           tmp->get_command() == COM_BINLOG_DUMP_GTID)
2338                       DEBUG_SYNC(thd, "processlist_after_LOCK_thd_count_before_LOCK_thd_data");
2339                       });
2340       /* DB */
2341       mysql_mutex_lock(&tmp->LOCK_thd_data);
2342       if ((db= tmp->db))
2343       {
2344         table->field[3]->store(db, strlen(db), cs);
2345         table->field[3]->set_notnull();
2346       }
2347 
2348       if ((mysys_var= tmp->mysys_var))
2349         mysql_mutex_lock(&mysys_var->mutex);
2350       /* COMMAND */
2351       if ((val= (char *) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0)))
2352         table->field[4]->store(val, strlen(val), cs);
2353       else
2354         table->field[4]->store(command_name[tmp->get_command()].str,
2355                                command_name[tmp->get_command()].length, cs);
2356       /* MYSQL_TIME */
2357       longlong value_in_time_column= 0;
2358       if(tmp->start_time.tv_sec)
2359       {
2360         value_in_time_column = (now - tmp->start_time.tv_sec);
2361         if(value_in_time_column > now)
2362         {
2363           value_in_time_column= 0;
2364         }
2365       }
2366       table->field[5]->store(value_in_time_column, FALSE);
2367 
2368       /* STATE */
2369       if ((val= thread_state_info(tmp)))
2370       {
2371         table->field[6]->store(val, strlen(val), cs);
2372         table->field[6]->set_notnull();
2373       }
2374 
2375       if (mysys_var)
2376         mysql_mutex_unlock(&mysys_var->mutex);
2377       /* INFO */
2378       if (tmp->query())
2379       {
2380         const char *query_str;
2381         size_t query_length;
2382 
2383         if ((query_length = tmp->rewritten_query.length()) > 0) {
2384           query_str = tmp->rewritten_query.c_ptr();
2385         } else {
2386           query_length = tmp->query_length();
2387           query_str = tmp->query();
2388         }
2389         size_t const width=
2390           min<size_t>(PROCESS_LIST_INFO_WIDTH, query_length);
2391         table->field[7]->store(query_str, width, cs);
2392         table->field[7]->set_notnull();
2393       }
2394 
2395       /* TIME_MS */
2396       ulonglong tmp_start_utime= tmp->start_utime;
2397       table->field[8]->store(((tmp_start_utime < now_utime ?
2398                                now_utime - tmp_start_utime : 0)/ 1000));
2399 
2400       /* ROWS_SENT */
2401       table->field[9]->store((ulonglong) tmp->get_sent_row_count());
2402       /* ROWS_EXAMINED */
2403       table->field[10]->store((ulonglong) tmp->get_examined_row_count());
2404       /* TID */
2405       if(tmp->system_tid != -1)
2406       {
2407         table->field[11]->store((ulonglong) tmp->system_tid, TRUE);
2408         table->field[11]->set_notnull();
2409       }
2410       mysql_mutex_unlock(&tmp->LOCK_thd_data);
2411 
2412       if (schema_table_store_record(thd, table))
2413       {
2414         mysql_mutex_unlock(&LOCK_thd_remove);
2415         DBUG_RETURN(1);
2416       }
2417     }
2418     mysql_mutex_unlock(&LOCK_thd_remove);
2419   }
2420 
2421   DBUG_RETURN(0);
2422 }
2423 
2424 /*****************************************************************************
2425   Status functions
2426 *****************************************************************************/
2427 
2428 static DYNAMIC_ARRAY all_status_vars;
2429 static bool status_vars_inited= 0;
2430 
2431 C_MODE_START
show_var_cmp(const void * var1,const void * var2)2432 static int show_var_cmp(const void *var1, const void *var2)
2433 {
2434   return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
2435 }
2436 C_MODE_END
2437 
2438 /*
2439   deletes all the SHOW_UNDEF elements from the array and calls
2440   delete_dynamic() if it's completely empty.
2441 */
shrink_var_array(DYNAMIC_ARRAY * array)2442 static void shrink_var_array(DYNAMIC_ARRAY *array)
2443 {
2444   uint a,b;
2445   SHOW_VAR *all= dynamic_element(array, 0, SHOW_VAR *);
2446 
2447   for (a= b= 0; b < array->elements; b++)
2448     if (all[b].type != SHOW_UNDEF)
2449       all[a++]= all[b];
2450   if (a)
2451   {
2452     memset(all+a, 0, sizeof(SHOW_VAR)); // writing NULL-element to the end
2453     array->elements= a;
2454   }
2455   else // array is completely empty - delete it
2456     delete_dynamic(array);
2457 }
2458 
2459 /*
2460   Adds an array of SHOW_VAR entries to the output of SHOW STATUS
2461 
2462   SYNOPSIS
2463     add_status_vars(SHOW_VAR *list)
2464     list - an array of SHOW_VAR entries to add to all_status_vars
2465            the last entry must be {0,0,SHOW_UNDEF}
2466 
2467   NOTE
2468     The handling of all_status_vars[] is completely internal, it's allocated
2469     automatically when something is added to it, and deleted completely when
2470     the last entry is removed.
2471 
2472     As a special optimization, if add_status_vars() is called before
2473     init_status_vars(), it assumes "startup mode" - neither concurrent access
2474     to the array nor SHOW STATUS are possible (thus it skips locks and qsort)
2475 
2476     The last entry of the all_status_vars[] should always be {0,0,SHOW_UNDEF}
2477 */
add_status_vars(SHOW_VAR * list)2478 int add_status_vars(SHOW_VAR *list)
2479 {
2480   int res= 0;
2481   if (status_vars_inited)
2482     mysql_mutex_lock(&LOCK_status);
2483   if (!all_status_vars.buffer && // array is not allocated yet - do it now
2484       my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 200, 20))
2485   {
2486     res= 1;
2487     goto err;
2488   }
2489   while (list->name)
2490     res|= insert_dynamic(&all_status_vars, list++);
2491   res|= insert_dynamic(&all_status_vars, list); // appending NULL-element
2492   all_status_vars.elements--; // but next insert_dynamic should overwite it
2493   if (status_vars_inited)
2494     sort_dynamic(&all_status_vars, show_var_cmp);
2495 err:
2496   if (status_vars_inited)
2497     mysql_mutex_unlock(&LOCK_status);
2498   return res;
2499 }
2500 
2501 /*
2502   Make all_status_vars[] usable for SHOW STATUS
2503 
2504   NOTE
2505     See add_status_vars(). Before init_status_vars() call, add_status_vars()
2506     works in a special fast "startup" mode. Thus init_status_vars()
2507     should be called as late as possible but before enabling multi-threading.
2508 */
init_status_vars()2509 void init_status_vars()
2510 {
2511   status_vars_inited=1;
2512   sort_dynamic(&all_status_vars, show_var_cmp);
2513 }
2514 
reset_status_vars()2515 void reset_status_vars()
2516 {
2517   SHOW_VAR *ptr= (SHOW_VAR*) all_status_vars.buffer;
2518   SHOW_VAR *last= ptr + all_status_vars.elements;
2519   for (; ptr < last; ptr++)
2520   {
2521     /* Note that SHOW_LONG_NOFLUSH variables are not reset */
2522     if (ptr->type == SHOW_LONG || ptr->type == SHOW_SIGNED_LONG)
2523       *(ulong*) ptr->value= 0;
2524   }
2525 }
2526 
2527 /*
2528   catch-all cleanup function, cleans up everything no matter what
2529 
2530   DESCRIPTION
2531     This function is not strictly required if all add_to_status/
2532     remove_status_vars are properly paired, but it's a safety measure that
2533     deletes everything from the all_status_vars[] even if some
2534     remove_status_vars were forgotten
2535 */
free_status_vars()2536 void free_status_vars()
2537 {
2538   delete_dynamic(&all_status_vars);
2539 }
2540 
2541 /**
2542   @brief           Get the value of given status variable
2543 
2544   @param[in]       thd        thread handler
2545   @param[in]       list       list of SHOW_VAR objects in which function should
2546                               search
2547   @param[in]       name       name of the status variable
2548   @param[in/out]   value      buffer in which value of the status variable
2549                               needs to be filled in
2550 
2551   @return          status
2552     @retval        FALSE      if variable is not found in the list
2553     @retval        TRUE       if variable is found in the list
2554   NOTE: Currently this function is implemented just to support 'bool' status
2555   variables and 'long' status variables *only*. It can be extended very easily
2556   for further show_types in future if required.
2557   TODO: Currently show_status_arary switch case is tightly coupled with
2558   pos, end, buff, value variables and also it stores the values in a 'table'.
2559   Decouple the switch case to fill the buffer value so that it can be used
2560   in show_status_array() and get_status_var() to avoid duplicate code.
2561  */
2562 
get_status_var(THD * thd,SHOW_VAR * list,const char * name,char * const value)2563 bool get_status_var(THD* thd, SHOW_VAR *list, const char * name, char * const value)
2564 {
2565   for (; list->name; list++)
2566   {
2567     int res= strcmp(list->name, name);
2568     if (res == 0)
2569     {
2570       /*
2571         if var->type is SHOW_FUNC, call the function.
2572         Repeat as necessary, if new var is again SHOW_FUNC
2573       */
2574       SHOW_VAR tmp;
2575       for (; list->type == SHOW_FUNC; list= &tmp)
2576         ((mysql_show_var_func)(list->value))(thd, &tmp, value);
2577       switch (list->type) {
2578       case SHOW_BOOL:
2579         strmov(value, *(bool*) list->value ? "ON" : "OFF");
2580         break;
2581       case SHOW_LONG:
2582         int10_to_str(*(long*) list->value, value, 10);
2583         break;
2584       default:
2585         /* not supported type */
2586         DBUG_ASSERT(0);
2587       }
2588       return TRUE;
2589     }
2590   }
2591   return FALSE;
2592 }
2593 
2594 /*
2595   Removes an array of SHOW_VAR entries from the output of SHOW STATUS
2596 
2597   SYNOPSIS
2598     remove_status_vars(SHOW_VAR *list)
2599     list - an array of SHOW_VAR entries to remove to all_status_vars
2600            the last entry must be {0,0,SHOW_UNDEF}
2601 
2602   NOTE
2603     there's lots of room for optimizing this, especially in non-sorted mode,
2604     but nobody cares - it may be called only in case of failed plugin
2605     initialization in the mysqld startup.
2606 */
2607 
remove_status_vars(SHOW_VAR * list)2608 void remove_status_vars(SHOW_VAR *list)
2609 {
2610   if (status_vars_inited)
2611   {
2612     mysql_mutex_lock(&LOCK_status);
2613     SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
2614     int a= 0, b= all_status_vars.elements, c= (a+b)/2;
2615 
2616     for (; list->name; list++)
2617     {
2618       int res= 0;
2619       for (a= 0, b= all_status_vars.elements; b-a > 1; c= (a+b)/2)
2620       {
2621         res= show_var_cmp(list, all+c);
2622         if (res < 0)
2623           b= c;
2624         else if (res > 0)
2625           a= c;
2626         else
2627           break;
2628       }
2629       if (res == 0)
2630         all[c].type= SHOW_UNDEF;
2631     }
2632     shrink_var_array(&all_status_vars);
2633     mysql_mutex_unlock(&LOCK_status);
2634   }
2635   else
2636   {
2637     SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
2638     uint i;
2639     for (; list->name; list++)
2640     {
2641       for (i= 0; i < all_status_vars.elements; i++)
2642       {
2643         if (show_var_cmp(list, all+i))
2644           continue;
2645         all[i].type= SHOW_UNDEF;
2646         break;
2647       }
2648     }
2649     shrink_var_array(&all_status_vars);
2650   }
2651 }
2652 
make_upper(char * buf)2653 inline void make_upper(char *buf)
2654 {
2655   for (; *buf; buf++)
2656     *buf= my_toupper(system_charset_info, *buf);
2657 }
2658 
show_status_array(THD * thd,const char * wild,SHOW_VAR * variables,enum enum_var_type value_type,struct system_status_var * status_var,const char * prefix,TABLE * table,bool ucase_names,Item * cond)2659 static bool show_status_array(THD *thd, const char *wild,
2660                               SHOW_VAR *variables,
2661                               enum enum_var_type value_type,
2662                               struct system_status_var *status_var,
2663                               const char *prefix, TABLE *table,
2664                               bool ucase_names,
2665                               Item *cond)
2666 {
2667   my_aligned_storage<SHOW_VAR_FUNC_BUFF_SIZE, MY_ALIGNOF(long)> buffer;
2668   char * const buff= buffer.data;
2669   char *prefix_end;
2670   /* the variable name should not be longer than 64 characters */
2671   char name_buffer[64];
2672   int len;
2673   LEX_STRING null_lex_str;
2674   SHOW_VAR tmp, *var;
2675   Item *partial_cond= 0;
2676   enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
2677   bool res= FALSE;
2678   const CHARSET_INFO *charset= system_charset_info;
2679   DBUG_ENTER("show_status_array");
2680 
2681   thd->count_cuted_fields= CHECK_FIELD_WARN;
2682   null_lex_str.str= 0;				// For sys_var->value_ptr()
2683   null_lex_str.length= 0;
2684 
2685   prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1);
2686   if (*prefix)
2687     *prefix_end++= '_';
2688   len=name_buffer + sizeof(name_buffer) - prefix_end;
2689   partial_cond= make_cond_for_info_schema(cond, table->pos_in_table_list);
2690 
2691   for (; variables->name; variables++)
2692   {
2693     strnmov(prefix_end, variables->name, len);
2694     name_buffer[sizeof(name_buffer)-1]=0;       /* Safety */
2695     if (ucase_names)
2696       make_upper(name_buffer);
2697 
2698     restore_record(table, s->default_values);
2699     table->field[0]->store(name_buffer, strlen(name_buffer),
2700                            system_charset_info);
2701     /*
2702       if var->type is SHOW_FUNC, call the function.
2703       Repeat as necessary, if new var is again SHOW_FUNC
2704     */
2705     for (var=variables; var->type == SHOW_FUNC; var= &tmp)
2706       ((mysql_show_var_func)(var->value))(thd, &tmp, buff);
2707 
2708     SHOW_TYPE show_type=var->type;
2709     if (show_type == SHOW_ARRAY)
2710     {
2711       show_status_array(thd, wild, (SHOW_VAR *) var->value, value_type,
2712                         status_var, name_buffer, table, ucase_names, partial_cond);
2713     }
2714     else
2715     {
2716       if (!(wild && wild[0] && wild_case_compare(system_charset_info,
2717                                                  name_buffer, wild)) &&
2718           (!partial_cond || partial_cond->val_int()))
2719       {
2720         char *value=var->value;
2721         const char *pos, *end;                  // We assign a lot of const's
2722 
2723         mysql_mutex_lock(&LOCK_global_system_variables);
2724 
2725         if (show_type == SHOW_SYS)
2726         {
2727           sys_var *var= ((sys_var *) value);
2728           show_type= var->show_type();
2729           value= (char*) var->value_ptr(thd, value_type, &null_lex_str);
2730           charset= var->charset(thd);
2731         }
2732 
2733         pos= end= buff;
2734         /*
2735           note that value may be == buff. All SHOW_xxx code below
2736           should still work in this case
2737         */
2738         switch (show_type) {
2739         case SHOW_DOUBLE_STATUS:
2740           value= ((char *) status_var + (ulong) value);
2741           /* fall through */
2742         case SHOW_DOUBLE:
2743           /* 6 is the default precision for '%f' in sprintf() */
2744           end= buff + my_fcvt(*(double *) value, 6, buff, NULL);
2745           break;
2746         case SHOW_LONG_STATUS:
2747           value= ((char *) status_var + (ulong) value);
2748           /* fall through */
2749         case SHOW_LONG:
2750         case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
2751           end= int10_to_str(*(long*) value, buff, 10);
2752           break;
2753         case SHOW_SIGNED_LONG:
2754           end= int10_to_str(*(long*) value, buff, -10);
2755           break;
2756         case SHOW_LONGLONG_STATUS:
2757           value= ((char *) status_var + (ulong) value);
2758           /* fall through */
2759         case SHOW_LONGLONG:
2760           end= longlong10_to_str(*(longlong*) value, buff, 10);
2761           break;
2762         case SHOW_HA_ROWS:
2763           end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
2764           break;
2765         case SHOW_BOOL:
2766           end= strmov(buff, *(bool*) value ? "ON" : "OFF");
2767           break;
2768         case SHOW_MY_BOOL:
2769           end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
2770           break;
2771         case SHOW_INT:
2772           end= int10_to_str((long) *(uint32*) value, buff, 10);
2773           break;
2774         case SHOW_HAVE:
2775         {
2776           SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
2777           pos= show_comp_option_name[(int) tmp];
2778           end= strend(pos);
2779           break;
2780         }
2781         case SHOW_CHAR:
2782         {
2783           if (!(pos= value))
2784             pos= "";
2785           end= strend(pos);
2786           break;
2787         }
2788        case SHOW_CHAR_PTR:
2789         {
2790           if (!(pos= *(char**) value))
2791             pos= "";
2792 
2793           DBUG_EXECUTE_IF("alter_server_version_str",
2794                           if (!my_strcasecmp(system_charset_info,
2795                                              variables->name,
2796                                              "version")) {
2797                             pos= "some-other-version";
2798                           });
2799 
2800           end= strend(pos);
2801           break;
2802         }
2803         case SHOW_LEX_STRING:
2804         {
2805           LEX_STRING *ls=(LEX_STRING*)value;
2806           if (!(pos= ls->str))
2807             end= pos= "";
2808           else
2809             end= pos + ls->length;
2810           break;
2811         }
2812         case SHOW_KEY_CACHE_LONG:
2813           value= (char*) dflt_key_cache + (ulong)value;
2814           end= int10_to_str(*(long*) value, buff, 10);
2815           break;
2816         case SHOW_KEY_CACHE_LONGLONG:
2817           value= (char*) dflt_key_cache + (ulong)value;
2818 	  end= longlong10_to_str(*(longlong*) value, buff, 10);
2819 	  break;
2820         case SHOW_UNDEF:
2821           break;                                        // Return empty string
2822         case SHOW_SYS:                                  // Cannot happen
2823         default:
2824           DBUG_ASSERT(0);
2825           break;
2826         }
2827         table->field[1]->store(pos, (uint32) (end - pos), charset);
2828         thd->count_cuted_fields= CHECK_FIELD_IGNORE;
2829         table->field[1]->set_notnull();
2830 
2831         mysql_mutex_unlock(&LOCK_global_system_variables);
2832 
2833         if (schema_table_store_record(thd, table))
2834         {
2835           res= TRUE;
2836           goto end;
2837         }
2838       }
2839     }
2840   }
2841 end:
2842   thd->count_cuted_fields= save_count_cuted_fields;
2843   DBUG_RETURN(res);
2844 }
2845 
2846 /*
2847    Write result to network for SHOW USER_STATISTICS
2848 
2849    SYNOPSIS
2850      send_user_stats
2851        all_user_stats - values to return
2852        table - I_S table
2853 
2854    RETURN
2855      0 - OK
2856      1 - error
2857 */
2858 static
send_user_stats(THD * thd,HASH * all_user_stats,TABLE * table)2859 int send_user_stats(THD* thd, HASH *all_user_stats, TABLE *table)
2860 {
2861   DBUG_ENTER("send_user_stats");
2862   for (uint i = 0; i < all_user_stats->records; ++i)
2863   {
2864     restore_record(table, s->default_values);
2865     USER_STATS *user_stats = (USER_STATS*) my_hash_element(all_user_stats, i);
2866     table->field[0]->store(user_stats->user, strlen(user_stats->user),
2867                            system_charset_info);
2868     table->field[1]->store(user_stats->total_connections, true);
2869     table->field[2]->store(user_stats->concurrent_connections, true);
2870     table->field[3]->store(user_stats->connected_time, true);
2871     table->field[4]->store((ulonglong)user_stats->busy_time, true);
2872     table->field[5]->store((ulonglong)user_stats->cpu_time, true);
2873     table->field[6]->store(user_stats->bytes_received, true);
2874     table->field[7]->store(user_stats->bytes_sent, true);
2875     table->field[8]->store(user_stats->binlog_bytes_written, true);
2876     table->field[9]->store(user_stats->rows_fetched, true);
2877     table->field[10]->store(user_stats->rows_updated, true);
2878     table->field[11]->store(user_stats->rows_read, true);
2879     table->field[12]->store(user_stats->select_commands, true);
2880     table->field[13]->store(user_stats->update_commands, true);
2881     table->field[14]->store(user_stats->other_commands, true);
2882     table->field[15]->store(user_stats->commit_trans, true);
2883     table->field[16]->store(user_stats->rollback_trans, true);
2884     table->field[17]->store(user_stats->denied_connections, true);
2885     table->field[18]->store(user_stats->lost_connections, true);
2886     table->field[19]->store(user_stats->access_denied_errors, true);
2887     table->field[20]->store(user_stats->empty_queries, true);
2888     table->field[21]->store(user_stats->total_ssl_connections, true);
2889     if (schema_table_store_record(thd, table))
2890     {
2891       DBUG_PRINT("error", ("store record error"));
2892       DBUG_RETURN(1);
2893     }
2894   }
2895   DBUG_RETURN(0);
2896 }
2897 
2898 static
send_thread_stats(THD * thd,HASH * all_thread_stats,TABLE * table)2899 int send_thread_stats(THD* thd, HASH *all_thread_stats, TABLE *table)
2900 {
2901   DBUG_ENTER("send_thread_stats");
2902   for (uint i = 0; i < all_thread_stats->records; ++i)
2903   {
2904     restore_record(table, s->default_values);
2905     THREAD_STATS *user_stats
2906       = (THREAD_STATS*)my_hash_element(all_thread_stats, i);
2907     table->field[0]->store(user_stats->id, true);
2908     table->field[1]->store(user_stats->total_connections, true);
2909     table->field[2]->store(user_stats->concurrent_connections, true);
2910     table->field[3]->store(user_stats->connected_time, true);
2911     table->field[4]->store((ulonglong)user_stats->busy_time, true);
2912     table->field[5]->store((ulonglong)user_stats->cpu_time, true);
2913     table->field[6]->store(user_stats->bytes_received, true);
2914     table->field[7]->store(user_stats->bytes_sent, true);
2915     table->field[8]->store(user_stats->binlog_bytes_written, true);
2916     table->field[9]->store(user_stats->rows_fetched, true);
2917     table->field[10]->store(user_stats->rows_updated, true);
2918     table->field[11]->store(user_stats->rows_read, true);
2919     table->field[12]->store(user_stats->select_commands, true);
2920     table->field[13]->store(user_stats->update_commands, true);
2921     table->field[14]->store(user_stats->other_commands, true);
2922     table->field[15]->store(user_stats->commit_trans, true);
2923     table->field[16]->store(user_stats->rollback_trans, true);
2924     table->field[17]->store(user_stats->denied_connections, true);
2925     table->field[18]->store(user_stats->lost_connections, true);
2926     table->field[19]->store(user_stats->access_denied_errors, true);
2927     table->field[20]->store(user_stats->empty_queries, true);
2928     table->field[21]->store(user_stats->total_ssl_connections, true);
2929     if (schema_table_store_record(thd, table))
2930     {
2931       DBUG_PRINT("error", ("store record error"));
2932       DBUG_RETURN(1);
2933     }
2934   }
2935   DBUG_RETURN(0);
2936 }
2937 
2938 /*
2939    Process SHOW USER_STATISTICS
2940 
2941    SYNOPSIS
2942      mysqld_show_user_stats
2943        thd - current thread
2944        wild - limit results to the entry for this user
2945        with_roles - when true, display role for mapped users
2946 
2947    RETURN
2948      0 - OK
2949      1 - error
2950 */
2951 
2952 static
fill_schema_user_stats(THD * thd,TABLE_LIST * tables,Item * cond)2953 int fill_schema_user_stats(THD* thd, TABLE_LIST* tables, Item* cond)
2954 {
2955   TABLE *table= tables->table;
2956   DBUG_ENTER("fill_schema_user_stats");
2957 
2958   if (check_global_access(thd, SUPER_ACL | PROCESS_ACL))
2959           DBUG_RETURN(1);
2960 
2961   refresh_concurrent_conn_stats();
2962   // Iterates through all the global stats and sends them to the client.
2963   // Pattern matching on the client IP is supported.
2964 
2965   mysql_mutex_lock(&LOCK_global_user_client_stats);
2966   int result= send_user_stats(thd, &global_user_stats, table);
2967   mysql_mutex_unlock(&LOCK_global_user_client_stats);
2968   if (result)
2969     goto err;
2970 
2971   DBUG_PRINT("exit", ("fill_schema_user_stats result is 0"));
2972   DBUG_RETURN(0);
2973 
2974  err:
2975   DBUG_PRINT("exit", ("fill_schema_user_stats result is 1"));
2976   DBUG_RETURN(1);
2977 }
2978 
2979 /*
2980    Process SHOW CLIENT_STATISTICS
2981 
2982    SYNOPSIS
2983      mysqld_show_client_stats
2984        thd - current thread
2985        wild - limit results to the entry for this client
2986 
2987    RETURN
2988      0 - OK
2989      1 - error
2990 */
2991 
2992 static
fill_schema_client_stats(THD * thd,TABLE_LIST * tables,Item * cond)2993 int fill_schema_client_stats(THD* thd, TABLE_LIST* tables, Item* cond)
2994 {
2995   TABLE *table= tables->table;
2996   DBUG_ENTER("fill_schema_client_stats");
2997 
2998   if (check_global_access(thd, SUPER_ACL | PROCESS_ACL))
2999           DBUG_RETURN(1);
3000 
3001   refresh_concurrent_conn_stats();
3002   // Iterates through all the global stats and sends them to the client.
3003   // Pattern matching on the client IP is supported.
3004 
3005   mysql_mutex_lock(&LOCK_global_user_client_stats);
3006   int result= send_user_stats(thd, &global_client_stats, table);
3007   mysql_mutex_unlock(&LOCK_global_user_client_stats);
3008   if (result)
3009     goto err;
3010 
3011   DBUG_PRINT("exit", ("mysqld_show_client_stats result is 0"));
3012   DBUG_RETURN(0);
3013 
3014  err:
3015   DBUG_PRINT("exit", ("mysqld_show_client_stats result is 1"));
3016   DBUG_RETURN(1);
3017 }
3018 
3019 static
fill_schema_thread_stats(THD * thd,TABLE_LIST * tables,Item * cond)3020 int fill_schema_thread_stats(THD* thd, TABLE_LIST* tables, Item* cond)
3021 {
3022   TABLE *table= tables->table;
3023   DBUG_ENTER("fill_schema_thread_stats");
3024 
3025   if (check_global_access(thd, SUPER_ACL | PROCESS_ACL))
3026           DBUG_RETURN(1);
3027 
3028   // Iterates through all the global stats and sends them to the client.
3029   // Pattern matching on the client IP is supported.
3030 
3031   mysql_mutex_lock(&LOCK_global_user_client_stats);
3032   int result= send_thread_stats(thd, &global_thread_stats, table);
3033   mysql_mutex_unlock(&LOCK_global_user_client_stats);
3034   if (result)
3035     goto err;
3036 
3037   DBUG_PRINT("exit", ("mysqld_show_thread_stats result is 0"));
3038   DBUG_RETURN(0);
3039 
3040  err:
3041   DBUG_PRINT("exit", ("mysqld_show_thread_stats result is 1"));
3042   DBUG_RETURN(1);
3043 }
3044 
3045 // Sends the global table stats back to the client.
3046 static
fill_schema_table_stats(THD * thd,TABLE_LIST * tables,Item * cond)3047 int fill_schema_table_stats(THD* thd, TABLE_LIST* tables, Item* cond)
3048 {
3049   TABLE *table= tables->table;
3050   DBUG_ENTER("fill_schema_table_stats");
3051   char *table_full_name, *table_schema;
3052 
3053   mysql_mutex_lock(&LOCK_global_table_stats);
3054   for (uint i = 0; i < global_table_stats.records; ++i)
3055   {
3056     restore_record(table, s->default_values);
3057     TABLE_STATS *table_stats =
3058       (TABLE_STATS *) my_hash_element(&global_table_stats, i);
3059 
3060     table_full_name= thd->strdup(table_stats->table);
3061     table_schema= strsep(&table_full_name, ".");
3062 
3063     TABLE_LIST tmp_table;
3064     memset((char *) &tmp_table, 0, sizeof(tmp_table));
3065     tmp_table.table_name= table_full_name;
3066     tmp_table.db= table_schema;
3067     tmp_table.grant.privilege= 0;
3068     if (check_access(thd, SELECT_ACL, tmp_table.db,
3069                       &tmp_table.grant.privilege, 0, 0,
3070                       is_infoschema_db(table_schema)) ||
3071          check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX, 1))
3072         continue;
3073 
3074     table->field[0]->store(table_schema, strlen(table_schema), system_charset_info);
3075     table->field[1]->store(table_full_name, strlen(table_full_name), system_charset_info);
3076     table->field[2]->store(table_stats->rows_read, true);
3077     table->field[3]->store(table_stats->rows_changed, true);
3078     table->field[4]->store(table_stats->rows_changed_x_indexes, true);
3079 
3080     if (schema_table_store_record(thd, table))
3081     {
3082       mysql_mutex_unlock(&LOCK_global_table_stats);
3083       DBUG_RETURN(1);
3084     }
3085   }
3086   mysql_mutex_unlock(&LOCK_global_table_stats);
3087   DBUG_RETURN(0);
3088 }
3089 
3090 // Sends the global index stats back to the client.
3091 static
fill_schema_index_stats(THD * thd,TABLE_LIST * tables,Item * cond)3092 int fill_schema_index_stats(THD* thd, TABLE_LIST* tables, Item* cond)
3093 {
3094   TABLE *table= tables->table;
3095   DBUG_ENTER("fill_schema_index_stats");
3096   char *index_full_name, *table_schema, *table_name;
3097 
3098   mysql_mutex_lock(&LOCK_global_index_stats);
3099   for (uint i = 0; i < global_index_stats.records; ++i)
3100   {
3101     restore_record(table, s->default_values);
3102     INDEX_STATS *index_stats =
3103       (INDEX_STATS *) my_hash_element(&global_index_stats, i);
3104 
3105     index_full_name= thd->strdup(index_stats->index);
3106     table_schema= strsep(&index_full_name, ".");
3107     table_name= strsep(&index_full_name, ".");
3108 
3109     TABLE_LIST tmp_table;
3110     memset((char *) &tmp_table, 0, sizeof(tmp_table));
3111     tmp_table.table_name= table_name;
3112     tmp_table.db= table_schema;
3113     tmp_table.grant.privilege= 0;
3114     if (check_access(thd, SELECT_ACL, tmp_table.db,
3115                       &tmp_table.grant.privilege, 0, 0,
3116                       is_infoschema_db(table_schema)) ||
3117          check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX, 1))
3118         continue;
3119 
3120     table->field[0]->store(table_schema, strlen(table_schema), system_charset_info);
3121     table->field[1]->store(table_name, strlen(table_name), system_charset_info);
3122     table->field[2]->store(index_full_name, strlen(index_full_name), system_charset_info);
3123     table->field[3]->store(index_stats->rows_read, true);
3124 
3125     if (schema_table_store_record(thd, table))
3126     {
3127       mysql_mutex_unlock(&LOCK_global_index_stats);
3128       DBUG_RETURN(1);
3129     }
3130   }
3131   mysql_mutex_unlock(&LOCK_global_index_stats);
3132   DBUG_RETURN(0);
3133 }
3134 
3135 
3136 /* collect status for all running threads */
3137 
calc_sum_of_all_status(STATUS_VAR * to)3138 void calc_sum_of_all_status(STATUS_VAR *to)
3139 {
3140   DBUG_ENTER("calc_sum_of_all_status");
3141 
3142   mysql_mutex_lock(&LOCK_thread_count);
3143 
3144   Thread_iterator it= global_thread_list_begin();
3145   Thread_iterator end= global_thread_list_end();
3146   /* Get global values as base */
3147   *to= global_status_var;
3148 
3149   /* Add to this status from existing threads */
3150   for (; it != end; ++it)
3151     add_to_status(to, &(*it)->status_var);
3152 
3153   mysql_mutex_unlock(&LOCK_thread_count);
3154   DBUG_VOID_RETURN;
3155 }
3156 
3157 
3158 /* This is only used internally, but we need it here as a forward reference */
3159 extern ST_SCHEMA_TABLE schema_tables[];
3160 
3161 /**
3162   Condition pushdown used for INFORMATION_SCHEMA / SHOW queries.
3163   This structure is to implement an optimization when
3164   accessing data dictionary data in the INFORMATION_SCHEMA
3165   or SHOW commands.
3166   When the query contain a TABLE_SCHEMA or TABLE_NAME clause,
3167   narrow the search for data based on the constraints given.
3168 */
3169 typedef struct st_lookup_field_values
3170 {
3171   /**
3172     Value of a TABLE_SCHEMA clause.
3173     Note that this value length may exceed @c NAME_LEN.
3174     @sa wild_db_value
3175   */
3176   LEX_STRING db_value;
3177   /**
3178     Value of a TABLE_NAME clause.
3179     Note that this value length may exceed @c NAME_LEN.
3180     @sa wild_table_value
3181   */
3182   LEX_STRING table_value;
3183   /**
3184     True when @c db_value is a LIKE clause,
3185     false when @c db_value is an '=' clause.
3186   */
3187   bool wild_db_value;
3188   /**
3189     True when @c table_value is a LIKE clause,
3190     false when @c table_value is an '=' clause.
3191   */
3192   bool wild_table_value;
3193 } LOOKUP_FIELD_VALUES;
3194 
3195 
3196 /*
3197   Store record to I_S table, convert HEAP table
3198   to MyISAM if necessary
3199 
3200   SYNOPSIS
3201     schema_table_store_record()
3202     thd                   thread handler
3203     table                 Information schema table to be updated
3204 
3205   RETURN
3206     0	                  success
3207     1	                  error
3208 */
3209 
schema_table_store_record(THD * thd,TABLE * table)3210 bool schema_table_store_record(THD *thd, TABLE *table)
3211 {
3212   int error;
3213   if ((error= table->file->ha_write_row(table->record[0])))
3214   {
3215     TMP_TABLE_PARAM *param= table->pos_in_table_list->schema_table_param;
3216 
3217     if (create_myisam_from_heap(thd, table, param->start_recinfo,
3218                                 &param->recinfo, error, FALSE, NULL))
3219       return 1;
3220   }
3221   return 0;
3222 }
3223 
3224 
make_table_list(THD * thd,SELECT_LEX * sel,LEX_STRING * db_name,LEX_STRING * table_name)3225 static int make_table_list(THD *thd, SELECT_LEX *sel,
3226                            LEX_STRING *db_name, LEX_STRING *table_name)
3227 {
3228   Table_ident *table_ident;
3229   table_ident= new Table_ident(thd, *db_name, *table_name, 1);
3230   if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ))
3231     return 1;
3232   return 0;
3233 }
3234 
3235 
3236 /**
3237   @brief    Get lookup value from the part of 'WHERE' condition
3238 
3239   @details This function gets lookup value from
3240            the part of 'WHERE' condition if it's possible and
3241            fill appropriate lookup_field_vals struct field
3242            with this value.
3243 
3244   @param[in]      thd                   thread handler
3245   @param[in]      item_func             part of WHERE condition
3246   @param[in]      table                 I_S table
3247   @param[in, out] lookup_field_vals     Struct which holds lookup values
3248 
3249   @return
3250     0             success
3251     1             error, there can be no matching records for the condition
3252 */
3253 
get_lookup_value(THD * thd,Item_func * item_func,TABLE_LIST * table,LOOKUP_FIELD_VALUES * lookup_field_vals)3254 bool get_lookup_value(THD *thd, Item_func *item_func,
3255                       TABLE_LIST *table,
3256                       LOOKUP_FIELD_VALUES *lookup_field_vals)
3257 {
3258   ST_SCHEMA_TABLE *schema_table= table->schema_table;
3259   ST_FIELD_INFO *field_info= schema_table->fields_info;
3260   const char *field_name1= schema_table->idx_field1 >= 0 ?
3261     field_info[schema_table->idx_field1].field_name : "";
3262   const char *field_name2= schema_table->idx_field2 >= 0 ?
3263     field_info[schema_table->idx_field2].field_name : "";
3264 
3265   if (item_func->functype() == Item_func::EQ_FUNC ||
3266       item_func->functype() == Item_func::EQUAL_FUNC)
3267   {
3268     int idx_field, idx_val;
3269     char tmp[MAX_FIELD_WIDTH];
3270     String *tmp_str, str_buff(tmp, sizeof(tmp), system_charset_info);
3271     Item_field *item_field;
3272     CHARSET_INFO *cs= system_charset_info;
3273 
3274     if (item_func->arguments()[0]->type() == Item::FIELD_ITEM &&
3275         item_func->arguments()[1]->const_item())
3276     {
3277       idx_field= 0;
3278       idx_val= 1;
3279     }
3280     else if (item_func->arguments()[1]->type() == Item::FIELD_ITEM &&
3281              item_func->arguments()[0]->const_item())
3282     {
3283       idx_field= 1;
3284       idx_val= 0;
3285     }
3286     else
3287       return 0;
3288 
3289     item_field= (Item_field*) item_func->arguments()[idx_field];
3290     if (table->table != item_field->field->table)
3291       return 0;
3292     tmp_str= item_func->arguments()[idx_val]->val_str(&str_buff);
3293 
3294     /* impossible value */
3295     if (!tmp_str)
3296       return 1;
3297 
3298     /* Lookup value is database name */
3299     if (!cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
3300                                (uchar *) item_field->field_name,
3301                                strlen(item_field->field_name), 0))
3302     {
3303       thd->make_lex_string(&lookup_field_vals->db_value, tmp_str->ptr(),
3304                            tmp_str->length(), FALSE);
3305     }
3306     /* Lookup value is table name */
3307     else if (!cs->coll->strnncollsp(cs, (uchar *) field_name2,
3308                                     strlen(field_name2),
3309                                     (uchar *) item_field->field_name,
3310                                     strlen(item_field->field_name), 0))
3311     {
3312       thd->make_lex_string(&lookup_field_vals->table_value, tmp_str->ptr(),
3313                            tmp_str->length(), FALSE);
3314     }
3315   }
3316   return 0;
3317 }
3318 
3319 
3320 /**
3321   @brief    Calculates lookup values from 'WHERE' condition
3322 
3323   @details This function calculates lookup value(database name, table name)
3324            from 'WHERE' condition if it's possible and
3325            fill lookup_field_vals struct fields with these values.
3326 
3327   @param[in]      thd                   thread handler
3328   @param[in]      cond                  WHERE condition
3329   @param[in]      table                 I_S table
3330   @param[in, out] lookup_field_vals     Struct which holds lookup values
3331 
3332   @return
3333     0             success
3334     1             error, there can be no matching records for the condition
3335 */
3336 
calc_lookup_values_from_cond(THD * thd,Item * cond,TABLE_LIST * table,LOOKUP_FIELD_VALUES * lookup_field_vals)3337 bool calc_lookup_values_from_cond(THD *thd, Item *cond, TABLE_LIST *table,
3338                                   LOOKUP_FIELD_VALUES *lookup_field_vals)
3339 {
3340   if (!cond)
3341     return 0;
3342 
3343   if (cond->type() == Item::COND_ITEM)
3344   {
3345     if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
3346     {
3347       List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
3348       Item *item;
3349       while ((item= li++))
3350       {
3351         if (item->type() == Item::FUNC_ITEM)
3352         {
3353           if (get_lookup_value(thd, (Item_func*)item, table, lookup_field_vals))
3354             return 1;
3355         }
3356         else
3357         {
3358           if (calc_lookup_values_from_cond(thd, item, table, lookup_field_vals))
3359             return 1;
3360         }
3361       }
3362     }
3363     return 0;
3364   }
3365   else if (cond->type() == Item::FUNC_ITEM &&
3366            get_lookup_value(thd, (Item_func*) cond, table, lookup_field_vals))
3367     return 1;
3368   return 0;
3369 }
3370 
3371 
uses_only_table_name_fields(Item * item,TABLE_LIST * table)3372 bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
3373 {
3374   if (item->type() == Item::FUNC_ITEM)
3375   {
3376     Item_func *item_func= (Item_func*)item;
3377     for (uint i=0; i<item_func->argument_count(); i++)
3378     {
3379       if (!uses_only_table_name_fields(item_func->arguments()[i], table))
3380         return 0;
3381     }
3382   }
3383   else if (item->type() == Item::FIELD_ITEM)
3384   {
3385     Item_field *item_field= (Item_field*)item;
3386     CHARSET_INFO *cs= system_charset_info;
3387     ST_SCHEMA_TABLE *schema_table= table->schema_table;
3388     ST_FIELD_INFO *field_info= schema_table->fields_info;
3389     const char *field_name1= schema_table->idx_field1 >= 0 ?
3390       field_info[schema_table->idx_field1].field_name : "";
3391     const char *field_name2= schema_table->idx_field2 >= 0 ?
3392       field_info[schema_table->idx_field2].field_name : "";
3393     if (table->table != item_field->field->table ||
3394         (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
3395                                (uchar *) item_field->field_name,
3396                                strlen(item_field->field_name), 0) &&
3397          cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2),
3398                                (uchar *) item_field->field_name,
3399                                strlen(item_field->field_name), 0)))
3400       return 0;
3401   }
3402   else if (item->type() == Item::REF_ITEM)
3403     return uses_only_table_name_fields(item->real_item(), table);
3404 
3405   if (item->type() == Item::SUBSELECT_ITEM && !item->const_item())
3406     return 0;
3407 
3408   return 1;
3409 }
3410 
3411 
make_cond_for_info_schema(Item * cond,TABLE_LIST * table)3412 static Item * make_cond_for_info_schema(Item *cond, TABLE_LIST *table)
3413 {
3414   if (!cond)
3415     return (Item*) 0;
3416   if (cond->type() == Item::COND_ITEM)
3417   {
3418     if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
3419     {
3420       /* Create new top level AND item */
3421       Item_cond_and *new_cond=new Item_cond_and;
3422       if (!new_cond)
3423 	return (Item*) 0;
3424       List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
3425       Item *item;
3426       while ((item=li++))
3427       {
3428 	Item *fix= make_cond_for_info_schema(item, table);
3429 	if (fix)
3430 	  new_cond->argument_list()->push_back(fix);
3431       }
3432       switch (new_cond->argument_list()->elements) {
3433       case 0:
3434 	return (Item*) 0;
3435       case 1:
3436 	return new_cond->argument_list()->head();
3437       default:
3438 	new_cond->quick_fix_field();
3439 	return new_cond;
3440       }
3441     }
3442     else
3443     {						// Or list
3444       Item_cond_or *new_cond=new Item_cond_or;
3445       if (!new_cond)
3446 	return (Item*) 0;
3447       List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
3448       Item *item;
3449       while ((item=li++))
3450       {
3451 	Item *fix=make_cond_for_info_schema(item, table);
3452 	if (!fix)
3453 	  return (Item*) 0;
3454 	new_cond->argument_list()->push_back(fix);
3455       }
3456       new_cond->quick_fix_field();
3457       new_cond->top_level_item();
3458       return new_cond;
3459     }
3460   }
3461 
3462   if (!uses_only_table_name_fields(cond, table))
3463     return (Item*) 0;
3464   return cond;
3465 }
3466 
3467 
3468 /**
3469   @brief   Calculate lookup values(database name, table name)
3470 
3471   @details This function calculates lookup values(database name, table name)
3472            from 'WHERE' condition or wild values (for 'SHOW' commands only)
3473            from LEX struct and fill lookup_field_vals struct field
3474            with these values.
3475 
3476   @param[in]      thd                   thread handler
3477   @param[in]      cond                  WHERE condition
3478   @param[in]      tables                I_S table
3479   @param[in, out] lookup_field_values   Struct which holds lookup values
3480 
3481   @return
3482     0             success
3483     1             error, there can be no matching records for the condition
3484 */
3485 
get_lookup_field_values(THD * thd,Item * cond,TABLE_LIST * tables,LOOKUP_FIELD_VALUES * lookup_field_values)3486 bool get_lookup_field_values(THD *thd, Item *cond, TABLE_LIST *tables,
3487                              LOOKUP_FIELD_VALUES *lookup_field_values)
3488 {
3489   LEX *lex= thd->lex;
3490   const char *wild= lex->wild ? lex->wild->ptr() : NullS;
3491   bool rc= 0;
3492 
3493   memset(lookup_field_values, 0, sizeof(LOOKUP_FIELD_VALUES));
3494   switch (lex->sql_command) {
3495   case SQLCOM_SHOW_DATABASES:
3496     if (wild)
3497     {
3498       thd->make_lex_string(&lookup_field_values->db_value,
3499                            wild, strlen(wild), 0);
3500       lookup_field_values->wild_db_value= 1;
3501     }
3502     break;
3503   case SQLCOM_SHOW_TABLES:
3504   case SQLCOM_SHOW_TABLE_STATUS:
3505   case SQLCOM_SHOW_TRIGGERS:
3506   case SQLCOM_SHOW_EVENTS:
3507     thd->make_lex_string(&lookup_field_values->db_value,
3508                          lex->select_lex.db, strlen(lex->select_lex.db), 0);
3509     if (wild)
3510     {
3511       thd->make_lex_string(&lookup_field_values->table_value,
3512                            wild, strlen(wild), 0);
3513       lookup_field_values->wild_table_value= 1;
3514     }
3515     break;
3516   default:
3517     /*
3518       The "default" is for queries over I_S.
3519       All previous cases handle SHOW commands.
3520     */
3521     rc= calc_lookup_values_from_cond(thd, cond, tables, lookup_field_values);
3522     break;
3523   }
3524 
3525   if (lower_case_table_names && !rc)
3526   {
3527     /*
3528       We can safely do in-place upgrades here since all of the above cases
3529       are allocating a new memory buffer for these strings.
3530     */
3531     if (lookup_field_values->db_value.str && lookup_field_values->db_value.str[0])
3532       my_casedn_str(system_charset_info, lookup_field_values->db_value.str);
3533     if (lookup_field_values->table_value.str &&
3534         lookup_field_values->table_value.str[0])
3535       my_casedn_str(system_charset_info, lookup_field_values->table_value.str);
3536   }
3537 
3538   return rc;
3539 }
3540 
3541 
get_schema_table_idx(ST_SCHEMA_TABLE * schema_table)3542 enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
3543 {
3544   return (enum enum_schema_tables) (schema_table - &schema_tables[0]);
3545 }
3546 
3547 
3548 /*
3549   Create db names list. Information schema name always is first in list
3550 
3551   SYNOPSIS
3552     make_db_list()
3553     thd                   thread handler
3554     files                 list of db names
3555     wild                  wild string
3556     idx_field_vals        idx_field_vals->db_name contains db name or
3557                           wild string
3558     with_i_schema         returns 1 if we added 'IS' name to list
3559                           otherwise returns 0
3560 
3561   RETURN
3562     zero                  success
3563     non-zero              error
3564 */
3565 
make_db_list(THD * thd,List<LEX_STRING> * files,LOOKUP_FIELD_VALUES * lookup_field_vals,bool * with_i_schema,MEM_ROOT * tmp_mem_root)3566 int make_db_list(THD *thd, List<LEX_STRING> *files,
3567                  LOOKUP_FIELD_VALUES *lookup_field_vals,
3568                  bool *with_i_schema, MEM_ROOT *tmp_mem_root)
3569 {
3570   LEX_STRING *i_s_name_copy= 0;
3571   i_s_name_copy= thd->make_lex_string(i_s_name_copy,
3572                                       INFORMATION_SCHEMA_NAME.str,
3573                                       INFORMATION_SCHEMA_NAME.length, TRUE);
3574   *with_i_schema= 0;
3575   if (lookup_field_vals->wild_db_value)
3576   {
3577     /*
3578       This part of code is only for SHOW DATABASES command.
3579       idx_field_vals->db_value can be 0 when we don't use
3580       LIKE clause (see also get_index_field_values() function)
3581     */
3582     if (!lookup_field_vals->db_value.str ||
3583         !wild_case_compare(system_charset_info,
3584                            INFORMATION_SCHEMA_NAME.str,
3585                            lookup_field_vals->db_value.str))
3586     {
3587       *with_i_schema= 1;
3588       if (files->push_back(i_s_name_copy))
3589         return 1;
3590     }
3591     return (find_files(thd, files, NullS, mysql_data_home,
3592                        lookup_field_vals->db_value.str, 1, tmp_mem_root) !=
3593                       FIND_FILES_OK);
3594   }
3595 
3596 
3597   /*
3598     If we have db lookup value we just add it to list and
3599     exit from the function.
3600     We don't do this for database names longer than the maximum
3601     name length.
3602   */
3603   if (lookup_field_vals->db_value.str)
3604   {
3605     if (lookup_field_vals->db_value.length > NAME_LEN)
3606     {
3607       /*
3608         Impossible value for a database name,
3609         found in a WHERE DATABASE_NAME = 'xxx' clause.
3610       */
3611       return 0;
3612     }
3613 
3614     if (is_infoschema_db(lookup_field_vals->db_value.str,
3615                          lookup_field_vals->db_value.length))
3616     {
3617       *with_i_schema= 1;
3618       if (files->push_back(i_s_name_copy))
3619         return 1;
3620       return 0;
3621     }
3622     if (files->push_back(&lookup_field_vals->db_value))
3623       return 1;
3624     return 0;
3625   }
3626 
3627   /*
3628     Create list of existing databases. It is used in case
3629     of select from information schema table
3630   */
3631   if (files->push_back(i_s_name_copy))
3632     return 1;
3633   *with_i_schema= 1;
3634   return (find_files(thd, files, NullS,
3635                      mysql_data_home, NullS, 1, tmp_mem_root) != FIND_FILES_OK);
3636 }
3637 
3638 
3639 struct st_add_schema_table
3640 {
3641   List<LEX_STRING> *files;
3642   const char *wild;
3643 };
3644 
3645 
add_schema_table(THD * thd,plugin_ref plugin,void * p_data)3646 static my_bool add_schema_table(THD *thd, plugin_ref plugin,
3647                                 void* p_data)
3648 {
3649   LEX_STRING *file_name= 0;
3650   st_add_schema_table *data= (st_add_schema_table *)p_data;
3651   List<LEX_STRING> *file_list= data->files;
3652   const char *wild= data->wild;
3653   ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
3654   DBUG_ENTER("add_schema_table");
3655 
3656   if (schema_table->hidden)
3657       DBUG_RETURN(0);
3658   if (wild)
3659   {
3660     if (lower_case_table_names)
3661     {
3662       if (wild_case_compare(files_charset_info,
3663                             schema_table->table_name,
3664                             wild))
3665         DBUG_RETURN(0);
3666     }
3667     else if (wild_compare(schema_table->table_name, wild, 0))
3668       DBUG_RETURN(0);
3669   }
3670 
3671   if ((file_name= thd->make_lex_string(file_name, schema_table->table_name,
3672                                        strlen(schema_table->table_name),
3673                                        TRUE)) &&
3674       !file_list->push_back(file_name))
3675     DBUG_RETURN(0);
3676   DBUG_RETURN(1);
3677 }
3678 
3679 
schema_tables_add(THD * thd,List<LEX_STRING> * files,const char * wild)3680 int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
3681 {
3682   LEX_STRING *file_name= 0;
3683   ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
3684   st_add_schema_table add_data;
3685   DBUG_ENTER("schema_tables_add");
3686 
3687   for (; tmp_schema_table->table_name; tmp_schema_table++)
3688   {
3689     if (tmp_schema_table->hidden)
3690       continue;
3691     if (wild)
3692     {
3693       if (lower_case_table_names)
3694       {
3695         if (wild_case_compare(files_charset_info,
3696                               tmp_schema_table->table_name,
3697                               wild))
3698           continue;
3699       }
3700       else if (wild_compare(tmp_schema_table->table_name, wild, 0))
3701         continue;
3702     }
3703     if ((file_name=
3704          thd->make_lex_string(file_name, tmp_schema_table->table_name,
3705                               strlen(tmp_schema_table->table_name), TRUE)) &&
3706         !files->push_back(file_name))
3707       continue;
3708     DBUG_RETURN(1);
3709   }
3710 
3711   add_data.files= files;
3712   add_data.wild= wild;
3713   if (plugin_foreach(thd, add_schema_table,
3714                      MYSQL_INFORMATION_SCHEMA_PLUGIN, &add_data))
3715       DBUG_RETURN(1);
3716 
3717   DBUG_RETURN(0);
3718 }
3719 
3720 
3721 /**
3722   @brief          Create table names list
3723 
3724   @details        The function creates the list of table names in
3725                   database
3726 
3727   @param[in]      thd                   thread handler
3728   @param[in]      table_names           List of table names in database
3729   @param[in]      lex                   pointer to LEX struct
3730   @param[in]      lookup_field_vals     pointer to LOOKUP_FIELD_VALUE struct
3731   @param[in]      with_i_schema         TRUE means that we add I_S tables to list
3732   @param[in]      db_name               database name
3733 
3734   @return         Operation status
3735     @retval       0           ok
3736     @retval       1           fatal error
3737     @retval       2           Not fatal error; Safe to ignore this file list
3738 */
3739 
3740 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,MEM_ROOT * tmp_mem_root)3741 make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
3742                      LOOKUP_FIELD_VALUES *lookup_field_vals,
3743                      bool with_i_schema, LEX_STRING *db_name,
3744                      MEM_ROOT *tmp_mem_root)
3745 {
3746   char path[FN_REFLEN + 1];
3747   build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0);
3748   if (!lookup_field_vals->wild_table_value &&
3749       lookup_field_vals->table_value.str)
3750   {
3751     if (lookup_field_vals->table_value.length > NAME_LEN)
3752     {
3753       /*
3754         Impossible value for a table name,
3755         found in a WHERE TABLE_NAME = 'xxx' clause.
3756       */
3757       return 0;
3758     }
3759 
3760     if (with_i_schema)
3761     {
3762       LEX_STRING *name;
3763       ST_SCHEMA_TABLE *schema_table=
3764         find_schema_table(thd, lookup_field_vals->table_value.str);
3765       if (schema_table && !schema_table->hidden)
3766       {
3767         if (!(name=
3768               thd->make_lex_string(NULL, schema_table->table_name,
3769                                    strlen(schema_table->table_name), TRUE)) ||
3770             table_names->push_back(name))
3771           return 1;
3772       }
3773     }
3774     else
3775     {
3776 #ifndef NO_EMBEDDED_ACCESS_CHECKS
3777       if (!(thd->col_access & TABLE_ACLS))
3778       {
3779         TABLE_LIST table_list;
3780         memset(&table_list, 0, sizeof(table_list));
3781 
3782         /*
3783           Database name and table name have already been converted to lowercase
3784           if lower_case_table_names is > 0. We can safely use lookup_field_vals
3785           here.
3786         */
3787         table_list.db= db_name->str;
3788         table_list.db_length= db_name->length;
3789         table_list.table_name_length= lookup_field_vals->table_value.length;
3790         table_list.table_name= lookup_field_vals->table_value.str;
3791         table_list.grant.privilege=thd->col_access;
3792 
3793         if (check_grant(thd, TABLE_ACLS, &table_list, TRUE, 1, TRUE))
3794           return 2;
3795       }
3796 #endif
3797       if (table_names->push_back(&lookup_field_vals->table_value))
3798         return 1;
3799       /*
3800         Check that table is relevant in current transaction.
3801         (used for ndb engine, see ndbcluster_find_files(), ha_ndbcluster.cc)
3802       */
3803       (void) ha_find_files(thd, db_name->str, path,
3804                          lookup_field_vals->table_value.str, 0,
3805                          table_names);
3806     }
3807     return 0;
3808   }
3809 
3810   /*
3811     This call will add all matching the wildcards (if specified) IS tables
3812     to the list
3813   */
3814   if (with_i_schema)
3815     return (schema_tables_add(thd, table_names,
3816                               lookup_field_vals->table_value.str));
3817 
3818   find_files_result res= find_files(thd, table_names, db_name->str, path,
3819                                     lookup_field_vals->table_value.str, 0,
3820                                     tmp_mem_root);
3821   if (res != FIND_FILES_OK)
3822   {
3823     /*
3824       Downgrade errors about problems with database directory to
3825       warnings if this is not a 'SHOW' command.  Another thread
3826       may have dropped database, and we may still have a name
3827       for that directory.
3828     */
3829     if (res == FIND_FILES_DIR)
3830     {
3831       if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)
3832         return 1;
3833       thd->clear_error();
3834       return 2;
3835     }
3836     return 1;
3837   }
3838   return 0;
3839 }
3840 
3841 
3842 /**
3843   Fill I_S table with data obtained by performing full-blown table open.
3844 
3845   @param  thd                       Thread handler.
3846   @param  is_show_fields_or_keys    Indicates whether it is a legacy SHOW
3847                                     COLUMNS or SHOW KEYS statement.
3848   @param  table                     TABLE object for I_S table to be filled.
3849   @param  schema_table              I_S table description structure.
3850   @param  orig_db_name              Database name.
3851   @param  orig_table_name           Table name.
3852   @param  open_tables_state_backup  Open_tables_state object which is used
3853                                     to save/restore original status of
3854                                     variables related to open tables state.
3855   @param  can_deadlock              Indicates that deadlocks are possible
3856                                     due to metadata locks, so to avoid
3857                                     them we should not wait in case if
3858                                     conflicting lock is present.
3859 
3860   @retval FALSE - Success.
3861   @retval TRUE  - Failure.
3862 */
3863 static bool
fill_schema_table_by_open(THD * thd,bool is_show_fields_or_keys,TABLE * table,ST_SCHEMA_TABLE * schema_table,LEX_STRING * orig_db_name,LEX_STRING * orig_table_name,Open_tables_backup * open_tables_state_backup,bool can_deadlock)3864 fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
3865                           TABLE *table, ST_SCHEMA_TABLE *schema_table,
3866                           LEX_STRING *orig_db_name,
3867                           LEX_STRING *orig_table_name,
3868                           Open_tables_backup *open_tables_state_backup,
3869                           bool can_deadlock)
3870 {
3871   Query_arena i_s_arena(thd->mem_root,
3872                         Query_arena::STMT_CONVENTIONAL_EXECUTION),
3873               backup_arena, *old_arena;
3874   LEX *old_lex= thd->lex, temp_lex, *lex;
3875   LEX_STRING db_name, table_name;
3876   TABLE_LIST *table_list;
3877   bool result= true;
3878 
3879   DBUG_ENTER("fill_schema_table_by_open");
3880   /*
3881     When a view is opened its structures are allocated on a permanent
3882     statement arena and linked into the LEX tree for the current statement
3883     (this happens even in cases when view is handled through TEMPTABLE
3884     algorithm).
3885 
3886     To prevent this process from unnecessary hogging of memory in the permanent
3887     arena of our I_S query and to avoid damaging its LEX we use temporary
3888     arena and LEX for table/view opening.
3889 
3890     Use temporary arena instead of statement permanent arena. Also make
3891     it active arena and save original one for successive restoring.
3892   */
3893   old_arena= thd->stmt_arena;
3894   thd->stmt_arena= &i_s_arena;
3895   thd->set_n_backup_active_arena(&i_s_arena, &backup_arena);
3896 
3897   /* Prepare temporary LEX. */
3898   thd->lex= lex= &temp_lex;
3899   lex_start(thd);
3900 
3901   /* Disable constant subquery evaluation as we won't be locking tables. */
3902   lex->context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW;
3903 
3904   /*
3905     Some of process_table() functions rely on wildcard being passed from
3906     old LEX (or at least being initialized).
3907   */
3908   lex->wild= old_lex->wild;
3909 
3910   /*
3911     Since make_table_list() might change database and table name passed
3912     to it we create copies of orig_db_name and orig_table_name here.
3913     These copies are used for make_table_list() while unaltered values
3914     are passed to process_table() functions.
3915   */
3916   if (!thd->make_lex_string(&db_name, orig_db_name->str,
3917                             orig_db_name->length, FALSE) ||
3918       !thd->make_lex_string(&table_name, orig_table_name->str,
3919                             orig_table_name->length, FALSE))
3920     goto end;
3921 
3922   /*
3923     Create table list element for table to be open. Link it with the
3924     temporary LEX. The latter is required to correctly open views and
3925     produce table describing their structure.
3926   */
3927   if (make_table_list(thd, &lex->select_lex, &db_name, &table_name))
3928     goto end;
3929 
3930   table_list= lex->select_lex.table_list.first;
3931 
3932   if (is_show_fields_or_keys)
3933   {
3934     /*
3935       Restore thd->temporary_tables to be able to process
3936       temporary tables (only for 'show index' & 'show columns').
3937       This should be changed when processing of temporary tables for
3938       I_S tables will be done.
3939     */
3940     thd->temporary_tables= open_tables_state_backup->temporary_tables;
3941   }
3942   else
3943   {
3944     /*
3945       Apply optimization flags for table opening which are relevant for
3946       this I_S table. We can't do this for SHOW COLUMNS/KEYS because of
3947       backward compatibility.
3948     */
3949     table_list->i_s_requested_object= schema_table->i_s_requested_object;
3950   }
3951 
3952   /*
3953     Let us set fake sql_command so views won't try to merge
3954     themselves into main statement. If we don't do this,
3955     SELECT * from information_schema.xxxx will cause problems.
3956     SQLCOM_SHOW_FIELDS is used because it satisfies
3957     'only_view_structure()'.
3958   */
3959   lex->sql_command= SQLCOM_SHOW_FIELDS;
3960 
3961   result= open_temporary_tables(thd, table_list);
3962 
3963   if (!result)
3964   {
3965     result= open_normal_and_derived_tables(thd, table_list,
3966                                            (MYSQL_OPEN_IGNORE_FLUSH |
3967                                             MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
3968                                             (can_deadlock ?
3969                                              MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
3970     lex->select_lex.handle_derived(lex, &mysql_derived_create);
3971   }
3972   /*
3973     Restore old value of sql_command back as it is being looked at in
3974     process_table() function.
3975   */
3976   lex->sql_command= old_lex->sql_command;
3977 
3978   DEBUG_SYNC(thd, "after_open_table_ignore_flush");
3979 
3980   /*
3981     XXX:  show_table_list has a flag i_is_requested,
3982     and when it's set, open_normal_and_derived_tables()
3983     can return an error without setting an error message
3984     in THD, which is a hack. This is why we have to
3985     check for res, then for thd->is_error() and only then
3986     for thd->main_da.sql_errno().
3987 
3988     Again we don't do this for SHOW COLUMNS/KEYS because
3989     of backward compatibility.
3990   */
3991   if (!is_show_fields_or_keys && result && thd->is_error() &&
3992       thd->get_stmt_da()->sql_errno() == ER_NO_SUCH_TABLE)
3993   {
3994     /*
3995       Hide error for a non-existing table.
3996       For example, this error can occur when we use a where condition
3997       with a db name and table, but the table does not exist.
3998     */
3999     result= false;
4000     thd->clear_error();
4001   }
4002   else
4003   {
4004     result= schema_table->process_table(thd, table_list,
4005                                         table, result,
4006                                         orig_db_name,
4007                                         orig_table_name);
4008   }
4009 
4010 
4011 end:
4012   lex->unit.cleanup();
4013 
4014   /* Restore original LEX value, statement's arena and THD arena values. */
4015   lex_end(thd->lex);
4016 
4017   // Free items, before restoring backup_arena below.
4018   DBUG_ASSERT(i_s_arena.free_list == NULL);
4019   thd->free_items();
4020 
4021   /*
4022     For safety reset list of open temporary tables before closing
4023     all tables open within this Open_tables_state.
4024   */
4025   thd->temporary_tables= NULL;
4026   close_thread_tables(thd);
4027   /*
4028     Release metadata lock we might have acquired.
4029     See comment in fill_schema_table_from_frm() for details.
4030   */
4031   thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
4032 
4033   thd->lex= old_lex;
4034 
4035   thd->stmt_arena= old_arena;
4036   thd->restore_active_arena(&i_s_arena, &backup_arena);
4037 
4038   DBUG_RETURN(result);
4039 }
4040 
4041 
4042 /**
4043   @brief          Fill I_S table for SHOW TABLE NAMES commands
4044 
4045   @param[in]      thd                      thread handler
4046   @param[in]      table                    TABLE struct for I_S table
4047   @param[in]      db_name                  database name
4048   @param[in]      table_name               table name
4049   @param[in]      with_i_schema            I_S table if TRUE
4050 
4051   @return         Operation status
4052     @retval       0           success
4053     @retval       1           error
4054 */
4055 
fill_schema_table_names(THD * thd,TABLE * table,LEX_STRING * db_name,LEX_STRING * table_name,bool with_i_schema,bool need_table_type)4056 static int fill_schema_table_names(THD *thd, TABLE *table,
4057                                    LEX_STRING *db_name, LEX_STRING *table_name,
4058                                    bool with_i_schema,
4059                                    bool need_table_type)
4060 {
4061   /* Avoid opening FRM files if table type is not needed. */
4062   if (need_table_type)
4063   {
4064     if (with_i_schema)
4065     {
4066       table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
4067                              system_charset_info);
4068     }
4069     else
4070     {
4071       enum legacy_db_type not_used;
4072       char path[FN_REFLEN + 1];
4073       (void) build_table_filename(path, sizeof(path) - 1, db_name->str,
4074                                   table_name->str, reg_ext, 0);
4075       switch (dd_frm_type(thd, path, &not_used)) {
4076       case FRMTYPE_ERROR:
4077         table->field[3]->store(STRING_WITH_LEN("ERROR"),
4078                                system_charset_info);
4079         break;
4080       case FRMTYPE_TABLE:
4081         table->field[3]->store(STRING_WITH_LEN("BASE TABLE"),
4082                                system_charset_info);
4083         break;
4084       case FRMTYPE_VIEW:
4085         table->field[3]->store(STRING_WITH_LEN("VIEW"),
4086                                system_charset_info);
4087         break;
4088       default:
4089         DBUG_ASSERT(0);
4090       }
4091     if (thd->is_error() && thd->get_stmt_da()->sql_errno() == ER_NO_SUCH_TABLE)
4092       {
4093         thd->clear_error();
4094         return 0;
4095       }
4096     }
4097   }
4098   if (schema_table_store_record(thd, table))
4099     return 1;
4100   return 0;
4101 }
4102 
4103 
4104 /**
4105   @brief          Get open table method
4106 
4107   @details        The function calculates the method which will be used
4108                   for table opening:
4109                   SKIP_OPEN_TABLE - do not open table
4110                   OPEN_FRM_ONLY   - open FRM file only
4111                   OPEN_FULL_TABLE - open FRM, data, index files
4112   @param[in]      tables               I_S table table_list
4113   @param[in]      schema_table         I_S table struct
4114   @param[in]      schema_table_idx     I_S table index
4115 
4116   @return         return a set of flags
4117     @retval       SKIP_OPEN_TABLE | OPEN_FRM_ONLY | OPEN_FULL_TABLE
4118 */
4119 
get_table_open_method(TABLE_LIST * tables,ST_SCHEMA_TABLE * schema_table,enum enum_schema_tables schema_table_idx)4120 uint get_table_open_method(TABLE_LIST *tables,
4121                                   ST_SCHEMA_TABLE *schema_table,
4122                                   enum enum_schema_tables schema_table_idx)
4123 {
4124   /*
4125     determine which method will be used for table opening
4126   */
4127   if (schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
4128   {
4129     Field **ptr, *field;
4130     int table_open_method= 0, field_indx= 0;
4131     uint star_table_open_method= OPEN_FULL_TABLE;
4132     bool used_star= true;                  // true if '*' is used in select
4133     for (ptr=tables->table->field; (field= *ptr) ; ptr++)
4134     {
4135       star_table_open_method=
4136         min(star_table_open_method,
4137             schema_table->fields_info[field_indx].open_method);
4138       if (bitmap_is_set(tables->table->read_set, field->field_index))
4139       {
4140         used_star= false;
4141         table_open_method|= schema_table->fields_info[field_indx].open_method;
4142       }
4143       field_indx++;
4144     }
4145     if (used_star)
4146       return star_table_open_method;
4147     return table_open_method;
4148   }
4149   /* I_S tables which use get_all_tables but can not be optimized */
4150   return (uint) OPEN_FULL_TABLE;
4151 }
4152 
4153 /**
4154   @brief          Change I_S table item list for SHOW [GLOBAL] TEMPORARY TABLES [FROM/IN db]
4155 
4156   @param[in]      thd                      thread handler
4157   @param[in]      schema_table             I_S table
4158 
4159   @return         Operation status
4160     @retval       0                        success
4161     @retval       1                        error
4162 */
4163 static
make_temporary_tables_old_format(THD * thd,ST_SCHEMA_TABLE * schema_table)4164 int make_temporary_tables_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
4165 {
4166   char tmp[128];
4167   String buffer(tmp,sizeof(tmp), thd->charset());
4168   LEX *lex= thd->lex;
4169   Name_resolution_context *context= &lex->select_lex.context;
4170 
4171   if (thd->lex->option_type == OPT_GLOBAL) {
4172     ST_FIELD_INFO *field_info= &schema_table->fields_info[0];
4173     Item_field *field= new Item_field(context, NullS, NullS, field_info->field_name);
4174     if (add_item_to_list(thd, field))
4175       return 1;
4176     field->item_name.copy(field_info->old_name, strlen(field_info->old_name), system_charset_info);
4177   }
4178 
4179   ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
4180   buffer.length(0);
4181   buffer.append(field_info->old_name);
4182   buffer.append(lex->select_lex.db);
4183 
4184   if (lex->wild && lex->wild->ptr())
4185   {
4186     buffer.append(STRING_WITH_LEN(" ("));
4187     buffer.append(lex->wild->ptr());
4188     buffer.append(')');
4189   }
4190 
4191   Item_field *field= new Item_field(context, NullS, NullS, field_info->field_name);
4192   if (add_item_to_list(thd, field))
4193     return 1;
4194 
4195   field->item_name.copy(buffer.ptr(), buffer.length(), system_charset_info);
4196   return 0;
4197 }
4198 
4199 /**
4200   @brief          Fill records for temporary tables by reading info from table object
4201 
4202   @param[in]      thd                      thread handler
4203   @param[in]      table                    I_S table
4204   @param[in]      tmp_table                temporary table
4205   @param[in]      db                       database name
4206   @param[in]      mem_root                 memory root for allocating cloned
4207                                            handlers, must have the lifetime of
4208                                            the current thread
4209 
4210   @return         Operation status
4211     @retval       0                        success
4212     @retval       1                        error
4213 */
4214 
store_temporary_table_record(THD * thd,TABLE * table,TABLE * tmp_table,const char * db,MEM_ROOT * mem_root)4215 static int store_temporary_table_record(THD *thd, TABLE *table,
4216                                         TABLE *tmp_table, const char *db,
4217                                         MEM_ROOT* mem_root)
4218 {
4219   CHARSET_INFO *cs= system_charset_info;
4220   DBUG_ENTER("store_temporary_table_record");
4221 
4222   if (db && my_strcasecmp(cs, db, tmp_table->s->db.str))
4223     DBUG_RETURN(0);
4224 
4225   restore_record(table, s->default_values);
4226 
4227   //session_id
4228   table->field[0]->store((longlong) thd->thread_id, TRUE);
4229 
4230   //database
4231   table->field[1]->store(tmp_table->s->db.str, tmp_table->s->db.length, cs);
4232 
4233   //table
4234   table->field[2]->store(tmp_table->s->table_name.str, tmp_table->s->table_name.length, cs);
4235 
4236   //engine
4237   handler *handle= tmp_table->file;
4238   // Assume that invoking handler::table_type() on a shared handler is safe
4239   const char *engineType = (char *)(handle ? handle->table_type() : "UNKNOWN");
4240   table->field[3]->store(engineType, strlen(engineType), cs);
4241 
4242   //name
4243   if (tmp_table->s->path.str) {
4244     char *p=strstr(tmp_table->s->path.str, "#sql");
4245     int len=tmp_table->s->path.length-(p-tmp_table->s->path.str);
4246     table->field[4]->store(p, min(FN_REFLEN, len), cs);
4247   }
4248 
4249   // file stats
4250   handler *file= tmp_table->file;
4251 
4252   /* We have only one handler object for a temp table globally and it might
4253   be in use by other thread.  Do not trash it by invoking handler methods on
4254   it but rather clone it. */
4255   if (file) {
4256     file= file->clone(tmp_table->s->normalized_path.str, mem_root);
4257   }
4258 
4259   if (file) {
4260 
4261     MYSQL_TIME time;
4262 
4263     /**
4264         TODO: InnoDB stat(file) checks file on short names within data dictionary
4265         rather than using full path, because of that, temp files created in
4266         TMPDIR will not have access/create time as it will not find the file
4267 
4268         The fix is to patch InnoDB to use full path
4269     */
4270     file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
4271 
4272     table->field[5]->store((longlong) file->stats.records, TRUE);
4273     table->field[5]->set_notnull();
4274 
4275     table->field[6]->store((longlong) file->stats.mean_rec_length, TRUE);
4276     table->field[7]->store((longlong) file->stats.data_file_length, TRUE);
4277     table->field[8]->store((longlong) file->stats.index_file_length, TRUE);
4278     if (file->stats.create_time)
4279     {
4280       thd->variables.time_zone->gmt_sec_to_TIME(&time,
4281                                                 (my_time_t) file->stats.create_time);
4282       table->field[9]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
4283       table->field[9]->set_notnull();
4284     }
4285     if (file->stats.update_time)
4286     {
4287       thd->variables.time_zone->gmt_sec_to_TIME(&time,
4288                                                 (my_time_t) file->stats.update_time);
4289       table->field[10]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
4290       table->field[10]->set_notnull();
4291     }
4292 
4293     file->ha_close();
4294   }
4295 
4296   DBUG_RETURN(schema_table_store_record(thd, table));
4297 }
4298 
4299 /**
4300   @brief          Fill I_S tables with global temporary tables
4301 
4302   @param[in]      thd                      thread handler
4303   @param[in]      tables                   I_S table
4304   @param[in]      cond                     'WHERE' condition
4305 
4306   @return         Operation status
4307     @retval       0                        success
4308     @retval       1                        error
4309 */
4310 
fill_global_temporary_tables(THD * thd,TABLE_LIST * tables,Item * cond)4311 static int fill_global_temporary_tables(THD *thd, TABLE_LIST *tables, Item *cond)
4312 {
4313   DBUG_ENTER("fill_global_temporary_tables");
4314 
4315   mysql_mutex_lock(&LOCK_thread_count);
4316 
4317   Thread_iterator it= global_thread_list_begin();
4318   Thread_iterator end= global_thread_list_end();
4319   THD *thd_item;
4320   TABLE *tmp;
4321 
4322 #ifndef NO_EMBEDDED_ACCESS_CHECKS
4323   Security_context *sctx= thd->security_ctx;
4324   uint db_access;
4325 #endif
4326 
4327   while (it != end && (thd_item=*(it++))) {
4328     mysql_mutex_lock(&thd_item->LOCK_temporary_tables);
4329 
4330 #ifndef DBUG_OFF
4331     const char* tmp_proc_info= thd_item->proc_info;
4332     if (tmp_proc_info &&
4333         !strncmp(tmp_proc_info,
4334                  STRING_WITH_LEN("debug sync point: before_open_in_get_all_tables"))) {
4335       DEBUG_SYNC(thd,
4336                  "fill_global_temporary_tables_thd_item_at_tables_debug_sync");
4337     }
4338 #endif
4339 
4340     for (tmp=thd_item->temporary_tables; tmp; tmp=tmp->next) {
4341 
4342 #ifndef NO_EMBEDDED_ACCESS_CHECKS
4343       if (test_all_bits(sctx->master_access, DB_ACLS))
4344         db_access=DB_ACLS;
4345       else
4346         db_access= (acl_get(sctx->get_host()->ptr(), sctx->get_ip()->ptr(),
4347                             sctx->priv_user, tmp->s->db.str, 0)
4348                     | sctx->master_access);
4349 
4350       if (!(db_access & DB_ACLS) && check_grant_db(thd,tmp->s->db.str)) {
4351         //no access for temp tables within this db for user
4352         continue;
4353       }
4354 #endif
4355 
4356       DEBUG_SYNC(thd, "fill_global_temporary_tables_before_storing_rec");
4357 
4358       if (store_temporary_table_record(thd_item, tables->table, tmp,
4359                                        thd->lex->select_lex.db,
4360                                        thd->mem_root)) {
4361         mysql_mutex_unlock(&thd_item->LOCK_temporary_tables);
4362         mysql_mutex_unlock(&LOCK_thread_count);
4363         DBUG_RETURN(1);
4364       }
4365 
4366     }
4367     mysql_mutex_unlock(&thd_item->LOCK_temporary_tables);
4368   }
4369 
4370   mysql_mutex_unlock(&LOCK_thread_count);
4371   DBUG_RETURN(0);
4372 }
4373 
4374 /**
4375   @brief          Fill I_S tables with session temporary tables
4376 
4377   @param[in]      thd                      thread handler
4378   @param[in]      tables                   I_S table
4379   @param[in]      cond                     'WHERE' condition
4380 
4381   @return         Operation status
4382     @retval       0                        success
4383     @retval       1                        error
4384 */
4385 static
fill_temporary_tables(THD * thd,TABLE_LIST * tables,Item * cond)4386 int fill_temporary_tables(THD *thd, TABLE_LIST *tables, Item *cond)
4387 {
4388   DBUG_ENTER("fill_temporary_tables");
4389 
4390   if (thd->lex->option_type == OPT_GLOBAL)
4391     DBUG_RETURN(fill_global_temporary_tables(thd, tables, cond));
4392 
4393   TABLE *tmp;
4394 
4395   for (tmp=thd->temporary_tables; tmp; tmp=tmp->next) {
4396     if (store_temporary_table_record(thd, tables->table, tmp,
4397                                      thd->lex->select_lex.db,
4398                                      thd->mem_root)) {
4399       DBUG_RETURN(1);
4400     }
4401   }
4402   DBUG_RETURN(0);
4403 }
4404 
4405 /**
4406    Try acquire high priority share metadata lock on a table (with
4407    optional wait for conflicting locks to go away).
4408 
4409    @param thd            Thread context.
4410    @param mdl_request    Pointer to memory to be used for MDL_request
4411                          object for a lock request.
4412    @param table          Table list element for the table
4413    @param can_deadlock   Indicates that deadlocks are possible due to
4414                          metadata locks, so to avoid them we should not
4415                          wait in case if conflicting lock is present.
4416 
4417    @note This is an auxiliary function to be used in cases when we want to
4418          access table's description by looking up info in TABLE_SHARE without
4419          going through full-blown table open.
4420    @note This function assumes that there are no other metadata lock requests
4421          in the current metadata locking context.
4422 
4423    @retval FALSE  No error, if lock was obtained TABLE_LIST::mdl_request::ticket
4424                   is set to non-NULL value.
4425    @retval TRUE   Some error occured (probably thread was killed).
4426 */
4427 
4428 static bool
try_acquire_high_prio_shared_mdl_lock(THD * thd,TABLE_LIST * table,bool can_deadlock)4429 try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
4430                                       bool can_deadlock)
4431 {
4432   bool error;
4433   table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
4434                           MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION);
4435 
4436   if (can_deadlock)
4437   {
4438     /*
4439       When .FRM is being open in order to get data for an I_S table,
4440       we might have some tables not only open but also locked.
4441       E.g. this happens when a SHOW or I_S statement is run
4442       under LOCK TABLES or inside a stored function.
4443       By waiting for the conflicting metadata lock to go away we
4444       might create a deadlock which won't entirely belong to the
4445       MDL subsystem and thus won't be detectable by this subsystem's
4446       deadlock detector. To avoid such situation, when there are
4447       other locked tables, we prefer not to wait on a conflicting
4448       lock.
4449     */
4450     error= thd->mdl_context.try_acquire_lock(&table->mdl_request);
4451   }
4452   else
4453     error= thd->mdl_context.acquire_lock(&table->mdl_request,
4454                                          thd->variables.lock_wait_timeout);
4455 
4456   return error;
4457 }
4458 
4459 
4460 /**
4461   @brief          Fill I_S table with data from FRM file only
4462 
4463   @param[in]      thd                      thread handler
4464   @param[in]      table                    TABLE struct for I_S table
4465   @param[in]      schema_table             I_S table struct
4466   @param[in]      db_name                  database name
4467   @param[in]      table_name               table name
4468   @param[in]      schema_table_idx         I_S table index
4469   @param[in]      open_tables_state_backup Open_tables_state object which is used
4470                                            to save/restore original state of metadata
4471                                            locks.
4472   @param[in]      can_deadlock             Indicates that deadlocks are possible
4473                                            due to metadata locks, so to avoid
4474                                            them we should not wait in case if
4475                                            conflicting lock is present.
4476 
4477   @return         Operation status
4478     @retval       0           Table is processed and we can continue
4479                               with new table
4480     @retval       1           It's view and we have to use
4481                               open_tables function for this table
4482 */
4483 
fill_schema_table_from_frm(THD * thd,TABLE_LIST * tables,ST_SCHEMA_TABLE * schema_table,LEX_STRING * db_name,LEX_STRING * table_name,enum enum_schema_tables schema_table_idx,Open_tables_backup * open_tables_state_backup,bool can_deadlock)4484 static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
4485                                       ST_SCHEMA_TABLE *schema_table,
4486                                       LEX_STRING *db_name,
4487                                       LEX_STRING *table_name,
4488                                       enum enum_schema_tables schema_table_idx,
4489                                       Open_tables_backup *open_tables_state_backup,
4490                                       bool can_deadlock)
4491 {
4492   TABLE *table= tables->table;
4493   TABLE_SHARE *share;
4494   TABLE tbl;
4495   TABLE_LIST table_list;
4496   uint res= 0;
4497   int not_used;
4498   my_hash_value_type hash_value;
4499   const char *key;
4500   uint key_length;
4501   char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1];
4502 
4503   memset(static_cast<void*>(&table_list), 0, sizeof(TABLE_LIST));
4504   memset(static_cast<void*>(&tbl), 0, sizeof(TABLE));
4505 
4506   DBUG_ASSERT(db_name->length <= NAME_LEN);
4507   DBUG_ASSERT(table_name->length <= NAME_LEN);
4508 
4509   if (lower_case_table_names)
4510   {
4511     /*
4512       In lower_case_table_names > 0 metadata locking and table definition
4513       cache subsystems require normalized (lowercased) database and table
4514       names as input.
4515     */
4516     strmov(db_name_buff, db_name->str);
4517     strmov(table_name_buff, table_name->str);
4518     my_casedn_str(files_charset_info, db_name_buff);
4519     my_casedn_str(files_charset_info, table_name_buff);
4520     table_list.db= db_name_buff;
4521     table_list.table_name= table_name_buff;
4522   }
4523   else
4524   {
4525     table_list.table_name= table_name->str;
4526     table_list.db= db_name->str;
4527   }
4528 
4529   /*
4530     TODO: investigate if in this particular situation we can get by
4531           simply obtaining internal lock of the data-dictionary
4532           instead of obtaining full-blown metadata lock.
4533   */
4534   if (try_acquire_high_prio_shared_mdl_lock(thd, &table_list, can_deadlock))
4535   {
4536     /*
4537       Some error occured (most probably we have been killed while
4538       waiting for conflicting locks to go away), let the caller to
4539       handle the situation.
4540     */
4541     return 1;
4542   }
4543 
4544   if (! table_list.mdl_request.ticket)
4545   {
4546     /*
4547       We are in situation when we have encountered conflicting metadata
4548       lock and deadlocks can occur due to waiting for it to go away.
4549       So instead of waiting skip this table with an appropriate warning.
4550     */
4551     DBUG_ASSERT(can_deadlock);
4552 
4553     push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4554                         ER_WARN_I_S_SKIPPED_TABLE,
4555                         ER(ER_WARN_I_S_SKIPPED_TABLE),
4556                         table_list.db, table_list.table_name);
4557     return 0;
4558   }
4559 
4560   if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY)
4561   {
4562     init_sql_alloc(&tbl.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
4563     if (!Table_triggers_list::check_n_load(thd, db_name->str,
4564                                            table_name->str, &tbl, 1))
4565     {
4566       table_list.table= &tbl;
4567       res= schema_table->process_table(thd, &table_list, table,
4568                                        res, db_name, table_name);
4569       delete tbl.triggers;
4570     }
4571     free_root(&tbl.mem_root, MYF(0));
4572     goto end;
4573   }
4574 
4575   key_length= get_table_def_key(&table_list, &key);
4576   hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
4577   mysql_mutex_lock(&LOCK_open);
4578   share= get_table_share(thd, &table_list, key,
4579                          key_length, OPEN_VIEW, &not_used, hash_value);
4580   if (!share)
4581   {
4582     res= 0;
4583     goto end_unlock;
4584   }
4585 
4586   if (share->is_view)
4587   {
4588     if (schema_table->i_s_requested_object & OPEN_TABLE_ONLY)
4589     {
4590       /* skip view processing */
4591       res= 0;
4592       goto end_share;
4593     }
4594     else if (schema_table->i_s_requested_object & OPEN_VIEW_FULL)
4595     {
4596       /*
4597         tell get_all_tables() to fall back to
4598         open_normal_and_derived_tables()
4599       */
4600       res= 1;
4601       goto end_share;
4602     }
4603   }
4604 
4605   if (share->is_view)
4606   {
4607     if (mysql_make_view(thd, share, &table_list, true))
4608       goto end_share;
4609     table_list.view= (LEX*) share->is_view;
4610     res= schema_table->process_table(thd, &table_list, table,
4611                                      res, db_name, table_name);
4612     goto end_share;
4613   }
4614 
4615   if (!open_table_from_share(thd, share, table_name->str, 0,
4616                              (EXTRA_RECORD | OPEN_FRM_FILE_ONLY),
4617                              thd->open_options, &tbl, FALSE))
4618   {
4619     tbl.s= share;
4620     table_list.table= &tbl;
4621     table_list.view= (LEX*) share->is_view;
4622     res= schema_table->process_table(thd, &table_list, table,
4623                                      res, db_name, table_name);
4624     free_root(&tbl.mem_root, MYF(0));
4625     my_free((void *) tbl.alias);
4626   }
4627 
4628 end_share:
4629   release_table_share(share);
4630 
4631 end_unlock:
4632   mysql_mutex_unlock(&LOCK_open);
4633 
4634 end:
4635   /*
4636     Release metadata lock we might have acquired.
4637 
4638     Without this step metadata locks acquired for each table processed
4639     will be accumulated. In situation when a lot of tables are processed
4640     by I_S query this will result in transaction with too many metadata
4641     locks. As result performance of acquisition of new lock will suffer.
4642 
4643     Of course, the fact that we don't hold metadata lock on tables which
4644     were processed till the end of I_S query makes execution less isolated
4645     from concurrent DDL. Consequently one might get 'dirty' results from
4646     such a query. But we have never promised serializability of I_S queries
4647     anyway.
4648 
4649     We don't have any tables open since we took backup, so rolling back to
4650     savepoint is safe.
4651   */
4652   DBUG_ASSERT(thd->open_tables == NULL);
4653   thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
4654   thd->clear_error();
4655   return res;
4656 }
4657 
4658 
4659 /**
4660   Trigger_error_handler is intended to intercept and silence SQL conditions
4661   that might happen during trigger loading for SHOW statements.
4662   The potential SQL conditions are:
4663 
4664     - ER_PARSE_ERROR -- this error is thrown if a trigger definition file
4665       is damaged or contains invalid CREATE TRIGGER statement. That should
4666       not happen in normal life.
4667 
4668     - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a
4669       trigger created/imported in/from the version of MySQL, which does not
4670       support trigger definers.
4671 
4672     - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a
4673       trigger created/imported in/from the version of MySQL, which does not
4674       support trigger creation contexts.
4675 */
4676 
4677 class Trigger_error_handler : public Internal_error_handler
4678 {
4679 public:
handle_condition(THD * thd,uint sql_errno,const char * sqlstate,Sql_condition::enum_warning_level level,const char * msg,Sql_condition ** cond_hdl)4680   bool handle_condition(THD *thd,
4681                         uint sql_errno,
4682                         const char* sqlstate,
4683                         Sql_condition::enum_warning_level level,
4684                         const char* msg,
4685                         Sql_condition ** cond_hdl)
4686   {
4687     if (sql_errno == ER_PARSE_ERROR ||
4688         sql_errno == ER_TRG_NO_DEFINER ||
4689         sql_errno == ER_TRG_NO_CREATION_CTX)
4690       return true;
4691 
4692     return false;
4693   }
4694 };
4695 
4696 
4697 
4698 /**
4699   @brief          Fill I_S tables whose data are retrieved
4700                   from frm files and storage engine
4701 
4702   @details        The information schema tables are internally represented as
4703                   temporary tables that are filled at query execution time.
4704                   Those I_S tables whose data are retrieved
4705                   from frm files and storage engine are filled by the function
4706                   get_all_tables().
4707 
4708   @param[in]      thd                      thread handler
4709   @param[in]      tables                   I_S table
4710   @param[in]      cond                     'WHERE' condition
4711 
4712   @return         Operation status
4713     @retval       0                        success
4714     @retval       1                        error
4715 */
4716 
get_all_tables(THD * thd,TABLE_LIST * tables,Item * cond)4717 int get_all_tables(THD *thd, TABLE_LIST *tables, Item *cond)
4718 {
4719   LEX *lex= thd->lex;
4720   TABLE *table= tables->table;
4721   SELECT_LEX *lsel= tables->schema_select_lex;
4722   ST_SCHEMA_TABLE *schema_table= tables->schema_table;
4723   LOOKUP_FIELD_VALUES lookup_field_vals;
4724   LEX_STRING *db_name, *table_name;
4725   bool with_i_schema;
4726   enum enum_schema_tables schema_table_idx;
4727   List<LEX_STRING> db_names;
4728   List_iterator_fast<LEX_STRING> it(db_names);
4729   Item *partial_cond= 0;
4730   int error= 1;
4731   Open_tables_backup open_tables_state_backup;
4732 #ifndef NO_EMBEDDED_ACCESS_CHECKS
4733   Security_context *sctx= thd->security_ctx;
4734 #endif
4735   uint table_open_method;
4736   bool can_deadlock;
4737   DBUG_ENTER("get_all_tables");
4738 
4739   MEM_ROOT tmp_mem_root;
4740   init_sql_alloc(&tmp_mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
4741 
4742   /*
4743     In cases when SELECT from I_S table being filled by this call is
4744     part of statement which also uses other tables or is being executed
4745     under LOCK TABLES or is part of transaction which also uses other
4746     tables waiting for metadata locks which happens below might result
4747     in deadlocks.
4748     To avoid them we don't wait if conflicting metadata lock is
4749     encountered and skip table with emitting an appropriate warning.
4750   */
4751   can_deadlock= thd->mdl_context.has_locks();
4752 
4753   /*
4754     We should not introduce deadlocks even if we already have some
4755     tables open and locked, since we won't lock tables which we will
4756     open and will ignore pending exclusive metadata locks for these
4757     tables by using high-priority requests for shared metadata locks.
4758   */
4759   thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
4760 
4761   schema_table_idx= get_schema_table_idx(schema_table);
4762   tables->table_open_method= table_open_method=
4763     get_table_open_method(tables, schema_table, schema_table_idx);
4764   DBUG_PRINT("open_method", ("%d", tables->table_open_method));
4765   /*
4766     this branch processes SHOW FIELDS, SHOW INDEXES commands.
4767     see sql_parse.cc, prepare_schema_table() function where
4768     this values are initialized
4769   */
4770   if (lsel && lsel->table_list.first)
4771   {
4772     LEX_STRING db_name, table_name;
4773 
4774     db_name.str= lsel->table_list.first->db;
4775     db_name.length= lsel->table_list.first->db_length;
4776 
4777     table_name.str= lsel->table_list.first->table_name;
4778     table_name.length= lsel->table_list.first->table_name_length;
4779 
4780     error= fill_schema_table_by_open(thd, TRUE,
4781                                      table, schema_table,
4782                                      &db_name, &table_name,
4783                                      &open_tables_state_backup,
4784                                      can_deadlock);
4785     goto err;
4786   }
4787 
4788   if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
4789   {
4790     error= 0;
4791     goto err;
4792   }
4793 
4794   DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'",
4795                              STR_OR_NIL(lookup_field_vals.db_value.str),
4796                              STR_OR_NIL(lookup_field_vals.table_value.str)));
4797 
4798   if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
4799   {
4800     /*
4801       if lookup value is empty string then
4802       it's impossible table name or db name
4803     */
4804     if ((lookup_field_vals.db_value.str &&
4805          !lookup_field_vals.db_value.str[0]) ||
4806         (lookup_field_vals.table_value.str &&
4807          !lookup_field_vals.table_value.str[0]))
4808     {
4809       error= 0;
4810       goto err;
4811     }
4812   }
4813 
4814   if (lookup_field_vals.db_value.length &&
4815       !lookup_field_vals.wild_db_value)
4816     tables->has_db_lookup_value= TRUE;
4817   if (lookup_field_vals.table_value.length &&
4818       !lookup_field_vals.wild_table_value)
4819     tables->has_table_lookup_value= TRUE;
4820 
4821   if (tables->has_db_lookup_value && tables->has_table_lookup_value)
4822     partial_cond= 0;
4823   else
4824     partial_cond= make_cond_for_info_schema(cond, tables);
4825 
4826   if (lex->describe)
4827   {
4828     /* EXPLAIN SELECT */
4829     error= 0;
4830     goto err;
4831   }
4832 
4833   if (make_db_list(thd, &db_names, &lookup_field_vals, &with_i_schema, &tmp_mem_root))
4834     goto err;
4835   it.rewind(); /* To get access to new elements in basis list */
4836   while ((db_name= it++))
4837   {
4838     DBUG_ASSERT(db_name->length <= NAME_LEN);
4839 #ifndef NO_EMBEDDED_ACCESS_CHECKS
4840     if (!(check_access(thd, SELECT_ACL, db_name->str,
4841                        &thd->col_access, NULL, 0, 1) ||
4842           (!thd->col_access && check_grant_db(thd, db_name->str))) ||
4843         sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
4844         acl_get(sctx->get_host()->ptr(), sctx->get_ip()->ptr(),
4845                 sctx->priv_user, db_name->str, 0))
4846 #endif
4847     {
4848       List<LEX_STRING> table_names;
4849       int res= make_table_name_list(thd, &table_names, lex,
4850                                     &lookup_field_vals,
4851                                     with_i_schema, db_name, &tmp_mem_root);
4852       if (res == 2)   /* Not fatal error, continue */
4853         continue;
4854       if (res)
4855         goto err;
4856 
4857       List_iterator_fast<LEX_STRING> it_files(table_names);
4858       while ((table_name= it_files++))
4859       {
4860         DBUG_ASSERT(table_name->length <= NAME_LEN);
4861 	restore_record(table, s->default_values);
4862         table->field[schema_table->idx_field1]->
4863           store(db_name->str, db_name->length, system_charset_info);
4864         table->field[schema_table->idx_field2]->
4865           store(table_name->str, table_name->length, system_charset_info);
4866 
4867         if (!partial_cond || partial_cond->val_int())
4868         {
4869           /*
4870             If table is I_S.tables and open_table_method is 0 (eg SKIP_OPEN)
4871             we can skip table opening and we don't have lookup value for
4872             table name or lookup value is wild string(table name list is
4873             already created by make_table_name_list() function).
4874           */
4875           if (!table_open_method && schema_table_idx == SCH_TABLES &&
4876               (!lookup_field_vals.table_value.length ||
4877                lookup_field_vals.wild_table_value))
4878           {
4879             table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
4880             if (schema_table_store_record(thd, table))
4881               goto err;      /* Out of space in temporary table */
4882             continue;
4883           }
4884 
4885           /* SHOW TABLE NAMES command */
4886           if (schema_table_idx == SCH_TABLE_NAMES)
4887           {
4888             if (fill_schema_table_names(thd, tables->table, db_name,
4889                                         table_name, with_i_schema,
4890                                         lex->verbose))
4891               continue;
4892           }
4893           else
4894           {
4895             if (!(table_open_method & ~OPEN_FRM_ONLY) &&
4896                 !with_i_schema)
4897             {
4898               /*
4899                 Here we need to filter out warnings, which can happen
4900                 during loading of triggers in fill_schema_table_from_frm(),
4901                 because we don't need those warnings to pollute output of
4902                 SELECT from I_S / SHOW-statements.
4903               */
4904 
4905               Trigger_error_handler err_handler;
4906               thd->push_internal_handler(&err_handler);
4907 
4908               int res= fill_schema_table_from_frm(thd, tables, schema_table,
4909                                                   db_name, table_name,
4910                                                   schema_table_idx,
4911                                                   &open_tables_state_backup,
4912                                                   can_deadlock);
4913 
4914               thd->pop_internal_handler();
4915 
4916               if (!res)
4917                 continue;
4918             }
4919 
4920             DEBUG_SYNC(thd, "before_open_in_get_all_tables");
4921 
4922             if (fill_schema_table_by_open(thd, FALSE,
4923                                           table, schema_table,
4924                                           db_name, table_name,
4925                                           &open_tables_state_backup,
4926                                           can_deadlock))
4927               goto err;
4928           }
4929         }
4930       }
4931       /*
4932         If we have information schema its always the first table and only
4933         the first table. Reset for other tables.
4934       */
4935       with_i_schema= 0;
4936     }
4937   }
4938   error= 0;
4939 err:
4940 
4941   free_root(&tmp_mem_root, MYF(0));
4942   thd->restore_backup_open_tables_state(&open_tables_state_backup);
4943 
4944   DBUG_RETURN(error);
4945 }
4946 
4947 
store_schema_shemata(THD * thd,TABLE * table,LEX_STRING * db_name,const CHARSET_INFO * cs)4948 bool store_schema_shemata(THD* thd, TABLE *table, LEX_STRING *db_name,
4949                           const CHARSET_INFO *cs)
4950 {
4951   restore_record(table, s->default_values);
4952   table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
4953   table->field[1]->store(db_name->str, db_name->length, system_charset_info);
4954   table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info);
4955   table->field[3]->store(cs->name, strlen(cs->name), system_charset_info);
4956   return schema_table_store_record(thd, table);
4957 }
4958 
4959 
fill_schema_schemata(THD * thd,TABLE_LIST * tables,Item * cond)4960 int fill_schema_schemata(THD *thd, TABLE_LIST *tables, Item *cond)
4961 {
4962   /*
4963     TODO: fill_schema_shemata() is called when new client is connected.
4964     Returning error status in this case leads to client hangup.
4965   */
4966 
4967   /*
4968    * A temporary class is created to free tmp_mem_root when we return from
4969    * this function, since we have 'return' from this function from many
4970    * places. This is just to avoid goto.
4971    */
4972   class free_tmp_mem_root
4973   {
4974   public:
4975     free_tmp_mem_root()
4976     {
4977       init_sql_alloc(&tmp_mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
4978     }
4979     ~free_tmp_mem_root()
4980     {
4981       free_root(&tmp_mem_root, MYF(0));
4982     }
4983     MEM_ROOT tmp_mem_root;
4984   };
4985 
4986   free_tmp_mem_root dummy_member;
4987 
4988   LOOKUP_FIELD_VALUES lookup_field_vals;
4989   List<LEX_STRING> db_names;
4990   LEX_STRING *db_name;
4991   bool with_i_schema;
4992   HA_CREATE_INFO create;
4993   TABLE *table= tables->table;
4994 #ifndef NO_EMBEDDED_ACCESS_CHECKS
4995   Security_context *sctx= thd->security_ctx;
4996 #endif
4997   DBUG_ENTER("fill_schema_shemata");
4998 
4999   if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
5000     DBUG_RETURN(0);
5001 
5002   DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'",
5003                              lookup_field_vals.db_value.str,
5004                              lookup_field_vals.table_value.str));
5005   if (make_db_list(thd, &db_names, &lookup_field_vals,
5006                    &with_i_schema, &dummy_member.tmp_mem_root))
5007     DBUG_RETURN(1);
5008 
5009   /*
5010     If we have lookup db value we should check that the database exists
5011   */
5012   if(lookup_field_vals.db_value.str && !lookup_field_vals.wild_db_value &&
5013      !with_i_schema)
5014   {
5015     char path[FN_REFLEN+16];
5016     uint path_len;
5017     MY_STAT stat_info;
5018     if (!lookup_field_vals.db_value.str[0])
5019       DBUG_RETURN(0);
5020     path_len= build_table_filename(path, sizeof(path) - 1,
5021                                    lookup_field_vals.db_value.str, "", "", 0);
5022     path[path_len-1]= 0;
5023     if (!mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
5024       DBUG_RETURN(0);
5025   }
5026 
5027   List_iterator_fast<LEX_STRING> it(db_names);
5028   while ((db_name=it++))
5029   {
5030     DBUG_ASSERT(db_name->length <= NAME_LEN);
5031     if (with_i_schema)       // information schema name is always first in list
5032     {
5033       if (store_schema_shemata(thd, table, db_name,
5034                                system_charset_info))
5035         DBUG_RETURN(1);
5036       with_i_schema= 0;
5037       continue;
5038     }
5039 #ifndef NO_EMBEDDED_ACCESS_CHECKS
5040     if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
5041 	acl_get(sctx->get_host()->ptr(), sctx->get_ip()->ptr(),
5042                 sctx->priv_user, db_name->str, 0) ||
5043 	!check_grant_db(thd, db_name->str))
5044 #endif
5045     {
5046       load_db_opt_by_name(thd, db_name->str, &create);
5047       if (store_schema_shemata(thd, table, db_name,
5048                                create.default_table_charset))
5049         DBUG_RETURN(1);
5050     }
5051   }
5052   DBUG_RETURN(0);
5053 }
5054 
5055 
get_schema_tables_record(THD * thd,TABLE_LIST * tables,TABLE * table,bool res,LEX_STRING * db_name,LEX_STRING * table_name)5056 static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
5057 				    TABLE *table, bool res,
5058 				    LEX_STRING *db_name,
5059 				    LEX_STRING *table_name)
5060 {
5061   const char *tmp_buff;
5062   MYSQL_TIME time;
5063   int info_error= 0;
5064   CHARSET_INFO *cs= system_charset_info;
5065   DBUG_ENTER("get_schema_tables_record");
5066 
5067   restore_record(table, s->default_values);
5068   table->field[0]->store(STRING_WITH_LEN("def"), cs);
5069   table->field[1]->store(db_name->str, db_name->length, cs);
5070   table->field[2]->store(table_name->str, table_name->length, cs);
5071 
5072   if (res)
5073   {
5074     /* There was a table open error, so set the table type and return */
5075     if (tables->view)
5076       table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
5077     else if (tables->schema_table)
5078       table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
5079     else
5080       table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
5081 
5082     goto err;
5083   }
5084 
5085   if (tables->view)
5086   {
5087     table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
5088     table->field[20]->store(STRING_WITH_LEN("VIEW"), cs);
5089   }
5090   else
5091   {
5092     char option_buff[350],*ptr;
5093     TABLE *show_table= tables->table;
5094     TABLE_SHARE *share= show_table->s;
5095     handler *file= show_table->file;
5096     handlerton *tmp_db_type= share->db_type();
5097 #ifdef WITH_PARTITION_STORAGE_ENGINE
5098     bool is_partitioned= FALSE;
5099 #endif
5100 
5101     if (share->tmp_table == SYSTEM_TMP_TABLE)
5102       table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
5103     else if (share->tmp_table)
5104       table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs);
5105     else
5106       table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
5107 
5108     for (int i= 4; i < 20; i++)
5109     {
5110       if (i == 7 || (i > 12 && i < 17) || i == 18)
5111         continue;
5112       table->field[i]->set_notnull();
5113     }
5114 
5115     /* Collect table info from the table share */
5116 
5117 #ifdef WITH_PARTITION_STORAGE_ENGINE
5118     if (share->db_type() == partition_hton &&
5119         share->partition_info_str_len)
5120     {
5121       tmp_db_type= share->default_part_db_type;
5122       is_partitioned= TRUE;
5123     }
5124 #endif
5125 
5126     tmp_buff= (char *) ha_resolve_storage_engine_name(tmp_db_type);
5127     table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
5128     table->field[5]->store((longlong) share->frm_version, TRUE);
5129 
5130     ptr=option_buff;
5131 
5132     if (share->min_rows)
5133     {
5134       ptr=strmov(ptr," min_rows=");
5135       ptr=longlong10_to_str(share->min_rows,ptr,10);
5136     }
5137 
5138     if (share->max_rows)
5139     {
5140       ptr=strmov(ptr," max_rows=");
5141       ptr=longlong10_to_str(share->max_rows,ptr,10);
5142     }
5143 
5144     if (share->avg_row_length)
5145     {
5146       ptr=strmov(ptr," avg_row_length=");
5147       ptr=longlong10_to_str(share->avg_row_length,ptr,10);
5148     }
5149 
5150     if (share->db_create_options & HA_OPTION_PACK_KEYS)
5151       ptr=strmov(ptr," pack_keys=1");
5152 
5153     if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
5154       ptr=strmov(ptr," pack_keys=0");
5155 
5156     if (share->db_create_options & HA_OPTION_STATS_PERSISTENT)
5157       ptr=strmov(ptr," stats_persistent=1");
5158 
5159     if (share->db_create_options & HA_OPTION_NO_STATS_PERSISTENT)
5160       ptr=strmov(ptr," stats_persistent=0");
5161 
5162     if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON)
5163       ptr=strmov(ptr," stats_auto_recalc=1");
5164     else if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF)
5165       ptr=strmov(ptr," stats_auto_recalc=0");
5166 
5167     if (share->stats_sample_pages != 0)
5168     {
5169       ptr= strmov(ptr, " stats_sample_pages=");
5170       ptr= longlong10_to_str(share->stats_sample_pages, ptr, 10);
5171     }
5172 
5173     /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
5174     if (share->db_create_options & HA_OPTION_CHECKSUM)
5175       ptr=strmov(ptr," checksum=1");
5176 
5177     if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
5178       ptr=strmov(ptr," delay_key_write=1");
5179 
5180     if (share->row_type != ROW_TYPE_DEFAULT)
5181       ptr=strxmov(ptr, " row_format=",
5182                   ha_row_type[(uint) share->row_type],
5183                   NullS);
5184 
5185     if (share->key_block_size)
5186     {
5187       ptr= strmov(ptr, " KEY_BLOCK_SIZE=");
5188       ptr= longlong10_to_str(share->key_block_size, ptr, 10);
5189     }
5190 
5191 #ifdef WITH_PARTITION_STORAGE_ENGINE
5192     if (is_partitioned)
5193       ptr= strmov(ptr, " partitioned");
5194 #endif
5195 
5196     table->field[19]->store(option_buff+1,
5197                             (ptr == option_buff ? 0 :
5198                              (uint) (ptr-option_buff)-1), cs);
5199 
5200     tmp_buff= (share->table_charset ?
5201                share->table_charset->name : "default");
5202 
5203     table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);
5204 
5205     if (share->comment.str)
5206       table->field[20]->store(share->comment.str, share->comment.length, cs);
5207 
5208     /* Collect table info from the storage engine  */
5209 
5210     if(file)
5211     {
5212       /* If info() fails, then there's nothing else to do */
5213       if ((info_error= file->info(HA_STATUS_VARIABLE |
5214                                   HA_STATUS_TIME |
5215                                   HA_STATUS_VARIABLE_EXTRA |
5216                                   HA_STATUS_AUTO)) != 0)
5217         goto err;
5218 
5219       enum row_type row_type = file->get_row_type();
5220       switch (row_type) {
5221       case ROW_TYPE_NOT_USED:
5222       case ROW_TYPE_DEFAULT:
5223         tmp_buff= ((share->db_options_in_use &
5224                     HA_OPTION_COMPRESS_RECORD) ? "Compressed" :
5225                    (share->db_options_in_use & HA_OPTION_PACK_RECORD) ?
5226                    "Dynamic" : "Fixed");
5227         break;
5228       case ROW_TYPE_FIXED:
5229         tmp_buff= "Fixed";
5230         break;
5231       case ROW_TYPE_DYNAMIC:
5232         tmp_buff= "Dynamic";
5233         break;
5234       case ROW_TYPE_COMPRESSED:
5235         tmp_buff= "Compressed";
5236         break;
5237       case ROW_TYPE_REDUNDANT:
5238         tmp_buff= "Redundant";
5239         break;
5240       case ROW_TYPE_COMPACT:
5241         tmp_buff= "Compact";
5242         break;
5243       case ROW_TYPE_PAGE:
5244         tmp_buff= "Paged";
5245         break;
5246       case ROW_TYPE_TOKU_UNCOMPRESSED:
5247         tmp_buff= "tokudb_uncompressed";
5248         break;
5249       case ROW_TYPE_TOKU_ZLIB:
5250         tmp_buff= "tokudb_zlib";
5251         break;
5252       case ROW_TYPE_TOKU_SNAPPY:
5253         tmp_buff= "tokudb_snappy";
5254         break;
5255       case ROW_TYPE_TOKU_QUICKLZ:
5256         tmp_buff= "tokudb_quicklz";
5257         break;
5258       case ROW_TYPE_TOKU_LZMA:
5259         tmp_buff= "tokudb_lzma";
5260         break;
5261       case ROW_TYPE_TOKU_FAST:
5262         tmp_buff= "tokudb_fast";
5263         break;
5264       case ROW_TYPE_TOKU_SMALL:
5265         tmp_buff= "tokudb_small";
5266         break;
5267       case ROW_TYPE_TOKU_DEFAULT:
5268         tmp_buff= "tokudb_default";
5269         break;
5270       }
5271 
5272       table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
5273 
5274       if (!tables->schema_table)
5275       {
5276         table->field[7]->store((longlong) file->stats.records, TRUE);
5277         table->field[7]->set_notnull();
5278       }
5279       table->field[8]->store((longlong) file->stats.mean_rec_length, TRUE);
5280       table->field[9]->store((longlong) file->stats.data_file_length, TRUE);
5281       if (file->stats.max_data_file_length)
5282       {
5283         table->field[10]->store((longlong) file->stats.max_data_file_length,
5284                                 TRUE);
5285       }
5286       table->field[11]->store((longlong) file->stats.index_file_length, TRUE);
5287       table->field[12]->store((longlong) file->stats.delete_length, TRUE);
5288       if (show_table->found_next_number_field)
5289       {
5290         table->field[13]->store((longlong) file->stats.auto_increment_value,
5291                                 TRUE);
5292         table->field[13]->set_notnull();
5293       }
5294       if (file->stats.create_time)
5295       {
5296         thd->variables.time_zone->gmt_sec_to_TIME(&time,
5297                                                   (my_time_t) file->stats.create_time);
5298         table->field[14]->store_time(&time);
5299         table->field[14]->set_notnull();
5300       }
5301       if (file->stats.update_time)
5302       {
5303         thd->variables.time_zone->gmt_sec_to_TIME(&time,
5304                                                   (my_time_t) file->stats.update_time);
5305         table->field[15]->store_time(&time);
5306         table->field[15]->set_notnull();
5307       }
5308       if (file->stats.check_time)
5309       {
5310         thd->variables.time_zone->gmt_sec_to_TIME(&time,
5311                                                   (my_time_t) file->stats.check_time);
5312         table->field[16]->store_time(&time);
5313         table->field[16]->set_notnull();
5314       }
5315       if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
5316       {
5317         table->field[18]->store((longlong) file->checksum(), TRUE);
5318         table->field[18]->set_notnull();
5319       }
5320     }
5321   }
5322 
5323 err:
5324   if (res || info_error)
5325   {
5326     /*
5327       If an error was encountered, push a warning, set the TABLE COMMENT
5328       column with the error text, and clear the error so that the operation
5329       can continue.
5330     */
5331     const char *error= thd->is_error() ? thd->get_stmt_da()->message() : "";
5332     table->field[20]->store(error, strlen(error), cs);
5333 
5334     if (thd->is_error())
5335     {
5336       push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
5337                    thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
5338       thd->clear_error();
5339     }
5340   }
5341 
5342   DBUG_RETURN(schema_table_store_record(thd, table));
5343 }
5344 
5345 
5346 /**
5347   @brief    Store field characteristics into appropriate I_S table columns
5348             starting from DATA_TYPE column till DTD_IDENTIFIER column.
5349 
5350   @param[in]      thd               Thread context.
5351   @param[in]      table             I_S table
5352   @param[in]      field             processed field
5353   @param[in]      cs                I_S table charset
5354   @param[in]      offset            offset from beginning of table
5355                                     to DATE_TYPE column in I_S table
5356   @return         void
5357 */
5358 
store_column_type(THD * thd,TABLE * table,Field * field,CHARSET_INFO * cs,uint offset)5359 void store_column_type(THD *thd, TABLE *table, Field *field, CHARSET_INFO *cs,
5360                        uint offset)
5361 {
5362   bool is_blob;
5363   int decimals, field_length;
5364   const char *tmp_buff;
5365   char column_type_buff[MAX_FIELD_WIDTH];
5366   String column_type(column_type_buff, sizeof(column_type_buff), cs);
5367   enum_field_types field_type= field->real_type();
5368   uint32 orig_column_type_length;
5369 
5370   field->sql_type(column_type);
5371   orig_column_type_length= column_type.length();
5372 
5373   /*
5374     If the session variable 'show_old_temporals' is enabled and the field
5375     is a temporal type of old format, add a comment to the COLUMN_TYPE
5376     indicate the same.
5377   */
5378   if (thd->variables.show_old_temporals &&
5379       (field_type == MYSQL_TYPE_TIME || field_type == MYSQL_TYPE_DATETIME ||
5380        field_type == MYSQL_TYPE_TIMESTAMP))
5381     column_type.append(" /* 5.5 binary format */");
5382 
5383   /* DTD_IDENTIFIER column */
5384   table->field[offset + 8]->store(column_type.ptr(), column_type.length(), cs);
5385   column_type.length(orig_column_type_length);
5386   table->field[offset + 8]->set_notnull();
5387   /*
5388     DATA_TYPE column:
5389     MySQL column type has the following format:
5390     base_type [(dimension)] [unsigned] [zerofill].
5391     For DATA_TYPE column we extract only base type.
5392   */
5393   tmp_buff= strchr(column_type.ptr(), '(');
5394   if (!tmp_buff)
5395     /*
5396       if there is no dimention part then check the presence of
5397       [unsigned] [zerofill] attributes and cut them of if exist.
5398     */
5399     tmp_buff= strchr(column_type.ptr(), ' ');
5400   table->field[offset]->store(column_type.ptr(),
5401                               (tmp_buff ? tmp_buff - column_type.ptr() :
5402                                column_type.length()), cs);
5403 
5404   is_blob= (field->type() == MYSQL_TYPE_BLOB);
5405   if (field->has_charset() || is_blob ||
5406       field->real_type() == MYSQL_TYPE_VARCHAR ||  // For varbinary type
5407       field->real_type() == MYSQL_TYPE_STRING)     // For binary type
5408   {
5409     uint32 octet_max_length= field->max_display_length();
5410     if (is_blob && octet_max_length != (uint32) 4294967295U)
5411       octet_max_length /= field->charset()->mbmaxlen;
5412     longlong char_max_len= is_blob ?
5413       (longlong) octet_max_length / field->charset()->mbminlen :
5414       (longlong) octet_max_length / field->charset()->mbmaxlen;
5415     /* CHARACTER_MAXIMUM_LENGTH column*/
5416     table->field[offset + 1]->store(char_max_len, TRUE);
5417     table->field[offset + 1]->set_notnull();
5418     /* CHARACTER_OCTET_LENGTH column */
5419     table->field[offset + 2]->store((longlong) octet_max_length, TRUE);
5420     table->field[offset + 2]->set_notnull();
5421   }
5422 
5423   /*
5424     Calculate field_length and decimals.
5425     They are set to -1 if they should not be set (we should return NULL)
5426   */
5427 
5428   decimals= field->decimals();
5429   switch (field->type()) {
5430   case MYSQL_TYPE_NEWDECIMAL:
5431     field_length= ((Field_new_decimal*) field)->precision;
5432     break;
5433   case MYSQL_TYPE_DECIMAL:
5434     field_length= field->field_length - (decimals  ? 2 : 1);
5435     break;
5436   case MYSQL_TYPE_TINY:
5437   case MYSQL_TYPE_SHORT:
5438   case MYSQL_TYPE_LONG:
5439   case MYSQL_TYPE_INT24:
5440     field_length= field->max_display_length() - 1;
5441     break;
5442   case MYSQL_TYPE_LONGLONG:
5443     field_length= field->max_display_length() -
5444       ((field->flags & UNSIGNED_FLAG) ? 0 : 1);
5445     break;
5446   case MYSQL_TYPE_BIT:
5447     field_length= field->max_display_length();
5448     decimals= -1;                             // return NULL
5449     break;
5450   case MYSQL_TYPE_FLOAT:
5451   case MYSQL_TYPE_DOUBLE:
5452     field_length= field->field_length;
5453     if (decimals == NOT_FIXED_DEC)
5454       decimals= -1;                           // return NULL
5455     break;
5456   case MYSQL_TYPE_DATETIME:
5457   case MYSQL_TYPE_TIMESTAMP:
5458   case MYSQL_TYPE_TIME:
5459     /* DATETIME_PRECISION column */
5460     table->field[offset + 5]->store(field->decimals(), TRUE);
5461     table->field[offset + 5]->set_notnull();
5462     field_length= decimals= -1;
5463     break;
5464   default:
5465     field_length= decimals= -1;
5466     break;
5467   }
5468 
5469   /* NUMERIC_PRECISION column */
5470   if (field_length >= 0)
5471   {
5472     table->field[offset + 3]->store((longlong) field_length, TRUE);
5473     table->field[offset + 3]->set_notnull();
5474   }
5475   /* NUMERIC_SCALE column */
5476   if (decimals >= 0)
5477   {
5478     table->field[offset + 4]->store((longlong) decimals, TRUE);
5479     table->field[offset + 4]->set_notnull();
5480   }
5481   if (field->has_charset())
5482   {
5483     /* CHARACTER_SET_NAME column*/
5484     tmp_buff= field->charset()->csname;
5485     table->field[offset + 6]->store(tmp_buff, strlen(tmp_buff), cs);
5486     table->field[offset + 6]->set_notnull();
5487     /* COLLATION_NAME column */
5488     tmp_buff= field->charset()->name;
5489     table->field[offset + 7]->store(tmp_buff, strlen(tmp_buff), cs);
5490     table->field[offset + 7]->set_notnull();
5491   }
5492 }
5493 
5494 
get_schema_column_record(THD * thd,TABLE_LIST * tables,TABLE * table,bool res,LEX_STRING * db_name,LEX_STRING * table_name)5495 static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
5496 				    TABLE *table, bool res,
5497 				    LEX_STRING *db_name,
5498 				    LEX_STRING *table_name)
5499 {
5500   LEX *lex= thd->lex;
5501   const char *wild= lex->wild ? lex->wild->ptr() : NullS;
5502   CHARSET_INFO *cs= system_charset_info;
5503   TABLE *show_table;
5504   Field **ptr, *field;
5505   int count;
5506   DBUG_ENTER("get_schema_column_record");
5507 
5508   if (res)
5509   {
5510     if (lex->sql_command != SQLCOM_SHOW_FIELDS)
5511     {
5512       /*
5513         I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
5514         rather than in SHOW COLUMNS
5515       */
5516       if (thd->is_error())
5517         push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
5518                      thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
5519       thd->clear_error();
5520       res= 0;
5521     }
5522     DBUG_RETURN(res);
5523   }
5524 
5525   show_table= tables->table;
5526   count= 0;
5527   ptr= show_table->field;
5528   show_table->use_all_columns();               // Required for default
5529   restore_record(show_table, s->default_values);
5530 
5531   for (; (field= *ptr) ; ptr++)
5532   {
5533     uchar *pos;
5534     char tmp[MAX_FIELD_WIDTH];
5535     String type(tmp,sizeof(tmp), system_charset_info);
5536 
5537     DEBUG_SYNC(thd, "get_schema_column");
5538 
5539     if (wild && wild[0] &&
5540         wild_case_compare(system_charset_info, field->field_name,wild))
5541       continue;
5542 
5543     count++;
5544     /* Get default row, with all NULL fields set to NULL */
5545     restore_record(table, s->default_values);
5546 
5547 #ifndef NO_EMBEDDED_ACCESS_CHECKS
5548     uint col_access;
5549     check_access(thd,SELECT_ACL, db_name->str,
5550                  &tables->grant.privilege, 0, 0, MY_TEST(tables->schema_table));
5551     col_access= get_column_grant(thd, &tables->grant,
5552                                  db_name->str, table_name->str,
5553                                  field->field_name) & COL_ACLS;
5554     if (!tables->schema_table && !col_access)
5555       continue;
5556     char *end= tmp;
5557     for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
5558     {
5559       if (col_access & 1)
5560       {
5561         *end++=',';
5562         end=strmov(end,grant_types.type_names[bitnr]);
5563       }
5564     }
5565     table->field[IS_COLUMNS_PRIVILEGES]->store(tmp+1,
5566                                                end == tmp ? 0 :
5567                                                (uint) (end-tmp-1), cs);
5568 
5569 #endif
5570     table->field[IS_COLUMNS_TABLE_CATALOG]->store(STRING_WITH_LEN("def"), cs);
5571     table->field[IS_COLUMNS_TABLE_SCHEMA]->store(db_name->str,
5572                                                  db_name->length, cs);
5573     table->field[IS_COLUMNS_TABLE_NAME]->store(table_name->str,
5574                                                table_name->length, cs);
5575     table->field[IS_COLUMNS_COLUMN_NAME]->store(field->field_name,
5576                                                 strlen(field->field_name), cs);
5577     table->field[IS_COLUMNS_ORDINAL_POSITION]->store((longlong) count, TRUE);
5578     field->sql_type(type);
5579     table->field[IS_COLUMNS_COLUMN_TYPE]->store(type.ptr(), type.length(), cs);
5580 
5581     if (print_default_clause(thd, field, &type, false))
5582     {
5583       table->field[IS_COLUMNS_COLUMN_DEFAULT]->store(type.ptr(), type.length(),
5584                                                     cs);
5585       table->field[IS_COLUMNS_COLUMN_DEFAULT]->set_notnull();
5586     }
5587     pos=(uchar*) ((field->flags & NOT_NULL_FLAG) ?  "NO" : "YES");
5588     table->field[IS_COLUMNS_IS_NULLABLE]->store((const char*) pos,
5589                            strlen((const char*) pos), cs);
5590     store_column_type(thd, table, field, cs, IS_COLUMNS_DATA_TYPE);
5591     pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
5592                  (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
5593                  (field->flags & CLUSTERING_FLAG) ? "CLU" :
5594                  (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
5595     table->field[IS_COLUMNS_COLUMN_KEY]->store((const char*) pos,
5596                             strlen((const char*) pos), cs);
5597 
5598     if (field->unireg_check == Field::NEXT_NUMBER)
5599       table->field[IS_COLUMNS_EXTRA]->store(STRING_WITH_LEN("auto_increment"),
5600                                             cs);
5601     if (print_on_update_clause(field, &type, true))
5602       table->field[IS_COLUMNS_EXTRA]->store(type.ptr(), type.length(), cs);
5603     table->field[IS_COLUMNS_COLUMN_COMMENT]->store(field->comment.str,
5604                                                    field->comment.length, cs);
5605     if (schema_table_store_record(thd, table))
5606       DBUG_RETURN(1);
5607   }
5608   DBUG_RETURN(0);
5609 }
5610 
5611 
fill_schema_charsets(THD * thd,TABLE_LIST * tables,Item * cond)5612 int fill_schema_charsets(THD *thd, TABLE_LIST *tables, Item *cond)
5613 {
5614   CHARSET_INFO **cs;
5615   const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
5616   TABLE *table= tables->table;
5617   CHARSET_INFO *scs= system_charset_info;
5618 
5619   for (cs= all_charsets ;
5620        cs < all_charsets + array_elements(all_charsets) ;
5621        cs++)
5622   {
5623     CHARSET_INFO *tmp_cs= cs[0];
5624     if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) &&
5625         (tmp_cs->state & MY_CS_AVAILABLE) &&
5626         !(tmp_cs->state & MY_CS_HIDDEN) &&
5627         !(wild && wild[0] &&
5628 	  wild_case_compare(scs, tmp_cs->csname,wild)))
5629     {
5630       const char *comment;
5631       restore_record(table, s->default_values);
5632       table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs);
5633       table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs);
5634       comment= tmp_cs->comment ? tmp_cs->comment : "";
5635       table->field[2]->store(comment, strlen(comment), scs);
5636       table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE);
5637       if (schema_table_store_record(thd, table))
5638         return 1;
5639     }
5640   }
5641   return 0;
5642 }
5643 
5644 
iter_schema_engines(THD * thd,plugin_ref plugin,void * ptable)5645 static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
5646                                    void *ptable)
5647 {
5648   TABLE *table= (TABLE *) ptable;
5649   handlerton *hton= plugin_data(plugin, handlerton *);
5650   const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
5651   CHARSET_INFO *scs= system_charset_info;
5652   handlerton *default_type= ha_default_handlerton(thd);
5653   DBUG_ENTER("iter_schema_engines");
5654 
5655 
5656   /* Disabled plugins */
5657   if (plugin_state(plugin) != PLUGIN_IS_READY)
5658   {
5659 
5660     struct st_mysql_plugin *plug= plugin_decl(plugin);
5661     if (!(wild && wild[0] &&
5662           wild_case_compare(scs, plug->name,wild)))
5663     {
5664       restore_record(table, s->default_values);
5665       table->field[0]->store(plug->name, strlen(plug->name), scs);
5666       table->field[1]->store(C_STRING_WITH_LEN("NO"), scs);
5667       table->field[2]->store(plug->descr, strlen(plug->descr), scs);
5668       if (schema_table_store_record(thd, table))
5669         DBUG_RETURN(1);
5670     }
5671     DBUG_RETURN(0);
5672   }
5673 
5674   if (!(hton->flags & HTON_HIDDEN))
5675   {
5676     LEX_STRING *name= plugin_name(plugin);
5677     if (!(wild && wild[0] &&
5678           wild_case_compare(scs, name->str,wild)))
5679     {
5680       LEX_STRING yesno[2]= {{ C_STRING_WITH_LEN("NO") },
5681                             { C_STRING_WITH_LEN("YES") }};
5682       LEX_STRING *tmp;
5683       const char *option_name= show_comp_option_name[(int) hton->state];
5684       restore_record(table, s->default_values);
5685 
5686       table->field[0]->store(name->str, name->length, scs);
5687       if (hton->state == SHOW_OPTION_YES && default_type == hton)
5688         option_name= "DEFAULT";
5689       table->field[1]->store(option_name, strlen(option_name), scs);
5690       table->field[2]->store(plugin_decl(plugin)->descr,
5691                              strlen(plugin_decl(plugin)->descr), scs);
5692       tmp= &yesno[MY_TEST(hton->commit)];
5693       table->field[3]->store(tmp->str, tmp->length, scs);
5694       table->field[3]->set_notnull();
5695       tmp= &yesno[MY_TEST(hton->prepare)];
5696       table->field[4]->store(tmp->str, tmp->length, scs);
5697       table->field[4]->set_notnull();
5698       tmp= &yesno[MY_TEST(hton->savepoint_set)];
5699       table->field[5]->store(tmp->str, tmp->length, scs);
5700       table->field[5]->set_notnull();
5701 
5702       if (schema_table_store_record(thd, table))
5703         DBUG_RETURN(1);
5704     }
5705   }
5706   DBUG_RETURN(0);
5707 }
5708 
fill_schema_engines(THD * thd,TABLE_LIST * tables,Item * cond)5709 int fill_schema_engines(THD *thd, TABLE_LIST *tables, Item *cond)
5710 {
5711   DBUG_ENTER("fill_schema_engines");
5712   if (plugin_foreach_with_mask(thd, iter_schema_engines,
5713                                MYSQL_STORAGE_ENGINE_PLUGIN,
5714                                ~PLUGIN_IS_FREED, tables->table))
5715     DBUG_RETURN(1);
5716   DBUG_RETURN(0);
5717 }
5718 
5719 
fill_schema_collation(THD * thd,TABLE_LIST * tables,Item * cond)5720 int fill_schema_collation(THD *thd, TABLE_LIST *tables, Item *cond)
5721 {
5722   CHARSET_INFO **cs;
5723   const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
5724   TABLE *table= tables->table;
5725   CHARSET_INFO *scs= system_charset_info;
5726   for (cs= all_charsets ;
5727        cs < all_charsets + array_elements(all_charsets)  ;
5728        cs++ )
5729   {
5730     CHARSET_INFO **cl;
5731     CHARSET_INFO *tmp_cs= cs[0];
5732     if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
5733          (tmp_cs->state & MY_CS_HIDDEN) ||
5734         !(tmp_cs->state & MY_CS_PRIMARY))
5735       continue;
5736     for (cl= all_charsets;
5737          cl < all_charsets + array_elements(all_charsets)  ;
5738          cl ++)
5739     {
5740       CHARSET_INFO *tmp_cl= cl[0];
5741       if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
5742           !my_charset_same(tmp_cs, tmp_cl))
5743 	continue;
5744       if (!(wild && wild[0] &&
5745 	  wild_case_compare(scs, tmp_cl->name,wild)))
5746       {
5747 	const char *tmp_buff;
5748 	restore_record(table, s->default_values);
5749 	table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
5750         table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
5751         table->field[2]->store((longlong) tmp_cl->number, TRUE);
5752         tmp_buff= (tmp_cl->state & MY_CS_PRIMARY) ? "Yes" : "";
5753 	table->field[3]->store(tmp_buff, strlen(tmp_buff), scs);
5754         tmp_buff= (tmp_cl->state & MY_CS_COMPILED)? "Yes" : "";
5755 	table->field[4]->store(tmp_buff, strlen(tmp_buff), scs);
5756         table->field[5]->store((longlong) tmp_cl->strxfrm_multiply, TRUE);
5757         if (schema_table_store_record(thd, table))
5758           return 1;
5759       }
5760     }
5761   }
5762   return 0;
5763 }
5764 
5765 
fill_schema_coll_charset_app(THD * thd,TABLE_LIST * tables,Item * cond)5766 int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, Item *cond)
5767 {
5768   CHARSET_INFO **cs;
5769   TABLE *table= tables->table;
5770   CHARSET_INFO *scs= system_charset_info;
5771   for (cs= all_charsets ;
5772        cs < all_charsets + array_elements(all_charsets) ;
5773        cs++ )
5774   {
5775     CHARSET_INFO **cl;
5776     CHARSET_INFO *tmp_cs= cs[0];
5777     if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
5778         !(tmp_cs->state & MY_CS_PRIMARY))
5779       continue;
5780     for (cl= all_charsets;
5781          cl < all_charsets + array_elements(all_charsets) ;
5782          cl ++)
5783     {
5784       CHARSET_INFO *tmp_cl= cl[0];
5785       if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
5786           (tmp_cl->state & MY_CS_HIDDEN) ||
5787           !my_charset_same(tmp_cs,tmp_cl))
5788 	continue;
5789       restore_record(table, s->default_values);
5790       table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
5791       table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
5792       if (schema_table_store_record(thd, table))
5793         return 1;
5794     }
5795   }
5796   return 0;
5797 }
5798 
5799 
copy_field_as_string(Field * to_field,Field * from_field)5800 static inline void copy_field_as_string(Field *to_field, Field *from_field)
5801 {
5802   char buff[MAX_FIELD_WIDTH];
5803   String tmp_str(buff, sizeof(buff), system_charset_info);
5804   from_field->val_str(&tmp_str);
5805   to_field->store(tmp_str.ptr(), tmp_str.length(), system_charset_info);
5806 }
5807 
5808 
5809 /**
5810   @brief Store record into I_S.PARAMETERS table
5811 
5812   @param[in]      thd                   thread handler
5813   @param[in]      table                 I_S table
5814   @param[in]      proc_table            'mysql.proc' table
5815   @param[in]      wild                  wild string, not used for now,
5816                                         will be useful
5817                                         if we add 'SHOW PARAMETERs'
5818   @param[in]      full_access           if 1 user has privileges on the routine
5819   @param[in]      sp_user               user in 'user@host' format
5820 
5821   @return         Operation status
5822     @retval       0                     ok
5823     @retval       1                     error
5824 */
5825 
store_schema_params(THD * thd,TABLE * table,TABLE * proc_table,const char * wild,bool full_access,const char * sp_user)5826 bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
5827                          const char *wild, bool full_access,
5828                          const char *sp_user)
5829 {
5830   TABLE_SHARE share;
5831   TABLE tbl;
5832   CHARSET_INFO *cs= system_charset_info;
5833   char params_buff[MAX_FIELD_WIDTH], returns_buff[MAX_FIELD_WIDTH],
5834     sp_db_buff[NAME_LEN], sp_name_buff[NAME_LEN], path[FN_REFLEN],
5835     definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 1];
5836   String params(params_buff, sizeof(params_buff), cs);
5837   String returns(returns_buff, sizeof(returns_buff), cs);
5838   String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
5839   String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
5840   String definer(definer_buff, sizeof(definer_buff), cs);
5841   sp_head *sp;
5842   enum_sp_type routine_type;
5843   bool free_sp_head;
5844   DBUG_ENTER("store_schema_params");
5845 
5846   memset(static_cast<void*>(&tbl), 0, sizeof(TABLE));
5847   (void) build_table_filename(path, sizeof(path), "", "", "", 0);
5848   init_tmp_table_share(thd, &share, "", 0, "", path);
5849 
5850   get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DB], &sp_db);
5851   get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_NAME], &sp_name);
5852   get_field(thd->mem_root,proc_table->field[MYSQL_PROC_FIELD_DEFINER],&definer);
5853   routine_type= (enum_sp_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
5854 
5855   if (!full_access)
5856     full_access= !strcmp(sp_user, definer.ptr());
5857   if (!full_access &&
5858       check_some_routine_access(thd, sp_db.ptr(),sp_name.ptr(),
5859                                 routine_type == SP_TYPE_PROCEDURE))
5860     DBUG_RETURN(0);
5861 
5862   params.length(0);
5863   get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST],
5864             &params);
5865   returns.length(0);
5866   if (routine_type == SP_TYPE_FUNCTION)
5867     get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS],
5868               &returns);
5869 
5870   sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
5871                                      (sql_mode_t) proc_table->
5872                                      field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(),
5873                                      routine_type,
5874                                      returns.c_ptr_safe(),
5875                                      params.c_ptr_safe(),
5876                                      &free_sp_head);
5877 
5878   if (sp)
5879   {
5880     Field *field;
5881     Create_field *field_def;
5882     String tmp_string;
5883     if (routine_type == SP_TYPE_FUNCTION)
5884     {
5885       restore_record(table, s->default_values);
5886       table->field[IS_PARAMETERS_SPECIFIC_CATALOG]->store(STRING_WITH_LEN
5887                                                           ("def"), cs);
5888       table->field[IS_PARAMETERS_SPECIFIC_SCHEMA]->store(sp_db.ptr(),
5889                                                          sp_db.length(), cs);
5890       table->field[IS_PARAMETERS_SPECIFIC_NAME]->store(sp_name.ptr(),
5891                                                        sp_name.length(), cs);
5892       table->field[IS_PARAMETERS_ORDINAL_POSITION]->store((longlong) 0, TRUE);
5893       get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
5894                 &tmp_string);
5895       table->field[IS_PARAMETERS_ROUTINE_TYPE]->store(tmp_string.ptr(),
5896                                                       tmp_string.length(), cs);
5897       field_def= &sp->m_return_field_def;
5898       field= make_field(&share, (uchar*) 0, field_def->length,
5899                         (uchar*) "", 0, field_def->pack_flag,
5900                         field_def->sql_type, field_def->charset,
5901                         field_def->geom_type, Field::NONE,
5902                         field_def->interval, "");
5903 
5904       field->table= &tbl;
5905       tbl.in_use= thd;
5906       store_column_type(thd, table, field, cs, IS_PARAMETERS_DATA_TYPE);
5907       if (schema_table_store_record(thd, table))
5908       {
5909         free_table_share(&share);
5910         if (free_sp_head)
5911           delete sp;
5912         DBUG_RETURN(1);
5913       }
5914     }
5915 
5916     sp_pcontext *sp_root_parsing_ctx= sp->get_root_parsing_context();
5917 
5918     for (uint i= 0; i < sp_root_parsing_ctx->context_var_count(); i++)
5919     {
5920       const char *tmp_buff;
5921       sp_variable *spvar= sp_root_parsing_ctx->find_variable(i);
5922       field_def= &spvar->field_def;
5923       switch (spvar->mode) {
5924       case sp_variable::MODE_IN:
5925         tmp_buff= "IN";
5926         break;
5927       case sp_variable::MODE_OUT:
5928         tmp_buff= "OUT";
5929         break;
5930       case sp_variable::MODE_INOUT:
5931         tmp_buff= "INOUT";
5932         break;
5933       default:
5934         tmp_buff= "";
5935         break;
5936       }
5937 
5938       restore_record(table, s->default_values);
5939       table->field[IS_PARAMETERS_SPECIFIC_CATALOG]->store(STRING_WITH_LEN
5940                                                           ("def"), cs);
5941       table->field[IS_PARAMETERS_SPECIFIC_SCHEMA]->store(sp_db.ptr(),
5942                                                          sp_db.length(), cs);
5943       table->field[IS_PARAMETERS_SPECIFIC_NAME]->store(sp_name.ptr(),
5944                                                        sp_name.length(), cs);
5945       table->field[IS_PARAMETERS_ORDINAL_POSITION]->store((longlong) i + 1,
5946                                                           TRUE);
5947       table->field[IS_PARAMETERS_PARAMETER_MODE]->store(tmp_buff,
5948                                                         strlen(tmp_buff), cs);
5949       table->field[IS_PARAMETERS_PARAMETER_MODE]->set_notnull();
5950       table->field[IS_PARAMETERS_PARAMETER_NAME]->store(spvar->name.str,
5951                                                         spvar->name.length, cs);
5952       table->field[IS_PARAMETERS_PARAMETER_NAME]->set_notnull();
5953       get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
5954                 &tmp_string);
5955       table->field[IS_PARAMETERS_ROUTINE_TYPE]->store(tmp_string.ptr(),
5956                                                       tmp_string.length(), cs);
5957 
5958       field= make_field(&share, (uchar*) 0, field_def->length,
5959                         (uchar*) "", 0, field_def->pack_flag,
5960                         field_def->sql_type, field_def->charset,
5961                         field_def->geom_type, Field::NONE,
5962                         field_def->interval, spvar->name.str);
5963 
5964       field->table= &tbl;
5965       tbl.in_use= thd;
5966       store_column_type(thd, table, field, cs, IS_PARAMETERS_DATA_TYPE);
5967       if (schema_table_store_record(thd, table))
5968       {
5969         free_table_share(&share);
5970         if (free_sp_head)
5971           delete sp;
5972         DBUG_RETURN(1);
5973       }
5974     }
5975     if (free_sp_head)
5976       delete sp;
5977   }
5978   free_table_share(&share);
5979   DBUG_RETURN(0);
5980 }
5981 
5982 
store_schema_proc(THD * thd,TABLE * table,TABLE * proc_table,const char * wild,bool full_access,const char * sp_user)5983 bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
5984                        const char *wild, bool full_access, const char *sp_user)
5985 {
5986   MYSQL_TIME time;
5987   LEX *lex= thd->lex;
5988   CHARSET_INFO *cs= system_charset_info;
5989   char sp_db_buff[NAME_LEN + 1], sp_name_buff[NAME_LEN + 1],
5990     definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 2],
5991     returns_buff[MAX_FIELD_WIDTH];
5992 
5993   String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
5994   String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
5995   String definer(definer_buff, sizeof(definer_buff), cs);
5996   String returns(returns_buff, sizeof(returns_buff), cs);
5997 
5998   proc_table->field[MYSQL_PROC_FIELD_DB]->val_str(&sp_db);
5999   proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str(&sp_name);
6000   proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str(&definer);
6001 
6002   enum_sp_type sp_type=
6003     (enum_sp_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
6004 
6005   if (!full_access)
6006     full_access= !strcmp(sp_user, definer.c_ptr_safe());
6007   if (!full_access &&
6008       check_some_routine_access(thd, sp_db.c_ptr_safe(), sp_name.c_ptr_safe(),
6009                                 sp_type == SP_TYPE_PROCEDURE))
6010     return 0;
6011 
6012   if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
6013       sp_type == SP_TYPE_PROCEDURE) ||
6014       (lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
6015       sp_type == SP_TYPE_FUNCTION) ||
6016       (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
6017   {
6018     restore_record(table, s->default_values);
6019     if (!wild || !wild[0] || !wild_case_compare(system_charset_info,
6020                                                 sp_name.c_ptr_safe(), wild))
6021     {
6022       int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int();
6023       table->field[IS_ROUTINES_ROUTINE_NAME]->store(sp_name.ptr(),
6024                                                     sp_name.length(), cs);
6025 
6026       copy_field_as_string(table->field[IS_ROUTINES_SPECIFIC_NAME],
6027                            proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]);
6028       table->field[IS_ROUTINES_ROUTINE_CATALOG]->store(STRING_WITH_LEN("def"),
6029                                                        cs);
6030       table->field[IS_ROUTINES_ROUTINE_SCHEMA]->store(sp_db.ptr(), sp_db.length(), cs);
6031       copy_field_as_string(table->field[IS_ROUTINES_ROUTINE_TYPE],
6032                            proc_table->field[MYSQL_PROC_MYSQL_TYPE]);
6033 
6034       if (sp_type == SP_TYPE_FUNCTION)
6035       {
6036         sp_head *sp;
6037         bool free_sp_head;
6038         proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str(&returns);
6039         sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
6040                                            (sql_mode_t) proc_table->
6041                                            field[MYSQL_PROC_FIELD_SQL_MODE]->
6042                                            val_int(),
6043                                            SP_TYPE_FUNCTION,
6044                                            returns.c_ptr_safe(),
6045                                            "", &free_sp_head);
6046 
6047         if (sp)
6048         {
6049           char path[FN_REFLEN];
6050           TABLE_SHARE share;
6051           TABLE tbl;
6052           Field *field;
6053           Create_field *field_def= &sp->m_return_field_def;
6054 
6055           memset(static_cast<void*>(&tbl), 0, sizeof(TABLE));
6056           (void) build_table_filename(path, sizeof(path), "", "", "", 0);
6057           init_tmp_table_share(thd, &share, "", 0, "", path);
6058           field= make_field(&share, (uchar*) 0, field_def->length,
6059                             (uchar*) "", 0, field_def->pack_flag,
6060                             field_def->sql_type, field_def->charset,
6061                             field_def->geom_type, Field::NONE,
6062                             field_def->interval, "");
6063 
6064           field->table= &tbl;
6065           tbl.in_use= thd;
6066           store_column_type(thd, table, field, cs, IS_ROUTINES_DATA_TYPE);
6067           free_table_share(&share);
6068           if (free_sp_head)
6069             delete sp;
6070         }
6071       }
6072 
6073       if (full_access)
6074       {
6075         copy_field_as_string(table->field[IS_ROUTINES_ROUTINE_DEFINITION],
6076                              proc_table->field[MYSQL_PROC_FIELD_BODY_UTF8]);
6077         table->field[IS_ROUTINES_ROUTINE_DEFINITION]->set_notnull();
6078       }
6079       table->field[IS_ROUTINES_ROUTINE_BODY]->store(STRING_WITH_LEN("SQL"), cs);
6080       table->field[IS_ROUTINES_PARAMETER_STYLE]->store(STRING_WITH_LEN("SQL"),
6081                                                        cs);
6082       copy_field_as_string(table->field[IS_ROUTINES_IS_DETERMINISTIC],
6083                            proc_table->field[MYSQL_PROC_FIELD_DETERMINISTIC]);
6084       table->field[IS_ROUTINES_SQL_DATA_ACCESS]->
6085                    store(sp_data_access_name[enum_idx].str,
6086                          sp_data_access_name[enum_idx].length , cs);
6087       copy_field_as_string(table->field[IS_ROUTINES_SECURITY_TYPE],
6088                            proc_table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]);
6089 
6090       memset(&time, 0, sizeof(time));
6091       proc_table->field[MYSQL_PROC_FIELD_CREATED]->get_time(&time);
6092       table->field[IS_ROUTINES_CREATED]->store_time(&time);
6093       memset(&time, 0, sizeof(time));
6094       proc_table->field[MYSQL_PROC_FIELD_MODIFIED]->get_time(&time);
6095       table->field[IS_ROUTINES_LAST_ALTERED]->store_time(&time);
6096       copy_field_as_string(table->field[IS_ROUTINES_SQL_MODE],
6097                            proc_table->field[MYSQL_PROC_FIELD_SQL_MODE]);
6098       copy_field_as_string(table->field[IS_ROUTINES_ROUTINE_COMMENT],
6099                            proc_table->field[MYSQL_PROC_FIELD_COMMENT]);
6100 
6101       table->field[IS_ROUTINES_DEFINER]->store(definer.ptr(),
6102                                                definer.length(), cs);
6103       copy_field_as_string(table->field[IS_ROUTINES_CHARACTER_SET_CLIENT],
6104                            proc_table->
6105                            field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]);
6106       copy_field_as_string(table->field[IS_ROUTINES_COLLATION_CONNECTION],
6107                            proc_table->
6108                            field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]);
6109       copy_field_as_string(table->field[IS_ROUTINES_DATABASE_COLLATION],
6110 			   proc_table->field[MYSQL_PROC_FIELD_DB_COLLATION]);
6111 
6112       return schema_table_store_record(thd, table);
6113     }
6114   }
6115   return 0;
6116 }
6117 
6118 
fill_schema_proc(THD * thd,TABLE_LIST * tables,Item * cond)6119 int fill_schema_proc(THD *thd, TABLE_LIST *tables, Item *cond)
6120 {
6121   TABLE *proc_table;
6122   TABLE_LIST proc_tables;
6123   const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
6124   int error, res= 0;
6125   TABLE *table= tables->table;
6126   bool full_access;
6127   char definer[USER_HOST_BUFF_SIZE];
6128   Open_tables_backup open_tables_state_backup;
6129   enum enum_schema_tables schema_table_idx=
6130     get_schema_table_idx(tables->schema_table);
6131   DBUG_ENTER("fill_schema_proc");
6132 
6133   strxmov(definer, thd->security_ctx->priv_user, "@",
6134           thd->security_ctx->priv_host, NullS);
6135   /* We use this TABLE_LIST instance only for checking of privileges. */
6136   memset(static_cast<void*>(&proc_tables), 0, sizeof(proc_tables));
6137   proc_tables.db= (char*) "mysql";
6138   proc_tables.db_length= 5;
6139   proc_tables.table_name= proc_tables.alias= (char*) "proc";
6140   proc_tables.table_name_length= 4;
6141   proc_tables.lock_type= TL_READ;
6142   full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, FALSE,
6143                                    1, TRUE);
6144   if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup)))
6145   {
6146     DBUG_RETURN(1);
6147   }
6148   if ((error= proc_table->file->ha_index_init(0, 1)))
6149   {
6150     proc_table->file->print_error(error, MYF(0));
6151     res= 1;
6152     goto err;
6153   }
6154   if ((error= proc_table->file->ha_index_first(proc_table->record[0])))
6155   {
6156     res= (error == HA_ERR_END_OF_FILE) ? 0 : 1;
6157     if (res)
6158       proc_table->file->print_error(error, MYF(0));
6159     goto err;
6160   }
6161 
6162   if (schema_table_idx == SCH_PROCEDURES ?
6163       store_schema_proc(thd, table, proc_table, wild, full_access, definer) :
6164       store_schema_params(thd, table, proc_table, wild, full_access, definer))
6165   {
6166     res= 1;
6167     goto err;
6168   }
6169   while (!proc_table->file->ha_index_next(proc_table->record[0]))
6170   {
6171     if (schema_table_idx == SCH_PROCEDURES ?
6172         store_schema_proc(thd, table, proc_table, wild, full_access, definer):
6173         store_schema_params(thd, table, proc_table, wild, full_access, definer))
6174     {
6175       res= 1;
6176       goto err;
6177     }
6178   }
6179 
6180 err:
6181   if (proc_table->file->inited)
6182     (void) proc_table->file->ha_index_end();
6183   close_system_tables(thd, &open_tables_state_backup);
6184   DBUG_RETURN(res);
6185 }
6186 
6187 
get_schema_stat_record(THD * thd,TABLE_LIST * tables,TABLE * table,bool res,LEX_STRING * db_name,LEX_STRING * table_name)6188 static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
6189 				  TABLE *table, bool res,
6190 				  LEX_STRING *db_name,
6191 				  LEX_STRING *table_name)
6192 {
6193   CHARSET_INFO *cs= system_charset_info;
6194   DBUG_ENTER("get_schema_stat_record");
6195   if (res)
6196   {
6197     if (thd->lex->sql_command != SQLCOM_SHOW_KEYS)
6198     {
6199       /*
6200         I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
6201         rather than in SHOW KEYS
6202       */
6203       if (thd->is_error())
6204         push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
6205                      thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
6206       thd->clear_error();
6207       res= 0;
6208     }
6209     DBUG_RETURN(res);
6210   }
6211   else if (!tables->view)
6212   {
6213     TABLE *show_table= tables->table;
6214     KEY *key_info=show_table->s->key_info;
6215     if (show_table->file)
6216       show_table->file->info(HA_STATUS_VARIABLE |
6217                              HA_STATUS_NO_LOCK |
6218                              HA_STATUS_TIME);
6219     for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
6220     {
6221       KEY_PART_INFO *key_part= key_info->key_part;
6222       const char *str;
6223       for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++)
6224       {
6225         restore_record(table, s->default_values);
6226         table->field[0]->store(STRING_WITH_LEN("def"), cs);
6227         table->field[1]->store(db_name->str, db_name->length, cs);
6228         table->field[2]->store(table_name->str, table_name->length, cs);
6229         table->field[3]->store((longlong) ((key_info->flags &
6230                                             HA_NOSAME) ? 0 : 1), TRUE);
6231         table->field[4]->store(db_name->str, db_name->length, cs);
6232         table->field[5]->store(key_info->name, strlen(key_info->name), cs);
6233         table->field[6]->store((longlong) (j+1), TRUE);
6234         str=(key_part->field ? key_part->field->field_name :
6235              "?unknown field?");
6236         table->field[7]->store(str, strlen(str), cs);
6237         if (show_table->file)
6238         {
6239           if (show_table->file->index_flags(i, j, 0) & HA_READ_ORDER)
6240           {
6241             table->field[8]->store(((key_part->key_part_flag &
6242                                      HA_REVERSE_SORT) ?
6243                                     "D" : "A"), 1, cs);
6244             table->field[8]->set_notnull();
6245           }
6246           KEY *key=show_table->key_info+i;
6247           if (key->rec_per_key[j])
6248           {
6249             ha_rows records=(show_table->file->stats.records /
6250                              key->rec_per_key[j]);
6251             table->field[9]->store((longlong) records, TRUE);
6252             table->field[9]->set_notnull();
6253           }
6254           str= show_table->file->index_type(i);
6255           table->field[13]->store(str, strlen(str), cs);
6256         }
6257         if (!(key_info->flags & HA_FULLTEXT) &&
6258             (key_part->field &&
6259              key_part->length !=
6260              show_table->s->field[key_part->fieldnr-1]->key_length()))
6261         {
6262           table->field[10]->store((longlong) key_part->length /
6263                                   key_part->field->charset()->mbmaxlen, TRUE);
6264           table->field[10]->set_notnull();
6265         }
6266         uint flags= key_part->field ? key_part->field->flags : 0;
6267         const char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
6268         table->field[12]->store(pos, strlen(pos), cs);
6269         if (!show_table->s->keys_in_use.is_set(i))
6270           table->field[14]->store(STRING_WITH_LEN("disabled"), cs);
6271         else
6272           table->field[14]->store("", 0, cs);
6273         table->field[14]->set_notnull();
6274         DBUG_ASSERT(MY_TEST(key_info->flags & HA_USES_COMMENT) ==
6275                    (key_info->comment.length > 0));
6276         if (key_info->flags & HA_USES_COMMENT)
6277           table->field[15]->store(key_info->comment.str,
6278                                   key_info->comment.length, cs);
6279         if (schema_table_store_record(thd, table))
6280           DBUG_RETURN(1);
6281       }
6282     }
6283   }
6284   DBUG_RETURN(res);
6285 }
6286 
6287 
get_schema_views_record(THD * thd,TABLE_LIST * tables,TABLE * table,bool res,LEX_STRING * db_name,LEX_STRING * table_name)6288 static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
6289 				   TABLE *table, bool res,
6290 				   LEX_STRING *db_name,
6291 				   LEX_STRING *table_name)
6292 {
6293   CHARSET_INFO *cs= system_charset_info;
6294   char definer[USER_HOST_BUFF_SIZE];
6295   uint definer_len;
6296   bool updatable_view;
6297   DBUG_ENTER("get_schema_views_record");
6298 
6299   if (tables->view)
6300   {
6301     Security_context *sctx= thd->security_ctx;
6302     if (!tables->allowed_show)
6303     {
6304       if (!my_strcasecmp(system_charset_info, tables->definer.user.str,
6305                          sctx->priv_user) &&
6306           !my_strcasecmp(system_charset_info, tables->definer.host.str,
6307                          sctx->priv_host))
6308         tables->allowed_show= TRUE;
6309 #ifndef NO_EMBEDDED_ACCESS_CHECKS
6310       else
6311       {
6312         if ((thd->col_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
6313             (SHOW_VIEW_ACL|SELECT_ACL))
6314           tables->allowed_show= TRUE;
6315         else
6316         {
6317           TABLE_LIST table_list;
6318           uint view_access;
6319           memset(static_cast<void*>(&table_list), 0, sizeof(table_list));
6320           table_list.db= tables->db;
6321           table_list.table_name= tables->table_name;
6322           table_list.grant.privilege= thd->col_access;
6323           view_access= get_table_grant(thd, &table_list);
6324 	  if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
6325 	      (SHOW_VIEW_ACL|SELECT_ACL))
6326 	    tables->allowed_show= TRUE;
6327         }
6328       }
6329 #endif
6330     }
6331     restore_record(table, s->default_values);
6332     table->field[0]->store(STRING_WITH_LEN("def"), cs);
6333     table->field[1]->store(db_name->str, db_name->length, cs);
6334     table->field[2]->store(table_name->str, table_name->length, cs);
6335 
6336     if (tables->allowed_show)
6337     {
6338       table->field[3]->store(tables->view_body_utf8.str,
6339                              tables->view_body_utf8.length,
6340                              cs);
6341     }
6342 
6343     if (tables->with_check != VIEW_CHECK_NONE)
6344     {
6345       if (tables->with_check == VIEW_CHECK_LOCAL)
6346         table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs);
6347       else
6348         table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs);
6349     }
6350     else
6351       table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
6352 
6353     /*
6354       Only try to fill in the information about view updatability
6355       if it is requested as part of the top-level query (i.e.
6356       it's select * from i_s.views, as opposed to, say, select
6357       security_type from i_s.views).  Do not try to access the
6358       underlying tables if there was an error when opening the
6359       view: all underlying tables are released back to the table
6360       definition cache on error inside open_normal_and_derived_tables().
6361       If a field is not assigned explicitly, it defaults to NULL.
6362     */
6363     if (res == FALSE &&
6364         table->pos_in_table_list->table_open_method & OPEN_FULL_TABLE)
6365     {
6366       updatable_view= 0;
6367       if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE)
6368       {
6369         /*
6370           We should use tables->view->select_lex.item_list here
6371           and can not use Field_iterator_view because the view
6372           always uses temporary algorithm during opening for I_S
6373           and TABLE_LIST fields 'field_translation'
6374           & 'field_translation_end' are uninitialized is this
6375           case.
6376         */
6377         List<Item> *fields= &tables->view->select_lex.item_list;
6378         List_iterator<Item> it(*fields);
6379         Item *item;
6380         Item_field *field;
6381         /*
6382           check that at least one column in view is updatable
6383         */
6384         while ((item= it++))
6385         {
6386           if ((field= item->field_for_view_update()) && field->field &&
6387               !field->field->table->pos_in_table_list->schema_table)
6388           {
6389             updatable_view= 1;
6390             break;
6391           }
6392         }
6393         if (updatable_view && !tables->view->can_be_merged())
6394           updatable_view= 0;
6395       }
6396       if (updatable_view)
6397         table->field[5]->store(STRING_WITH_LEN("YES"), cs);
6398       else
6399         table->field[5]->store(STRING_WITH_LEN("NO"), cs);
6400     }
6401 
6402     definer_len= (strxmov(definer, tables->definer.user.str, "@",
6403                           tables->definer.host.str, NullS) - definer);
6404     table->field[6]->store(definer, definer_len, cs);
6405     if (tables->view_suid)
6406       table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs);
6407     else
6408       table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs);
6409 
6410     table->field[8]->store(tables->view_creation_ctx->get_client_cs()->csname,
6411                            strlen(tables->view_creation_ctx->
6412                                   get_client_cs()->csname), cs);
6413 
6414     table->field[9]->store(tables->view_creation_ctx->
6415                            get_connection_cl()->name,
6416                            strlen(tables->view_creation_ctx->
6417                                   get_connection_cl()->name), cs);
6418 
6419 
6420     if (schema_table_store_record(thd, table))
6421       DBUG_RETURN(1);
6422     if (res && thd->is_error())
6423       push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
6424                    thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
6425   }
6426   if (res)
6427     thd->clear_error();
6428   DBUG_RETURN(0);
6429 }
6430 
6431 
store_constraints(THD * thd,TABLE * table,LEX_STRING * db_name,LEX_STRING * table_name,const char * key_name,uint key_len,const char * con_type,uint con_len)6432 bool store_constraints(THD *thd, TABLE *table, LEX_STRING *db_name,
6433                        LEX_STRING *table_name, const char *key_name,
6434                        uint key_len, const char *con_type, uint con_len)
6435 {
6436   CHARSET_INFO *cs= system_charset_info;
6437   restore_record(table, s->default_values);
6438   table->field[0]->store(STRING_WITH_LEN("def"), cs);
6439   table->field[1]->store(db_name->str, db_name->length, cs);
6440   table->field[2]->store(key_name, key_len, cs);
6441   table->field[3]->store(db_name->str, db_name->length, cs);
6442   table->field[4]->store(table_name->str, table_name->length, cs);
6443   table->field[5]->store(con_type, con_len, cs);
6444   return schema_table_store_record(thd, table);
6445 }
6446 
6447 
get_schema_constraints_record(THD * thd,TABLE_LIST * tables,TABLE * table,bool res,LEX_STRING * db_name,LEX_STRING * table_name)6448 static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
6449 					 TABLE *table, bool res,
6450 					 LEX_STRING *db_name,
6451 					 LEX_STRING *table_name)
6452 {
6453   DBUG_ENTER("get_schema_constraints_record");
6454   if (res)
6455   {
6456     if (thd->is_error())
6457       push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
6458                    thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
6459     thd->clear_error();
6460     DBUG_RETURN(0);
6461   }
6462   else if (!tables->view)
6463   {
6464     List<FOREIGN_KEY_INFO> f_key_list;
6465     TABLE *show_table= tables->table;
6466     KEY *key_info=show_table->key_info;
6467     uint primary_key= show_table->s->primary_key;
6468     for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
6469     {
6470       if (i != primary_key && !(key_info->flags & HA_NOSAME))
6471         continue;
6472 
6473       if (i == primary_key && !strcmp(key_info->name, primary_key_name))
6474       {
6475         if (store_constraints(thd, table, db_name, table_name, key_info->name,
6476                               strlen(key_info->name),
6477                               STRING_WITH_LEN("PRIMARY KEY")))
6478           DBUG_RETURN(1);
6479       }
6480       else if (key_info->flags & HA_NOSAME)
6481       {
6482         if (store_constraints(thd, table, db_name, table_name, key_info->name,
6483                               strlen(key_info->name),
6484                               STRING_WITH_LEN("UNIQUE")))
6485           DBUG_RETURN(1);
6486       }
6487     }
6488 
6489     show_table->file->get_foreign_key_list(thd, &f_key_list);
6490     FOREIGN_KEY_INFO *f_key_info;
6491     List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
6492     while ((f_key_info=it++))
6493     {
6494       if (store_constraints(thd, table, db_name, table_name,
6495                             f_key_info->foreign_id->str,
6496                             strlen(f_key_info->foreign_id->str),
6497                             "FOREIGN KEY", 11))
6498         DBUG_RETURN(1);
6499     }
6500   }
6501   DBUG_RETURN(res);
6502 }
6503 
6504 
store_trigger(THD * thd,TABLE * table,LEX_STRING * db_name,LEX_STRING * table_name,LEX_STRING * trigger_name,enum trg_event_type event,enum trg_action_time_type timing,LEX_STRING * trigger_stmt,sql_mode_t sql_mode,LEX_STRING * definer_buffer,LEX_STRING * client_cs_name,LEX_STRING * connection_cl_name,LEX_STRING * db_cl_name)6505 static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name,
6506                           LEX_STRING *table_name, LEX_STRING *trigger_name,
6507                           enum trg_event_type event,
6508                           enum trg_action_time_type timing,
6509                           LEX_STRING *trigger_stmt,
6510                           sql_mode_t sql_mode,
6511                           LEX_STRING *definer_buffer,
6512                           LEX_STRING *client_cs_name,
6513                           LEX_STRING *connection_cl_name,
6514                           LEX_STRING *db_cl_name)
6515 {
6516   CHARSET_INFO *cs= system_charset_info;
6517   LEX_STRING sql_mode_rep;
6518 
6519   restore_record(table, s->default_values);
6520   table->field[0]->store(STRING_WITH_LEN("def"), cs);
6521   table->field[1]->store(db_name->str, db_name->length, cs);
6522   table->field[2]->store(trigger_name->str, trigger_name->length, cs);
6523   table->field[3]->store(trg_event_type_names[event].str,
6524                          trg_event_type_names[event].length, cs);
6525   table->field[4]->store(STRING_WITH_LEN("def"), cs);
6526   table->field[5]->store(db_name->str, db_name->length, cs);
6527   table->field[6]->store(table_name->str, table_name->length, cs);
6528   table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
6529   table->field[10]->store(STRING_WITH_LEN("ROW"), cs);
6530   table->field[11]->store(trg_action_time_type_names[timing].str,
6531                           trg_action_time_type_names[timing].length, cs);
6532   table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
6533   table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
6534 
6535   sql_mode_string_representation(thd, sql_mode, &sql_mode_rep);
6536   table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs);
6537   table->field[18]->store(definer_buffer->str, definer_buffer->length, cs);
6538   table->field[19]->store(client_cs_name->str, client_cs_name->length, cs);
6539   table->field[20]->store(connection_cl_name->str,
6540                           connection_cl_name->length, cs);
6541   table->field[21]->store(db_cl_name->str, db_cl_name->length, cs);
6542 
6543   return schema_table_store_record(thd, table);
6544 }
6545 
6546 
get_schema_triggers_record(THD * thd,TABLE_LIST * tables,TABLE * table,bool res,LEX_STRING * db_name,LEX_STRING * table_name)6547 static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables,
6548 				      TABLE *table, bool res,
6549 				      LEX_STRING *db_name,
6550 				      LEX_STRING *table_name)
6551 {
6552   DBUG_ENTER("get_schema_triggers_record");
6553   /*
6554     res can be non zero value when processed table is a view or
6555     error happened during opening of processed table.
6556   */
6557   if (res)
6558   {
6559     if (thd->is_error())
6560       push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
6561                    thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
6562     thd->clear_error();
6563     DBUG_RETURN(0);
6564   }
6565   if (!tables->view && tables->table->triggers)
6566   {
6567     Table_triggers_list *triggers= tables->table->triggers;
6568     int event, timing;
6569 
6570     if (check_table_access(thd, TRIGGER_ACL, tables, FALSE, 1, TRUE))
6571       goto ret;
6572 
6573     for (event= 0; event < (int)TRG_EVENT_MAX; event++)
6574     {
6575       for (timing= 0; timing < (int)TRG_ACTION_MAX; timing++)
6576       {
6577         LEX_STRING trigger_name;
6578         LEX_STRING trigger_stmt;
6579         sql_mode_t sql_mode;
6580         char definer_holder[USER_HOST_BUFF_SIZE];
6581         LEX_STRING definer_buffer;
6582         LEX_STRING client_cs_name;
6583         LEX_STRING connection_cl_name;
6584         LEX_STRING db_cl_name;
6585 
6586         definer_buffer.str= definer_holder;
6587         if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
6588                                        (enum trg_action_time_type)timing,
6589                                        &trigger_name, &trigger_stmt,
6590                                        &sql_mode,
6591                                        &definer_buffer,
6592                                        &client_cs_name,
6593                                        &connection_cl_name,
6594                                        &db_cl_name))
6595           continue;
6596 
6597         if (store_trigger(thd, table, db_name, table_name, &trigger_name,
6598                          (enum trg_event_type) event,
6599                          (enum trg_action_time_type) timing, &trigger_stmt,
6600                          sql_mode,
6601                          &definer_buffer,
6602                          &client_cs_name,
6603                          &connection_cl_name,
6604                          &db_cl_name))
6605           DBUG_RETURN(1);
6606       }
6607     }
6608   }
6609 ret:
6610   DBUG_RETURN(0);
6611 }
6612 
6613 
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)6614 void store_key_column_usage(TABLE *table, LEX_STRING *db_name,
6615                             LEX_STRING *table_name, const char *key_name,
6616                             uint key_len, const char *con_type, uint con_len,
6617                             longlong idx)
6618 {
6619   CHARSET_INFO *cs= system_charset_info;
6620   table->field[0]->store(STRING_WITH_LEN("def"), cs);
6621   table->field[1]->store(db_name->str, db_name->length, cs);
6622   table->field[2]->store(key_name, key_len, cs);
6623   table->field[3]->store(STRING_WITH_LEN("def"), cs);
6624   table->field[4]->store(db_name->str, db_name->length, cs);
6625   table->field[5]->store(table_name->str, table_name->length, cs);
6626   table->field[6]->store(con_type, con_len, cs);
6627   table->field[7]->store((longlong) idx, TRUE);
6628 }
6629 
6630 
get_schema_key_column_usage_record(THD * thd,TABLE_LIST * tables,TABLE * table,bool res,LEX_STRING * db_name,LEX_STRING * table_name)6631 static int get_schema_key_column_usage_record(THD *thd,
6632 					      TABLE_LIST *tables,
6633 					      TABLE *table, bool res,
6634 					      LEX_STRING *db_name,
6635 					      LEX_STRING *table_name)
6636 {
6637   DBUG_ENTER("get_schema_key_column_usage_record");
6638   if (res)
6639   {
6640     if (thd->is_error())
6641       push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
6642                    thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
6643     thd->clear_error();
6644     DBUG_RETURN(0);
6645   }
6646   else if (!tables->view)
6647   {
6648     List<FOREIGN_KEY_INFO> f_key_list;
6649     TABLE *show_table= tables->table;
6650     KEY *key_info=show_table->key_info;
6651     uint primary_key= show_table->s->primary_key;
6652     for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
6653     {
6654       if (i != primary_key && !(key_info->flags & HA_NOSAME))
6655         continue;
6656       uint f_idx= 0;
6657       KEY_PART_INFO *key_part= key_info->key_part;
6658       for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++)
6659       {
6660         if (key_part->field)
6661         {
6662           f_idx++;
6663           restore_record(table, s->default_values);
6664           store_key_column_usage(table, db_name, table_name,
6665                                  key_info->name,
6666                                  strlen(key_info->name),
6667                                  key_part->field->field_name,
6668                                  strlen(key_part->field->field_name),
6669                                  (longlong) f_idx);
6670           if (schema_table_store_record(thd, table))
6671             DBUG_RETURN(1);
6672         }
6673       }
6674     }
6675 
6676     show_table->file->get_foreign_key_list(thd, &f_key_list);
6677     FOREIGN_KEY_INFO *f_key_info;
6678     List_iterator_fast<FOREIGN_KEY_INFO> fkey_it(f_key_list);
6679     while ((f_key_info= fkey_it++))
6680     {
6681       LEX_STRING *f_info;
6682       LEX_STRING *r_info;
6683       List_iterator_fast<LEX_STRING> it(f_key_info->foreign_fields),
6684         it1(f_key_info->referenced_fields);
6685       uint f_idx= 0;
6686       while ((f_info= it++))
6687       {
6688         r_info= it1++;
6689         f_idx++;
6690         restore_record(table, s->default_values);
6691         store_key_column_usage(table, db_name, table_name,
6692                                f_key_info->foreign_id->str,
6693                                f_key_info->foreign_id->length,
6694                                f_info->str, f_info->length,
6695                                (longlong) f_idx);
6696         table->field[8]->store((longlong) f_idx, TRUE);
6697         table->field[8]->set_notnull();
6698         table->field[9]->store(f_key_info->referenced_db->str,
6699                                f_key_info->referenced_db->length,
6700                                system_charset_info);
6701         table->field[9]->set_notnull();
6702         table->field[10]->store(f_key_info->referenced_table->str,
6703                                 f_key_info->referenced_table->length,
6704                                 system_charset_info);
6705         table->field[10]->set_notnull();
6706         table->field[11]->store(r_info->str, r_info->length,
6707                                 system_charset_info);
6708         table->field[11]->set_notnull();
6709         if (schema_table_store_record(thd, table))
6710           DBUG_RETURN(1);
6711       }
6712     }
6713   }
6714   DBUG_RETURN(res);
6715 }
6716 
6717 
6718 #ifdef WITH_PARTITION_STORAGE_ENGINE
collect_partition_expr(THD * thd,List<char> & field_list,String * str)6719 static void collect_partition_expr(THD *thd, List<char> &field_list,
6720                                    String *str)
6721 {
6722   List_iterator<char> part_it(field_list);
6723   ulong no_fields= field_list.elements;
6724   const char *field_str;
6725   str->length(0);
6726   while ((field_str= part_it++))
6727   {
6728     append_identifier(thd, str, field_str, strlen(field_str));
6729     if (--no_fields != 0)
6730       str->append(",");
6731   }
6732   return;
6733 }
6734 
6735 
6736 /*
6737   Convert a string in a given character set to a string which can be
6738   used for FRM file storage in which case use_hex is TRUE and we store
6739   the character constants as hex strings in the character set encoding
6740   their field have. In the case of SHOW CREATE TABLE and the
6741   PARTITIONS information schema table we instead provide utf8 strings
6742   to the user and convert to the utf8 character set.
6743 
6744   SYNOPSIS
6745     get_cs_converted_part_value_from_string()
6746     item                           Item from which constant comes
6747     input_str                      String as provided by val_str after
6748                                    conversion to character set
6749     output_str                     Out value: The string created
6750     cs                             Character set string is encoded in
6751                                    NULL for INT_RESULT's here
6752     use_hex                        TRUE => hex string created
6753                                    FALSE => utf8 constant string created
6754 
6755   RETURN VALUES
6756     TRUE                           Error
6757     FALSE                          Ok
6758 */
6759 
get_cs_converted_part_value_from_string(THD * thd,Item * item,String * input_str,String * output_str,const CHARSET_INFO * cs,bool use_hex)6760 int get_cs_converted_part_value_from_string(THD *thd,
6761                                             Item *item,
6762                                             String *input_str,
6763                                             String *output_str,
6764                                             const CHARSET_INFO *cs,
6765                                             bool use_hex)
6766 {
6767   if (item->result_type() == INT_RESULT)
6768   {
6769     longlong value= item->val_int();
6770     output_str->set(value, system_charset_info);
6771     return FALSE;
6772   }
6773   if (!input_str)
6774   {
6775     my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
6776     return TRUE;
6777   }
6778   get_cs_converted_string_value(thd,
6779                                 input_str,
6780                                 output_str,
6781                                 cs,
6782                                 use_hex);
6783   return FALSE;
6784 }
6785 #endif
6786 
6787 
store_schema_partitions_record(THD * thd,TABLE * schema_table,TABLE * showing_table,partition_element * part_elem,handler * file,uint part_id)6788 static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
6789                                            TABLE *showing_table,
6790                                            partition_element *part_elem,
6791                                            handler *file, uint part_id)
6792 {
6793   TABLE* table= schema_table;
6794   CHARSET_INFO *cs= system_charset_info;
6795   PARTITION_STATS stat_info;
6796   MYSQL_TIME time;
6797   file->get_dynamic_partition_info(&stat_info, part_id);
6798   table->field[0]->store(STRING_WITH_LEN("def"), cs);
6799   table->field[12]->store((longlong) stat_info.records, TRUE);
6800   table->field[13]->store((longlong) stat_info.mean_rec_length, TRUE);
6801   table->field[14]->store((longlong) stat_info.data_file_length, TRUE);
6802   if (stat_info.max_data_file_length)
6803   {
6804     table->field[15]->store((longlong) stat_info.max_data_file_length, TRUE);
6805     table->field[15]->set_notnull();
6806   }
6807   table->field[16]->store((longlong) stat_info.index_file_length, TRUE);
6808   table->field[17]->store((longlong) stat_info.delete_length, TRUE);
6809   if (stat_info.create_time)
6810   {
6811     thd->variables.time_zone->gmt_sec_to_TIME(&time,
6812                                               (my_time_t)stat_info.create_time);
6813     table->field[18]->store_time(&time);
6814     table->field[18]->set_notnull();
6815   }
6816   if (stat_info.update_time)
6817   {
6818     thd->variables.time_zone->gmt_sec_to_TIME(&time,
6819                                               (my_time_t)stat_info.update_time);
6820     table->field[19]->store_time(&time);
6821     table->field[19]->set_notnull();
6822   }
6823   if (stat_info.check_time)
6824   {
6825     thd->variables.time_zone->gmt_sec_to_TIME(&time,
6826                                               (my_time_t)stat_info.check_time);
6827     table->field[20]->store_time(&time);
6828     table->field[20]->set_notnull();
6829   }
6830   if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
6831   {
6832     table->field[21]->store((longlong) stat_info.check_sum, TRUE);
6833     table->field[21]->set_notnull();
6834   }
6835   if (part_elem)
6836   {
6837     if (part_elem->part_comment)
6838       table->field[22]->store(part_elem->part_comment,
6839                               strlen(part_elem->part_comment), cs);
6840     else
6841       table->field[22]->store(STRING_WITH_LEN(""), cs);
6842     if (part_elem->nodegroup_id != UNDEF_NODEGROUP)
6843       table->field[23]->store((longlong) part_elem->nodegroup_id, TRUE);
6844     else
6845       table->field[23]->store(STRING_WITH_LEN("default"), cs);
6846 
6847     table->field[24]->set_notnull();
6848     if (part_elem->tablespace_name)
6849       table->field[24]->store(part_elem->tablespace_name,
6850                               strlen(part_elem->tablespace_name), cs);
6851     else
6852     {
6853       char *ts= showing_table->s->tablespace;
6854       if(ts)
6855         table->field[24]->store(ts, strlen(ts), cs);
6856       else
6857         table->field[24]->set_null();
6858     }
6859   }
6860   return;
6861 }
6862 
6863 #ifdef WITH_PARTITION_STORAGE_ENGINE
6864 static int
get_partition_column_description(THD * thd,partition_info * part_info,part_elem_value * list_value,String & tmp_str)6865 get_partition_column_description(THD *thd,
6866                                  partition_info *part_info,
6867                                  part_elem_value *list_value,
6868                                  String &tmp_str)
6869 {
6870   uint num_elements= part_info->part_field_list.elements;
6871   uint i;
6872   DBUG_ENTER("get_partition_column_description");
6873 
6874   for (i= 0; i < num_elements; i++)
6875   {
6876     part_column_list_val *col_val= &list_value->col_val_array[i];
6877     if (col_val->max_value)
6878       tmp_str.append(partition_keywords[PKW_MAXVALUE].str);
6879     else if (col_val->null_value)
6880       tmp_str.append("NULL");
6881     else
6882     {
6883       char buffer[MAX_KEY_LENGTH];
6884       String str(buffer, sizeof(buffer), &my_charset_bin);
6885       String val_conv;
6886       Item *item= col_val->item_expression;
6887 
6888       if (!(item= part_info->get_column_item(item,
6889                               part_info->part_field_array[i])))
6890       {
6891         DBUG_RETURN(1);
6892       }
6893       String *res= item->val_str(&str);
6894       if (get_cs_converted_part_value_from_string(thd, item, res, &val_conv,
6895                               part_info->part_field_array[i]->charset(),
6896                               FALSE))
6897       {
6898         DBUG_RETURN(1);
6899       }
6900       tmp_str.append(val_conv);
6901     }
6902     if (i != num_elements - 1)
6903       tmp_str.append(",");
6904   }
6905   DBUG_RETURN(0);
6906 }
6907 #endif /* WITH_PARTITION_STORAGE_ENGINE */
6908 
get_schema_partitions_record(THD * thd,TABLE_LIST * tables,TABLE * table,bool res,LEX_STRING * db_name,LEX_STRING * table_name)6909 static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
6910                                         TABLE *table, bool res,
6911                                         LEX_STRING *db_name,
6912                                         LEX_STRING *table_name)
6913 {
6914   CHARSET_INFO *cs= system_charset_info;
6915   char buff[61];
6916   String tmp_res(buff, sizeof(buff), cs);
6917   String tmp_str;
6918   TABLE *show_table= tables->table;
6919   handler *file;
6920 #ifdef WITH_PARTITION_STORAGE_ENGINE
6921   partition_info *part_info;
6922 #endif
6923   DBUG_ENTER("get_schema_partitions_record");
6924 
6925   if (res)
6926   {
6927     if (thd->is_error())
6928       push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
6929                    thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
6930     thd->clear_error();
6931     DBUG_RETURN(0);
6932   }
6933   file= show_table->file;
6934 #ifdef WITH_PARTITION_STORAGE_ENGINE
6935   part_info= show_table->part_info;
6936   if (part_info)
6937   {
6938     partition_element *part_elem;
6939     List_iterator<partition_element> part_it(part_info->partitions);
6940     uint part_pos= 0, part_id= 0;
6941 
6942     restore_record(table, s->default_values);
6943     table->field[0]->store(STRING_WITH_LEN("def"), cs);
6944     table->field[1]->store(db_name->str, db_name->length, cs);
6945     table->field[2]->store(table_name->str, table_name->length, cs);
6946 
6947 
6948     /* Partition method*/
6949     switch (part_info->part_type) {
6950     case RANGE_PARTITION:
6951     case LIST_PARTITION:
6952       tmp_res.length(0);
6953       if (part_info->part_type == RANGE_PARTITION)
6954         tmp_res.append(partition_keywords[PKW_RANGE].str,
6955                        partition_keywords[PKW_RANGE].length);
6956       else
6957         tmp_res.append(partition_keywords[PKW_LIST].str,
6958                        partition_keywords[PKW_LIST].length);
6959       if (part_info->column_list)
6960         tmp_res.append(partition_keywords[PKW_COLUMNS].str,
6961                        partition_keywords[PKW_COLUMNS].length);
6962       table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs);
6963       break;
6964     case HASH_PARTITION:
6965       tmp_res.length(0);
6966       if (part_info->linear_hash_ind)
6967         tmp_res.append(partition_keywords[PKW_LINEAR].str,
6968                        partition_keywords[PKW_LINEAR].length);
6969       if (part_info->list_of_part_fields)
6970         tmp_res.append(partition_keywords[PKW_KEY].str,
6971                        partition_keywords[PKW_KEY].length);
6972       else
6973         tmp_res.append(partition_keywords[PKW_HASH].str,
6974                        partition_keywords[PKW_HASH].length);
6975       table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs);
6976       break;
6977     default:
6978       DBUG_ASSERT(0);
6979       my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
6980       DBUG_RETURN(1);
6981     }
6982     table->field[7]->set_notnull();
6983 
6984     /* Partition expression */
6985     if (part_info->part_expr)
6986     {
6987       table->field[9]->store(part_info->part_func_string,
6988                              part_info->part_func_len, cs);
6989     }
6990     else if (part_info->list_of_part_fields)
6991     {
6992       collect_partition_expr(thd, part_info->part_field_list, &tmp_str);
6993       table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs);
6994     }
6995     table->field[9]->set_notnull();
6996 
6997     if (part_info->is_sub_partitioned())
6998     {
6999       /* Subpartition method */
7000       tmp_res.length(0);
7001       if (part_info->linear_hash_ind)
7002         tmp_res.append(partition_keywords[PKW_LINEAR].str,
7003                        partition_keywords[PKW_LINEAR].length);
7004       if (part_info->list_of_subpart_fields)
7005         tmp_res.append(partition_keywords[PKW_KEY].str,
7006                        partition_keywords[PKW_KEY].length);
7007       else
7008         tmp_res.append(partition_keywords[PKW_HASH].str,
7009                        partition_keywords[PKW_HASH].length);
7010       table->field[8]->store(tmp_res.ptr(), tmp_res.length(), cs);
7011       table->field[8]->set_notnull();
7012 
7013       /* Subpartition expression */
7014       if (part_info->subpart_expr)
7015       {
7016         table->field[10]->store(part_info->subpart_func_string,
7017                                 part_info->subpart_func_len, cs);
7018       }
7019       else if (part_info->list_of_subpart_fields)
7020       {
7021         collect_partition_expr(thd, part_info->subpart_field_list, &tmp_str);
7022         table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs);
7023       }
7024       table->field[10]->set_notnull();
7025     }
7026 
7027     while ((part_elem= part_it++))
7028     {
7029       table->field[3]->store(part_elem->partition_name,
7030                              strlen(part_elem->partition_name), cs);
7031       table->field[3]->set_notnull();
7032       /* PARTITION_ORDINAL_POSITION */
7033       table->field[5]->store((longlong) ++part_pos, TRUE);
7034       table->field[5]->set_notnull();
7035 
7036       /* Partition description */
7037       if (part_info->part_type == RANGE_PARTITION)
7038       {
7039         if (part_info->column_list)
7040         {
7041           List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
7042           part_elem_value *list_value= list_val_it++;
7043           tmp_str.length(0);
7044           if (get_partition_column_description(thd,
7045                                                part_info,
7046                                                list_value,
7047                                                tmp_str))
7048           {
7049             DBUG_RETURN(1);
7050           }
7051           table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
7052         }
7053         else
7054         {
7055           if (part_elem->range_value != LONGLONG_MAX)
7056             table->field[11]->store((longlong) part_elem->range_value, FALSE);
7057           else
7058             table->field[11]->store(partition_keywords[PKW_MAXVALUE].str,
7059                                  partition_keywords[PKW_MAXVALUE].length, cs);
7060         }
7061         table->field[11]->set_notnull();
7062       }
7063       else if (part_info->part_type == LIST_PARTITION)
7064       {
7065         List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
7066         part_elem_value *list_value;
7067         uint num_items= part_elem->list_val_list.elements;
7068         tmp_str.length(0);
7069         tmp_res.length(0);
7070         if (part_elem->has_null_value)
7071         {
7072           tmp_str.append("NULL");
7073           if (num_items > 0)
7074             tmp_str.append(",");
7075         }
7076         while ((list_value= list_val_it++))
7077         {
7078           if (part_info->column_list)
7079           {
7080             if (part_info->part_field_list.elements > 1U)
7081               tmp_str.append("(");
7082             if (get_partition_column_description(thd,
7083                                                  part_info,
7084                                                  list_value,
7085                                                  tmp_str))
7086             {
7087               DBUG_RETURN(1);
7088             }
7089             if (part_info->part_field_list.elements > 1U)
7090               tmp_str.append(")");
7091           }
7092           else
7093           {
7094             if (!list_value->unsigned_flag)
7095               tmp_res.set(list_value->value, cs);
7096             else
7097               tmp_res.set((ulonglong)list_value->value, cs);
7098             tmp_str.append(tmp_res);
7099           }
7100           if (--num_items != 0)
7101             tmp_str.append(",");
7102         }
7103         table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
7104         table->field[11]->set_notnull();
7105       }
7106 
7107       if (part_elem->subpartitions.elements)
7108       {
7109         List_iterator<partition_element> sub_it(part_elem->subpartitions);
7110         partition_element *subpart_elem;
7111         uint subpart_pos= 0;
7112 
7113         while ((subpart_elem= sub_it++))
7114         {
7115           table->field[4]->store(subpart_elem->partition_name,
7116                                  strlen(subpart_elem->partition_name), cs);
7117           table->field[4]->set_notnull();
7118           /* SUBPARTITION_ORDINAL_POSITION */
7119           table->field[6]->store((longlong) ++subpart_pos, TRUE);
7120           table->field[6]->set_notnull();
7121 
7122           store_schema_partitions_record(thd, table, show_table, subpart_elem,
7123                                          file, part_id);
7124           part_id++;
7125           if(schema_table_store_record(thd, table))
7126             DBUG_RETURN(1);
7127         }
7128       }
7129       else
7130       {
7131         store_schema_partitions_record(thd, table, show_table, part_elem,
7132                                        file, part_id);
7133         part_id++;
7134         if(schema_table_store_record(thd, table))
7135           DBUG_RETURN(1);
7136       }
7137     }
7138     DBUG_RETURN(0);
7139   }
7140   else
7141 #endif
7142   {
7143     store_schema_partitions_record(thd, table, show_table, 0, file, 0);
7144     if(schema_table_store_record(thd, table))
7145       DBUG_RETURN(1);
7146   }
7147   DBUG_RETURN(0);
7148 }
7149 
7150 
7151 #ifdef HAVE_EVENT_SCHEDULER
7152 /*
7153   Loads an event from mysql.event and copies it's data to a row of
7154   I_S.EVENTS
7155 
7156   Synopsis
7157     copy_event_to_schema_table()
7158       thd         Thread
7159       sch_table   The schema table (information_schema.event)
7160       event_table The event table to use for loading (mysql.event).
7161 
7162   Returns
7163     0  OK
7164     1  Error
7165 */
7166 
7167 int
copy_event_to_schema_table(THD * thd,TABLE * sch_table,TABLE * event_table)7168 copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
7169 {
7170   const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
7171   CHARSET_INFO *scs= system_charset_info;
7172   MYSQL_TIME time;
7173   Event_timed et;
7174   DBUG_ENTER("copy_event_to_schema_table");
7175 
7176   restore_record(sch_table, s->default_values);
7177 
7178   if (et.load_from_row(thd, event_table))
7179   {
7180     my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(0), "mysql", "event");
7181     DBUG_RETURN(1);
7182   }
7183 
7184   if (!(!wild || !wild[0] || !wild_case_compare(scs, et.name.str, wild)))
7185     DBUG_RETURN(0);
7186 
7187   /*
7188     Skip events in schemas one does not have access to. The check is
7189     optimized. It's guaranteed in case of SHOW EVENTS that the user
7190     has access.
7191   */
7192   if (thd->lex->sql_command != SQLCOM_SHOW_EVENTS &&
7193       check_access(thd, EVENT_ACL, et.dbname.str, NULL, NULL, 0, 1))
7194     DBUG_RETURN(0);
7195 
7196   sch_table->field[ISE_EVENT_CATALOG]->store(STRING_WITH_LEN("def"), scs);
7197   sch_table->field[ISE_EVENT_SCHEMA]->
7198                                 store(et.dbname.str, et.dbname.length,scs);
7199   sch_table->field[ISE_EVENT_NAME]->
7200                                 store(et.name.str, et.name.length, scs);
7201   sch_table->field[ISE_DEFINER]->
7202                                 store(et.definer.str, et.definer.length, scs);
7203   const String *tz_name= et.time_zone->get_name();
7204   sch_table->field[ISE_TIME_ZONE]->
7205                                 store(tz_name->ptr(), tz_name->length(), scs);
7206   sch_table->field[ISE_EVENT_BODY]->
7207                                 store(STRING_WITH_LEN("SQL"), scs);
7208   sch_table->field[ISE_EVENT_DEFINITION]->store(
7209     et.body_utf8.str, et.body_utf8.length, scs);
7210 
7211   /* SQL_MODE */
7212   {
7213     LEX_STRING sql_mode;
7214     sql_mode_string_representation(thd, et.sql_mode, &sql_mode);
7215     sch_table->field[ISE_SQL_MODE]->
7216                                 store(sql_mode.str, sql_mode.length, scs);
7217   }
7218 
7219   int not_used=0;
7220 
7221   if (et.expression)
7222   {
7223     String show_str;
7224     /* type */
7225     sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("RECURRING"), scs);
7226 
7227     if (Events::reconstruct_interval_expression(&show_str, et.interval,
7228                                                 et.expression))
7229       DBUG_RETURN(1);
7230 
7231     sch_table->field[ISE_INTERVAL_VALUE]->set_notnull();
7232     sch_table->field[ISE_INTERVAL_VALUE]->
7233                                 store(show_str.ptr(), show_str.length(), scs);
7234 
7235     LEX_STRING *ival= &interval_type_to_name[et.interval];
7236     sch_table->field[ISE_INTERVAL_FIELD]->set_notnull();
7237     sch_table->field[ISE_INTERVAL_FIELD]->store(ival->str, ival->length, scs);
7238 
7239     /* starts & ends . STARTS is always set - see sql_yacc.yy */
7240     et.time_zone->gmt_sec_to_TIME(&time, et.starts);
7241     sch_table->field[ISE_STARTS]->set_notnull();
7242     sch_table->field[ISE_STARTS]->store_time(&time);
7243 
7244     if (!et.ends_null)
7245     {
7246       et.time_zone->gmt_sec_to_TIME(&time, et.ends);
7247       sch_table->field[ISE_ENDS]->set_notnull();
7248       sch_table->field[ISE_ENDS]->store_time(&time);
7249     }
7250   }
7251   else
7252   {
7253     /* type */
7254     sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("ONE TIME"), scs);
7255 
7256     et.time_zone->gmt_sec_to_TIME(&time, et.execute_at);
7257     sch_table->field[ISE_EXECUTE_AT]->set_notnull();
7258     sch_table->field[ISE_EXECUTE_AT]->store_time(&time);
7259   }
7260 
7261   /* status */
7262 
7263   switch (et.status)
7264   {
7265     case Event_parse_data::ENABLED:
7266       sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("ENABLED"), scs);
7267       break;
7268     case Event_parse_data::SLAVESIDE_DISABLED:
7269       sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("SLAVESIDE_DISABLED"),
7270                                           scs);
7271       break;
7272     case Event_parse_data::DISABLED:
7273       sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("DISABLED"), scs);
7274       break;
7275     default:
7276       DBUG_ASSERT(0);
7277   }
7278   sch_table->field[ISE_ORIGINATOR]->store(et.originator, TRUE);
7279 
7280   /* on_completion */
7281   if (et.on_completion == Event_parse_data::ON_COMPLETION_DROP)
7282     sch_table->field[ISE_ON_COMPLETION]->
7283                                 store(STRING_WITH_LEN("NOT PRESERVE"), scs);
7284   else
7285     sch_table->field[ISE_ON_COMPLETION]->
7286                                 store(STRING_WITH_LEN("PRESERVE"), scs);
7287 
7288   number_to_datetime(et.created, &time, 0, &not_used);
7289   DBUG_ASSERT(not_used==0);
7290   sch_table->field[ISE_CREATED]->store_time(&time);
7291 
7292   number_to_datetime(et.modified, &time, 0, &not_used);
7293   DBUG_ASSERT(not_used==0);
7294   sch_table->field[ISE_LAST_ALTERED]->store_time(&time);
7295 
7296   if (et.last_executed)
7297   {
7298     et.time_zone->gmt_sec_to_TIME(&time, et.last_executed);
7299     sch_table->field[ISE_LAST_EXECUTED]->set_notnull();
7300     sch_table->field[ISE_LAST_EXECUTED]->store_time(&time);
7301   }
7302 
7303   sch_table->field[ISE_EVENT_COMMENT]->
7304                       store(et.comment.str, et.comment.length, scs);
7305 
7306   sch_table->field[ISE_CLIENT_CS]->set_notnull();
7307   sch_table->field[ISE_CLIENT_CS]->store(
7308     et.creation_ctx->get_client_cs()->csname,
7309     strlen(et.creation_ctx->get_client_cs()->csname),
7310     scs);
7311 
7312   sch_table->field[ISE_CONNECTION_CL]->set_notnull();
7313   sch_table->field[ISE_CONNECTION_CL]->store(
7314     et.creation_ctx->get_connection_cl()->name,
7315     strlen(et.creation_ctx->get_connection_cl()->name),
7316     scs);
7317 
7318   sch_table->field[ISE_DB_CL]->set_notnull();
7319   sch_table->field[ISE_DB_CL]->store(
7320     et.creation_ctx->get_db_cl()->name,
7321     strlen(et.creation_ctx->get_db_cl()->name),
7322     scs);
7323 
7324   if (schema_table_store_record(thd, sch_table))
7325     DBUG_RETURN(1);
7326 
7327   DBUG_RETURN(0);
7328 }
7329 #endif
7330 
fill_open_tables(THD * thd,TABLE_LIST * tables,Item * cond)7331 int fill_open_tables(THD *thd, TABLE_LIST *tables, Item *cond)
7332 {
7333   DBUG_ENTER("fill_open_tables");
7334   const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
7335   TABLE *table= tables->table;
7336   CHARSET_INFO *cs= system_charset_info;
7337   OPEN_TABLE_LIST *open_list;
7338   if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild))
7339             && thd->is_fatal_error)
7340     DBUG_RETURN(1);
7341 
7342   for (; open_list ; open_list=open_list->next)
7343   {
7344     restore_record(table, s->default_values);
7345     table->field[0]->store(open_list->db, strlen(open_list->db), cs);
7346     table->field[1]->store(open_list->table, strlen(open_list->table), cs);
7347     table->field[2]->store((longlong) open_list->in_use, TRUE);
7348     table->field[3]->store((longlong) open_list->locked, TRUE);
7349     if (schema_table_store_record(thd, table))
7350       DBUG_RETURN(1);
7351   }
7352   DBUG_RETURN(0);
7353 }
7354 
7355 
fill_variables(THD * thd,TABLE_LIST * tables,Item * cond)7356 int fill_variables(THD *thd, TABLE_LIST *tables, Item *cond)
7357 {
7358   DBUG_ENTER("fill_variables");
7359   SHOW_VAR *sys_var_array;
7360   int res= 0;
7361   LEX *lex= thd->lex;
7362   const char *wild= lex->wild ? lex->wild->ptr() : NullS;
7363   enum enum_schema_tables schema_table_idx=
7364     get_schema_table_idx(tables->schema_table);
7365   enum enum_var_type option_type= OPT_SESSION;
7366   bool upper_case_names= (schema_table_idx != SCH_VARIABLES);
7367   bool sorted_vars= (schema_table_idx == SCH_VARIABLES);
7368 
7369   if (lex->option_type == OPT_GLOBAL ||
7370       schema_table_idx == SCH_GLOBAL_VARIABLES)
7371     option_type= OPT_GLOBAL;
7372 
7373   /*
7374     Lock LOCK_plugin_delete to avoid deletion of any plugins while creating
7375     SHOW_VAR array and hold it until all variables are stored in the table.
7376   */
7377   if (thd->fill_variables_recursion_level++ == 0)
7378   {
7379     mysql_mutex_lock(&LOCK_plugin_delete);
7380   }
7381 
7382   // Lock LOCK_system_variables_hash to prepare SHOW_VARs array.
7383   mysql_rwlock_rdlock(&LOCK_system_variables_hash);
7384   DEBUG_SYNC(thd, "acquired_LOCK_system_variables_hash");
7385   sys_var_array= enumerate_sys_vars(thd, sorted_vars, option_type);
7386   mysql_rwlock_unlock(&LOCK_system_variables_hash);
7387 
7388   res= show_status_array(thd, wild, sys_var_array, option_type, NULL, "",
7389                          tables->table, upper_case_names, cond);
7390 
7391   if (thd->fill_variables_recursion_level-- == 1)
7392   {
7393     mysql_mutex_unlock(&LOCK_plugin_delete);
7394   }
7395 
7396   DBUG_RETURN(res);
7397 }
7398 
7399 
fill_status(THD * thd,TABLE_LIST * tables,Item * cond)7400 int fill_status(THD *thd, TABLE_LIST *tables, Item *cond)
7401 {
7402   DBUG_ENTER("fill_status");
7403   LEX *lex= thd->lex;
7404   const char *wild= lex->wild ? lex->wild->ptr() : NullS;
7405   int res= 0;
7406   STATUS_VAR *tmp1, tmp;
7407   enum enum_schema_tables schema_table_idx=
7408     get_schema_table_idx(tables->schema_table);
7409   enum enum_var_type option_type;
7410   bool upper_case_names= (schema_table_idx != SCH_STATUS);
7411 
7412   if (schema_table_idx == SCH_STATUS)
7413   {
7414     option_type= lex->option_type;
7415     if (option_type == OPT_GLOBAL)
7416       tmp1= &tmp;
7417     else
7418       tmp1= thd->initial_status_var;
7419   }
7420   else if (schema_table_idx == SCH_GLOBAL_STATUS)
7421   {
7422     option_type= OPT_GLOBAL;
7423     tmp1= &tmp;
7424   }
7425   else
7426   {
7427     option_type= OPT_SESSION;
7428     tmp1= &thd->status_var;
7429   }
7430 
7431   /*
7432     Avoid recursive acquisition of LOCK_status in cases when WHERE clause
7433     represented by "cond" contains subquery on I_S.SESSION/GLOBAL_STATUS.
7434   */
7435   DEBUG_SYNC(thd, "before_preparing_global_status_array");
7436 
7437   if (thd->fill_status_recursion_level++ == 0)
7438     mysql_mutex_lock(&LOCK_status);
7439   if (option_type == OPT_GLOBAL)
7440     calc_sum_of_all_status(&tmp);
7441   res= show_status_array(thd, wild,
7442                          (SHOW_VAR *)all_status_vars.buffer,
7443                          option_type, tmp1, "", tables->table,
7444                          upper_case_names, cond);
7445   if (thd->fill_status_recursion_level-- == 1)
7446     mysql_mutex_unlock(&LOCK_status);
7447 
7448   DEBUG_SYNC(thd, "after_preparing_global_status_array");
7449   DBUG_RETURN(res);
7450 }
7451 
7452 
7453 /*
7454   Fill and store records into I_S.referential_constraints table
7455 
7456   SYNOPSIS
7457     get_referential_constraints_record()
7458     thd                 thread handle
7459     tables              table list struct(processed table)
7460     table               I_S table
7461     res                 1 means the error during opening of the processed table
7462                         0 means processed table is opened without error
7463     base_name           db name
7464     file_name           table name
7465 
7466   RETURN
7467     0	ok
7468     #   error
7469 */
7470 
7471 static int
get_referential_constraints_record(THD * thd,TABLE_LIST * tables,TABLE * table,bool res,LEX_STRING * db_name,LEX_STRING * table_name)7472 get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
7473                                    TABLE *table, bool res,
7474                                    LEX_STRING *db_name, LEX_STRING *table_name)
7475 {
7476   CHARSET_INFO *cs= system_charset_info;
7477   DBUG_ENTER("get_referential_constraints_record");
7478 
7479   if (res)
7480   {
7481     if (thd->is_error())
7482       push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
7483                    thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
7484     thd->clear_error();
7485     DBUG_RETURN(0);
7486   }
7487   if (!tables->view)
7488   {
7489     List<FOREIGN_KEY_INFO> f_key_list;
7490     TABLE *show_table= tables->table;
7491 
7492     show_table->file->get_foreign_key_list(thd, &f_key_list);
7493     FOREIGN_KEY_INFO *f_key_info;
7494     List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
7495     while ((f_key_info= it++))
7496     {
7497       restore_record(table, s->default_values);
7498       table->field[0]->store(STRING_WITH_LEN("def"), cs);
7499       table->field[1]->store(db_name->str, db_name->length, cs);
7500       table->field[9]->store(table_name->str, table_name->length, cs);
7501       table->field[2]->store(f_key_info->foreign_id->str,
7502                              f_key_info->foreign_id->length, cs);
7503       table->field[3]->store(STRING_WITH_LEN("def"), cs);
7504       table->field[4]->store(f_key_info->referenced_db->str,
7505                              f_key_info->referenced_db->length, cs);
7506       table->field[10]->store(f_key_info->referenced_table->str,
7507                              f_key_info->referenced_table->length, cs);
7508       if (f_key_info->referenced_key_name)
7509       {
7510         table->field[5]->store(f_key_info->referenced_key_name->str,
7511                                f_key_info->referenced_key_name->length, cs);
7512         table->field[5]->set_notnull();
7513       }
7514       else
7515         table->field[5]->set_null();
7516       table->field[6]->store(STRING_WITH_LEN("NONE"), cs);
7517       table->field[7]->store(f_key_info->update_method->str,
7518                              f_key_info->update_method->length, cs);
7519       table->field[8]->store(f_key_info->delete_method->str,
7520                              f_key_info->delete_method->length, cs);
7521       if (schema_table_store_record(thd, table))
7522         DBUG_RETURN(1);
7523     }
7524   }
7525   DBUG_RETURN(0);
7526 }
7527 
7528 struct schema_table_ref
7529 {
7530   const char *table_name;
7531   ST_SCHEMA_TABLE *schema_table;
7532 };
7533 
7534 
7535 /*
7536   Find schema_tables elment by name
7537 
7538   SYNOPSIS
7539     find_schema_table_in_plugin()
7540     thd                 thread handler
7541     plugin              plugin
7542     table_name          table name
7543 
7544   RETURN
7545     0	table not found
7546     1   found the schema table
7547 */
find_schema_table_in_plugin(THD * thd,plugin_ref plugin,void * p_table)7548 static my_bool find_schema_table_in_plugin(THD *thd, plugin_ref plugin,
7549                                            void* p_table)
7550 {
7551   schema_table_ref *p_schema_table= (schema_table_ref *)p_table;
7552   const char* table_name= p_schema_table->table_name;
7553   ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
7554   DBUG_ENTER("find_schema_table_in_plugin");
7555 
7556   if (!my_strcasecmp(system_charset_info,
7557                      schema_table->table_name,
7558                      table_name)) {
7559     p_schema_table->schema_table= schema_table;
7560     DBUG_RETURN(1);
7561   }
7562 
7563   DBUG_RETURN(0);
7564 }
7565 
7566 
7567 /*
7568   Find schema_tables elment by name
7569 
7570   SYNOPSIS
7571     find_schema_table()
7572     thd                 thread handler
7573     table_name          table name
7574 
7575   RETURN
7576     0	table not found
7577     #   pointer to 'schema_tables' element
7578 */
7579 
find_schema_table(THD * thd,const char * table_name)7580 ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
7581 {
7582   schema_table_ref schema_table_a;
7583   ST_SCHEMA_TABLE *schema_table= schema_tables;
7584   DBUG_ENTER("find_schema_table");
7585 
7586   for (; schema_table->table_name; schema_table++)
7587   {
7588     if (!my_strcasecmp(system_charset_info,
7589                        schema_table->table_name,
7590                        table_name))
7591       DBUG_RETURN(schema_table);
7592   }
7593 
7594   schema_table_a.table_name= table_name;
7595   if (plugin_foreach(thd, find_schema_table_in_plugin,
7596                      MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a))
7597     DBUG_RETURN(schema_table_a.schema_table);
7598 
7599   DBUG_RETURN(NULL);
7600 }
7601 
7602 
get_schema_table(enum enum_schema_tables schema_table_idx)7603 ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx)
7604 {
7605   return &schema_tables[schema_table_idx];
7606 }
7607 
7608 
7609 /**
7610   Create information_schema table using schema_table data.
7611 
7612   @note
7613     For MYSQL_TYPE_DECIMAL fields only, the field_length member has encoded
7614     into it two numbers, based on modulus of base-10 numbers.  In the ones
7615     position is the number of decimals.  Tens position is unused.  In the
7616     hundreds and thousands position is a two-digit decimal number representing
7617     length.  Encode this value with  (decimals*100)+length  , where
7618     0<decimals<10 and 0<=length<100 .
7619 
7620   @param
7621     thd	       	          thread handler
7622 
7623   @param table_list Used to pass I_S table information(fields info, tables
7624   parameters etc) and table name.
7625 
7626   @retval  \#             Pointer to created table
7627   @retval  NULL           Can't create table
7628 */
7629 
create_schema_table(THD * thd,TABLE_LIST * table_list)7630 TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
7631 {
7632   int field_count= 0;
7633   Item *item;
7634   TABLE *table;
7635   List<Item> field_list;
7636   ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
7637   ST_FIELD_INFO *fields_info= schema_table->fields_info;
7638   CHARSET_INFO *cs= system_charset_info;
7639   DBUG_ENTER("create_schema_table");
7640 
7641   for (; fields_info->field_name; fields_info++)
7642   {
7643     switch (fields_info->field_type) {
7644     case MYSQL_TYPE_TINY:
7645     case MYSQL_TYPE_LONG:
7646     case MYSQL_TYPE_SHORT:
7647     case MYSQL_TYPE_LONGLONG:
7648     case MYSQL_TYPE_INT24:
7649       if (!(item= new Item_return_int(fields_info->field_name,
7650                                       fields_info->field_length,
7651                                       fields_info->field_type,
7652                                       fields_info->value)))
7653       {
7654         DBUG_RETURN(0);
7655       }
7656       item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
7657       break;
7658     case MYSQL_TYPE_DATE:
7659     case MYSQL_TYPE_TIME:
7660     case MYSQL_TYPE_TIMESTAMP:
7661     case MYSQL_TYPE_DATETIME:
7662     {
7663       const Name_string field_name(fields_info->field_name,
7664                                    strlen(fields_info->field_name));
7665       if (!(item=new Item_temporal(fields_info->field_type, field_name, 0, 0)))
7666         DBUG_RETURN(0);
7667       break;
7668     }
7669     case MYSQL_TYPE_FLOAT:
7670     case MYSQL_TYPE_DOUBLE:
7671     {
7672       const Name_string field_name(fields_info->field_name,
7673                                    strlen(fields_info->field_name));
7674       if ((item= new Item_float(field_name, 0.0, NOT_FIXED_DEC,
7675                                 fields_info->field_length)) == NULL)
7676         DBUG_RETURN(NULL);
7677       break;
7678     }
7679     case MYSQL_TYPE_DECIMAL:
7680     case MYSQL_TYPE_NEWDECIMAL:
7681       if (!(item= new Item_decimal((longlong) fields_info->value, false)))
7682       {
7683         DBUG_RETURN(0);
7684       }
7685       item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
7686       item->decimals= fields_info->field_length%10;
7687       item->max_length= (fields_info->field_length/100)%100;
7688       if (item->unsigned_flag == 0)
7689         item->max_length+= 1;
7690       if (item->decimals > 0)
7691         item->max_length+= 1;
7692       item->item_name.copy(fields_info->field_name);
7693       break;
7694     case MYSQL_TYPE_TINY_BLOB:
7695     case MYSQL_TYPE_MEDIUM_BLOB:
7696     case MYSQL_TYPE_LONG_BLOB:
7697     case MYSQL_TYPE_BLOB:
7698       if (!(item= new Item_blob(fields_info->field_name,
7699                                 fields_info->field_length)))
7700       {
7701         DBUG_RETURN(0);
7702       }
7703       break;
7704     default:
7705       /* Don't let unimplemented types pass through. Could be a grave error. */
7706       DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING);
7707 
7708       if (!(item= new Item_empty_string("", fields_info->field_length, cs)))
7709       {
7710         DBUG_RETURN(0);
7711       }
7712       item->item_name.copy(fields_info->field_name);
7713       break;
7714     }
7715     field_list.push_back(item);
7716     item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL);
7717     field_count++;
7718   }
7719   TMP_TABLE_PARAM *tmp_table_param =
7720     (TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM)));
7721   tmp_table_param->init();
7722   tmp_table_param->table_charset= cs;
7723   tmp_table_param->field_count= field_count;
7724   tmp_table_param->schema_table= 1;
7725   SELECT_LEX *select_lex= thd->lex->current_select;
7726   if (!(table= create_tmp_table(thd, tmp_table_param,
7727                                 field_list, (ORDER*) 0, 0, 0,
7728                                 (select_lex->options | thd->variables.option_bits |
7729                                  TMP_TABLE_ALL_COLUMNS),
7730                                 HA_POS_ERROR, table_list->alias)))
7731     DBUG_RETURN(0);
7732   my_bitmap_map* bitmaps=
7733     (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count));
7734   bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
7735               FALSE);
7736   table->read_set= &table->def_read_set;
7737   bitmap_clear_all(table->read_set);
7738   table_list->schema_table_param= tmp_table_param;
7739   DBUG_RETURN(table);
7740 }
7741 
7742 
7743 /*
7744   For old SHOW compatibility. It is used when
7745   old SHOW doesn't have generated column names
7746   Make list of fields for SHOW
7747 
7748   SYNOPSIS
7749     make_old_format()
7750     thd			thread handler
7751     schema_table        pointer to 'schema_tables' element
7752 
7753   RETURN
7754    1	error
7755    0	success
7756 */
7757 
make_old_format(THD * thd,ST_SCHEMA_TABLE * schema_table)7758 int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
7759 {
7760   ST_FIELD_INFO *field_info= schema_table->fields_info;
7761   Name_resolution_context *context= &thd->lex->select_lex.context;
7762   for (; field_info->field_name; field_info++)
7763   {
7764     if (field_info->old_name)
7765     {
7766       Item_field *field= new Item_field(context,
7767                                         NullS, NullS, field_info->field_name);
7768       if (field)
7769       {
7770         field->item_name.copy(field_info->old_name);
7771         if (add_item_to_list(thd, field))
7772           return 1;
7773       }
7774     }
7775   }
7776   return 0;
7777 }
7778 
7779 
make_schemata_old_format(THD * thd,ST_SCHEMA_TABLE * schema_table)7780 int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
7781 {
7782   char tmp[128];
7783   LEX *lex= thd->lex;
7784   SELECT_LEX *sel= lex->current_select;
7785   Name_resolution_context *context= &sel->context;
7786 
7787   if (!sel->item_list.elements)
7788   {
7789     ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
7790     String buffer(tmp,sizeof(tmp), system_charset_info);
7791     Item_field *field= new Item_field(context,
7792                                       NullS, NullS, field_info->field_name);
7793     if (!field || add_item_to_list(thd, field))
7794       return 1;
7795     buffer.length(0);
7796     buffer.append(field_info->old_name);
7797     if (lex->wild && lex->wild->ptr())
7798     {
7799       buffer.append(STRING_WITH_LEN(" ("));
7800       buffer.append(lex->wild->ptr());
7801       buffer.append(')');
7802     }
7803     field->item_name.copy(buffer.ptr(), buffer.length(), system_charset_info);
7804   }
7805   return 0;
7806 }
7807 
7808 
make_table_names_old_format(THD * thd,ST_SCHEMA_TABLE * schema_table)7809 int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
7810 {
7811   char tmp[128];
7812   String buffer(tmp,sizeof(tmp), thd->charset());
7813   LEX *lex= thd->lex;
7814   Name_resolution_context *context= &lex->select_lex.context;
7815 
7816   ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
7817   buffer.length(0);
7818   buffer.append(field_info->old_name);
7819   buffer.append(lex->select_lex.db);
7820   if (lex->wild && lex->wild->ptr())
7821   {
7822     buffer.append(STRING_WITH_LEN(" ("));
7823     buffer.append(lex->wild->ptr());
7824     buffer.append(')');
7825   }
7826   Item_field *field= new Item_field(context,
7827                                     NullS, NullS, field_info->field_name);
7828   if (add_item_to_list(thd, field))
7829     return 1;
7830   field->item_name.copy(buffer.ptr(), buffer.length(), system_charset_info);
7831   if (thd->lex->verbose)
7832   {
7833     field->item_name.copy(buffer.ptr(), buffer.length(), system_charset_info);
7834     field_info= &schema_table->fields_info[3];
7835     field= new Item_field(context, NullS, NullS, field_info->field_name);
7836     if (add_item_to_list(thd, field))
7837       return 1;
7838     field->item_name.copy(field_info->old_name);
7839   }
7840   return 0;
7841 }
7842 
7843 
make_columns_old_format(THD * thd,ST_SCHEMA_TABLE * schema_table)7844 int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
7845 {
7846   int fields_arr[]= {IS_COLUMNS_COLUMN_NAME,
7847                      IS_COLUMNS_COLUMN_TYPE,
7848                      IS_COLUMNS_COLLATION_NAME,
7849                      IS_COLUMNS_IS_NULLABLE,
7850                      IS_COLUMNS_COLUMN_KEY,
7851                      IS_COLUMNS_COLUMN_DEFAULT,
7852                      IS_COLUMNS_EXTRA,
7853                      IS_COLUMNS_PRIVILEGES,
7854                      IS_COLUMNS_COLUMN_COMMENT,
7855                      -1};
7856   int *field_num= fields_arr;
7857   ST_FIELD_INFO *field_info;
7858   Name_resolution_context *context= &thd->lex->select_lex.context;
7859 
7860   for (; *field_num >= 0; field_num++)
7861   {
7862     field_info= &schema_table->fields_info[*field_num];
7863     if (!thd->lex->verbose && (*field_num == IS_COLUMNS_COLLATION_NAME ||
7864                                *field_num == IS_COLUMNS_PRIVILEGES     ||
7865                                *field_num == IS_COLUMNS_COLUMN_COMMENT))
7866       continue;
7867     Item_field *field= new Item_field(context,
7868                                       NullS, NullS, field_info->field_name);
7869     if (field)
7870     {
7871       field->item_name.copy(field_info->old_name);
7872       if (add_item_to_list(thd, field))
7873         return 1;
7874     }
7875   }
7876   return 0;
7877 }
7878 
7879 
make_character_sets_old_format(THD * thd,ST_SCHEMA_TABLE * schema_table)7880 int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
7881 {
7882   int fields_arr[]= {0, 2, 1, 3, -1};
7883   int *field_num= fields_arr;
7884   ST_FIELD_INFO *field_info;
7885   Name_resolution_context *context= &thd->lex->select_lex.context;
7886 
7887   for (; *field_num >= 0; field_num++)
7888   {
7889     field_info= &schema_table->fields_info[*field_num];
7890     Item_field *field= new Item_field(context,
7891                                       NullS, NullS, field_info->field_name);
7892     if (field)
7893     {
7894       field->item_name.copy(field_info->old_name);
7895       if (add_item_to_list(thd, field))
7896         return 1;
7897     }
7898   }
7899   return 0;
7900 }
7901 
7902 
make_proc_old_format(THD * thd,ST_SCHEMA_TABLE * schema_table)7903 int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
7904 {
7905   int fields_arr[]= {IS_ROUTINES_ROUTINE_SCHEMA,
7906                      IS_ROUTINES_ROUTINE_NAME,
7907                      IS_ROUTINES_ROUTINE_TYPE,
7908                      IS_ROUTINES_DEFINER,
7909                      IS_ROUTINES_LAST_ALTERED,
7910                      IS_ROUTINES_CREATED,
7911                      IS_ROUTINES_SECURITY_TYPE,
7912                      IS_ROUTINES_ROUTINE_COMMENT,
7913                      IS_ROUTINES_CHARACTER_SET_CLIENT,
7914                      IS_ROUTINES_COLLATION_CONNECTION,
7915                      IS_ROUTINES_DATABASE_COLLATION,
7916                      -1};
7917   int *field_num= fields_arr;
7918   ST_FIELD_INFO *field_info;
7919   Name_resolution_context *context= &thd->lex->select_lex.context;
7920 
7921   for (; *field_num >= 0; field_num++)
7922   {
7923     field_info= &schema_table->fields_info[*field_num];
7924     Item_field *field= new Item_field(context,
7925                                       NullS, NullS, field_info->field_name);
7926     if (field)
7927     {
7928       field->item_name.copy(field_info->old_name);
7929       if (add_item_to_list(thd, field))
7930         return 1;
7931     }
7932   }
7933   return 0;
7934 }
7935 
7936 
7937 /*
7938   Create information_schema table
7939 
7940   SYNOPSIS
7941   mysql_schema_table()
7942     thd                thread handler
7943     lex                pointer to LEX
7944     table_list         pointer to table_list
7945 
7946   RETURN
7947     0	success
7948     1   error
7949 */
7950 
mysql_schema_table(THD * thd,LEX * lex,TABLE_LIST * table_list)7951 int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
7952 {
7953   TABLE *table;
7954   DBUG_ENTER("mysql_schema_table");
7955   if (!(table= table_list->schema_table->create_table(thd, table_list)))
7956     DBUG_RETURN(1);
7957   table->s->tmp_table= SYSTEM_TMP_TABLE;
7958   table->grant.privilege= SELECT_ACL;
7959   /*
7960     This test is necessary to make
7961     case insensitive file systems +
7962     upper case table names(information schema tables) +
7963     views
7964     working correctly
7965   */
7966   if (table_list->schema_table_name)
7967     table->alias_name_used= my_strcasecmp(table_alias_charset,
7968                                           table_list->schema_table_name,
7969                                           table_list->alias);
7970   table_list->table_name= table->s->table_name.str;
7971   table_list->table_name_length= table->s->table_name.length;
7972   table_list->table= table;
7973   table->next= thd->derived_tables;
7974   thd->derived_tables= table;
7975   table_list->select_lex->options |= OPTION_SCHEMA_TABLE;
7976   lex->safe_to_cache_query= 0;
7977 
7978   if (table_list->schema_table_reformed) // show command
7979   {
7980     SELECT_LEX *sel= lex->current_select;
7981     Item *item;
7982     Field_translator *transl, *org_transl;
7983 
7984     if (table_list->field_translation)
7985     {
7986       Field_translator *end= table_list->field_translation_end;
7987       for (transl= table_list->field_translation; transl < end; transl++)
7988       {
7989         if (!transl->item->fixed &&
7990             transl->item->fix_fields(thd, &transl->item))
7991           DBUG_RETURN(1);
7992       }
7993       DBUG_RETURN(0);
7994     }
7995     List_iterator_fast<Item> it(sel->item_list);
7996     if (!(transl=
7997           (Field_translator*)(thd->stmt_arena->
7998                               alloc(sel->item_list.elements *
7999                                     sizeof(Field_translator)))))
8000     {
8001       DBUG_RETURN(1);
8002     }
8003     for (org_transl= transl; (item= it++); transl++)
8004     {
8005       transl->item= item;
8006       transl->name= item->item_name.ptr();
8007       if (!item->fixed && item->fix_fields(thd, &transl->item))
8008       {
8009         DBUG_RETURN(1);
8010       }
8011     }
8012     table_list->field_translation= org_transl;
8013     table_list->field_translation_end= transl;
8014   }
8015 
8016   DBUG_RETURN(0);
8017 }
8018 
8019 
8020 /*
8021   Generate select from information_schema table
8022 
8023   SYNOPSIS
8024     make_schema_select()
8025     thd                  thread handler
8026     sel                  pointer to SELECT_LEX
8027     schema_table_idx     index of 'schema_tables' element
8028 
8029   RETURN
8030     0	success
8031     1   error
8032 */
8033 
make_schema_select(THD * thd,SELECT_LEX * sel,enum enum_schema_tables schema_table_idx)8034 int make_schema_select(THD *thd, SELECT_LEX *sel,
8035 		       enum enum_schema_tables schema_table_idx)
8036 {
8037   ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx);
8038   LEX_STRING db, table;
8039   DBUG_ENTER("make_schema_select");
8040   DBUG_PRINT("enter", ("mysql_schema_select: %s", schema_table->table_name));
8041   /*
8042      We have to make non const db_name & table_name
8043      because of lower_case_table_names
8044   */
8045   thd->make_lex_string(&db, INFORMATION_SCHEMA_NAME.str,
8046                        INFORMATION_SCHEMA_NAME.length, 0);
8047   thd->make_lex_string(&table, schema_table->table_name,
8048                        strlen(schema_table->table_name), 0);
8049   if (schema_table->old_format(thd, schema_table) ||   /* Handle old syntax */
8050       !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
8051                               0, 0, TL_READ, MDL_SHARED_READ))
8052   {
8053     DBUG_RETURN(1);
8054   }
8055   DBUG_RETURN(0);
8056 }
8057 
8058 
8059 /**
8060   Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area /
8061   Warning_info state after itself.
8062 
8063   This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which
8064   may "partially silence" some errors. The thing is that during
8065   fill_table() many errors might be emitted. These errors stem from the
8066   nature of fill_table().
8067 
8068   For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx'
8069   results in a number of 'Table <db name>.xxx does not exist' errors,
8070   because fill_table() tries to open the 'xxx' table in every possible
8071   database.
8072 
8073   Those errors are cleared (the error status is cleared from
8074   Diagnostics_area) inside fill_table(), but they remain in Warning_info
8075   (Warning_info is not cleared because it may contain useful warnings).
8076 
8077   This function is responsible for making sure that Warning_info does not
8078   contain warnings corresponding to the cleared errors.
8079 
8080   @note: THD::no_warnings_for_error used to be set before calling
8081   fill_table(), thus those errors didn't go to Warning_info. This is not
8082   the case now (THD::no_warnings_for_error was eliminated as a hack), so we
8083   need to take care of those warnings here.
8084 
8085   @param thd            Thread context.
8086   @param table_list     I_S table.
8087   @param join_table     JOIN/SELECT table.
8088 
8089   @return Error status.
8090   @retval TRUE Error.
8091   @retval FALSE Success.
8092 */
do_fill_table(THD * thd,TABLE_LIST * table_list,JOIN_TAB * join_table)8093 static bool do_fill_table(THD *thd,
8094                           TABLE_LIST *table_list,
8095                           JOIN_TAB *join_table)
8096 {
8097   // NOTE: fill_table() may generate many "useless" warnings, which will be
8098   // ignored afterwards. On the other hand, there might be "useful"
8099   // warnings, which should be presented to the user. Warning_info usually
8100   // stores no more than THD::variables.max_error_count warnings.
8101   // The problem is that "useless warnings" may occupy all the slots in the
8102   // Warning_info, so "useful warnings" get rejected. In order to avoid
8103   // that problem we create a Warning_info instance, which is capable of
8104   // storing "unlimited" number of warnings.
8105   Diagnostics_area *da= thd->get_stmt_da();
8106   Warning_info wi_tmp(thd->query_id, true);
8107 
8108   da->push_warning_info(&wi_tmp);
8109 
8110   bool res= table_list->schema_table->fill_table(
8111     thd, table_list, join_table->unified_condition());
8112 
8113   da->pop_warning_info();
8114 
8115   // Pass an error if any.
8116 
8117   if (da->is_error())
8118   {
8119     da->push_warning(thd,
8120                      da->sql_errno(),
8121                      da->get_sqlstate(),
8122                      Sql_condition::WARN_LEVEL_ERROR,
8123                      da->message());
8124   }
8125 
8126   // Pass warnings (if any).
8127   //
8128   // Filter out warnings with WARN_LEVEL_ERROR level, because they
8129   // correspond to the errors which were filtered out in fill_table().
8130   da->copy_non_errors_from_wi(thd, &wi_tmp);
8131 
8132   return res;
8133 }
8134 
8135 
8136 /*
8137   Fill temporary schema tables before SELECT
8138 
8139   SYNOPSIS
8140     get_schema_tables_result()
8141     join  join which use schema tables
8142     executed_place place where I_S table processed
8143 
8144   RETURN
8145     FALSE success
8146     TRUE  error
8147 */
8148 
get_schema_tables_result(JOIN * join,enum enum_schema_table_state executed_place)8149 bool get_schema_tables_result(JOIN *join,
8150                               enum enum_schema_table_state executed_place)
8151 {
8152   THD *thd= join->thd;
8153   LEX *lex= thd->lex;
8154   bool result= 0;
8155   DBUG_ENTER("get_schema_tables_result");
8156 
8157   /* Check if the schema table is optimized away */
8158   if (!join->join_tab)
8159     DBUG_RETURN(result);
8160 
8161   for (uint i= 0; i < join->tables; i++)
8162   {
8163     JOIN_TAB *const tab= join->join_tab + i;
8164     if (!tab->table || !tab->table->pos_in_table_list)
8165       continue;
8166 
8167     TABLE_LIST *table_list= tab->table->pos_in_table_list;
8168     if (table_list->schema_table && thd->fill_information_schema_tables())
8169     {
8170       bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
8171                           lex->current_select->master_unit()->item);
8172 
8173       /* A value of 0 indicates a dummy implementation */
8174       if (table_list->schema_table->fill_table == 0)
8175         continue;
8176 
8177       /* skip I_S optimizations specific to get_all_tables */
8178       if (thd->lex->describe &&
8179           (table_list->schema_table->fill_table != get_all_tables))
8180         continue;
8181 
8182       /*
8183         If schema table is already processed and
8184         the statement is not a subselect then
8185         we don't need to fill this table again.
8186         If schema table is already processed and
8187         schema_table_state != executed_place then
8188         table is already processed and
8189         we should skip second data processing.
8190       */
8191       if (table_list->schema_table_state &&
8192           (!is_subselect || table_list->schema_table_state != executed_place))
8193         continue;
8194 
8195       /*
8196         if table is used in a subselect and
8197         table has been processed earlier with the same
8198         'executed_place' value then we should refresh the table.
8199       */
8200       if (table_list->schema_table_state && is_subselect)
8201       {
8202         table_list->table->file->extra(HA_EXTRA_NO_CACHE);
8203         table_list->table->file->extra(HA_EXTRA_RESET_STATE);
8204         table_list->table->file->ha_delete_all_rows();
8205         free_io_cache(table_list->table);
8206         filesort_free_buffers(table_list->table,1);
8207         table_list->table->null_row= 0;
8208       }
8209       else
8210         table_list->table->file->stats.records= 0;
8211 
8212       if (do_fill_table(thd, table_list, tab))
8213       {
8214         result= 1;
8215         join->error= 1;
8216         table_list->schema_table_state= executed_place;
8217         break;
8218       }
8219       table_list->schema_table_state= executed_place;
8220     }
8221   }
8222   DBUG_RETURN(result);
8223 }
8224 
8225 struct run_hton_fill_schema_table_args
8226 {
8227   TABLE_LIST *tables;
8228   Item *cond;
8229 };
8230 
run_hton_fill_schema_table(THD * thd,plugin_ref plugin,void * arg)8231 static my_bool run_hton_fill_schema_table(THD *thd, plugin_ref plugin,
8232                                           void *arg)
8233 {
8234   struct run_hton_fill_schema_table_args *args=
8235     (run_hton_fill_schema_table_args *) arg;
8236   handlerton *hton= plugin_data(plugin, handlerton *);
8237   if (hton->fill_is_table && hton->state == SHOW_OPTION_YES)
8238       hton->fill_is_table(hton, thd, args->tables, args->cond,
8239             get_schema_table_idx(args->tables->schema_table));
8240   return false;
8241 }
8242 
hton_fill_schema_table(THD * thd,TABLE_LIST * tables,Item * cond)8243 int hton_fill_schema_table(THD *thd, TABLE_LIST *tables, Item *cond)
8244 {
8245   DBUG_ENTER("hton_fill_schema_table");
8246 
8247   struct run_hton_fill_schema_table_args args;
8248   args.tables= tables;
8249   args.cond= cond;
8250 
8251   if (check_global_access(thd, PROCESS_ACL))
8252     DBUG_RETURN(1);
8253 
8254   plugin_foreach(thd, run_hton_fill_schema_table,
8255                  MYSQL_STORAGE_ENGINE_PLUGIN, &args);
8256 
8257   DBUG_RETURN(0);
8258 }
8259 
8260 
8261 ST_FIELD_INFO schema_fields_info[]=
8262 {
8263   {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8264   {"SCHEMA_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
8265    SKIP_OPEN_TABLE},
8266   {"DEFAULT_CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
8267    SKIP_OPEN_TABLE},
8268   {"DEFAULT_COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
8269    SKIP_OPEN_TABLE},
8270   {"SQL_PATH", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8271   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8272 };
8273 
8274 
8275 ST_FIELD_INFO tables_fields_info[]=
8276 {
8277   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8278   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8279   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
8280    SKIP_OPEN_TABLE},
8281   {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8282   {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine", OPEN_FRM_ONLY},
8283   {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8284    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version", OPEN_FRM_ONLY},
8285   {"ROW_FORMAT", 20, MYSQL_TYPE_STRING, 0, 1, "Row_format", OPEN_FULL_TABLE},
8286   {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8287    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", OPEN_FULL_TABLE},
8288   {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8289    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", OPEN_FULL_TABLE},
8290   {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8291    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", OPEN_FULL_TABLE},
8292   {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8293    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", OPEN_FULL_TABLE},
8294   {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8295    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", OPEN_FULL_TABLE},
8296   {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8297    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", OPEN_FULL_TABLE},
8298   {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0,
8299    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Auto_increment", OPEN_FULL_TABLE},
8300   {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", OPEN_FULL_TABLE},
8301   {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", OPEN_FULL_TABLE},
8302   {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", OPEN_FULL_TABLE},
8303   {"TABLE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
8304    OPEN_FRM_ONLY},
8305   {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8306    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", OPEN_FULL_TABLE},
8307   {"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options",
8308    OPEN_FRM_ONLY},
8309   {"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
8310    "Comment", OPEN_FRM_ONLY},
8311   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8312 };
8313 
8314 static ST_FIELD_INFO temporary_table_fields_info[]=
8315 {
8316   {"SESSION_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Session", SKIP_OPEN_TABLE},
8317   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db", SKIP_OPEN_TABLE},
8318   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Temp_tables_in_", SKIP_OPEN_TABLE},
8319   {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Engine", OPEN_FRM_ONLY},
8320   {"NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, "Name", SKIP_OPEN_TABLE},
8321   {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8322    MY_I_S_UNSIGNED, "Rows", OPEN_FULL_TABLE},
8323   {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8324    MY_I_S_UNSIGNED, "Avg Row", OPEN_FULL_TABLE},
8325   {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8326    MY_I_S_UNSIGNED, "Data Length", OPEN_FULL_TABLE},
8327   {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8328    MY_I_S_UNSIGNED, "Index Size", OPEN_FULL_TABLE},
8329   {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create Time", OPEN_FULL_TABLE},
8330   {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update Time", OPEN_FULL_TABLE},
8331   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8332 };
8333 
8334 ST_FIELD_INFO columns_fields_info[]=
8335 {
8336   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8337   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8338   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8339   {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field",
8340    OPEN_FRM_ONLY},
8341   {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8342    MY_I_S_UNSIGNED, 0, OPEN_FRM_ONLY},
8343   {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0,
8344    1, "Default", OPEN_FRM_ONLY},
8345   {"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null", OPEN_FRM_ONLY},
8346   {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8347   {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8348    0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
8349   {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
8350    0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
8351   {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8352    0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
8353   {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
8354    0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
8355   {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
8356    0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
8357   {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, 0,
8358    OPEN_FRM_ONLY},
8359   {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
8360    OPEN_FRM_ONLY},
8361   {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type", OPEN_FRM_ONLY},
8362   {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY},
8363   {"EXTRA", 30, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
8364   {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY},
8365   {"COLUMN_COMMENT", COLUMN_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
8366    "Comment", OPEN_FRM_ONLY},
8367   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8368 };
8369 
8370 
8371 ST_FIELD_INFO charsets_fields_info[]=
8372 {
8373   {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
8374    SKIP_OPEN_TABLE},
8375   {"DEFAULT_COLLATE_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8376    "Default collation", SKIP_OPEN_TABLE},
8377   {"DESCRIPTION", 60, MYSQL_TYPE_STRING, 0, 0, "Description",
8378    SKIP_OPEN_TABLE},
8379   {"MAXLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Maxlen", SKIP_OPEN_TABLE},
8380   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8381 };
8382 
8383 
8384 ST_FIELD_INFO collation_fields_info[]=
8385 {
8386   {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Collation",
8387    SKIP_OPEN_TABLE},
8388   {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
8389    SKIP_OPEN_TABLE},
8390   {"ID", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Id",
8391    SKIP_OPEN_TABLE},
8392   {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default", SKIP_OPEN_TABLE},
8393   {"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled", SKIP_OPEN_TABLE},
8394   {"SORTLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Sortlen", SKIP_OPEN_TABLE},
8395   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8396 };
8397 
8398 
8399 ST_FIELD_INFO engines_fields_info[]=
8400 {
8401   {"ENGINE", 64, MYSQL_TYPE_STRING, 0, 0, "Engine", SKIP_OPEN_TABLE},
8402   {"SUPPORT", 8, MYSQL_TYPE_STRING, 0, 0, "Support", SKIP_OPEN_TABLE},
8403   {"COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment", SKIP_OPEN_TABLE},
8404   {"TRANSACTIONS", 3, MYSQL_TYPE_STRING, 0, 1, "Transactions", SKIP_OPEN_TABLE},
8405   {"XA", 3, MYSQL_TYPE_STRING, 0, 1, "XA", SKIP_OPEN_TABLE},
8406   {"SAVEPOINTS", 3 ,MYSQL_TYPE_STRING, 0, 1, "Savepoints", SKIP_OPEN_TABLE},
8407   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8408 };
8409 
8410 
8411 ST_FIELD_INFO events_fields_info[]=
8412 {
8413   {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8414   {"EVENT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db",
8415    SKIP_OPEN_TABLE},
8416   {"EVENT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
8417    SKIP_OPEN_TABLE},
8418   {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
8419   {"TIME_ZONE", 64, MYSQL_TYPE_STRING, 0, 0, "Time zone", SKIP_OPEN_TABLE},
8420   {"EVENT_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8421   {"EVENT_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8422   {"EVENT_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
8423   {"EXECUTE_AT", 0, MYSQL_TYPE_DATETIME, 0, 1, "Execute at", SKIP_OPEN_TABLE},
8424   {"INTERVAL_VALUE", 256, MYSQL_TYPE_STRING, 0, 1, "Interval value",
8425    SKIP_OPEN_TABLE},
8426   {"INTERVAL_FIELD", 18, MYSQL_TYPE_STRING, 0, 1, "Interval field",
8427    SKIP_OPEN_TABLE},
8428   {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8429   {"STARTS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Starts", SKIP_OPEN_TABLE},
8430   {"ENDS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Ends", SKIP_OPEN_TABLE},
8431   {"STATUS", 18, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
8432   {"ON_COMPLETION", 12, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8433   {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
8434   {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
8435   {"LAST_EXECUTED", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
8436   {"EVENT_COMMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8437   {"ORIGINATOR", 10, MYSQL_TYPE_LONGLONG, 0, 0, "Originator", SKIP_OPEN_TABLE},
8438   {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8439    "character_set_client", SKIP_OPEN_TABLE},
8440   {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8441    "collation_connection", SKIP_OPEN_TABLE},
8442   {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8443    "Database Collation", SKIP_OPEN_TABLE},
8444   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8445 };
8446 
8447 
8448 
8449 ST_FIELD_INFO coll_charset_app_fields_info[]=
8450 {
8451   {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
8452    SKIP_OPEN_TABLE},
8453   {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
8454    SKIP_OPEN_TABLE},
8455   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8456 };
8457 
8458 
8459 ST_FIELD_INFO proc_fields_info[]=
8460 {
8461   {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8462   {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8463   {"ROUTINE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db",
8464    SKIP_OPEN_TABLE},
8465   {"ROUTINE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
8466    SKIP_OPEN_TABLE},
8467   {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
8468   {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8469   {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
8470   {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
8471   {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8472    0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
8473   {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
8474   {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
8475    0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
8476   {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8477   {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8478   {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8479   {"ROUTINE_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8480   {"ROUTINE_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8481   {"EXTERNAL_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8482   {"EXTERNAL_LANGUAGE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8483    SKIP_OPEN_TABLE},
8484   {"PARAMETER_STYLE", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8485   {"IS_DETERMINISTIC", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8486   {"SQL_DATA_ACCESS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
8487    SKIP_OPEN_TABLE},
8488   {"SQL_PATH", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8489   {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, "Security_type",
8490    SKIP_OPEN_TABLE},
8491   {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Created", SKIP_OPEN_TABLE},
8492   {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Modified", SKIP_OPEN_TABLE},
8493   {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8494   {"ROUTINE_COMMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Comment",
8495    SKIP_OPEN_TABLE},
8496   {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
8497   {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8498    "character_set_client", SKIP_OPEN_TABLE},
8499   {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8500    "collation_connection", SKIP_OPEN_TABLE},
8501   {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8502    "Database Collation", SKIP_OPEN_TABLE},
8503   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8504 };
8505 
8506 
8507 ST_FIELD_INFO stat_fields_info[]=
8508 {
8509   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8510   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8511   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", OPEN_FRM_ONLY},
8512   {"NON_UNIQUE", 1, MYSQL_TYPE_LONGLONG, 0, 0, "Non_unique", OPEN_FRM_ONLY},
8513   {"INDEX_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8514   {"INDEX_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Key_name",
8515    OPEN_FRM_ONLY},
8516   {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONGLONG, 0, 0, "Seq_in_index", OPEN_FRM_ONLY},
8517   {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name",
8518    OPEN_FRM_ONLY},
8519   {"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation", OPEN_FRM_ONLY},
8520   {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 1,
8521    "Cardinality", OPEN_FULL_TABLE},
8522   {"SUB_PART", 3, MYSQL_TYPE_LONGLONG, 0, 1, "Sub_part", OPEN_FRM_ONLY},
8523   {"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed", OPEN_FRM_ONLY},
8524   {"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null", OPEN_FRM_ONLY},
8525   {"INDEX_TYPE", 16, MYSQL_TYPE_STRING, 0, 0, "Index_type", OPEN_FULL_TABLE},
8526   {"COMMENT", 16, MYSQL_TYPE_STRING, 0, 1, "Comment", OPEN_FRM_ONLY},
8527   {"INDEX_COMMENT", INDEX_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
8528    "Index_comment", OPEN_FRM_ONLY},
8529   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8530 };
8531 
8532 
8533 ST_FIELD_INFO view_fields_info[]=
8534 {
8535   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8536   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8537   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8538   {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8539   {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8540   {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8541   {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8542   {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8543   {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
8544    OPEN_FRM_ONLY},
8545   {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
8546    OPEN_FRM_ONLY},
8547   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8548 };
8549 
8550 
8551 ST_FIELD_INFO user_privileges_fields_info[]=
8552 {
8553   {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8554   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8555   {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8556   {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8557   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8558 };
8559 
8560 
8561 ST_FIELD_INFO schema_privileges_fields_info[]=
8562 {
8563   {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8564   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8565   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8566   {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8567   {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8568   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8569 };
8570 
8571 
8572 ST_FIELD_INFO table_privileges_fields_info[]=
8573 {
8574   {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8575   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8576   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8577   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8578   {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8579   {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8580   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8581 };
8582 
8583 
8584 ST_FIELD_INFO column_privileges_fields_info[]=
8585 {
8586   {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8587   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8588   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8589   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8590   {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8591   {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8592   {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8593   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8594 };
8595 
8596 
8597 ST_FIELD_INFO table_constraints_fields_info[]=
8598 {
8599   {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8600   {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
8601    OPEN_FULL_TABLE},
8602   {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
8603    OPEN_FULL_TABLE},
8604   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8605   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8606   {"CONSTRAINT_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
8607    OPEN_FULL_TABLE},
8608   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8609 };
8610 
8611 
8612 ST_FIELD_INFO key_column_usage_fields_info[]=
8613 {
8614   {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8615   {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
8616    OPEN_FULL_TABLE},
8617   {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
8618    OPEN_FULL_TABLE},
8619   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8620   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8621   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8622   {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8623   {"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FULL_TABLE},
8624   {"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONGLONG, 0, 1, 0,
8625    OPEN_FULL_TABLE},
8626   {"REFERENCED_TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8627    OPEN_FULL_TABLE},
8628   {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8629    OPEN_FULL_TABLE},
8630   {"REFERENCED_COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8631    OPEN_FULL_TABLE},
8632   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8633 };
8634 
8635 
8636 ST_FIELD_INFO table_names_fields_info[]=
8637 {
8638   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8639   {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8640   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Tables_in_",
8641    SKIP_OPEN_TABLE},
8642   {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type",
8643    OPEN_FRM_ONLY},
8644   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8645 };
8646 
8647 
8648 ST_FIELD_INFO open_tables_fields_info[]=
8649 {
8650   {"Database", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
8651    SKIP_OPEN_TABLE},
8652   {"Table",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", SKIP_OPEN_TABLE},
8653   {"In_use", 1, MYSQL_TYPE_LONGLONG, 0, 0, "In_use", SKIP_OPEN_TABLE},
8654   {"Name_locked", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Name_locked", SKIP_OPEN_TABLE},
8655   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8656 };
8657 
8658 
8659 ST_FIELD_INFO triggers_fields_info[]=
8660 {
8661   {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8662   {"TRIGGER_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8663   {"TRIGGER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger",
8664    OPEN_FRM_ONLY},
8665   {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FRM_ONLY},
8666   {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
8667    OPEN_FRM_ONLY},
8668   {"EVENT_OBJECT_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
8669    OPEN_FRM_ONLY},
8670   {"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table",
8671    OPEN_FRM_ONLY},
8672   {"ACTION_ORDER", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FRM_ONLY},
8673   {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY},
8674   {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement",
8675    OPEN_FRM_ONLY},
8676   {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8677   {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing", OPEN_FRM_ONLY},
8678   {"ACTION_REFERENCE_OLD_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8679    OPEN_FRM_ONLY},
8680   {"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8681    OPEN_FRM_ONLY},
8682   {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8683   {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
8684   {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FRM_ONLY},
8685   {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FRM_ONLY},
8686   {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FRM_ONLY},
8687   {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8688    "character_set_client", OPEN_FRM_ONLY},
8689   {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8690    "collation_connection", OPEN_FRM_ONLY},
8691   {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
8692    "Database Collation", OPEN_FRM_ONLY},
8693   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8694 };
8695 
8696 
8697 ST_FIELD_INFO partitions_fields_info[]=
8698 {
8699   {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8700   {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8701   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8702   {"PARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
8703   {"SUBPARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8704    OPEN_FULL_TABLE},
8705   {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
8706    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
8707   {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
8708    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
8709   {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
8710   {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
8711   {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
8712   {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0,
8713    OPEN_FULL_TABLE},
8714   {"PARTITION_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
8715   {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
8716    OPEN_FULL_TABLE},
8717   {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
8718    OPEN_FULL_TABLE},
8719   {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
8720    OPEN_FULL_TABLE},
8721   {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
8722    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
8723   {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
8724    OPEN_FULL_TABLE},
8725   {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
8726    OPEN_FULL_TABLE},
8727   {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
8728   {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
8729   {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
8730   {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
8731    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
8732   {"PARTITION_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8733   {"NODEGROUP", 12 , MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
8734   {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8735    OPEN_FULL_TABLE},
8736   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8737 };
8738 
8739 
8740 ST_FIELD_INFO variables_fields_info[]=
8741 {
8742   {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name",
8743    SKIP_OPEN_TABLE},
8744   {"VARIABLE_VALUE", 1024, MYSQL_TYPE_STRING, 0, 1, "Value", SKIP_OPEN_TABLE},
8745   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8746 };
8747 
8748 
8749 static ST_FIELD_INFO user_stats_fields_info[]=
8750 {
8751   {"USER", USERNAME_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User", SKIP_OPEN_TABLE},
8752   {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8753    MY_I_S_UNSIGNED, "Total_connections", SKIP_OPEN_TABLE},
8754   {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8755    0, MY_I_S_UNSIGNED, "Concurrent_connections", SKIP_OPEN_TABLE},
8756   {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8757    MY_I_S_UNSIGNED, "Connected_time", SKIP_OPEN_TABLE},
8758   {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8759    MY_I_S_UNSIGNED, "Busy_time", SKIP_OPEN_TABLE},
8760   {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8761    MY_I_S_UNSIGNED, "Cpu_time", SKIP_OPEN_TABLE},
8762   {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8763    MY_I_S_UNSIGNED, "Bytes_received", SKIP_OPEN_TABLE},
8764   {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8765    MY_I_S_UNSIGNED, "Bytes_sent", SKIP_OPEN_TABLE},
8766   {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8767    0, MY_I_S_UNSIGNED, "Binlog_bytes_written", SKIP_OPEN_TABLE},
8768   {"ROWS_FETCHED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8769    MY_I_S_UNSIGNED, "Rows_fetched", SKIP_OPEN_TABLE},
8770   {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8771    MY_I_S_UNSIGNED, "Rows_updated", SKIP_OPEN_TABLE},
8772   {"TABLE_ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8773    MY_I_S_UNSIGNED, "Table_rows_read", SKIP_OPEN_TABLE},
8774   {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8775    MY_I_S_UNSIGNED, "Select_commands", SKIP_OPEN_TABLE},
8776   {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8777    MY_I_S_UNSIGNED, "Update_commands", SKIP_OPEN_TABLE},
8778   {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8779    MY_I_S_UNSIGNED, "Other_commands", SKIP_OPEN_TABLE},
8780   {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8781    MY_I_S_UNSIGNED, "Commit_transactions", SKIP_OPEN_TABLE},
8782   {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8783    0, MY_I_S_UNSIGNED, "Rollback_transactions", SKIP_OPEN_TABLE},
8784   {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8785    MY_I_S_UNSIGNED, "Denied_connections", SKIP_OPEN_TABLE},
8786   {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8787    MY_I_S_UNSIGNED, "Lost_connections", SKIP_OPEN_TABLE},
8788   {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8789    MY_I_S_UNSIGNED, "Access_denied", SKIP_OPEN_TABLE},
8790   {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8791    MY_I_S_UNSIGNED, "Empty_queries", SKIP_OPEN_TABLE},
8792   {"TOTAL_SSL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8793    0, MY_I_S_UNSIGNED, "Total_ssl_connections", SKIP_OPEN_TABLE},
8794   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
8795 };
8796 
8797 static ST_FIELD_INFO client_stats_fields_info[]=
8798 {
8799   {"CLIENT", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Client",
8800    SKIP_OPEN_TABLE},
8801   {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8802    MY_I_S_UNSIGNED, "Total_connections", SKIP_OPEN_TABLE},
8803   {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8804    0, MY_I_S_UNSIGNED, "Concurrent_connections", SKIP_OPEN_TABLE},
8805   {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8806    MY_I_S_UNSIGNED, "Connected_time", SKIP_OPEN_TABLE},
8807   {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8808    MY_I_S_UNSIGNED, "Busy_time", SKIP_OPEN_TABLE},
8809   {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8810    MY_I_S_UNSIGNED, "Cpu_time", SKIP_OPEN_TABLE},
8811   {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8812    MY_I_S_UNSIGNED, "Bytes_received", SKIP_OPEN_TABLE},
8813   {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8814    MY_I_S_UNSIGNED, "Bytes_sent", SKIP_OPEN_TABLE},
8815   {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8816    0, MY_I_S_UNSIGNED, "Binlog_bytes_written", SKIP_OPEN_TABLE},
8817   {"ROWS_FETCHED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8818    MY_I_S_UNSIGNED, "Rows_fetched", SKIP_OPEN_TABLE},
8819   {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8820    MY_I_S_UNSIGNED, "Rows_updated", SKIP_OPEN_TABLE},
8821   {"TABLE_ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8822    MY_I_S_UNSIGNED, "Table_rows_read", SKIP_OPEN_TABLE},
8823   {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8824    MY_I_S_UNSIGNED, "Select_commands", SKIP_OPEN_TABLE},
8825   {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8826    MY_I_S_UNSIGNED, "Update_commands", SKIP_OPEN_TABLE},
8827   {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8828    MY_I_S_UNSIGNED, "Other_commands", SKIP_OPEN_TABLE},
8829   {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8830    MY_I_S_UNSIGNED, "Commit_transactions", SKIP_OPEN_TABLE},
8831   {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8832    0, MY_I_S_UNSIGNED, "Rollback_transactions", SKIP_OPEN_TABLE},
8833   {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8834    MY_I_S_UNSIGNED, "Denied_connections", SKIP_OPEN_TABLE},
8835   {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8836    MY_I_S_UNSIGNED, "Lost_connections", SKIP_OPEN_TABLE},
8837   {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8838    MY_I_S_UNSIGNED, "Access_denied", SKIP_OPEN_TABLE},
8839   {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8840    MY_I_S_UNSIGNED, "Empty_queries", SKIP_OPEN_TABLE},
8841   {"TOTAL_SSL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8842    0, MY_I_S_UNSIGNED, "Total_ssl_connections", SKIP_OPEN_TABLE},
8843   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
8844 };
8845 
8846 static ST_FIELD_INFO thread_stats_fields_info[]=
8847 {
8848   {"THREAD_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8849    MY_I_S_UNSIGNED, "Thread_id", SKIP_OPEN_TABLE},
8850   {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8851    MY_I_S_UNSIGNED, "Total_connections", SKIP_OPEN_TABLE},
8852   {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8853    0, MY_I_S_UNSIGNED, "Concurrent_connections", SKIP_OPEN_TABLE},
8854   {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8855    MY_I_S_UNSIGNED, "Connected_time", SKIP_OPEN_TABLE},
8856   {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8857    MY_I_S_UNSIGNED, "Busy_time", SKIP_OPEN_TABLE},
8858   {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8859    MY_I_S_UNSIGNED, "Cpu_time", SKIP_OPEN_TABLE},
8860   {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8861    MY_I_S_UNSIGNED, "Bytes_received", SKIP_OPEN_TABLE},
8862   {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8863    MY_I_S_UNSIGNED, "Bytes_sent", SKIP_OPEN_TABLE},
8864   {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8865    MY_I_S_UNSIGNED, "Binlog_bytes_written", SKIP_OPEN_TABLE},
8866   {"ROWS_FETCHED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8867    MY_I_S_UNSIGNED, "Rows_fetched", SKIP_OPEN_TABLE},
8868   {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8869    MY_I_S_UNSIGNED, "Rows_updated", SKIP_OPEN_TABLE},
8870   {"TABLE_ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8871    MY_I_S_UNSIGNED, "Table_rows_read", SKIP_OPEN_TABLE},
8872   {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8873    MY_I_S_UNSIGNED, "Select_commands", SKIP_OPEN_TABLE},
8874   {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8875    MY_I_S_UNSIGNED, "Update_commands", SKIP_OPEN_TABLE},
8876   {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8877    MY_I_S_UNSIGNED, "Other_commands", SKIP_OPEN_TABLE},
8878   {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8879    MY_I_S_UNSIGNED, "Commit_transactions", SKIP_OPEN_TABLE},
8880   {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8881    0, MY_I_S_UNSIGNED, "Rollback_transactions", SKIP_OPEN_TABLE},
8882   {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8883    MY_I_S_UNSIGNED, "Denied_connections", SKIP_OPEN_TABLE},
8884   {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8885    MY_I_S_UNSIGNED, "Lost_connections", SKIP_OPEN_TABLE},
8886   {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8887    MY_I_S_UNSIGNED, "Access_denied", SKIP_OPEN_TABLE},
8888   {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8889    MY_I_S_UNSIGNED, "Empty_queries", SKIP_OPEN_TABLE},
8890   {"TOTAL_SSL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8891    0, MY_I_S_UNSIGNED, "Total_ssl_connections", SKIP_OPEN_TABLE},
8892   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
8893 };
8894 
8895 static ST_FIELD_INFO table_stats_fields_info[]=
8896 {
8897   {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema",
8898    SKIP_OPEN_TABLE},
8899   {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name",
8900    SKIP_OPEN_TABLE},
8901   {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8902    MY_I_S_UNSIGNED, "Rows_read", SKIP_OPEN_TABLE},
8903   {"ROWS_CHANGED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8904    MY_I_S_UNSIGNED, "Rows_changed", SKIP_OPEN_TABLE},
8905   {"ROWS_CHANGED_X_INDEXES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8906    0, MY_I_S_UNSIGNED, "Rows_changed_x_#indexes", SKIP_OPEN_TABLE},
8907   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
8908 };
8909 
8910 static ST_FIELD_INFO index_stats_fields_info[]=
8911 {
8912   {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema",
8913    SKIP_OPEN_TABLE},
8914   {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name",
8915    SKIP_OPEN_TABLE},
8916   {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Index_name",
8917    SKIP_OPEN_TABLE},
8918   {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8919    MY_I_S_UNSIGNED, "Rows_read", SKIP_OPEN_TABLE},
8920   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
8921 };
8922 
8923 
8924 ST_FIELD_INFO processlist_fields_info[]=
8925 {
8926   {"ID", 21, MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, "Id", SKIP_OPEN_TABLE},
8927   {"USER", 16, MYSQL_TYPE_STRING, 0, 0, "User", SKIP_OPEN_TABLE},
8928   {"HOST", LIST_PROCESS_HOST_LEN,  MYSQL_TYPE_STRING, 0, 0, "Host",
8929    SKIP_OPEN_TABLE},
8930   {"DB", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Db", SKIP_OPEN_TABLE},
8931   {"COMMAND", 16, MYSQL_TYPE_STRING, 0, 0, "Command", SKIP_OPEN_TABLE},
8932   {"TIME", 7, MYSQL_TYPE_LONG, 0, 0, "Time", SKIP_OPEN_TABLE},
8933   {"STATE", 64, MYSQL_TYPE_STRING, 0, 1, "State", SKIP_OPEN_TABLE},
8934   {"INFO", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_STRING, 0, 1, "Info",
8935    SKIP_OPEN_TABLE},
8936   {"TIME_MS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
8937    0, 0, "Time_ms", SKIP_OPEN_TABLE},
8938   {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8939    MY_I_S_UNSIGNED, "Rows_sent", SKIP_OPEN_TABLE},
8940   {"ROWS_EXAMINED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
8941    MY_I_S_UNSIGNED, "Rows_examined", SKIP_OPEN_TABLE},
8942   {"TID", 21, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED),
8943    "Tid", SKIP_OPEN_TABLE},
8944   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8945 };
8946 
8947 
8948 ST_FIELD_INFO plugin_fields_info[]=
8949 {
8950   {"PLUGIN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
8951    SKIP_OPEN_TABLE},
8952   {"PLUGIN_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8953   {"PLUGIN_STATUS", 10, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
8954   {"PLUGIN_TYPE", 80, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
8955   {"PLUGIN_TYPE_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8956   {"PLUGIN_LIBRARY", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Library",
8957    SKIP_OPEN_TABLE},
8958   {"PLUGIN_LIBRARY_VERSION", 20, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8959   {"PLUGIN_AUTHOR", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8960   {"PLUGIN_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8961   {"PLUGIN_LICENSE", 80, MYSQL_TYPE_STRING, 0, 1, "License", SKIP_OPEN_TABLE},
8962   {"LOAD_OPTION", 64, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8963   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
8964 };
8965 
8966 ST_FIELD_INFO files_fields_info[]=
8967 {
8968   {"FILE_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
8969   {"FILE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8970   {"FILE_TYPE", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8971   {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8972    SKIP_OPEN_TABLE},
8973   {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8974   {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8975   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8976   {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
8977    SKIP_OPEN_TABLE},
8978   {"LOGFILE_GROUP_NUMBER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
8979   {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
8980   {"FULLTEXT_KEYS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
8981   {"DELETED_ROWS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
8982   {"UPDATE_COUNT", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
8983   {"FREE_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
8984   {"TOTAL_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
8985   {"EXTENT_SIZE", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
8986   {"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
8987    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
8988   {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
8989    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
8990   {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
8991    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
8992   {"CREATION_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
8993   {"LAST_UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
8994   {"LAST_ACCESS_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
8995   {"RECOVER_TIME", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
8996   {"TRANSACTION_COUNTER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
8997   {"VERSION", 21 , MYSQL_TYPE_LONGLONG, 0,
8998    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version", SKIP_OPEN_TABLE},
8999   {"ROW_FORMAT", 20, MYSQL_TYPE_STRING, 0, 1, "Row_format", SKIP_OPEN_TABLE},
9000   {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0,
9001    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", SKIP_OPEN_TABLE},
9002   {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
9003    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", SKIP_OPEN_TABLE},
9004   {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
9005    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", SKIP_OPEN_TABLE},
9006   {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
9007    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", SKIP_OPEN_TABLE},
9008   {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
9009    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", SKIP_OPEN_TABLE},
9010   {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0,
9011    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", SKIP_OPEN_TABLE},
9012   {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", SKIP_OPEN_TABLE},
9013   {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", SKIP_OPEN_TABLE},
9014   {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", SKIP_OPEN_TABLE},
9015   {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
9016    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", SKIP_OPEN_TABLE},
9017   {"STATUS", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
9018   {"EXTRA", 255, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
9019   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
9020 };
9021 
init_fill_schema_files_row(TABLE * table)9022 void init_fill_schema_files_row(TABLE* table)
9023 {
9024   int i;
9025   for(i=0; files_fields_info[i].field_name!=NULL; i++)
9026     table->field[i]->set_null();
9027 
9028   table->field[IS_FILES_STATUS]->set_notnull();
9029   table->field[IS_FILES_STATUS]->store("NORMAL", 6, system_charset_info);
9030 }
9031 
9032 ST_FIELD_INFO referential_constraints_fields_info[]=
9033 {
9034   {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9035   {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
9036    OPEN_FULL_TABLE},
9037   {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
9038    OPEN_FULL_TABLE},
9039   {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
9040    OPEN_FULL_TABLE},
9041   {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
9042    OPEN_FULL_TABLE},
9043   {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0,
9044    MY_I_S_MAYBE_NULL, 0, OPEN_FULL_TABLE},
9045   {"MATCH_OPTION", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9046   {"UPDATE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9047   {"DELETE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9048   {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9049   {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
9050    OPEN_FULL_TABLE},
9051   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
9052 };
9053 
9054 
9055 ST_FIELD_INFO parameters_fields_info[]=
9056 {
9057   {"SPECIFIC_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9058   {"SPECIFIC_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
9059    OPEN_FULL_TABLE},
9060   {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9061   {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0, OPEN_FULL_TABLE},
9062   {"PARAMETER_MODE", 5, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
9063   {"PARAMETER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
9064   {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9065   {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
9066   {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
9067   {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
9068    0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
9069   {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
9070   {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
9071    0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
9072   {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
9073   {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
9074   {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9075   {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
9076   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}
9077 };
9078 
9079 
9080 ST_FIELD_INFO tablespaces_fields_info[]=
9081 {
9082   {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
9083    SKIP_OPEN_TABLE},
9084   {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
9085   {"TABLESPACE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL,
9086    0, SKIP_OPEN_TABLE},
9087   {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL,
9088    0, SKIP_OPEN_TABLE},
9089   {"EXTENT_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
9090    MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
9091   {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
9092    MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
9093   {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
9094    MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
9095   {"NODEGROUP_ID", 21, MYSQL_TYPE_LONGLONG, 0,
9096    MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
9097   {"TABLESPACE_COMMENT", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0,
9098    SKIP_OPEN_TABLE},
9099   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
9100 };
9101 
9102 
9103 /** For creating fields of information_schema.OPTIMIZER_TRACE */
9104 extern ST_FIELD_INFO optimizer_trace_info[];
9105 
9106 /*
9107   Description of ST_FIELD_INFO in table.h
9108 
9109   Make sure that the order of schema_tables and enum_schema_tables are the same.
9110 
9111 */
9112 
9113 ST_SCHEMA_TABLE schema_tables[]=
9114 {
9115   {"CHARACTER_SETS", charsets_fields_info, create_schema_table,
9116    fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0},
9117   {"CLIENT_STATISTICS", client_stats_fields_info, create_schema_table,
9118     fill_schema_client_stats, make_old_format, 0, -1, -1, 0, 0},
9119   {"COLLATIONS", collation_fields_info, create_schema_table,
9120    fill_schema_collation, make_old_format, 0, -1, -1, 0, 0},
9121   {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
9122    create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0, 0},
9123   {"COLUMNS", columns_fields_info, create_schema_table,
9124    get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0,
9125    OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
9126   {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
9127    fill_schema_column_privileges, 0, 0, -1, -1, 0, 0},
9128   {"INDEX_STATISTICS", index_stats_fields_info, create_schema_table,
9129    fill_schema_index_stats, make_old_format, 0, -1, -1, 0, 0},
9130   {"ENGINES", engines_fields_info, create_schema_table,
9131    fill_schema_engines, make_old_format, 0, -1, -1, 0, 0},
9132 #ifdef HAVE_EVENT_SCHEDULER
9133   {"EVENTS", events_fields_info, create_schema_table,
9134    Events::fill_schema_events, make_old_format, 0, -1, -1, 0, 0},
9135 #else // for alignment with enum_schema_tables
9136   {"EVENTS", events_fields_info, create_schema_table,
9137    0, make_old_format, 0, -1, -1, 0, 0},
9138 #endif
9139   {"FILES", files_fields_info, create_schema_table,
9140    hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
9141   {"GLOBAL_STATUS", variables_fields_info, create_schema_table,
9142    fill_status, make_old_format, 0, 0, -1, 0, 0},
9143   {"GLOBAL_TEMPORARY_TABLES", temporary_table_fields_info, create_schema_table,
9144    fill_global_temporary_tables, make_temporary_tables_old_format, 0, 2, 3, 0,
9145    OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
9146   {"GLOBAL_VARIABLES", variables_fields_info, create_schema_table,
9147    fill_variables, make_old_format, 0, 0, -1, 0, 0},
9148   {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
9149    get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0,
9150    OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
9151   {"OPEN_TABLES", open_tables_fields_info, create_schema_table,
9152    fill_open_tables, make_old_format, 0, -1, -1, 1, 0},
9153 #ifdef OPTIMIZER_TRACE
9154   {"OPTIMIZER_TRACE", optimizer_trace_info, create_schema_table,
9155    fill_optimizer_trace_info, NULL, NULL, -1, -1, false, 0},
9156 #else // for alignment with enum_schema_tables
9157   {"OPTIMIZER_TRACE", optimizer_trace_info, create_schema_table,
9158    NULL, NULL, NULL, -1, -1, false, 0},
9159 #endif
9160   {"PARAMETERS", parameters_fields_info, create_schema_table,
9161    fill_schema_proc, 0, 0, -1, -1, 0, 0},
9162   {"PARTITIONS", partitions_fields_info, create_schema_table,
9163    get_all_tables, 0, get_schema_partitions_record, 1, 2, 0,
9164    OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
9165   {"PLUGINS", plugin_fields_info, create_schema_table,
9166    fill_plugins, make_old_format, 0, -1, -1, 0, 0},
9167   {"PROCESSLIST", processlist_fields_info, create_schema_table,
9168    fill_schema_processlist, make_old_format, 0, -1, -1, 0, 0},
9169   {"PROFILING", query_profile_statistics_info, create_schema_table,
9170     fill_query_profile_statistics_info, make_profile_table_for_show,
9171     NULL, -1, -1, false, 0},
9172   {"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info,
9173    create_schema_table, get_all_tables, 0, get_referential_constraints_record,
9174    1, 9, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
9175   {"ROUTINES", proc_fields_info, create_schema_table,
9176    fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0},
9177   {"SCHEMATA", schema_fields_info, create_schema_table,
9178    fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0},
9179   {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table,
9180    fill_schema_schema_privileges, 0, 0, -1, -1, 0, 0},
9181   {"SESSION_STATUS", variables_fields_info, create_schema_table,
9182    fill_status, make_old_format, 0, 0, -1, 0, 0},
9183   {"SESSION_VARIABLES", variables_fields_info, create_schema_table,
9184    fill_variables, make_old_format, 0, 0, -1, 0, 0},
9185   {"STATISTICS", stat_fields_info, create_schema_table,
9186    get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0,
9187    OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
9188   {"STATUS", variables_fields_info, create_schema_table, fill_status,
9189    make_old_format, 0, 0, -1, 1, 0},
9190   {"TABLES", tables_fields_info, create_schema_table,
9191    get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0,
9192    OPTIMIZE_I_S_TABLE},
9193   {"TABLESPACES", tablespaces_fields_info, create_schema_table,
9194    hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
9195   {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table,
9196    get_all_tables, 0, get_schema_constraints_record, 3, 4, 0,
9197    OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
9198   {"TABLE_NAMES", table_names_fields_info, create_schema_table,
9199    get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0},
9200   {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
9201    fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
9202   {"TABLE_STATISTICS", table_stats_fields_info, create_schema_table,
9203     fill_schema_table_stats, make_old_format, 0, -1, -1, 0, 0},
9204   {"TEMPORARY_TABLES", temporary_table_fields_info, create_schema_table,
9205    fill_temporary_tables, make_temporary_tables_old_format, 0, 2, 3, 0,
9206    OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
9207   {"THREAD_STATISTICS", thread_stats_fields_info, create_schema_table,
9208     fill_schema_thread_stats, make_old_format, 0, -1, -1, 0, 0},
9209   {"TRIGGERS", triggers_fields_info, create_schema_table,
9210    get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
9211    OPEN_TRIGGER_ONLY|OPTIMIZE_I_S_TABLE},
9212   {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table,
9213    fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
9214   {"USER_STATISTICS", user_stats_fields_info, create_schema_table,
9215     fill_schema_user_stats, make_old_format, 0, -1, -1, 0, 0},
9216   {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
9217    make_old_format, 0, 0, -1, 1, 0},
9218   {"VIEWS", view_fields_info, create_schema_table,
9219    get_all_tables, 0, get_schema_views_record, 1, 2, 0,
9220    OPEN_VIEW_ONLY|OPTIMIZE_I_S_TABLE},
9221   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
9222 };
9223 
9224 
initialize_schema_table(st_plugin_int * plugin)9225 int initialize_schema_table(st_plugin_int *plugin)
9226 {
9227   ST_SCHEMA_TABLE *schema_table;
9228   DBUG_ENTER("initialize_schema_table");
9229 
9230   if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(sizeof(ST_SCHEMA_TABLE),
9231                                 MYF(MY_WME | MY_ZEROFILL))))
9232       DBUG_RETURN(1);
9233   /* Historical Requirement */
9234   plugin->data= schema_table; // shortcut for the future
9235   if (plugin->plugin->init)
9236   {
9237     schema_table->create_table= create_schema_table;
9238     schema_table->old_format= make_old_format;
9239     schema_table->idx_field1= -1,
9240     schema_table->idx_field2= -1;
9241 
9242     /* Make the name available to the init() function. */
9243     schema_table->table_name= plugin->name.str;
9244 
9245     if (plugin->plugin->init(schema_table))
9246     {
9247       sql_print_error("Plugin '%s' init function returned error.",
9248                       plugin->name.str);
9249       plugin->data= NULL;
9250       my_free(schema_table);
9251       DBUG_RETURN(1);
9252     }
9253 
9254     /* Make sure the plugin name is not set inside the init() function. */
9255     schema_table->table_name= plugin->name.str;
9256   }
9257   DBUG_RETURN(0);
9258 }
9259 
finalize_schema_table(st_plugin_int * plugin)9260 int finalize_schema_table(st_plugin_int *plugin)
9261 {
9262   ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
9263   DBUG_ENTER("finalize_schema_table");
9264 
9265   if (schema_table)
9266   {
9267     if (plugin->plugin->deinit)
9268     {
9269       DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
9270       if (plugin->plugin->deinit(NULL))
9271       {
9272         DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
9273                                plugin->name.str));
9274       }
9275     }
9276     my_free(schema_table);
9277   }
9278   DBUG_RETURN(0);
9279 }
9280 
9281 
9282 /**
9283   Output trigger information (SHOW CREATE TRIGGER) to the client.
9284 
9285   @param thd          Thread context.
9286   @param triggers     List of triggers for the table.
9287   @param trigger_idx  Index of the trigger to dump.
9288 
9289   @return Operation status
9290     @retval TRUE Error.
9291     @retval FALSE Success.
9292 */
9293 
show_create_trigger_impl(THD * thd,Table_triggers_list * triggers,int trigger_idx)9294 static bool show_create_trigger_impl(THD *thd,
9295                                      Table_triggers_list *triggers,
9296                                      int trigger_idx)
9297 {
9298   int ret_code;
9299 
9300   Protocol *p= thd->protocol;
9301   List<Item> fields;
9302 
9303   LEX_STRING trg_name;
9304   sql_mode_t trg_sql_mode;
9305   LEX_STRING trg_sql_mode_str;
9306   LEX_STRING trg_sql_original_stmt;
9307   LEX_STRING trg_client_cs_name;
9308   LEX_STRING trg_connection_cl_name;
9309   LEX_STRING trg_db_cl_name;
9310 
9311   const CHARSET_INFO *trg_client_cs;
9312 
9313   /*
9314     TODO: Check privileges here. This functionality will be added by
9315     implementation of the following WL items:
9316       - WL#2227: New privileges for new objects
9317       - WL#3482: Protect SHOW CREATE PROCEDURE | FUNCTION | VIEW | TRIGGER
9318         properly
9319 
9320     SHOW TRIGGERS and I_S.TRIGGERS will be affected too.
9321   */
9322 
9323   /* Prepare trigger "object". */
9324 
9325   triggers->get_trigger_info(thd,
9326                              trigger_idx,
9327                              &trg_name,
9328                              &trg_sql_mode,
9329                              &trg_sql_original_stmt,
9330                              &trg_client_cs_name,
9331                              &trg_connection_cl_name,
9332                              &trg_db_cl_name);
9333 
9334   sql_mode_string_representation(thd, trg_sql_mode, &trg_sql_mode_str);
9335 
9336   /* Resolve trigger client character set. */
9337 
9338   if (resolve_charset(trg_client_cs_name.str, NULL, &trg_client_cs))
9339     return TRUE;
9340 
9341   /* Send header. */
9342 
9343   fields.push_back(new Item_empty_string("Trigger", NAME_LEN));
9344   fields.push_back(new Item_empty_string("sql_mode", trg_sql_mode_str.length));
9345 
9346   {
9347     /*
9348       NOTE: SQL statement field must be not less than 1024 in order not to
9349       confuse old clients.
9350     */
9351 
9352     Item_empty_string *stmt_fld=
9353       new Item_empty_string("SQL Original Statement",
9354                             max<size_t>(trg_sql_original_stmt.length, 1024));
9355 
9356     stmt_fld->maybe_null= TRUE;
9357 
9358     fields.push_back(stmt_fld);
9359   }
9360 
9361   fields.push_back(new Item_empty_string("character_set_client",
9362                                          MY_CS_NAME_SIZE));
9363 
9364   fields.push_back(new Item_empty_string("collation_connection",
9365                                          MY_CS_NAME_SIZE));
9366 
9367   fields.push_back(new Item_empty_string("Database Collation",
9368                                          MY_CS_NAME_SIZE));
9369 
9370   if (p->send_result_set_metadata(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
9371     return TRUE;
9372 
9373   /* Send data. */
9374 
9375   p->prepare_for_resend();
9376 
9377   p->store(trg_name.str,
9378            trg_name.length,
9379            system_charset_info);
9380 
9381   p->store(trg_sql_mode_str.str,
9382            trg_sql_mode_str.length,
9383            system_charset_info);
9384 
9385   p->store(trg_sql_original_stmt.str,
9386            trg_sql_original_stmt.length,
9387            trg_client_cs);
9388 
9389   p->store(trg_client_cs_name.str,
9390            trg_client_cs_name.length,
9391            system_charset_info);
9392 
9393   p->store(trg_connection_cl_name.str,
9394            trg_connection_cl_name.length,
9395            system_charset_info);
9396 
9397   p->store(trg_db_cl_name.str,
9398            trg_db_cl_name.length,
9399            system_charset_info);
9400 
9401   ret_code= p->write();
9402 
9403   if (!ret_code)
9404     my_eof(thd);
9405 
9406   return ret_code != 0;
9407 }
9408 
9409 
9410 /**
9411   Read TRN and TRG files to obtain base table name for the specified
9412   trigger name and construct TABE_LIST object for the base table.
9413 
9414   @param thd      Thread context.
9415   @param trg_name Trigger name.
9416 
9417   @return TABLE_LIST object corresponding to the base table.
9418 
9419   TODO: This function is a copy&paste from add_table_to_list() and
9420   sp_add_to_query_tables(). The problem is that in order to be compatible
9421   with Stored Programs (Prepared Statements), we should not touch thd->lex.
9422   The "source" functions also add created TABLE_LIST object to the
9423   thd->lex->query_tables.
9424 
9425   The plan to eliminate this copy&paste is to:
9426 
9427     - get rid of sp_add_to_query_tables() and use Lex::add_table_to_list().
9428       Only add_table_to_list() must be used to add tables from the parser
9429       into Lex::query_tables list.
9430 
9431     - do not update Lex::query_tables in add_table_to_list().
9432 */
9433 
9434 static
get_trigger_table(THD * thd,const sp_name * trg_name)9435 TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
9436 {
9437   char trn_path_buff[FN_REFLEN];
9438   LEX_STRING trn_path= { trn_path_buff, 0 };
9439   LEX_STRING db;
9440   LEX_STRING tbl_name;
9441   TABLE_LIST *table;
9442 
9443   build_trn_path(thd, trg_name, &trn_path);
9444 
9445   if (check_trn_exists(&trn_path))
9446   {
9447     my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
9448     return NULL;
9449   }
9450 
9451   if (load_table_name_for_trigger(thd, trg_name, &trn_path, &tbl_name))
9452     return NULL;
9453 
9454   /* We need to reset statement table list to be PS/SP friendly. */
9455   if (!(table= (TABLE_LIST*) thd->alloc(sizeof(TABLE_LIST))))
9456     return NULL;
9457 
9458   db= trg_name->m_db;
9459 
9460   db.str= thd->strmake(db.str, db.length);
9461   tbl_name.str= thd->strmake(tbl_name.str, tbl_name.length);
9462 
9463   if (db.str == NULL || tbl_name.str == NULL)
9464     return NULL;
9465 
9466   table->init_one_table(db.str, db.length, tbl_name.str, tbl_name.length,
9467                         tbl_name.str, TL_IGNORE);
9468 
9469   return table;
9470 }
9471 
9472 
9473 /**
9474   SHOW CREATE TRIGGER high-level implementation.
9475 
9476   @param thd      Thread context.
9477   @param trg_name Trigger name.
9478 
9479   @return Operation status
9480     @retval TRUE Error.
9481     @retval FALSE Success.
9482 */
9483 
show_create_trigger(THD * thd,const sp_name * trg_name)9484 bool show_create_trigger(THD *thd, const sp_name *trg_name)
9485 {
9486   TABLE_LIST *lst= get_trigger_table(thd, trg_name);
9487   uint num_tables; /* NOTE: unused, only to pass to open_tables(). */
9488   Table_triggers_list *triggers;
9489   int trigger_idx;
9490   bool error= TRUE;
9491 
9492   if (!lst)
9493     return TRUE;
9494 
9495   if (check_table_access(thd, TRIGGER_ACL, lst, FALSE, 1, TRUE))
9496   {
9497     my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "TRIGGER");
9498     return TRUE;
9499   }
9500 
9501   /*
9502     Metadata locks taken during SHOW CREATE TRIGGER should be released when
9503     the statement completes as it is an information statement.
9504   */
9505   MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
9506 
9507   /*
9508     Open the table by name in order to load Table_triggers_list object.
9509   */
9510   if (open_tables(thd, &lst, &num_tables,
9511                   MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
9512   {
9513     my_error(ER_TRG_CANT_OPEN_TABLE, MYF(0),
9514              (const char *) trg_name->m_db.str,
9515              (const char *) lst->table_name);
9516 
9517     goto exit;
9518 
9519     /* Perform closing actions and return error status. */
9520   }
9521 
9522   triggers= lst->table->triggers;
9523 
9524   if (!triggers)
9525   {
9526     my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
9527     goto exit;
9528   }
9529 
9530   trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name);
9531 
9532   if (trigger_idx < 0)
9533   {
9534     my_error(ER_TRG_CORRUPTED_FILE, MYF(0),
9535              (const char *) trg_name->m_db.str,
9536              (const char *) lst->table_name);
9537 
9538     goto exit;
9539   }
9540 
9541   error= show_create_trigger_impl(thd, triggers, trigger_idx);
9542 
9543   /*
9544     NOTE: if show_create_trigger_impl() failed, that means we could not
9545     send data to the client. In this case we simply raise the error
9546     status and client connection will be closed.
9547   */
9548 
9549 exit:
9550   close_thread_tables(thd);
9551   /* Release any metadata locks taken during SHOW CREATE TRIGGER. */
9552   thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
9553   return error;
9554 }
9555 
9556 class IS_internal_schema_access : public ACL_internal_schema_access
9557 {
9558 public:
IS_internal_schema_access()9559   IS_internal_schema_access()
9560   {}
9561 
~IS_internal_schema_access()9562   ~IS_internal_schema_access()
9563   {}
9564 
9565   ACL_internal_access_result check(ulong want_access,
9566                                    ulong *save_priv) const;
9567 
9568   const ACL_internal_table_access *lookup(const char *name) const;
9569 };
9570 
9571 ACL_internal_access_result
check(ulong want_access,ulong * save_priv) const9572 IS_internal_schema_access::check(ulong want_access,
9573                                  ulong *save_priv) const
9574 {
9575   want_access &= ~SELECT_ACL;
9576 
9577   /*
9578     We don't allow any simple privileges but SELECT_ACL on
9579     the information_schema database.
9580   */
9581   if (unlikely(want_access & DB_ACLS))
9582     return ACL_INTERNAL_ACCESS_DENIED;
9583 
9584   /* Always grant SELECT for the information schema. */
9585   *save_priv|= SELECT_ACL;
9586 
9587   return want_access ? ACL_INTERNAL_ACCESS_CHECK_GRANT :
9588                        ACL_INTERNAL_ACCESS_GRANTED;
9589 }
9590 
9591 const ACL_internal_table_access *
lookup(const char * name) const9592 IS_internal_schema_access::lookup(const char *name) const
9593 {
9594   /* There are no per table rules for the information schema. */
9595   return NULL;
9596 }
9597 
9598 static IS_internal_schema_access is_internal_schema_access;
9599 
initialize_information_schema_acl()9600 void initialize_information_schema_acl()
9601 {
9602   ACL_internal_schema_registry::register_schema(&INFORMATION_SCHEMA_NAME,
9603                                                 &is_internal_schema_access);
9604 }
9605 
9606 #ifdef WITH_PARTITION_STORAGE_ENGINE
9607 /*
9608   Convert a string in character set in column character set format
9609   to utf8 character set if possible, the utf8 character set string
9610   will later possibly be converted to character set used by client.
9611   Thus we attempt conversion from column character set to both
9612   utf8 and to character set client.
9613 
9614   Examples of strings that should fail conversion to utf8 are unassigned
9615   characters as e.g. 0x81 in cp1250 (Windows character set for for countries
9616   like Czech and Poland). Example of string that should fail conversion to
9617   character set on client (e.g. if this is latin1) is 0x2020 (daggger) in
9618   ucs2.
9619 
9620   If the conversion fails we will as a fall back convert the string to
9621   hex encoded format. The caller of the function can also ask for hex
9622   encoded format of output string unconditionally.
9623 
9624   SYNOPSIS
9625     get_cs_converted_string_value()
9626     thd                             Thread object
9627     input_str                       Input string in cs character set
9628     output_str                      Output string to be produced in utf8
9629     cs                              Character set of input string
9630     use_hex                         Use hex string unconditionally
9631 
9632 
9633   RETURN VALUES
9634     No return value
9635 */
9636 
get_cs_converted_string_value(THD * thd,String * input_str,String * output_str,const CHARSET_INFO * cs,bool use_hex)9637 static void get_cs_converted_string_value(THD *thd,
9638                                           String *input_str,
9639                                           String *output_str,
9640                                           const CHARSET_INFO *cs,
9641                                           bool use_hex)
9642 {
9643 
9644   output_str->length(0);
9645   if (input_str->length() == 0)
9646   {
9647     output_str->append("''");
9648     return;
9649   }
9650   if (!use_hex)
9651   {
9652     String try_val;
9653     uint try_conv_error= 0;
9654 
9655     try_val.copy(input_str->ptr(), input_str->length(), cs,
9656                  thd->variables.character_set_client, &try_conv_error);
9657     if (!try_conv_error)
9658     {
9659       String val;
9660       uint conv_error= 0;
9661 
9662       val.copy(input_str->ptr(), input_str->length(), cs,
9663                system_charset_info, &conv_error);
9664       if (!conv_error)
9665       {
9666         append_unescaped(output_str, val.ptr(), val.length());
9667         return;
9668       }
9669     }
9670     /* We had a conversion error, use hex encoded string for safety */
9671   }
9672   {
9673     const uchar *ptr;
9674     uint i, len;
9675     char buf[3];
9676 
9677     output_str->append("_");
9678     output_str->append(cs->csname);
9679     output_str->append(" ");
9680     output_str->append("0x");
9681     len= input_str->length();
9682     ptr= (uchar*)input_str->ptr();
9683     for (i= 0; i < len; i++)
9684     {
9685       uint high, low;
9686 
9687       high= (*ptr) >> 4;
9688       low= (*ptr) & 0x0F;
9689       buf[0]= _dig_vec_upper[high];
9690       buf[1]= _dig_vec_upper[low];
9691       buf[2]= 0;
9692       output_str->append((const char*)buf);
9693       ptr++;
9694     }
9695   }
9696   return;
9697 }
9698 #endif
9699