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