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