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