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.