The world's most popular open source database
00001 /* Copyright (C) 2000-2004 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 00018 /* Function with list databases, tables or fields */ 00019 00020 #include "mysql_priv.h" 00021 #include "sql_select.h" // For select_describe 00022 #include "sql_show.h" 00023 #include "repl_failsafe.h" 00024 #include "sp.h" 00025 #include "sp_head.h" 00026 #include "sql_trigger.h" 00027 #include "authors.h" 00028 #include "contributors.h" 00029 #include "events.h" 00030 #include "event_timed.h" 00031 #include <my_dir.h> 00032 00033 #ifdef WITH_PARTITION_STORAGE_ENGINE 00034 #include "ha_partition.h" 00035 #endif 00036 00037 enum enum_i_s_events_fields 00038 { 00039 ISE_EVENT_CATALOG= 0, 00040 ISE_EVENT_SCHEMA, 00041 ISE_EVENT_NAME, 00042 ISE_DEFINER, 00043 ISE_EVENT_BODY, 00044 ISE_EVENT_DEFINITION, 00045 ISE_EVENT_TYPE, 00046 ISE_EXECUTE_AT, 00047 ISE_INTERVAL_VALUE, 00048 ISE_INTERVAL_FIELD, 00049 ISE_SQL_MODE, 00050 ISE_STARTS, 00051 ISE_ENDS, 00052 ISE_STATUS, 00053 ISE_ON_COMPLETION, 00054 ISE_CREATED, 00055 ISE_LAST_ALTERED, 00056 ISE_LAST_EXECUTED, 00057 ISE_EVENT_COMMENT 00058 }; 00059 00060 00061 static const char *grant_names[]={ 00062 "select","insert","update","delete","create","drop","reload","shutdown", 00063 "process","file","grant","references","index","alter"}; 00064 00065 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00066 static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **), 00067 "grant_types", 00068 grant_names, NULL}; 00069 #endif 00070 00071 static void store_key_options(THD *thd, String *packet, TABLE *table, 00072 KEY *key_info); 00073 00074 static void 00075 append_algorithm(TABLE_LIST *table, String *buff); 00076 00077 00078 /*************************************************************************** 00079 ** List all table types supported 00080 ***************************************************************************/ 00081 00082 static my_bool show_handlerton(THD *thd, st_plugin_int *plugin, 00083 void *arg) 00084 { 00085 handlerton *default_type= (handlerton *) arg; 00086 Protocol *protocol= thd->protocol; 00087 handlerton *hton= (handlerton *)plugin->data; 00088 00089 if (!(hton->flags & HTON_HIDDEN)) 00090 { 00091 protocol->prepare_for_resend(); 00092 protocol->store(plugin->name.str, plugin->name.length, 00093 system_charset_info); 00094 const char *option_name= show_comp_option_name[(int) hton->state]; 00095 00096 if (hton->state == SHOW_OPTION_YES && default_type == hton) 00097 option_name= "DEFAULT"; 00098 protocol->store(option_name, system_charset_info); 00099 protocol->store(plugin->plugin->descr, system_charset_info); 00100 protocol->store(hton->commit ? "YES" : "NO", system_charset_info); 00101 protocol->store(hton->prepare ? "YES" : "NO", system_charset_info); 00102 protocol->store(hton->savepoint_set ? "YES" : "NO", system_charset_info); 00103 00104 return protocol->write() ? 1 : 0; 00105 } 00106 return 0; 00107 } 00108 00109 bool mysqld_show_storage_engines(THD *thd) 00110 { 00111 List<Item> field_list; 00112 Protocol *protocol= thd->protocol; 00113 DBUG_ENTER("mysqld_show_storage_engines"); 00114 00115 field_list.push_back(new Item_empty_string("Engine",10)); 00116 field_list.push_back(new Item_empty_string("Support",10)); 00117 field_list.push_back(new Item_empty_string("Comment",80)); 00118 field_list.push_back(new Item_empty_string("Transactions",3)); 00119 field_list.push_back(new Item_empty_string("XA",3)); 00120 field_list.push_back(new Item_empty_string("Savepoints",3)); 00121 00122 if (protocol->send_fields(&field_list, 00123 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 00124 DBUG_RETURN(TRUE); 00125 00126 if (plugin_foreach(thd, show_handlerton, 00127 MYSQL_STORAGE_ENGINE_PLUGIN, thd->variables.table_type)) 00128 DBUG_RETURN(TRUE); 00129 00130 send_eof(thd); 00131 DBUG_RETURN(FALSE); 00132 } 00133 00134 static int make_version_string(char *buf, int buf_length, uint version) 00135 { 00136 return my_snprintf(buf, buf_length, "%d.%d", version>>8,version&0xff); 00137 } 00138 00139 static my_bool show_plugins(THD *thd, st_plugin_int *plugin, 00140 void *arg) 00141 { 00142 TABLE *table= (TABLE*) arg; 00143 struct st_mysql_plugin *plug= plugin->plugin; 00144 Protocol *protocol= thd->protocol; 00145 CHARSET_INFO *cs= system_charset_info; 00146 char version_buf[20]; 00147 00148 restore_record(table, s->default_values); 00149 00150 table->field[0]->store(plugin->name.str, plugin->name.length, cs); 00151 00152 table->field[1]->store(version_buf, 00153 make_version_string(version_buf, sizeof(version_buf), plug->version), 00154 cs); 00155 00156 00157 switch (plugin->state) 00158 { 00159 /* case PLUGIN_IS_FREED: does not happen */ 00160 case PLUGIN_IS_DELETED: 00161 table->field[2]->store(STRING_WITH_LEN("DELETED"), cs); 00162 break; 00163 case PLUGIN_IS_UNINITIALIZED: 00164 table->field[2]->store(STRING_WITH_LEN("INACTIVE"), cs); 00165 break; 00166 case PLUGIN_IS_READY: 00167 table->field[2]->store(STRING_WITH_LEN("ACTIVE"), cs); 00168 break; 00169 default: 00170 DBUG_ASSERT(0); 00171 } 00172 00173 table->field[3]->store(plugin_type_names[plug->type].str, 00174 plugin_type_names[plug->type].length, 00175 cs); 00176 table->field[4]->store(version_buf, 00177 make_version_string(version_buf, sizeof(version_buf), 00178 *(uint *)plug->info), cs); 00179 00180 if (plugin->plugin_dl) 00181 { 00182 table->field[5]->store(plugin->plugin_dl->dl.str, 00183 plugin->plugin_dl->dl.length, cs); 00184 table->field[5]->set_notnull(); 00185 table->field[6]->store(version_buf, 00186 make_version_string(version_buf, sizeof(version_buf), 00187 plugin->plugin_dl->version), 00188 cs); 00189 table->field[6]->set_notnull(); 00190 } 00191 else 00192 { 00193 table->field[5]->set_null(); 00194 table->field[6]->set_null(); 00195 } 00196 00197 00198 if (plug->author) 00199 { 00200 table->field[7]->store(plug->author, strlen(plug->author), cs); 00201 table->field[7]->set_notnull(); 00202 } 00203 else 00204 table->field[7]->set_null(); 00205 00206 if (plug->descr) 00207 { 00208 table->field[8]->store(plug->descr, strlen(plug->descr), cs); 00209 table->field[8]->set_notnull(); 00210 } 00211 else 00212 table->field[8]->set_null(); 00213 00214 return schema_table_store_record(thd, table); 00215 } 00216 00217 00218 int fill_plugins(THD *thd, TABLE_LIST *tables, COND *cond) 00219 { 00220 DBUG_ENTER("fill_plugins"); 00221 TABLE *table= tables->table; 00222 00223 if (plugin_foreach(thd, show_plugins, MYSQL_ANY_PLUGIN, table)) 00224 DBUG_RETURN(1); 00225 00226 DBUG_RETURN(0); 00227 } 00228 00229 00230 /*************************************************************************** 00231 ** List all Authors. 00232 ** If you can update it, you get to be in it :) 00233 ***************************************************************************/ 00234 00235 bool mysqld_show_authors(THD *thd) 00236 { 00237 List<Item> field_list; 00238 Protocol *protocol= thd->protocol; 00239 DBUG_ENTER("mysqld_show_authors"); 00240 00241 field_list.push_back(new Item_empty_string("Name",40)); 00242 field_list.push_back(new Item_empty_string("Location",40)); 00243 field_list.push_back(new Item_empty_string("Comment",80)); 00244 00245 if (protocol->send_fields(&field_list, 00246 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 00247 DBUG_RETURN(TRUE); 00248 00249 show_table_authors_st *authors; 00250 for (authors= show_table_authors; authors->name; authors++) 00251 { 00252 protocol->prepare_for_resend(); 00253 protocol->store(authors->name, system_charset_info); 00254 protocol->store(authors->location, system_charset_info); 00255 protocol->store(authors->comment, system_charset_info); 00256 if (protocol->write()) 00257 DBUG_RETURN(TRUE); 00258 } 00259 send_eof(thd); 00260 DBUG_RETURN(FALSE); 00261 } 00262 00263 00264 /*************************************************************************** 00265 ** List all Contributors. 00266 ** Please get permission before updating 00267 ***************************************************************************/ 00268 00269 bool mysqld_show_contributors(THD *thd) 00270 { 00271 List<Item> field_list; 00272 Protocol *protocol= thd->protocol; 00273 DBUG_ENTER("mysqld_show_contributors"); 00274 00275 field_list.push_back(new Item_empty_string("Name",40)); 00276 field_list.push_back(new Item_empty_string("Location",40)); 00277 field_list.push_back(new Item_empty_string("Comment",80)); 00278 00279 if (protocol->send_fields(&field_list, 00280 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 00281 DBUG_RETURN(TRUE); 00282 00283 show_table_contributors_st *contributors; 00284 for (contributors= show_table_contributors; contributors->name; contributors++) 00285 { 00286 protocol->prepare_for_resend(); 00287 protocol->store(contributors->name, system_charset_info); 00288 protocol->store(contributors->location, system_charset_info); 00289 protocol->store(contributors->comment, system_charset_info); 00290 if (protocol->write()) 00291 DBUG_RETURN(TRUE); 00292 } 00293 send_eof(thd); 00294 DBUG_RETURN(FALSE); 00295 } 00296 00297 00298 /*************************************************************************** 00299 List all privileges supported 00300 ***************************************************************************/ 00301 00302 struct show_privileges_st { 00303 const char *privilege; 00304 const char *context; 00305 const char *comment; 00306 }; 00307 00308 static struct show_privileges_st sys_privileges[]= 00309 { 00310 {"Alter", "Tables", "To alter the table"}, 00311 {"Alter routine", "Functions,Procedures", "To alter or drop stored functions/procedures"}, 00312 {"Create", "Databases,Tables,Indexes", "To create new databases and tables"}, 00313 {"Create routine","Functions,Procedures","To use CREATE FUNCTION/PROCEDURE"}, 00314 {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"}, 00315 {"Create view", "Tables", "To create new views"}, 00316 {"Create user", "Server Admin", "To create new users"}, 00317 {"Delete", "Tables", "To delete existing rows"}, 00318 {"Drop", "Databases,Tables", "To drop databases, tables, and views"}, 00319 {"Event","Server Admin","To create, alter, drop and execute events"}, 00320 {"Execute", "Functions,Procedures", "To execute stored routines"}, 00321 {"File", "File access on server", "To read and write files on the server"}, 00322 {"Grant option", "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"}, 00323 {"Index", "Tables", "To create or drop indexes"}, 00324 {"Insert", "Tables", "To insert data into tables"}, 00325 {"Lock tables","Databases","To use LOCK TABLES (together with SELECT privilege)"}, 00326 {"Process", "Server Admin", "To view the plain text of currently executing queries"}, 00327 {"References", "Databases,Tables", "To have references on tables"}, 00328 {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"}, 00329 {"Replication client","Server Admin","To ask where the slave or master servers are"}, 00330 {"Replication slave","Server Admin","To read binary log events from the master"}, 00331 {"Select", "Tables", "To retrieve rows from table"}, 00332 {"Show databases","Server Admin","To see all databases with SHOW DATABASES"}, 00333 {"Show view","Tables","To see views with SHOW CREATE VIEW"}, 00334 {"Shutdown","Server Admin", "To shut down the server"}, 00335 {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."}, 00336 {"Trigger","Tables", "To use triggers"}, 00337 {"Update", "Tables", "To update existing rows"}, 00338 {"Usage","Server Admin","No privileges - allow connect only"}, 00339 {NullS, NullS, NullS} 00340 }; 00341 00342 bool mysqld_show_privileges(THD *thd) 00343 { 00344 List<Item> field_list; 00345 Protocol *protocol= thd->protocol; 00346 DBUG_ENTER("mysqld_show_privileges"); 00347 00348 field_list.push_back(new Item_empty_string("Privilege",10)); 00349 field_list.push_back(new Item_empty_string("Context",15)); 00350 field_list.push_back(new Item_empty_string("Comment",NAME_LEN)); 00351 00352 if (protocol->send_fields(&field_list, 00353 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 00354 DBUG_RETURN(TRUE); 00355 00356 show_privileges_st *privilege= sys_privileges; 00357 for (privilege= sys_privileges; privilege->privilege ; privilege++) 00358 { 00359 protocol->prepare_for_resend(); 00360 protocol->store(privilege->privilege, system_charset_info); 00361 protocol->store(privilege->context, system_charset_info); 00362 protocol->store(privilege->comment, system_charset_info); 00363 if (protocol->write()) 00364 DBUG_RETURN(TRUE); 00365 } 00366 send_eof(thd); 00367 DBUG_RETURN(FALSE); 00368 } 00369 00370 00371 /*************************************************************************** 00372 List all column types 00373 ***************************************************************************/ 00374 00375 struct show_column_type_st 00376 { 00377 const char *type; 00378 uint size; 00379 const char *min_value; 00380 const char *max_value; 00381 uint precision; 00382 uint scale; 00383 const char *nullable; 00384 const char *auto_increment; 00385 const char *unsigned_attr; 00386 const char *zerofill; 00387 const char *searchable; 00388 const char *case_sensitivity; 00389 const char *default_value; 00390 const char *comment; 00391 }; 00392 00393 /* TODO: Add remaning types */ 00394 00395 static struct show_column_type_st sys_column_types[]= 00396 { 00397 {"tinyint", 00398 1, "-128", "127", 0, 0, "YES", "YES", 00399 "NO", "YES", "YES", "NO", "NULL,0", 00400 "A very small integer"}, 00401 {"tinyint unsigned", 00402 1, "0" , "255", 0, 0, "YES", "YES", 00403 "YES", "YES", "YES", "NO", "NULL,0", 00404 "A very small integer"}, 00405 }; 00406 00407 bool mysqld_show_column_types(THD *thd) 00408 { 00409 List<Item> field_list; 00410 Protocol *protocol= thd->protocol; 00411 DBUG_ENTER("mysqld_show_column_types"); 00412 00413 field_list.push_back(new Item_empty_string("Type",30)); 00414 field_list.push_back(new Item_int("Size",(longlong) 1,21)); 00415 field_list.push_back(new Item_empty_string("Min_Value",20)); 00416 field_list.push_back(new Item_empty_string("Max_Value",20)); 00417 field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT)); 00418 field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT)); 00419 field_list.push_back(new Item_empty_string("Nullable",4)); 00420 field_list.push_back(new Item_empty_string("Auto_Increment",4)); 00421 field_list.push_back(new Item_empty_string("Unsigned",4)); 00422 field_list.push_back(new Item_empty_string("Zerofill",4)); 00423 field_list.push_back(new Item_empty_string("Searchable",4)); 00424 field_list.push_back(new Item_empty_string("Case_Sensitive",4)); 00425 field_list.push_back(new Item_empty_string("Default",NAME_LEN)); 00426 field_list.push_back(new Item_empty_string("Comment",NAME_LEN)); 00427 00428 if (protocol->send_fields(&field_list, 00429 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 00430 DBUG_RETURN(TRUE); 00431 00432 /* TODO: Change the loop to not use 'i' */ 00433 for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++) 00434 { 00435 protocol->prepare_for_resend(); 00436 protocol->store(sys_column_types[i].type, system_charset_info); 00437 protocol->store((ulonglong) sys_column_types[i].size); 00438 protocol->store(sys_column_types[i].min_value, system_charset_info); 00439 protocol->store(sys_column_types[i].max_value, system_charset_info); 00440 protocol->store_short((longlong) sys_column_types[i].precision); 00441 protocol->store_short((longlong) sys_column_types[i].scale); 00442 protocol->store(sys_column_types[i].nullable, system_charset_info); 00443 protocol->store(sys_column_types[i].auto_increment, system_charset_info); 00444 protocol->store(sys_column_types[i].unsigned_attr, system_charset_info); 00445 protocol->store(sys_column_types[i].zerofill, system_charset_info); 00446 protocol->store(sys_column_types[i].searchable, system_charset_info); 00447 protocol->store(sys_column_types[i].case_sensitivity, system_charset_info); 00448 protocol->store(sys_column_types[i].default_value, system_charset_info); 00449 protocol->store(sys_column_types[i].comment, system_charset_info); 00450 if (protocol->write()) 00451 DBUG_RETURN(TRUE); 00452 } 00453 send_eof(thd); 00454 DBUG_RETURN(FALSE); 00455 } 00456 00457 00458 /* 00459 find_files() - find files in a given directory. 00460 00461 SYNOPSIS 00462 find_files() 00463 thd thread handler 00464 files put found files in this list 00465 db database name to set in TABLE_LIST structure 00466 path path to database 00467 wild filter for found files 00468 dir read databases in path if TRUE, read .frm files in 00469 database otherwise 00470 00471 RETURN 00472 FIND_FILES_OK success 00473 FIND_FILES_OOM out of memory error 00474 FIND_FILES_DIR no such directory, or directory can't be read 00475 */ 00476 00477 enum find_files_result { 00478 FIND_FILES_OK, 00479 FIND_FILES_OOM, 00480 FIND_FILES_DIR 00481 }; 00482 00483 static 00484 find_files_result 00485 find_files(THD *thd, List<char> *files, const char *db, 00486 const char *path, const char *wild, bool dir) 00487 { 00488 uint i; 00489 char *ext; 00490 MY_DIR *dirp; 00491 FILEINFO *file; 00492 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00493 uint col_access=thd->col_access; 00494 #endif 00495 TABLE_LIST table_list; 00496 DBUG_ENTER("find_files"); 00497 00498 if (wild && !wild[0]) 00499 wild=0; 00500 00501 bzero((char*) &table_list,sizeof(table_list)); 00502 00503 if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0)))) 00504 { 00505 if (my_errno == ENOENT) 00506 my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db); 00507 else 00508 my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno); 00509 DBUG_RETURN(FIND_FILES_DIR); 00510 } 00511 00512 for (i=0 ; i < (uint) dirp->number_off_files ; i++) 00513 { 00514 char uname[NAME_LEN*3+1]; /* Unencoded name */ 00515 file=dirp->dir_entry+i; 00516 if (dir) 00517 { /* Return databases */ 00518 if ((file->name[0] == '.' && 00519 ((file->name[1] == '.' && file->name[2] == '\0') || 00520 file->name[1] == '\0'))) 00521 continue; /* . or .. */ 00522 #ifdef USE_SYMDIR 00523 char *ext; 00524 char buff[FN_REFLEN]; 00525 if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym")) 00526 { 00527 /* Only show the sym file if it points to a directory */ 00528 char *end; 00529 *ext=0; /* Remove extension */ 00530 unpack_dirname(buff, file->name); 00531 end= strend(buff); 00532 if (end != buff && end[-1] == FN_LIBCHAR) 00533 end[-1]= 0; // Remove end FN_LIBCHAR 00534 if (!my_stat(buff, file->mystat, MYF(0))) 00535 continue; 00536 } 00537 #endif 00538 if (!MY_S_ISDIR(file->mystat->st_mode)) 00539 continue; 00540 VOID(filename_to_tablename(file->name, uname, sizeof(uname))); 00541 if (wild && wild_compare(uname, wild, 0)) 00542 continue; 00543 file->name= uname; 00544 } 00545 else 00546 { 00547 // Return only .frm files which aren't temp files. 00548 if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),reg_ext) || 00549 is_prefix(file->name, tmp_file_prefix)) 00550 continue; 00551 *ext=0; 00552 VOID(filename_to_tablename(file->name, uname, sizeof(uname))); 00553 file->name= uname; 00554 if (wild) 00555 { 00556 if (lower_case_table_names) 00557 { 00558 if (wild_case_compare(files_charset_info, file->name, wild)) 00559 continue; 00560 } 00561 else if (wild_compare(file->name,wild,0)) 00562 continue; 00563 } 00564 } 00565 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00566 /* Don't show tables where we don't have any privileges */ 00567 if (db && !(col_access & TABLE_ACLS)) 00568 { 00569 table_list.db= (char*) db; 00570 table_list.db_length= strlen(db); 00571 table_list.table_name= file->name; 00572 table_list.table_name_length= strlen(file->name); 00573 table_list.grant.privilege=col_access; 00574 if (check_grant(thd, TABLE_ACLS, &table_list, 1, 1, 1)) 00575 continue; 00576 } 00577 #endif 00578 if (files->push_back(thd->strdup(file->name))) 00579 { 00580 my_dirend(dirp); 00581 DBUG_RETURN(FIND_FILES_OOM); 00582 } 00583 } 00584 DBUG_PRINT("info",("found: %d files", files->elements)); 00585 my_dirend(dirp); 00586 00587 VOID(ha_find_files(thd,db,path,wild,dir,files)); 00588 00589 DBUG_RETURN(FIND_FILES_OK); 00590 } 00591 00592 00593 bool 00594 mysqld_show_create(THD *thd, TABLE_LIST *table_list) 00595 { 00596 Protocol *protocol= thd->protocol; 00597 char buff[2048]; 00598 String buffer(buff, sizeof(buff), system_charset_info); 00599 DBUG_ENTER("mysqld_show_create"); 00600 DBUG_PRINT("enter",("db: %s table: %s",table_list->db, 00601 table_list->table_name)); 00602 00603 /* We want to preserve the tree for views. */ 00604 thd->lex->view_prepare_mode= TRUE; 00605 00606 /* Only one table for now, but VIEW can involve several tables */ 00607 if (open_normal_and_derived_tables(thd, table_list, 0)) 00608 { 00609 if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID) 00610 DBUG_RETURN(TRUE); 00611 00612 /* 00613 Clear all messages with 'error' level status and 00614 issue a warning with 'warning' level status in 00615 case of invalid view and last error is ER_VIEW_INVALID 00616 */ 00617 mysql_reset_errors(thd, true); 00618 thd->clear_error(); 00619 00620 push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN, 00621 ER_VIEW_INVALID, 00622 ER(ER_VIEW_INVALID), 00623 table_list->view_db.str, 00624 table_list->view_name.str); 00625 } 00626 00627 /* TODO: add environment variables show when it become possible */ 00628 if (thd->lex->only_view && !table_list->view) 00629 { 00630 my_error(ER_WRONG_OBJECT, MYF(0), 00631 table_list->db, table_list->table_name, "VIEW"); 00632 DBUG_RETURN(TRUE); 00633 } 00634 00635 buffer.length(0); 00636 if ((table_list->view ? 00637 view_store_create_info(thd, table_list, &buffer) : 00638 store_create_info(thd, table_list, &buffer, NULL))) 00639 DBUG_RETURN(TRUE); 00640 00641 List<Item> field_list; 00642 if (table_list->view) 00643 { 00644 field_list.push_back(new Item_empty_string("View",NAME_LEN)); 00645 field_list.push_back(new Item_empty_string("Create View", 00646 max(buffer.length(),1024))); 00647 } 00648 else 00649 { 00650 field_list.push_back(new Item_empty_string("Table",NAME_LEN)); 00651 // 1024 is for not to confuse old clients 00652 field_list.push_back(new Item_empty_string("Create Table", 00653 max(buffer.length(),1024))); 00654 } 00655 00656 if (protocol->send_fields(&field_list, 00657 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 00658 DBUG_RETURN(TRUE); 00659 protocol->prepare_for_resend(); 00660 if (table_list->view) 00661 protocol->store(table_list->view_name.str, system_charset_info); 00662 else 00663 { 00664 if (table_list->schema_table) 00665 protocol->store(table_list->schema_table->table_name, 00666 system_charset_info); 00667 else 00668 protocol->store(table_list->table->alias, system_charset_info); 00669 } 00670 protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); 00671 00672 if (protocol->write()) 00673 DBUG_RETURN(TRUE); 00674 send_eof(thd); 00675 DBUG_RETURN(FALSE); 00676 } 00677 00678 bool mysqld_show_create_db(THD *thd, char *dbname, 00679 HA_CREATE_INFO *create_info) 00680 { 00681 Security_context *sctx= thd->security_ctx; 00682 int length; 00683 char buff[2048]; 00684 String buffer(buff, sizeof(buff), system_charset_info); 00685 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00686 uint db_access; 00687 #endif 00688 HA_CREATE_INFO create; 00689 uint create_options = create_info ? create_info->options : 0; 00690 Protocol *protocol=thd->protocol; 00691 DBUG_ENTER("mysql_show_create_db"); 00692 00693 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00694 if (test_all_bits(sctx->master_access, DB_ACLS)) 00695 db_access=DB_ACLS; 00696 else 00697 db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) | 00698 sctx->master_access); 00699 if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) 00700 { 00701 my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), 00702 sctx->priv_user, sctx->host_or_ip, dbname); 00703 general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), 00704 sctx->priv_user, sctx->host_or_ip, dbname); 00705 DBUG_RETURN(TRUE); 00706 } 00707 #endif 00708 if (!my_strcasecmp(system_charset_info, dbname, 00709 information_schema_name.str)) 00710 { 00711 dbname= information_schema_name.str; 00712 create.default_table_charset= system_charset_info; 00713 } 00714 else 00715 { 00716 if (check_db_dir_existence(dbname)) 00717 { 00718 my_error(ER_BAD_DB_ERROR, MYF(0), dbname); 00719 DBUG_RETURN(TRUE); 00720 } 00721 00722 load_db_opt_by_name(thd, dbname, &create); 00723 } 00724 List<Item> field_list; 00725 field_list.push_back(new Item_empty_string("Database",NAME_LEN)); 00726 field_list.push_back(new Item_empty_string("Create Database",1024)); 00727 00728 if (protocol->send_fields(&field_list, 00729 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 00730 DBUG_RETURN(TRUE); 00731 00732 protocol->prepare_for_resend(); 00733 protocol->store(dbname, strlen(dbname), system_charset_info); 00734 buffer.length(0); 00735 buffer.append(STRING_WITH_LEN("CREATE DATABASE ")); 00736 if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS) 00737 buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ ")); 00738 append_identifier(thd, &buffer, dbname, strlen(dbname)); 00739 00740 if (create.default_table_charset) 00741 { 00742 buffer.append(STRING_WITH_LEN(" /*!40100")); 00743 buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET ")); 00744 buffer.append(create.default_table_charset->csname); 00745 if (!(create.default_table_charset->state & MY_CS_PRIMARY)) 00746 { 00747 buffer.append(STRING_WITH_LEN(" COLLATE ")); 00748 buffer.append(create.default_table_charset->name); 00749 } 00750 buffer.append(STRING_WITH_LEN(" */")); 00751 } 00752 protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); 00753 00754 if (protocol->write()) 00755 DBUG_RETURN(TRUE); 00756 send_eof(thd); 00757 DBUG_RETURN(FALSE); 00758 } 00759 00760 00761 00762 /**************************************************************************** 00763 Return only fields for API mysql_list_fields 00764 Use "show table wildcard" in mysql instead of this 00765 ****************************************************************************/ 00766 00767 void 00768 mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) 00769 { 00770 TABLE *table; 00771 DBUG_ENTER("mysqld_list_fields"); 00772 DBUG_PRINT("enter",("table: %s",table_list->table_name)); 00773 00774 if (open_normal_and_derived_tables(thd, table_list, 0)) 00775 DBUG_VOID_RETURN; 00776 table= table_list->table; 00777 00778 List<Item> field_list; 00779 00780 Field **ptr,*field; 00781 for (ptr=table->field ; (field= *ptr); ptr++) 00782 { 00783 if (!wild || !wild[0] || 00784 !wild_case_compare(system_charset_info, field->field_name,wild)) 00785 { 00786 if (table_list->view) 00787 field_list.push_back(new Item_ident_for_show(field, 00788 table_list->view_db.str, 00789 table_list->view_name.str)); 00790 else 00791 field_list.push_back(new Item_field(field)); 00792 } 00793 } 00794 restore_record(table, s->default_values); // Get empty record 00795 table->use_all_columns(); 00796 if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS | 00797 Protocol::SEND_EOF)) 00798 DBUG_VOID_RETURN; 00799 thd->protocol->flush(); 00800 DBUG_VOID_RETURN; 00801 } 00802 00803 00804 int 00805 mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd) 00806 { 00807 Protocol *protocol= thd->protocol; 00808 String *packet= protocol->storage_packet(); 00809 DBUG_ENTER("mysqld_dump_create_info"); 00810 DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name.str)); 00811 00812 protocol->prepare_for_resend(); 00813 if (store_create_info(thd, table_list, packet, NULL)) 00814 DBUG_RETURN(-1); 00815 00816 if (fd < 0) 00817 { 00818 if (protocol->write()) 00819 DBUG_RETURN(-1); 00820 protocol->flush(); 00821 } 00822 else 00823 { 00824 if (my_write(fd, (const byte*) packet->ptr(), packet->length(), 00825 MYF(MY_WME))) 00826 DBUG_RETURN(-1); 00827 } 00828 DBUG_RETURN(0); 00829 } 00830 00831 /* 00832 Go through all character combinations and ensure that sql_lex.cc can 00833 parse it as an identifier. 00834 00835 SYNOPSIS 00836 require_quotes() 00837 name attribute name 00838 name_length length of name 00839 00840 RETURN 00841 # Pointer to conflicting character 00842 0 No conflicting character 00843 */ 00844 00845 static const char *require_quotes(const char *name, uint name_length) 00846 { 00847 uint length; 00848 bool pure_digit= TRUE; 00849 const char *end= name + name_length; 00850 00851 for (; name < end ; name++) 00852 { 00853 uchar chr= (uchar) *name; 00854 length= my_mbcharlen(system_charset_info, chr); 00855 if (length == 1 && !system_charset_info->ident_map[chr]) 00856 return name; 00857 if (length == 1 && (chr < '0' || chr > '9')) 00858 pure_digit= FALSE; 00859 } 00860 if (pure_digit) 00861 return name; 00862 return 0; 00863 } 00864 00865 00866 /* 00867 Quote the given identifier if needed and append it to the target string. 00868 If the given identifier is empty, it will be quoted. 00869 00870 SYNOPSIS 00871 append_identifier() 00872 thd thread handler 00873 packet target string 00874 name the identifier to be appended 00875 name_length length of the appending identifier 00876 */ 00877 00878 void 00879 append_identifier(THD *thd, String *packet, const char *name, uint length) 00880 { 00881 const char *name_end; 00882 char quote_char; 00883 int q= get_quote_char_for_identifier(thd, name, length); 00884 00885 if (q == EOF) 00886 { 00887 packet->append(name, length, system_charset_info); 00888 return; 00889 } 00890 00891 /* 00892 The identifier must be quoted as it includes a quote character or 00893 it's a keyword 00894 */ 00895 00896 VOID(packet->reserve(length*2 + 2)); 00897 quote_char= (char) q; 00898 packet->append("e_char, 1, system_charset_info); 00899 00900 for (name_end= name+length ; name < name_end ; name+= length) 00901 { 00902 uchar chr= (uchar) *name; 00903 length= my_mbcharlen(system_charset_info, chr); 00904 /* 00905 my_mbcharlen can retur 0 on a wrong multibyte 00906 sequence. It is possible when upgrading from 4.0, 00907 and identifier contains some accented characters. 00908 The manual says it does not work. So we'll just 00909 change length to 1 not to hang in the endless loop. 00910 */ 00911 if (!length) 00912 length= 1; 00913 if (length == 1 && chr == (uchar) quote_char) 00914 packet->append("e_char, 1, system_charset_info); 00915 packet->append(name, length, packet->charset()); 00916 } 00917 packet->append("e_char, 1, system_charset_info); 00918 } 00919 00920 00921 /* 00922 Get the quote character for displaying an identifier. 00923 00924 SYNOPSIS 00925 get_quote_char_for_identifier() 00926 thd Thread handler 00927 name name to quote 00928 length length of name 00929 00930 IMPLEMENTATION 00931 Force quoting in the following cases: 00932 - name is empty (for one, it is possible when we use this function for 00933 quoting user and host names for DEFINER clause); 00934 - name is a keyword; 00935 - name includes a special character; 00936 Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE 00937 is set. 00938 00939 RETURN 00940 EOF No quote character is needed 00941 # Quote character 00942 */ 00943 00944 int get_quote_char_for_identifier(THD *thd, const char *name, uint length) 00945 { 00946 if (length && 00947 !is_keyword(name,length) && 00948 !require_quotes(name, length) && 00949 !(thd->options & OPTION_QUOTE_SHOW_CREATE)) 00950 return EOF; 00951 if (thd->variables.sql_mode & MODE_ANSI_QUOTES) 00952 return '"'; 00953 return '`'; 00954 } 00955 00956 00957 /* Append directory name (if exists) to CREATE INFO */ 00958 00959 static void append_directory(THD *thd, String *packet, const char *dir_type, 00960 const char *filename) 00961 { 00962 if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) 00963 { 00964 uint length= dirname_length(filename); 00965 packet->append(' '); 00966 packet->append(dir_type); 00967 packet->append(STRING_WITH_LEN(" DIRECTORY='")); 00968 #ifdef __WIN__ 00969 /* Convert \ to / to be able to create table on unix */ 00970 char *winfilename= (char*) thd->memdup(filename, length); 00971 char *pos, *end; 00972 for (pos= winfilename, end= pos+length ; pos < end ; pos++) 00973 { 00974 if (*pos == '\\') 00975 *pos = '/'; 00976 } 00977 filename= winfilename; 00978 #endif 00979 packet->append(filename, length); 00980 packet->append('\''); 00981 } 00982 } 00983 00984 00985 #define LIST_PROCESS_HOST_LEN 64 00986 00987 /* 00988 Build a CREATE TABLE statement for a table. 00989 00990 SYNOPSIS 00991 store_create_info() 00992 thd The thread 00993 table_list A list containing one table to write statement 00994 for. 00995 packet Pointer to a string where statement will be 00996 written. 00997 create_info_arg Pointer to create information that can be used 00998 to tailor the format of the statement. Can be 00999 NULL, in which case only SQL_MODE is considered 01000 when building the statement. 01001 01002 NOTE 01003 Currently always return 0, but might return error code in the 01004 future. 01005 01006 RETURN 01007 0 OK 01008 */ 01009 01010 int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, 01011 HA_CREATE_INFO *create_info_arg) 01012 { 01013 List<Item> field_list; 01014 char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end, uname[NAME_LEN*3+1]; 01015 const char *alias; 01016 String type(tmp, sizeof(tmp), system_charset_info); 01017 Field **ptr,*field; 01018 uint primary_key; 01019 KEY *key_info; 01020 TABLE *table= table_list->table; 01021 handler *file= table->file; 01022 TABLE_SHARE *share= table->s; 01023 HA_CREATE_INFO create_info; 01024 bool show_table_options= FALSE; 01025 bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | 01026 MODE_ORACLE | 01027 MODE_MSSQL | 01028 MODE_DB2 | 01029 MODE_MAXDB | 01030 MODE_ANSI)) != 0; 01031 bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS | 01032 MODE_MYSQL323 | 01033 MODE_MYSQL40)) != 0; 01034 my_bitmap_map *old_map; 01035 DBUG_ENTER("store_create_info"); 01036 DBUG_PRINT("enter",("table: %s", table->s->table_name.str)); 01037 01038 restore_record(table, s->default_values); // Get empty record 01039 01040 if (share->tmp_table) 01041 packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE ")); 01042 else 01043 packet->append(STRING_WITH_LEN("CREATE TABLE ")); 01044 if (table_list->schema_table) 01045 alias= table_list->schema_table->table_name; 01046 else 01047 { 01048 if (lower_case_table_names == 2) 01049 alias= table->alias; 01050 else 01051 { 01052 alias= share->table_name.str; 01053 } 01054 } 01055 append_identifier(thd, packet, alias, strlen(alias)); 01056 packet->append(STRING_WITH_LEN(" (\n")); 01057 /* 01058 We need this to get default values from the table 01059 We have to restore the read_set if we are called from insert in case 01060 of row based replication. 01061 */ 01062 old_map= tmp_use_all_columns(table, table->read_set); 01063 01064 for (ptr=table->field ; (field= *ptr); ptr++) 01065 { 01066 bool has_default; 01067 bool has_now_default; 01068 uint flags = field->flags; 01069 01070 if (ptr != table->field) 01071 packet->append(STRING_WITH_LEN(",\n")); 01072 01073 packet->append(STRING_WITH_LEN(" ")); 01074 append_identifier(thd,packet,field->field_name, strlen(field->field_name)); 01075 packet->append(' '); 01076 // check for surprises from the previous call to Field::sql_type() 01077 if (type.ptr() != tmp) 01078 type.set(tmp, sizeof(tmp), system_charset_info); 01079 else 01080 type.set_charset(system_charset_info); 01081 01082 field->sql_type(type); 01083 packet->append(type.ptr(), type.length(), system_charset_info); 01084 01085 if (field->has_charset() && 01086 !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))) 01087 { 01088 if (field->charset() != share->table_charset) 01089 { 01090 packet->append(STRING_WITH_LEN(" CHARACTER SET ")); 01091 packet->append(field->charset()->csname); 01092 } 01093 /* 01094 For string types dump collation name only if 01095 collation is not primary for the given charset 01096 */ 01097 if (!(field->charset()->state & MY_CS_PRIMARY)) 01098 { 01099 packet->append(STRING_WITH_LEN(" COLLATE ")); 01100 packet->append(field->charset()->name); 01101 } 01102 } 01103 01104 if (flags & NOT_NULL_FLAG) 01105 packet->append(STRING_WITH_LEN(" NOT NULL")); 01106 else if (field->type() == FIELD_TYPE_TIMESTAMP) 01107 { 01108 /* 01109 TIMESTAMP field require explicit NULL flag, because unlike 01110 all other fields they are treated as NOT NULL by default. 01111 */ 01112 packet->append(STRING_WITH_LEN(" NULL")); 01113 } 01114 01115 /* 01116 Again we are using CURRENT_TIMESTAMP instead of NOW because it is 01117 more standard 01118 */ 01119 has_now_default= table->timestamp_field == field && 01120 field->unireg_check != Field::TIMESTAMP_UN_FIELD; 01121 01122 has_default= (field->type() != FIELD_TYPE_BLOB && 01123 !(field->flags & NO_DEFAULT_VALUE_FLAG) && 01124 field->unireg_check != Field::NEXT_NUMBER && 01125 !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) 01126 && has_now_default)); 01127 01128 if (has_default) 01129 { 01130 packet->append(STRING_WITH_LEN(" DEFAULT ")); 01131 if (has_now_default) 01132 packet->append(STRING_WITH_LEN("CURRENT_TIMESTAMP")); 01133 else if (!field->is_null()) 01134 { // Not null by default 01135 type.set(tmp, sizeof(tmp), field->charset()); 01136 field->val_str(&type); 01137 if (type.length()) 01138 { 01139 String def_val; 01140 uint dummy_errors; 01141 /* convert to system_charset_info == utf8 */ 01142 def_val.copy(type.ptr(), type.length(), field->charset(), 01143 system_charset_info, &dummy_errors); 01144 append_unescaped(packet, def_val.ptr(), def_val.length()); 01145 } 01146 else 01147 packet->append(STRING_WITH_LEN("''")); 01148 } 01149 else if (field->maybe_null()) 01150 packet->append(STRING_WITH_LEN("NULL")); // Null as default 01151 else 01152 packet->append(tmp); 01153 } 01154 01155 if (!limited_mysql_mode && table->timestamp_field == field && 01156 field->unireg_check != Field::TIMESTAMP_DN_FIELD) 01157 packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP")); 01158 01159 if (field->unireg_check == Field::NEXT_NUMBER && 01160 !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS)) 01161 packet->append(STRING_WITH_LEN(" AUTO_INCREMENT")); 01162 01163 if (field->comment.length) 01164 { 01165 packet->append(STRING_WITH_LEN(" COMMENT ")); 01166 append_unescaped(packet, field->comment.str, field->comment.length); 01167 } 01168 } 01169 01170 key_info= table->key_info; 01171 bzero((char*) &create_info, sizeof(create_info)); 01172 file->update_create_info(&create_info); 01173 primary_key= share->primary_key; 01174 01175 for (uint i=0 ; i < share->keys ; i++,key_info++) 01176 { 01177 KEY_PART_INFO *key_part= key_info->key_part; 01178 bool found_primary=0; 01179 packet->append(STRING_WITH_LEN(",\n ")); 01180 01181 if (i == primary_key && !strcmp(key_info->name, primary_key_name)) 01182 { 01183 found_primary=1; 01184 /* 01185 No space at end, because a space will be added after where the 01186 identifier would go, but that is not added for primary key. 01187 */ 01188 packet->append(STRING_WITH_LEN("PRIMARY KEY")); 01189 } 01190 else if (key_info->flags & HA_NOSAME) 01191 packet->append(STRING_WITH_LEN("UNIQUE KEY ")); 01192 else if (key_info->flags & HA_FULLTEXT) 01193 packet->append(STRING_WITH_LEN("FULLTEXT KEY ")); 01194 else if (key_info->flags & HA_SPATIAL) 01195 packet->append(STRING_WITH_LEN("SPATIAL KEY ")); 01196 else 01197 packet->append(STRING_WITH_LEN("KEY ")); 01198 01199 if (!found_primary) 01200 append_identifier(thd, packet, key_info->name, strlen(key_info->name)); 01201 01202 packet->append(STRING_WITH_LEN(" (")); 01203 01204 for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) 01205 { 01206 if (j) 01207 packet->append(','); 01208 01209 if (key_part->field) 01210 append_identifier(thd,packet,key_part->field->field_name, 01211 strlen(key_part->field->field_name)); 01212 if (key_part->field && 01213 (key_part->length != 01214 table->field[key_part->fieldnr-1]->key_length() && 01215 !(key_info->flags & HA_FULLTEXT))) 01216 { 01217 char *end; 01218 buff[0] = '('; 01219 end= int10_to_str((long) key_part->length / 01220 key_part->field->charset()->mbmaxlen, 01221 buff + 1,10); 01222 *end++ = ')'; 01223 packet->append(buff,(uint) (end-buff)); 01224 } 01225 } 01226 packet->append(')'); 01227 store_key_options(thd, packet, table, key_info); 01228 if (key_info->parser) 01229 { 01230 packet->append(" WITH PARSER ", 13); 01231 append_identifier(thd, packet, key_info->parser->name.str, 01232 key_info->parser->name.length); 01233 } 01234 } 01235 01236 /* 01237 Get possible foreign key definitions stored in InnoDB and append them 01238 to the CREATE TABLE statement 01239 */ 01240 01241 if ((for_str= file->get_foreign_key_create_info())) 01242 { 01243 packet->append(for_str, strlen(for_str)); 01244 file->free_foreign_key_create_info(for_str); 01245 } 01246 01247 packet->append(STRING_WITH_LEN("\n)")); 01248 if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode) 01249 { 01250 show_table_options= TRUE; 01251 /* 01252 Get possible table space definitions and append them 01253 to the CREATE TABLE statement 01254 */ 01255 01256 if ((for_str= file->get_tablespace_name(thd))) 01257 { 01258 packet->append(" TABLESPACE "); 01259 packet->append(for_str, strlen(for_str)); 01260 packet->append(" STORAGE DISK"); 01261 my_free(for_str, MYF(0)); 01262 } 01263 01264 /* 01265 IF check_create_info 01266 THEN add ENGINE only if it was used when creating the table 01267 */ 01268 if (!create_info_arg || 01269 (create_info_arg->used_fields & HA_CREATE_USED_ENGINE)) 01270 { 01271 if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) 01272 packet->append(STRING_WITH_LEN(" TYPE=")); 01273 else 01274 packet->append(STRING_WITH_LEN(" ENGINE=")); 01275 #ifdef WITH_PARTITION_STORAGE_ENGINE 01276 if (table->part_info) 01277 packet->append(ha_resolve_storage_engine_name( 01278 table->part_info->default_engine_type)); 01279 else 01280 packet->append(file->table_type()); 01281 #else 01282 packet->append(file->table_type()); 01283 #endif 01284 } 01285 01286 /* 01287 Add AUTO_INCREMENT=... if there is an AUTO_INCREMENT column, 01288 and NEXT_ID > 1 (the default). We must not print the clause 01289 for engines that do not support this as it would break the 01290 import of dumps, but as of this writing, the test for whether 01291 AUTO_INCREMENT columns are allowed and wether AUTO_INCREMENT=... 01292 is supported is identical, !(file->table_flags() & HA_NO_AUTO_INCREMENT)) 01293 Because of that, we do not explicitly test for the feature, 01294 but may extrapolate its existence from that of an AUTO_INCREMENT column. 01295 */ 01296 01297 if(create_info.auto_increment_value > 1) 01298 { 01299 packet->append(" AUTO_INCREMENT=", 16); 01300 end= longlong10_to_str(create_info.auto_increment_value, buff,10); 01301 packet->append(buff, (uint) (end - buff)); 01302 } 01303 01304 01305 if (share->table_charset && 01306 !(thd->variables.sql_mode & MODE_MYSQL323) && 01307 !(thd->variables.sql_mode & MODE_MYSQL40)) 01308 { 01309 /* 01310 IF check_create_info 01311 THEN add DEFAULT CHARSET only if it was used when creating the table 01312 */ 01313 if (!create_info_arg || 01314 (create_info_arg->used_fields & HA_CREATE_USED_DEFAULT_CHARSET)) 01315 { 01316 packet->append(STRING_WITH_LEN(" DEFAULT CHARSET=")); 01317 packet->append(share->table_charset->csname); 01318 if (!(share->table_charset->state & MY_CS_PRIMARY)) 01319 { 01320 packet->append(STRING_WITH_LEN(" COLLATE=")); 01321 packet->append(table->s->table_charset->name); 01322 } 01323 } 01324 } 01325 01326 if (share->min_rows) 01327 { 01328 packet->append(STRING_WITH_LEN(" MIN_ROWS=")); 01329 end= longlong10_to_str(share->min_rows, buff, 10); 01330 packet->append(buff, (uint) (end- buff)); 01331 } 01332 01333 if (share->max_rows && !table_list->schema_table) 01334 { 01335 packet->append(STRING_WITH_LEN(" MAX_ROWS=")); 01336 end= longlong10_to_str(share->max_rows, buff, 10); 01337 packet->append(buff, (uint) (end - buff)); 01338 } 01339 01340 if (share->avg_row_length) 01341 { 01342 packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH=")); 01343 end= longlong10_to_str(share->avg_row_length, buff,10); 01344 packet->append(buff, (uint) (end - buff)); 01345 } 01346 01347 if (share->db_create_options & HA_OPTION_PACK_KEYS) 01348 packet->append(STRING_WITH_LEN(" PACK_KEYS=1")); 01349 if (share->db_create_options & HA_OPTION_NO_PACK_KEYS) 01350 packet->append(STRING_WITH_LEN(" PACK_KEYS=0")); 01351 if (share->db_create_options & HA_OPTION_CHECKSUM) 01352 packet->append(STRING_WITH_LEN(" CHECKSUM=1")); 01353 if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) 01354 packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1")); 01355 if (share->row_type != ROW_TYPE_DEFAULT) 01356 { 01357 packet->append(STRING_WITH_LEN(" ROW_FORMAT=")); 01358 packet->append(ha_row_type[(uint) share->row_type]); 01359 } 01360 if (table->s->key_block_size) 01361 { 01362 packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE=")); 01363 end= longlong10_to_str(table->s->key_block_size, buff, 10); 01364 packet->append(buff, (uint) (end - buff)); 01365 } 01366 table->file->append_create_info(packet); 01367 if (share->comment.length) 01368 { 01369 packet->append(STRING_WITH_LEN(" COMMENT=")); 01370 append_unescaped(packet, share->comment.str, share->comment.length); 01371 } 01372 if (share->connect_string.length) 01373 { 01374 packet->append(STRING_WITH_LEN(" CONNECTION=")); 01375 append_unescaped(packet, share->connect_string.str, share->connect_string.length); 01376 } 01377 append_directory(thd, packet, "DATA", create_info.data_file_name); 01378 append_directory(thd, packet, "INDEX", create_info.index_file_name); 01379 } 01380 #ifdef WITH_PARTITION_STORAGE_ENGINE 01381 { 01382 /* 01383 Partition syntax for CREATE TABLE is at the end of the syntax. 01384 */ 01385 uint part_syntax_len; 01386 char *part_syntax; 01387 if (table->part_info && 01388 (!table->part_info->is_auto_partitioned) && 01389 ((part_syntax= generate_partition_syntax(table->part_info, 01390 &part_syntax_len, 01391 FALSE, 01392 show_table_options)))) 01393 { 01394 packet->append(STRING_WITH_LEN(" /*!50100")); 01395 packet->append(part_syntax, part_syntax_len); 01396 packet->append(STRING_WITH_LEN(" */")); 01397 my_free(part_syntax, MYF(0)); 01398 } 01399 } 01400 #endif 01401 tmp_restore_column_map(table->read_set, old_map); 01402 DBUG_RETURN(0); 01403 } 01404 01405 01406 static void store_key_options(THD *thd, String *packet, TABLE *table, 01407 KEY *key_info) 01408 { 01409 bool limited_mysql_mode= (thd->variables.sql_mode & 01410 (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 | 01411 MODE_MYSQL40)) != 0; 01412 bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | 01413 MODE_ORACLE | 01414 MODE_MSSQL | 01415 MODE_DB2 | 01416 MODE_MAXDB | 01417 MODE_ANSI)) != 0; 01418 char *end, buff[32]; 01419 01420 if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) && 01421 !limited_mysql_mode && !foreign_db_mode) 01422 { 01423 01424 if (key_info->algorithm == HA_KEY_ALG_BTREE) 01425 packet->append(STRING_WITH_LEN(" USING BTREE")); 01426 01427 if (key_info->algorithm == HA_KEY_ALG_HASH) 01428 packet->append(STRING_WITH_LEN(" USING HASH")); 01429 01430 /* send USING only in non-default case: non-spatial rtree */ 01431 if ((key_info->algorithm == HA_KEY_ALG_RTREE) && 01432 !(key_info->flags & HA_SPATIAL)) 01433 packet->append(STRING_WITH_LEN(" USING RTREE")); 01434 01435 if ((key_info->flags & HA_USES_BLOCK_SIZE) && 01436 table->s->key_block_size != key_info->block_size) 01437 { 01438 packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE=")); 01439 end= longlong10_to_str(key_info->block_size, buff, 10); 01440 packet->append(buff, (uint) (end - buff)); 01441 } 01442 } 01443 } 01444 01445 01446 void 01447 view_store_options(THD *thd, TABLE_LIST *table, String *buff) 01448 { 01449 append_algorithm(table, buff); 01450 append_definer(thd, buff, &table->definer.user, &table->definer.host); 01451 if (table->view_suid) 01452 buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER ")); 01453 else 01454 buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER ")); 01455 } 01456 01457 01458 /* 01459 Append DEFINER clause to the given buffer. 01460 01461 SYNOPSIS 01462 append_definer() 01463 thd [in] thread handle 01464 buffer [inout] buffer to hold DEFINER clause 01465 definer_user [in] user name part of definer 01466 definer_host [in] host name part of definer 01467 */ 01468 01469 static void append_algorithm(TABLE_LIST *table, String *buff) 01470 { 01471 buff->append(STRING_WITH_LEN("ALGORITHM=")); 01472 switch ((int8)table->algorithm) { 01473 case VIEW_ALGORITHM_UNDEFINED: 01474 buff->append(STRING_WITH_LEN("UNDEFINED ")); 01475 break; 01476 case VIEW_ALGORITHM_TMPTABLE: 01477 buff->append(STRING_WITH_LEN("TEMPTABLE ")); 01478 break; 01479 case VIEW_ALGORITHM_MERGE: 01480 buff->append(STRING_WITH_LEN("MERGE ")); 01481 break; 01482 default: 01483 DBUG_ASSERT(0); // never should happen 01484 } 01485 } 01486 01487 /* 01488 Append DEFINER clause to the given buffer. 01489 01490 SYNOPSIS 01491 append_definer() 01492 thd [in] thread handle 01493 buffer [inout] buffer to hold DEFINER clause 01494 definer_user [in] user name part of definer 01495 definer_host [in] host name part of definer 01496 */ 01497 01498 void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user, 01499 const LEX_STRING *definer_host) 01500 { 01501 buffer->append(STRING_WITH_LEN("DEFINER=")); 01502 append_identifier(thd, buffer, definer_user->str, definer_user->length); 01503 buffer->append('@'); 01504 append_identifier(thd, buffer, definer_host->str, definer_host->length); 01505 buffer->append(' '); 01506 } 01507 01508 01509 int 01510 view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) 01511 { 01512 my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | 01513 MODE_ORACLE | 01514 MODE_MSSQL | 01515 MODE_DB2 | 01516 MODE_MAXDB | 01517 MODE_ANSI)) != 0; 01518 /* 01519 Compact output format for view can be used 01520 - if user has db of this view as current db 01521 - if this view only references table inside it's own db 01522 */ 01523 if (!thd->db || strcmp(thd->db, table->view_db.str)) 01524 table->compact_view_format= FALSE; 01525 else 01526 { 01527 TABLE_LIST *tbl; 01528 table->compact_view_format= TRUE; 01529 for (tbl= thd->lex->query_tables; 01530 tbl; 01531 tbl= tbl->next_global) 01532 { 01533 if (strcmp(table->view_db.str, tbl->view ? tbl->view_db.str :tbl->db)!= 0) 01534 { 01535 table->compact_view_format= FALSE; 01536 break; 01537 } 01538 } 01539 } 01540 01541 buff->append(STRING_WITH_LEN("CREATE ")); 01542 if (!foreign_db_mode) 01543 { 01544 view_store_options(thd, table, buff); 01545 } 01546 buff->append(STRING_WITH_LEN("VIEW ")); 01547 if (!table->compact_view_format) 01548 { 01549 append_identifier(thd, buff, table->view_db.str, table->view_db.length); 01550 buff->append('.'); 01551 } 01552 append_identifier(thd, buff, table->view_name.str, table->view_name.length); 01553 buff->append(STRING_WITH_LEN(" AS ")); 01554 01555 /* 01556 We can't just use table->query, because our SQL_MODE may trigger 01557 a different syntax, like when ANSI_QUOTES is defined. 01558 */ 01559 table->view->unit.print(buff); 01560 01561 if (table->with_check != VIEW_CHECK_NONE) 01562 { 01563 if (table->with_check == VIEW_CHECK_LOCAL) 01564 buff->append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION")); 01565 else 01566 buff->append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION")); 01567 } 01568 return 0; 01569 } 01570 01571 01572 /**************************************************************************** 01573 Return info about all processes 01574 returns for each thread: thread id, user, host, db, command, info 01575 ****************************************************************************/ 01576 01577 class thread_info :public ilink { 01578 public: 01579 static void *operator new(size_t size) 01580 { 01581 return (void*) sql_alloc((uint) size); 01582 } 01583 static void operator delete(void *ptr __attribute__((unused)), 01584 size_t size __attribute__((unused))) 01585 { TRASH(ptr, size); } 01586 01587 ulong thread_id; 01588 time_t start_time; 01589 uint command; 01590 const char *user,*host,*db,*proc_info,*state_info; 01591 char *query; 01592 }; 01593 01594 #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION 01595 template class I_List<thread_info>; 01596 #endif 01597 01598 void mysqld_list_processes(THD *thd,const char *user, bool verbose) 01599 { 01600 Item *field; 01601 List<Item> field_list; 01602 I_List<thread_info> thread_infos; 01603 ulong max_query_length= (verbose ? thd->variables.max_allowed_packet : 01604 PROCESS_LIST_WIDTH); 01605 Protocol *protocol= thd->protocol; 01606 DBUG_ENTER("mysqld_list_processes"); 01607 01608 field_list.push_back(new Item_int("Id",0,11)); 01609 field_list.push_back(new Item_empty_string("User",16)); 01610 field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN)); 01611 field_list.push_back(field=new Item_empty_string("db",NAME_LEN)); 01612 field->maybe_null=1; 01613 field_list.push_back(new Item_empty_string("Command",16)); 01614 field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG)); 01615 field_list.push_back(field=new Item_empty_string("State",30)); 01616 field->maybe_null=1; 01617 field_list.push_back(field=new Item_empty_string("Info",max_query_length)); 01618 field->maybe_null=1; 01619 if (protocol->send_fields(&field_list, 01620 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 01621 DBUG_VOID_RETURN; 01622 01623 VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list 01624 if (!thd->killed) 01625 { 01626 I_List_iterator<THD> it(threads); 01627 THD *tmp; 01628 while ((tmp=it++)) 01629 { 01630 Security_context *tmp_sctx= tmp->security_ctx; 01631 struct st_my_thread_var *mysys_var; 01632 if ((tmp->vio_ok() || tmp->system_thread) && 01633 (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user)))) 01634 { 01635 thread_info *thd_info= new thread_info; 01636 01637 thd_info->thread_id=tmp->thread_id; 01638 thd_info->user= thd->strdup(tmp_sctx->user ? tmp_sctx->user : 01639 (tmp->system_thread ? 01640 "system user" : "unauthenticated user")); 01641 if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) && 01642 thd->security_ctx->host_or_ip[0]) 01643 { 01644 if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1))) 01645 my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN, 01646 "%s:%u", tmp_sctx->host_or_ip, tmp->peer_port); 01647 } 01648 else 01649 thd_info->host= thd->strdup(tmp_sctx->host_or_ip); 01650 if ((thd_info->db=tmp->db)) // Safe test 01651 thd_info->db=thd->strdup(thd_info->db); 01652 thd_info->command=(int) tmp->command; 01653 if ((mysys_var= tmp->mysys_var)) 01654 pthread_mutex_lock(&mysys_var->mutex); 01655 thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0); 01656 #ifndef EMBEDDED_LIBRARY 01657 thd_info->state_info= (char*) (tmp->locked ? "Locked" : 01658 tmp->net.reading_or_writing ? 01659 (tmp->net.reading_or_writing == 2 ? 01660 "Writing to net" : 01661 thd_info->command == COM_SLEEP ? "" : 01662 "Reading from net") : 01663 tmp->proc_info ? tmp->proc_info : 01664 tmp->mysys_var && 01665 tmp->mysys_var->current_cond ? 01666 "Waiting on cond" : NullS); 01667 #else 01668 thd_info->state_info= (char*)"Writing to net"; 01669 #endif 01670 if (mysys_var) 01671 pthread_mutex_unlock(&mysys_var->mutex); 01672 01673 #if !defined(DONT_USE_THR_ALARM) && ! defined(SCO) 01674 if (pthread_kill(tmp->real_id,0)) 01675 tmp->proc_info="*** DEAD ***"; // This shouldn't happen 01676 #endif 01677 #ifdef EXTRA_DEBUG 01678 thd_info->start_time= tmp->time_after_lock; 01679 #else 01680 thd_info->start_time= tmp->start_time; 01681 #endif 01682 thd_info->query=0; 01683 if (tmp->query) 01684 { 01685 /* 01686 query_length is always set to 0 when we set query = NULL; see 01687 the comment in sql_class.h why this prevents crashes in possible 01688 races with query_length 01689 */ 01690 uint length= min(max_query_length, tmp->query_length); 01691 thd_info->query=(char*) thd->strmake(tmp->query,length); 01692 } 01693 thread_infos.append(thd_info); 01694 } 01695 } 01696 } 01697 VOID(pthread_mutex_unlock(&LOCK_thread_count)); 01698 01699 thread_info *thd_info; 01700 time_t now= time(0); 01701 while ((thd_info=thread_infos.get())) 01702 { 01703 protocol->prepare_for_resend(); 01704 protocol->store((ulonglong) thd_info->thread_id); 01705 protocol->store(thd_info->user, system_charset_info); 01706 protocol->store(thd_info->host, system_charset_info); 01707 protocol->store(thd_info->db, system_charset_info); 01708 if (thd_info->proc_info) 01709 protocol->store(thd_info->proc_info, system_charset_info); 01710 else 01711 protocol->store(command_name[thd_info->command].str, system_charset_info); 01712 if (thd_info->start_time) 01713 protocol->store((uint32) (now - thd_info->start_time)); 01714 else 01715 protocol->store_null(); 01716 protocol->store(thd_info->state_info, system_charset_info); 01717 protocol->store(thd_info->query, system_charset_info); 01718 if (protocol->write()) 01719 break; /* purecov: inspected */ 01720 } 01721 send_eof(thd); 01722 DBUG_VOID_RETURN; 01723 } 01724 01725 int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) 01726 { 01727 TABLE *table= tables->table; 01728 CHARSET_INFO *cs= system_charset_info; 01729 char *user; 01730 time_t now= time(0); 01731 DBUG_ENTER("fill_process_list"); 01732 01733 user= thd->security_ctx->master_access & PROCESS_ACL ? 01734 NullS : thd->security_ctx->priv_user; 01735 01736 VOID(pthread_mutex_lock(&LOCK_thread_count)); 01737 01738 if (!thd->killed) 01739 { 01740 I_List_iterator<THD> it(threads); 01741 THD* tmp; 01742 01743 while ((tmp= it++)) 01744 { 01745 Security_context *tmp_sctx= tmp->security_ctx; 01746 struct st_my_thread_var *mysys_var; 01747 const char *val; 01748 01749 if ((!tmp->vio_ok() && !tmp->system_thread) || 01750 (user && (!tmp_sctx->user || strcmp(tmp_sctx->user, user)))) 01751 continue; 01752 01753 restore_record(table, s->default_values); 01754 /* ID */ 01755 table->field[0]->store((longlong) tmp->thread_id, TRUE); 01756 /* USER */ 01757 val= tmp_sctx->user ? tmp_sctx->user : 01758 (tmp->system_thread ? "system user" : "unauthenticated user"); 01759 table->field[1]->store(val, strlen(val), cs); 01760 /* HOST */ 01761 if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) && 01762 thd->security_ctx->host_or_ip[0]) 01763 { 01764 char host[LIST_PROCESS_HOST_LEN + 1]; 01765 my_snprintf(host, LIST_PROCESS_HOST_LEN, "%s:%u", 01766 tmp_sctx->host_or_ip, tmp->peer_port); 01767 table->field[2]->store(host, strlen(host), cs); 01768 } 01769 else 01770 table->field[2]->store(tmp_sctx->host_or_ip, 01771 strlen(tmp_sctx->host_or_ip), cs); 01772 /* DB */ 01773 if (tmp->db) 01774 { 01775 table->field[3]->store(tmp->db, strlen(tmp->db), cs); 01776 table->field[3]->set_notnull(); 01777 } 01778 01779 if ((mysys_var= tmp->mysys_var)) 01780 pthread_mutex_lock(&mysys_var->mutex); 01781 /* COMMAND */ 01782 if ((val= (char *) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0))) 01783 table->field[4]->store(val, strlen(val), cs); 01784 else 01785 table->field[4]->store(command_name[tmp->command].str, 01786 command_name[tmp->command].length, cs); 01787 /* TIME */ 01788 table->field[5]->store((uint32)(tmp->start_time ? 01789 now - tmp->start_time : 0), TRUE); 01790 /* STATE */ 01791 #ifndef EMBEDDED_LIBRARY 01792 val= (char*) (tmp->locked ? "Locked" : 01793 tmp->net.reading_or_writing ? 01794 (tmp->net.reading_or_writing == 2 ? 01795 "Writing to net" : 01796 tmp->command == COM_SLEEP ? "" : 01797 "Reading from net") : 01798 tmp->proc_info ? tmp->proc_info : 01799 tmp->mysys_var && 01800 tmp->mysys_var->current_cond ? 01801 "Waiting on cond" : NullS); 01802 #else 01803 val= (char *) "Writing to net"; 01804 #endif 01805 if (val) 01806 { 01807 table->field[6]->store(val, strlen(val), cs); 01808 table->field[6]->set_notnull(); 01809 } 01810 01811 if (mysys_var) 01812 pthread_mutex_unlock(&mysys_var->mutex); 01813 01814 /* INFO */ 01815 if (tmp->query) 01816 { 01817 table->field[7]->store(tmp->query, 01818 min(PROCESS_LIST_INFO_WIDTH, 01819 tmp->query_length), cs); 01820 table->field[7]->set_notnull(); 01821 } 01822 01823 if (schema_table_store_record(thd, table)) 01824 { 01825 VOID(pthread_mutex_unlock(&LOCK_thread_count)); 01826 DBUG_RETURN(1); 01827 } 01828 } 01829 } 01830 01831 VOID(pthread_mutex_unlock(&LOCK_thread_count)); 01832 DBUG_RETURN(0); 01833 } 01834 01835 /***************************************************************************** 01836 Status functions 01837 *****************************************************************************/ 01838 01839 static DYNAMIC_ARRAY all_status_vars; 01840 static bool status_vars_inited= 0; 01841 static int show_var_cmp(const void *var1, const void *var2) 01842 { 01843 return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name); 01844 } 01845 01846 /* 01847 deletes all the SHOW_UNDEF elements from the array and calls 01848 delete_dynamic() if it's completely empty. 01849 */ 01850 static void shrink_var_array(DYNAMIC_ARRAY *array) 01851 { 01852 uint a,b; 01853 SHOW_VAR *all= dynamic_element(array, 0, SHOW_VAR *); 01854 01855 for (a= b= 0; b < array->elements; b++) 01856 if (all[b].type != SHOW_UNDEF) 01857 all[a++]= all[b]; 01858 if (a) 01859 { 01860 bzero(all+a, sizeof(SHOW_VAR)); // writing NULL-element to the end 01861 array->elements= a; 01862 } 01863 else // array is completely empty - delete it 01864 delete_dynamic(array); 01865 } 01866 01867 /* 01868 Adds an array of SHOW_VAR entries to the output of SHOW STATUS 01869 01870 SYNOPSIS 01871 add_status_vars(SHOW_VAR *list) 01872 list - an array of SHOW_VAR entries to add to all_status_vars 01873 the last entry must be {0,0,SHOW_UNDEF} 01874 01875 NOTE 01876 The handling of all_status_vars[] is completely internal, it's allocated 01877 automatically when something is added to it, and deleted completely when 01878 the last entry is removed. 01879 01880 As a special optimization, if add_status_vars() is called before 01881 init_status_vars(), it assumes "startup mode" - neither concurrent access 01882 to the array nor SHOW STATUS are possible (thus it skips locks and qsort) 01883 01884 The last entry of the all_status_vars[] should always be {0,0,SHOW_UNDEF} 01885 */ 01886 int add_status_vars(SHOW_VAR *list) 01887 { 01888 int res= 0; 01889 if (status_vars_inited) 01890 pthread_mutex_lock(&LOCK_status); 01891 if (!all_status_vars.buffer && // array is not allocated yet - do it now 01892 my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 200, 20)) 01893 { 01894 res= 1; 01895 goto err; 01896 } 01897 while (list->name) 01898 res|= insert_dynamic(&all_status_vars, (gptr)list++); 01899 res|= insert_dynamic(&all_status_vars, (gptr)list); // appending NULL-element 01900 all_status_vars.elements--; // but next insert_dynamic should overwite it 01901 if (status_vars_inited) 01902 sort_dynamic(&all_status_vars, show_var_cmp); 01903 err: 01904 if (status_vars_inited) 01905 pthread_mutex_unlock(&LOCK_status); 01906 return res; 01907 } 01908 01909 /* 01910 Make all_status_vars[] usable for SHOW STATUS 01911 01912 NOTE 01913 See add_status_vars(). Before init_status_vars() call, add_status_vars() 01914 works in a special fast "startup" mode. Thus init_status_vars() 01915 should be called as late as possible but before enabling multi-threading. 01916 */ 01917 void init_status_vars() 01918 { 01919 status_vars_inited=1; 01920 sort_dynamic(&all_status_vars, show_var_cmp); 01921 } 01922 01923 /* 01924 catch-all cleanup function, cleans up everything no matter what 01925 01926 DESCRIPTION 01927 This function is not strictly required if all add_to_status/ 01928 remove_status_vars are properly paired, but it's a safety measure that 01929 deletes everything from the all_status_vars[] even if some 01930 remove_status_vars were forgotten 01931 */ 01932 void free_status_vars() 01933 { 01934 delete_dynamic(&all_status_vars); 01935 } 01936 01937 /* 01938 Removes an array of SHOW_VAR entries from the output of SHOW STATUS 01939 01940 SYNOPSIS 01941 remove_status_vars(SHOW_VAR *list) 01942 list - an array of SHOW_VAR entries to remove to all_status_vars 01943 the last entry must be {0,0,SHOW_UNDEF} 01944 01945 NOTE 01946 there's lots of room for optimizing this, especially in non-sorted mode, 01947 but nobody cares - it may be called only in case of failed plugin 01948 initialization in the mysqld startup. 01949 */ 01950 01951 void remove_status_vars(SHOW_VAR *list) 01952 { 01953 if (status_vars_inited) 01954 { 01955 pthread_mutex_lock(&LOCK_status); 01956 SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *); 01957 int a= 0, b= all_status_vars.elements, c= (a+b)/2; 01958 01959 for (; list->name; list++) 01960 { 01961 int res= 0; 01962 for (a= 0, b= all_status_vars.elements; b-a > 1; c= (a+b)/2) 01963 { 01964 res= show_var_cmp(list, all+c); 01965 if (res < 0) 01966 b= c; 01967 else if (res > 0) 01968 a= c; 01969 else 01970 break; 01971 } 01972 if (res == 0) 01973 all[c].type= SHOW_UNDEF; 01974 } 01975 shrink_var_array(&all_status_vars); 01976 pthread_mutex_unlock(&LOCK_status); 01977 } 01978 else 01979 { 01980 SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *); 01981 uint i; 01982 for (; list->name; list++) 01983 { 01984 for (i= 0; i < all_status_vars.elements; i++) 01985 { 01986 if (show_var_cmp(list, all+i)) 01987 continue; 01988 all[i].type= SHOW_UNDEF; 01989 break; 01990 } 01991 } 01992 shrink_var_array(&all_status_vars); 01993 } 01994 } 01995 01996 static bool show_status_array(THD *thd, const char *wild, 01997 SHOW_VAR *variables, 01998 enum enum_var_type value_type, 01999 struct system_status_var *status_var, 02000 const char *prefix, TABLE *table) 02001 { 02002 char buff[SHOW_VAR_FUNC_BUFF_SIZE], *prefix_end; 02003 /* the variable name should not be longer then 80 characters */ 02004 char name_buffer[80]; 02005 int len; 02006 LEX_STRING null_lex_str; 02007 SHOW_VAR tmp, *var; 02008 DBUG_ENTER("show_status_array"); 02009 02010 null_lex_str.str= 0; // For sys_var->value_ptr() 02011 null_lex_str.length= 0; 02012 02013 prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1); 02014 if (*prefix) 02015 *prefix_end++= '_'; 02016 len=name_buffer + sizeof(name_buffer) - prefix_end; 02017 02018 for (; variables->name; variables++) 02019 { 02020 strnmov(prefix_end, variables->name, len); 02021 name_buffer[sizeof(name_buffer)-1]=0; /* Safety */ 02022 02023 /* 02024 if var->type is SHOW_FUNC, call the function. 02025 Repeat as necessary, if new var is again SHOW_FUNC 02026 */ 02027 for (var=variables; var->type == SHOW_FUNC; var= &tmp) 02028 ((mysql_show_var_func)(var->value))(thd, &tmp, buff); 02029 02030 SHOW_TYPE show_type=var->type; 02031 if (show_type == SHOW_ARRAY) 02032 { 02033 show_status_array(thd, wild, (SHOW_VAR *) var->value, 02034 value_type, status_var, name_buffer, table); 02035 } 02036 else 02037 { 02038 if (!(wild && wild[0] && wild_case_compare(system_charset_info, 02039 name_buffer, wild))) 02040 { 02041 char *value=var->value; 02042 const char *pos, *end; // We assign a lot of const's 02043 long nr; 02044 if (show_type == SHOW_SYS) 02045 { 02046 show_type= ((sys_var*) value)->type(); 02047 value= (char*) ((sys_var*) value)->value_ptr(thd, value_type, 02048 &null_lex_str); 02049 } 02050 02051 pos= end= buff; 02052 /* 02053 note that value may be == buff. All SHOW_xxx code below 02054 should still work in this case 02055 */ 02056 switch (show_type) { 02057 case SHOW_DOUBLE_STATUS: 02058 { 02059 value= ((char *) status_var + (ulong) value); 02060 end= buff + sprintf(buff, "%f", *(double*) value); 02061 break; 02062 } 02063 case SHOW_LONG_STATUS: 02064 value= ((char *) status_var + (ulong) value); 02065 /* fall through */ 02066 case SHOW_LONG: 02067 case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status() 02068 end= int10_to_str(*(long*) value, buff, 10); 02069 break; 02070 case SHOW_LONGLONG: 02071 end= longlong10_to_str(*(longlong*) value, buff, 10); 02072 break; 02073 case SHOW_HA_ROWS: 02074 end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10); 02075 break; 02076 case SHOW_BOOL: 02077 end= strmov(buff, *(bool*) value ? "ON" : "OFF"); 02078 break; 02079 case SHOW_MY_BOOL: 02080 end= strmov(buff, *(my_bool*) value ? "ON" : "OFF"); 02081 break; 02082 case SHOW_INT: 02083 end= int10_to_str((long) *(uint32*) value, buff, 10); 02084 break; 02085 case SHOW_HAVE: 02086 { 02087 SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value; 02088 pos= show_comp_option_name[(int) tmp]; 02089 end= strend(pos); 02090 break; 02091 } 02092 case SHOW_CHAR: 02093 { 02094 if (!(pos= value)) 02095 pos= ""; 02096 end= strend(pos); 02097 break; 02098 } 02099 case SHOW_CHAR_PTR: 02100 { 02101 if (!(pos= *(char**) value)) 02102 pos= ""; 02103 end= strend(pos); 02104 break; 02105 } 02106 case SHOW_KEY_CACHE_LONG: 02107 value= (char*) dflt_key_cache + (ulong)value; 02108 end= int10_to_str(*(long*) value, buff, 10); 02109 break; 02110 case SHOW_KEY_CACHE_LONGLONG: 02111 value= (char*) dflt_key_cache + (ulong)value; 02112 end= longlong10_to_str(*(longlong*) value, buff, 10); 02113 break; 02114 case SHOW_UNDEF: 02115 break; // Return empty string 02116 case SHOW_SYS: // Cannot happen 02117 default: 02118 DBUG_ASSERT(0); 02119 break; 02120 } 02121 restore_record(table, s->default_values); 02122 table->field[0]->store(name_buffer, strlen(name_buffer), 02123 system_charset_info); 02124 table->field[1]->store(pos, (uint32) (end - pos), system_charset_info); 02125 if (schema_table_store_record(thd, table)) 02126 DBUG_RETURN(TRUE); 02127 } 02128 } 02129 } 02130 02131 DBUG_RETURN(FALSE); 02132 } 02133 02134 02135 /* collect status for all running threads */ 02136 02137 void calc_sum_of_all_status(STATUS_VAR *to) 02138 { 02139 DBUG_ENTER("calc_sum_of_all_status"); 02140 02141 /* Ensure that thread id not killed during loop */ 02142 VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list 02143 02144 I_List_iterator<THD> it(threads); 02145 THD *tmp; 02146 02147 /* Get global values as base */ 02148 *to= global_status_var; 02149 02150 /* Add to this status from existing threads */ 02151 while ((tmp= it++)) 02152 add_to_status(to, &tmp->status_var); 02153 02154 VOID(pthread_mutex_unlock(&LOCK_thread_count)); 02155 DBUG_VOID_RETURN; 02156 } 02157 02158 02159 LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str, 02160 const char* str, uint length, 02161 bool allocate_lex_string) 02162 { 02163 MEM_ROOT *mem= thd->mem_root; 02164 if (allocate_lex_string) 02165 if (!(lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING)))) 02166 return 0; 02167 lex_str->str= strmake_root(mem, str, length); 02168 lex_str->length= length; 02169 return lex_str; 02170 } 02171 02172 02173 /* INFORMATION_SCHEMA name */ 02174 LEX_STRING information_schema_name= { C_STRING_WITH_LEN("information_schema")}; 02175 02176 /* This is only used internally, but we need it here as a forward reference */ 02177 extern ST_SCHEMA_TABLE schema_tables[]; 02178 02179 typedef struct st_index_field_values 02180 { 02181 const char *db_value, *table_value; 02182 } INDEX_FIELD_VALUES; 02183 02184 02185 /* 02186 Store record to I_S table, convert HEAP table 02187 to MyISAM if necessary 02188 02189 SYNOPSIS 02190 schema_table_store_record() 02191 thd thread handler 02192 table Information schema table to be updated 02193 02194 RETURN 02195 0 success 02196 1 error 02197 */ 02198 02199 bool schema_table_store_record(THD *thd, TABLE *table) 02200 { 02201 int error; 02202 if ((error= table->file->ha_write_row(table->record[0]))) 02203 { 02204 if (create_myisam_from_heap(thd, table, 02205 table->pos_in_table_list->schema_table_param, 02206 error, 0)) 02207 return 1; 02208 } 02209 return 0; 02210 } 02211 02212 02213 void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values) 02214 { 02215 const char *wild= lex->wild ? lex->wild->ptr() : NullS; 02216 switch (lex->sql_command) { 02217 case SQLCOM_SHOW_DATABASES: 02218 index_field_values->db_value= wild; 02219 break; 02220 case SQLCOM_SHOW_TABLES: 02221 case SQLCOM_SHOW_TABLE_STATUS: 02222 case SQLCOM_SHOW_TRIGGERS: 02223 case SQLCOM_SHOW_EVENTS: 02224 index_field_values->db_value= lex->select_lex.db; 02225 index_field_values->table_value= wild; 02226 break; 02227 default: 02228 index_field_values->db_value= NullS; 02229 index_field_values->table_value= NullS; 02230 break; 02231 } 02232 } 02233 02234 02235 int make_table_list(THD *thd, SELECT_LEX *sel, 02236 char *db, char *table) 02237 { 02238 Table_ident *table_ident; 02239 LEX_STRING ident_db, ident_table; 02240 ident_db.str= db; 02241 ident_db.length= strlen(db); 02242 ident_table.str= table; 02243 ident_table.length= strlen(table); 02244 table_ident= new Table_ident(thd, ident_db, ident_table, 1); 02245 sel->init_query(); 02246 if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, 02247 (List<String> *) 0, (List<String> *) 0)) 02248 return 1; 02249 return 0; 02250 } 02251 02252 02253 bool uses_only_table_name_fields(Item *item, TABLE_LIST *table) 02254 { 02255 if (item->type() == Item::FUNC_ITEM) 02256 { 02257 Item_func *item_func= (Item_func*)item; 02258 Item **child; 02259 Item **item_end= (item_func->arguments()) + item_func->argument_count(); 02260 for (child= item_func->arguments(); child != item_end; child++) 02261 { 02262 if (!uses_only_table_name_fields(*child, table)) 02263 return 0; 02264 } 02265 } 02266 else if (item->type() == Item::FIELD_ITEM) 02267 { 02268 Item_field *item_field= (Item_field*)item; 02269 CHARSET_INFO *cs= system_charset_info; 02270 ST_SCHEMA_TABLE *schema_table= table->schema_table; 02271 ST_FIELD_INFO *field_info= schema_table->fields_info; 02272 const char *field_name1= schema_table->idx_field1 >= 0 ? field_info[schema_table->idx_field1].field_name : ""; 02273 const char *field_name2= schema_table->idx_field2 >= 0 ? field_info[schema_table->idx_field2].field_name : ""; 02274 if (table->table != item_field->field->table || 02275 (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1), 02276 (uchar *) item_field->field_name, 02277 strlen(item_field->field_name), 0) && 02278 cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2), 02279 (uchar *) item_field->field_name, 02280 strlen(item_field->field_name), 0))) 02281 return 0; 02282 } 02283 else if (item->type() == Item::REF_ITEM) 02284 return uses_only_table_name_fields(item->real_item(), table); 02285 if (item->type() == Item::SUBSELECT_ITEM && 02286 !item->const_item()) 02287 return 0; 02288 02289 return 1; 02290 } 02291 02292 02293 static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table) 02294 { 02295 if (!cond) 02296 return (COND*) 0; 02297 if (cond->type() == Item::COND_ITEM) 02298 { 02299 if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) 02300 { 02301 /* Create new top level AND item */ 02302 Item_cond_and *new_cond=new Item_cond_and; 02303 if (!new_cond) 02304 return (COND*) 0; 02305 List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); 02306 Item *item; 02307 while ((item=li++)) 02308 { 02309 Item *fix= make_cond_for_info_schema(item, table); 02310 if (fix) 02311 new_cond->argument_list()->push_back(fix); 02312 } 02313 switch (new_cond->argument_list()->elements) { 02314 case 0: 02315 return (COND*) 0; 02316 case 1: 02317 return new_cond->argument_list()->head(); 02318 default: 02319 new_cond->quick_fix_field(); 02320 return new_cond; 02321 } 02322 } 02323 else 02324 { // Or list 02325 Item_cond_or *new_cond=new Item_cond_or; 02326 if (!new_cond) 02327 return (COND*) 0; 02328 List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); 02329 Item *item; 02330 while ((item=li++)) 02331 { 02332 Item *fix=make_cond_for_info_schema(item, table); 02333 if (!fix) 02334 return (COND*) 0; 02335 new_cond->argument_list()->push_back(fix); 02336 } 02337 new_cond->quick_fix_field(); 02338 new_cond->top_level_item(); 02339 return new_cond; 02340 } 02341 } 02342 02343 if (!uses_only_table_name_fields(cond, table)) 02344 return (COND*) 0; 02345 return cond; 02346 } 02347 02348 02349 enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table) 02350 { 02351 return (enum enum_schema_tables) (schema_table - &schema_tables[0]); 02352 } 02353 02354 02355 /* 02356 Create db names list. Information schema name always is first in list 02357 02358 SYNOPSIS 02359 make_db_list() 02360 thd thread handler 02361 files list of db names 02362 wild wild string 02363 idx_field_vals idx_field_vals->db_name contains db name or 02364 wild string 02365 with_i_schema returns 1 if we added 'IS' name to list 02366 otherwise returns 0 02367 is_wild_value if value is 1 then idx_field_vals->db_name is 02368 wild string otherwise it's db name; 02369 02370 RETURN 02371 zero success 02372 non-zero error 02373 */ 02374 02375 int make_db_list(THD *thd, List<char> *files, 02376 INDEX_FIELD_VALUES *idx_field_vals, 02377 bool *with_i_schema, bool is_wild_value) 02378 { 02379 LEX *lex= thd->lex; 02380 *with_i_schema= 0; 02381 get_index_field_values(lex, idx_field_vals); 02382 if (is_wild_value) 02383 { 02384 /* 02385 This part of code is only for SHOW DATABASES command. 02386 idx_field_vals->db_value can be 0 when we don't use 02387 LIKE clause (see also get_index_field_values() function) 02388 */ 02389 if (!idx_field_vals->db_value || 02390 !wild_case_compare(system_charset_info, 02391 information_schema_name.str, 02392 idx_field_vals->db_value)) 02393 { 02394 *with_i_schema= 1; 02395 if (files->push_back(thd->strdup(information_schema_name.str))) 02396 return 1; 02397 } 02398 return (find_files(thd, files, NullS, mysql_data_home, 02399 idx_field_vals->db_value, 1) != FIND_FILES_OK); 02400 } 02401 02402 /* 02403 This part of code is for SHOW TABLES, SHOW TABLE STATUS commands. 02404 idx_field_vals->db_value can't be 0 (see get_index_field_values() 02405 function). 02406 */ 02407 if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) 02408 { 02409 if (!my_strcasecmp(system_charset_info, information_schema_name.str, 02410 idx_field_vals->db_value)) 02411 { 02412 *with_i_schema= 1; 02413 return files->push_back(thd->strdup(information_schema_name.str)); 02414 } 02415 return files->push_back(thd->strdup(idx_field_vals->db_value)); 02416 } 02417 02418 /* 02419 Create list of existing databases. It is used in case 02420 of select from information schema table 02421 */ 02422 if (files->push_back(thd->strdup(information_schema_name.str))) 02423 return 1; 02424 *with_i_schema= 1; 02425 return (find_files(thd, files, NullS, 02426 mysql_data_home, NullS, 1) != FIND_FILES_OK); 02427 } 02428 02429 02430 int schema_tables_add(THD *thd, List<char> *files, const char *wild) 02431 { 02432 ST_SCHEMA_TABLE *tmp_schema_table= schema_tables; 02433 for (; tmp_schema_table->table_name; tmp_schema_table++) 02434 { 02435 if (tmp_schema_table->hidden) 02436 continue; 02437 if (wild) 02438 { 02439 if (lower_case_table_names) 02440 { 02441 if (wild_case_compare(files_charset_info, 02442 tmp_schema_table->table_name, 02443 wild)) 02444 continue; 02445 } 02446 else if (wild_compare(tmp_schema_table->table_name, wild, 0)) 02447 continue; 02448 } 02449 if (files->push_back(thd->strdup(tmp_schema_table->table_name))) 02450 return 1; 02451 } 02452 return 0; 02453 } 02454 02455 02456 int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) 02457 { 02458 LEX *lex= thd->lex; 02459 TABLE *table= tables->table; 02460 SELECT_LEX *select_lex= &lex->select_lex; 02461 SELECT_LEX *old_all_select_lex= lex->all_selects_list; 02462 enum_sql_command save_sql_command= lex->sql_command; 02463 SELECT_LEX *lsel= tables->schema_select_lex; 02464 ST_SCHEMA_TABLE *schema_table= tables->schema_table; 02465 SELECT_LEX sel; 02466 INDEX_FIELD_VALUES idx_field_vals; 02467 char path[FN_REFLEN], *end, *base_name, *orig_base_name, *file_name; 02468 uint len; 02469 bool with_i_schema; 02470 enum enum_schema_tables schema_table_idx; 02471 List<char> bases; 02472 List_iterator_fast<char> it(bases); 02473 COND *partial_cond; 02474 Security_context *sctx= thd->security_ctx; 02475 uint derived_tables= lex->derived_tables; 02476 int error= 1; 02477 enum legacy_db_type not_used; 02478 Open_tables_state open_tables_state_backup; 02479 bool save_view_prepare_mode= lex->view_prepare_mode; 02480 Query_tables_list query_tables_list_backup; 02481 lex->view_prepare_mode= TRUE; 02482 DBUG_ENTER("get_all_tables"); 02483 02484 LINT_INIT(end); 02485 LINT_INIT(len); 02486 02487 lex->reset_n_backup_query_tables_list(&query_tables_list_backup); 02488 02489 /* 02490 We should not introduce deadlocks even if we already have some 02491 tables open and locked, since we won't lock tables which we will 02492 open and will ignore possible name-locks for these tables. 02493 */ 02494 thd->reset_n_backup_open_tables_state(&open_tables_state_backup); 02495 02496 if (lsel) 02497 { 02498 TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first; 02499 bool res; 02500 02501 lex->all_selects_list= lsel; 02502 /* 02503 Restore thd->temporary_tables to be able to process 02504 temporary tables(only for 'show index' & 'show columns'). 02505 This should be changed when processing of temporary tables for 02506 I_S tables will be done. 02507 */ 02508 thd->temporary_tables= open_tables_state_backup.temporary_tables; 02509 /* 02510 Let us set fake sql_command so views won't try to merge 02511 themselves into main statement. If we don't do this, 02512 SELECT * from information_schema.xxxx will cause problems. 02513 SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' 02514 */ 02515 lex->sql_command= SQLCOM_SHOW_FIELDS; 02516 res= open_normal_and_derived_tables(thd, show_table_list, 02517 MYSQL_LOCK_IGNORE_FLUSH); 02518 lex->sql_command= save_sql_command; 02519 /* 02520 get_all_tables() returns 1 on failure and 0 on success thus 02521 return only these and not the result code of ::process_table() 02522 02523 We should use show_table_list->alias instead of 02524 show_table_list->table_name because table_name 02525 could be changed during opening of I_S tables. It's safe 02526 to use alias because alias contains original table name 02527 in this case(this part of code is used only for 02528 'show columns' & 'show statistics' commands). 02529 */ 02530 error= test(schema_table->process_table(thd, show_table_list, 02531 table, res, 02532 (show_table_list->view ? 02533 show_table_list->view_db.str : 02534 show_table_list->db), 02535 show_table_list->alias)); 02536 thd->temporary_tables= 0; 02537 close_tables_for_reopen(thd, &show_table_list); 02538 goto err; 02539 } 02540 02541 schema_table_idx= get_schema_table_idx(schema_table); 02542 02543 if (make_db_list(thd, &bases, &idx_field_vals, 02544 &with_i_schema, 0)) 02545 goto err; 02546 02547 partial_cond= make_cond_for_info_schema(cond, tables); 02548 it.rewind(); /* To get access to new elements in basis list */ 02549 02550 /* 02551 Below we generate error for non existing database. 02552 (to save old behaviour for SHOW TABLES FROM db) 02553 */ 02554 while ((orig_base_name= base_name= it++) || 02555 ((sql_command_flags[save_sql_command] & CF_SHOW_TABLE_COMMAND) && 02556 (base_name= select_lex->db) && !bases.elements)) 02557 { 02558 #ifndef NO_EMBEDDED_ACCESS_CHECKS 02559 if (!check_access(thd,SELECT_ACL, base_name, 02560 &thd->col_access, 0, 1, with_i_schema) || 02561 sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || 02562 acl_get(sctx->host, sctx->ip, sctx->priv_user, base_name,0) || 02563 (grant_option && !check_grant_db(thd, base_name))) 02564 #endif 02565 { 02566 List<char> files; 02567 if (with_i_schema) // information schema table names 02568 { 02569 if (schema_tables_add(thd, &files, idx_field_vals.table_value)) 02570 goto err; 02571 } 02572 else 02573 { 02574 len= build_table_filename(path, sizeof(path), base_name, "", "", 0); 02575 end= path + len; 02576 len= FN_LEN - len; 02577 find_files_result res= find_files(thd, &files, base_name, 02578 path, idx_field_vals.table_value, 0); 02579 if (res != FIND_FILES_OK) 02580 { 02581 /* 02582 Downgrade errors about problems with database directory to 02583 warnings if this is not a 'SHOW' command. Another thread 02584 may have dropped database, and we may still have a name 02585 for that directory. 02586 */ 02587 if (res == FIND_FILES_DIR && lex->sql_command == SQLCOM_END) 02588 { 02589 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 02590 thd->net.last_errno, thd->net.last_error); 02591 thd->clear_error(); 02592 continue; 02593 } 02594 else 02595 { 02596 goto err; 02597 } 02598 } 02599 if (lower_case_table_names) 02600 orig_base_name= thd->strdup(base_name); 02601 } 02602 02603 List_iterator_fast<char> it_files(files); 02604 while ((file_name= it_files++)) 02605 { 02606 restore_record(table, s->default_values); 02607 table->field[schema_table->idx_field1]-> 02608 store(base_name, strlen(base_name), system_charset_info); 02609 table->field[schema_table->idx_field2]-> 02610 store(file_name, strlen(file_name),system_charset_info); 02611 if (!partial_cond || partial_cond->val_int()) 02612 { 02613 if (schema_table_idx == SCH_TABLE_NAMES) 02614 { 02615 if (lex->verbose || 02616 (sql_command_flags[save_sql_command] & CF_STATUS_COMMAND) == 0) 02617 { 02618 if (with_i_schema) 02619 { 02620 table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), 02621 system_charset_info); 02622 } 02623 else 02624 { 02625 my_snprintf(end, len, "/%s%s", file_name, reg_ext); 02626 switch (mysql_frm_type(thd, path, ¬_used)) { 02627 case FRMTYPE_ERROR: 02628 table->field[3]->store(STRING_WITH_LEN("ERROR"), 02629 system_charset_info); 02630 break; 02631 case FRMTYPE_TABLE: 02632 table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), 02633 system_charset_info); 02634 break; 02635 case FRMTYPE_VIEW: 02636 table->field[3]->store(STRING_WITH_LEN("VIEW"), 02637 system_charset_info); 02638 break; 02639 default: 02640 DBUG_ASSERT(0); 02641 } 02642 } 02643 } 02644 if (schema_table_store_record(thd, table)) 02645 goto err; 02646 } 02647 else 02648 { 02649 int res; 02650 /* 02651 Set the parent lex of 'sel' because it is needed by 02652 sel.init_query() which is called inside make_table_list. 02653 */ 02654 sel.parent_lex= lex; 02655 if (make_table_list(thd, &sel, base_name, file_name)) 02656 goto err; 02657 TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first; 02658 lex->all_selects_list= &sel; 02659 lex->derived_tables= 0; 02660 lex->sql_command= SQLCOM_SHOW_FIELDS; 02661 res= open_normal_and_derived_tables(thd, show_table_list, 02662 MYSQL_LOCK_IGNORE_FLUSH); 02663 lex->sql_command= save_sql_command; 02664 /* 02665 We should use show_table_list->alias instead of 02666 show_table_list->table_name because table_name 02667 could be changed during opening of I_S tables. It's safe 02668 to use alias because alias contains original table name 02669 in this case. 02670 */ 02671 res= schema_table->process_table(thd, show_table_list, table, 02672 res, orig_base_name, 02673 show_table_list->alias); 02674 close_tables_for_reopen(thd, &show_table_list); 02675 DBUG_ASSERT(!lex->query_tables_own_last); 02676 if (res) 02677 goto err; 02678 } 02679 } 02680 } 02681 /* 02682 If we have information schema its always the first table and only 02683 the first table. Reset for other tables. 02684 */ 02685 with_i_schema= 0; 02686 } 02687 } 02688 02689 error= 0; 02690 err: 02691 thd->restore_backup_open_tables_state(&open_tables_state_backup); 02692 lex->restore_backup_query_tables_list(&query_tables_list_backup); 02693 lex->derived_tables= derived_tables; 02694 lex->all_selects_list= old_all_select_lex; 02695 lex->view_prepare_mode= save_view_prepare_mode; 02696 lex->sql_command= save_sql_command; 02697 DBUG_RETURN(error); 02698 } 02699 02700 02701 bool store_schema_shemata(THD* thd, TABLE *table, const char *db_name, 02702 CHARSET_INFO *cs) 02703 { 02704 restore_record(table, s->default_values); 02705 table->field[1]->store(db_name, strlen(db_name), system_charset_info); 02706 table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info); 02707 table->field[3]->store(cs->name, strlen(cs->name), system_charset_info); 02708 return schema_table_store_record(thd, table); 02709 } 02710 02711 02712 int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) 02713 { 02714 /* 02715 TODO: fill_schema_shemata() is called when new client is connected. 02716 Returning error status in this case leads to client hangup. 02717 */ 02718 02719 INDEX_FIELD_VALUES idx_field_vals; 02720 List<char> files; 02721 char *file_name; 02722 uint length; 02723 bool with_i_schema; 02724 HA_CREATE_INFO create; 02725 TABLE *table= tables->table; 02726 Security_context *sctx= thd->security_ctx; 02727 DBUG_ENTER("fill_schema_shemata"); 02728 02729 if (make_db_list(thd, &files, &idx_field_vals, 02730 &with_i_schema, 1)) 02731 DBUG_RETURN(1); 02732 02733 List_iterator_fast<char> it(files); 02734 while ((file_name=it++)) 02735 { 02736 if (with_i_schema) // information schema name is always first in list 02737 { 02738 if (store_schema_shemata(thd, table, file_name, 02739 system_charset_info)) 02740 DBUG_RETURN(1); 02741 with_i_schema= 0; 02742 continue; 02743 } 02744 #ifndef NO_EMBEDDED_ACCESS_CHECKS 02745 if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || 02746 acl_get(sctx->host, sctx->ip, sctx->priv_user, file_name,0) || 02747 (grant_option && !check_grant_db(thd, file_name))) 02748 #endif 02749 { 02750 load_db_opt_by_name(thd, file_name, &create); 02751 02752 if (store_schema_shemata(thd, table, file_name, 02753 create.default_table_charset)) 02754 DBUG_RETURN(1); 02755 } 02756 } 02757 DBUG_RETURN(0); 02758 } 02759 02760 02761 static int get_schema_tables_record(THD *thd, struct st_table_list *tables, 02762 TABLE *table, bool res, 02763 const char *base_name, 02764 const char *file_name) 02765 { 02766 const char *tmp_buff; 02767 TIME time; 02768 CHARSET_INFO *cs= system_charset_info; 02769 DBUG_ENTER("get_schema_tables_record"); 02770 02771 restore_record(table, s->default_values); 02772 table->field[1]->store(base_name, strlen(base_name), cs); 02773 table->field[2]->store(file_name, strlen(file_name), cs); 02774 if (res) 02775 { 02776 /* 02777 there was errors during opening tables 02778 */ 02779 const char *error= thd->net.last_error; 02780 if (tables->view) 02781 table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); 02782 else if (tables->schema_table) 02783 table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); 02784 else 02785 table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs); 02786 table->field[20]->store(error, strlen(error), cs); 02787 thd->clear_error(); 02788 } 02789 else if (tables->view) 02790 { 02791 table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); 02792 table->field[20]->store(STRING_WITH_LEN("VIEW"), cs); 02793 } 02794 else 02795 { 02796 TABLE *show_table= tables->table; 02797 TABLE_SHARE *share= show_table->s; 02798 handler *file= show_table->file; 02799 02800 file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO | 02801 HA_STATUS_NO_LOCK); 02802 if (share->tmp_table == SYSTEM_TMP_TABLE) 02803 table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); 02804 else if (share->tmp_table) 02805 table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs); 02806 else 02807 table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs); 02808 02809 for (int i= 4; i < 20; i++) 02810 { 02811 if (i == 7 || (i > 12 && i < 17) || i == 18) 02812 continue; 02813 table->field[i]->set_notnull(); 02814 } 02815 tmp_buff= file->table_type(); 02816 table->field[4]->store(tmp_buff, strlen(tmp_buff), cs); 02817 table->field[5]->store((longlong) share->frm_version, TRUE); 02818 enum row_type row_type = file->get_row_type(); 02819 switch (row_type) { 02820 case ROW_TYPE_NOT_USED: 02821 case ROW_TYPE_DEFAULT: 02822 tmp_buff= ((share->db_options_in_use & 02823 HA_OPTION_COMPRESS_RECORD) ? "Compressed" : 02824 (share->db_options_in_use & HA_OPTION_PACK_RECORD) ? 02825 "Dynamic" : "Fixed"); 02826 break; 02827 case ROW_TYPE_FIXED: 02828 tmp_buff= "Fixed"; 02829 break; 02830 case ROW_TYPE_DYNAMIC: 02831 tmp_buff= "Dynamic"; 02832 break; 02833 case ROW_TYPE_COMPRESSED: 02834 tmp_buff= "Compressed"; 02835 break; 02836 case ROW_TYPE_REDUNDANT: 02837 tmp_buff= "Redundant"; 02838 break; 02839 case ROW_TYPE_COMPACT: 02840 tmp_buff= "Compact"; 02841 break; 02842 case ROW_TYPE_PAGES: 02843 tmp_buff= "Paged"; 02844 break; 02845 } 02846 table->field[6]->store(tmp_buff, strlen(tmp_buff), cs); 02847 if (!tables->schema_table) 02848 { 02849 table->field[7]->store((longlong) file->stats.records, TRUE); 02850 table->field[7]->set_notnull(); 02851 } 02852 table->field[8]->store((longlong) file->stats.mean_rec_length, TRUE); 02853 table->field[9]->store((longlong) file->stats.data_file_length, TRUE); 02854 if (file->stats.max_data_file_length) 02855 { 02856 table->field[10]->store((longlong) file->stats.max_data_file_length, 02857 TRUE); 02858 } 02859 table->field[11]->store((longlong) file->stats.index_file_length, TRUE); 02860 table->field[12]->store((longlong) file->stats.delete_length, TRUE); 02861 if (show_table->found_next_number_field) 02862 { 02863 table->field[13]->store((longlong) file->stats.auto_increment_value, 02864 TRUE); 02865 table->field[13]->set_notnull(); 02866 } 02867 if (file->stats.create_time) 02868 { 02869 thd->variables.time_zone->gmt_sec_to_TIME(&time, 02870 file->stats.create_time); 02871 table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); 02872 table->field[14]->set_notnull(); 02873 } 02874 if (file->stats.update_time) 02875 { 02876 thd->variables.time_zone->gmt_sec_to_TIME(&time, 02877 file->stats.update_time); 02878 table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); 02879 table->field[15]->set_notnull(); 02880 } 02881 if (file->stats.check_time) 02882 { 02883 thd->variables.time_zone->gmt_sec_to_TIME(&time, file->stats.check_time); 02884 table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); 02885 table->field[16]->set_notnull(); 02886 } 02887 tmp_buff= (share->table_charset ? 02888 share->table_charset->name : "default"); 02889 table->field[17]->store(tmp_buff, strlen(tmp_buff), cs); 02890 if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM) 02891 { 02892 table->field[18]->store((longlong) file->checksum(), TRUE); 02893 table->field[18]->set_notnull(); 02894 } 02895 02896 char option_buff[350],*ptr; 02897 ptr=option_buff; 02898 if (share->min_rows) 02899 { 02900 ptr=strmov(ptr," min_rows="); 02901 ptr=longlong10_to_str(share->min_rows,ptr,10); 02902 } 02903 if (share->max_rows) 02904 { 02905 ptr=strmov(ptr," max_rows="); 02906 ptr=longlong10_to_str(share->max_rows,ptr,10); 02907 } 02908 if (share->avg_row_length) 02909 { 02910 ptr=strmov(ptr," avg_row_length="); 02911 ptr=longlong10_to_str(share->avg_row_length,ptr,10); 02912 } 02913 if (share->db_create_options & HA_OPTION_PACK_KEYS) 02914 ptr=strmov(ptr," pack_keys=1"); 02915 if (share->db_create_options & HA_OPTION_NO_PACK_KEYS) 02916 ptr=strmov(ptr," pack_keys=0"); 02917 if (share->db_create_options & HA_OPTION_CHECKSUM) 02918 ptr=strmov(ptr," checksum=1"); 02919 if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) 02920 ptr=strmov(ptr," delay_key_write=1"); 02921 if (share->row_type != ROW_TYPE_DEFAULT) 02922 ptr=strxmov(ptr, " row_format=", 02923 ha_row_type[(uint) share->row_type], 02924 NullS); 02925 #ifdef WITH_PARTITION_STORAGE_ENGINE 02926 if (show_table->s->db_type == &partition_hton && 02927 show_table->part_info != NULL && 02928 show_table->part_info->no_parts > 0) 02929 ptr= strmov(ptr, " partitioned"); 02930 #endif 02931 table->field[19]->store(option_buff+1, 02932 (ptr == option_buff ? 0 : 02933 (uint) (ptr-option_buff)-1), cs); 02934 { 02935 char *comment; 02936 comment= show_table->file->update_table_comment(share->comment.str); 02937 if (comment) 02938 { 02939 table->field[20]->store(comment, 02940 (comment == share->comment.str ? 02941 share->comment.length : 02942 strlen(comment)), cs); 02943 if (comment != share->comment.str) 02944 my_free(comment, MYF(0)); 02945 } 02946 } 02947 } 02948 DBUG_RETURN(schema_table_store_record(thd, table)); 02949 } 02950 02951 02952 static int get_schema_column_record(THD *thd, struct st_table_list *tables, 02953 TABLE *table, bool res, 02954 const char *base_name, 02955 const char *file_name) 02956 { 02957 LEX *lex= thd->lex; 02958 const char *wild= lex->wild ? lex->wild->ptr() : NullS; 02959 CHARSET_INFO *cs= system_charset_info; 02960 TABLE *show_table; 02961 handler *file; 02962 Field **ptr,*field; 02963 int count; 02964 uint base_name_length, file_name_length; 02965 DBUG_ENTER("get_schema_column_record"); 02966 02967 if (res) 02968 { 02969 if (lex->sql_command != SQLCOM_SHOW_FIELDS) 02970 { 02971 /* 02972 I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS 02973 rather than in SHOW COLUMNS 02974 */ 02975 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 02976 thd->net.last_errno, thd->net.last_error); 02977 thd->clear_error(); 02978 res= 0; 02979 } 02980 DBUG_RETURN(res); 02981 } 02982 02983 show_table= tables->table; 02984 file= show_table->file; 02985 count= 0; 02986 file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); 02987 restore_record(show_table, s->default_values); 02988 base_name_length= strlen(base_name); 02989 file_name_length= strlen(file_name); 02990 show_table->use_all_columns(); // Required for default 02991 02992 for (ptr=show_table->field; (field= *ptr) ; ptr++) 02993 { 02994 const char *tmp_buff; 02995 byte *pos; 02996 bool is_blob; 02997 uint flags=field->flags; 02998 char tmp[MAX_FIELD_WIDTH]; 02999 char tmp1[MAX_FIELD_WIDTH]; 03000 String type(tmp,sizeof(tmp), system_charset_info); 03001 char *end; 03002 int decimals, field_length; 03003 03004 if (wild && wild[0] && 03005 wild_case_compare(system_charset_info, field->field_name,wild)) 03006 continue; 03007 03008 flags= field->flags; 03009 count++; 03010 /* Get default row, with all NULL fields set to NULL */ 03011 restore_record(table, s->default_values); 03012 03013 #ifndef NO_EMBEDDED_ACCESS_CHECKS 03014 uint col_access; 03015 check_access(thd,SELECT_ACL | EXTRA_ACL, base_name, 03016 &tables->grant.privilege, 0, 0, test(tables->schema_table)); 03017 col_access= get_column_grant(thd, &tables->grant, 03018 base_name, file_name, 03019 field->field_name) & COL_ACLS; 03020 if (lex->sql_command != SQLCOM_SHOW_FIELDS && 03021 !tables->schema_table && !col_access) 03022 continue; 03023 end= tmp; 03024 for (uint bitnr=0; col_access ; col_access>>=1,bitnr++) 03025 { 03026 if (col_access & 1) 03027 { 03028 *end++=','; 03029 end=strmov(end,grant_types.type_names[bitnr]); 03030 } 03031 } 03032 table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs); 03033 03034 #endif 03035 table->field[1]->store(base_name, base_name_length, cs); 03036 table->field[2]->store(file_name, file_name_length, cs); 03037 table->field[3]->store(field->field_name, strlen(field->field_name), 03038 cs); 03039 table->field[4]->store((longlong) count, TRUE); 03040 field->sql_type(type); 03041 table->field[14]->store(type.ptr(), type.length(), cs); 03042 tmp_buff= strchr(type.ptr(), '('); 03043 table->field[7]->store(type.ptr(), 03044 (tmp_buff ? tmp_buff - type.ptr() : 03045 type.length()), cs); 03046 if (show_table->timestamp_field == field && 03047 field->unireg_check != Field::TIMESTAMP_UN_FIELD) 03048 { 03049 table->field[5]->store(STRING_WITH_LEN("CURRENT_TIMESTAMP"), cs); 03050 table->field[5]->set_notnull(); 03051 } 03052 else if (field->unireg_check != Field::NEXT_NUMBER && 03053 !field->is_null() && 03054 !(field->flags & NO_DEFAULT_VALUE_FLAG)) 03055 { 03056 String def(tmp1,sizeof(tmp1), cs); 03057 type.set(tmp, sizeof(tmp), field->charset()); 03058 field->val_str(&type); 03059 uint dummy_errors; 03060 def.copy(type.ptr(), type.length(), type.charset(), cs, &dummy_errors); 03061 table->field[5]->store(def.ptr(), def.length(), def.charset()); 03062 table->field[5]->set_notnull(); 03063 } 03064 else if (field->unireg_check == Field::NEXT_NUMBER || 03065 lex->sql_command != SQLCOM_SHOW_FIELDS || 03066 field->maybe_null()) 03067 table->field[5]->set_null(); // Null as default 03068 else 03069 { 03070 table->field[5]->store("",0, cs); 03071 table->field[5]->set_notnull(); 03072 } 03073 pos=(byte*) ((flags & NOT_NULL_FLAG) ? "NO" : "YES"); 03074 table->field[6]->store((const char*) pos, 03075 strlen((const char*) pos), cs); 03076 is_blob= (field->type() == FIELD_TYPE_BLOB); 03077 if (field->has_charset() || is_blob || 03078 field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type 03079 field->real_type() == MYSQL_TYPE_STRING) // For binary type 03080 { 03081 uint32 octet_max_length= field->max_length(); 03082 if (is_blob && octet_max_length != (uint32) 4294967295U) 03083 octet_max_length /= field->charset()->mbmaxlen; 03084 longlong char_max_len= is_blob ? 03085 (longlong) octet_max_length / field->charset()->mbminlen : 03086 (longlong) octet_max_length / field->charset()->mbmaxlen; 03087 table->field[8]->store(char_max_len, TRUE); 03088 table->field[8]->set_notnull(); 03089 table->field[9]->store((longlong) octet_max_length, TRUE); 03090 table->field[9]->set_notnull(); 03091 } 03092 03093 /* 03094 Calculate field_length and decimals. 03095 They are set to -1 if they should not be set (we should return NULL) 03096 */ 03097 03098 decimals= field->decimals(); 03099 switch (field->type()) { 03100 case FIELD_TYPE_NEWDECIMAL: 03101 field_length= ((Field_new_decimal*) field)->precision; 03102 break; 03103 case FIELD_TYPE_DECIMAL: 03104 field_length= field->field_length - (decimals ? 2 : 1); 03105 break; 03106 case FIELD_TYPE_TINY: 03107 case FIELD_TYPE_SHORT: 03108 case FIELD_TYPE_LONG: 03109 case FIELD_TYPE_LONGLONG: 03110 case FIELD_TYPE_INT24: 03111 field_length= field->max_length() - 1; 03112 break; 03113 case FIELD_TYPE_BIT: 03114 field_length= field->max_length(); 03115 decimals= -1; // return NULL 03116 break; 03117 case FIELD_TYPE_FLOAT: 03118 case FIELD_TYPE_DOUBLE: 03119 field_length= field->field_length; 03120 if (decimals == NOT_FIXED_DEC) 03121 decimals= -1; // return NULL 03122 break; 03123 default: 03124 field_length= decimals= -1; 03125 break; 03126 } 03127 03128 if (field_length >= 0) 03129 { 03130 table->field[10]->store((longlong) field_length, TRUE); 03131 table->field[10]->set_notnull(); 03132 } 03133 if (decimals >= 0) 03134 { 03135 table->field[11]->store((longlong) decimals, TRUE); 03136 table->field[11]->set_notnull(); 03137 } 03138 03139 if (field->has_charset()) 03140 { 03141 pos=(byte*) field->charset()->csname; 03142 table->field[12]->store((const char*) pos, 03143 strlen((const char*) pos), cs); 03144 table->field[12]->set_notnull(); 03145 pos=(byte*) field->charset()->name; 03146 table->field[13]->store((const char*) pos, 03147 strlen((const char*) pos), cs); 03148 table->field[13]->set_notnull(); 03149 } 03150 pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" : 03151 (field->flags & UNIQUE_KEY_FLAG) ? "UNI" : 03152 (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":""); 03153 table->field[15]->store((const char*) pos, 03154 strlen((const char*) pos), cs); 03155 03156 end= tmp; 03157 if (field->unireg_check == Field::NEXT_NUMBER) 03158 end=strmov(tmp,"auto_increment"); 03159 table->field[16]->store(tmp, (uint) (end-tmp), cs); 03160 03161 table->field[18]->store(field->comment.str, field->comment.length, cs); 03162 if (schema_table_store_record(thd, table)) 03163 DBUG_RETURN(1); 03164 } 03165 DBUG_RETURN(0); 03166 } 03167 03168 03169 03170 int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) 03171 { 03172 CHARSET_INFO **cs; 03173 const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; 03174 TABLE *table= tables->table; 03175 CHARSET_INFO *scs= system_charset_info; 03176 03177 for (cs= all_charsets ; cs < all_charsets+255 ; cs++) 03178 { 03179 CHARSET_INFO *tmp_cs= cs[0]; 03180 if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && 03181 (tmp_cs->state & MY_CS_AVAILABLE) && 03182 !(tmp_cs->state & MY_CS_HIDDEN) && 03183 !(wild && wild[0] && 03184 wild_case_compare(scs, tmp_cs->csname,wild))) 03185 { 03186 const char *comment; 03187 restore_record(table, s->default_values); 03188 table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs); 03189 table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs); 03190 comment= tmp_cs->comment ? tmp_cs->comment : ""; 03191 table->field[2]->store(comment, strlen(comment), scs); 03192 table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE); 03193 if (schema_table_store_record(thd, table)) 03194 return 1; 03195 } 03196 } 03197 return 0; 03198 } 03199 03200 03201 static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin, 03202 void *ptable) 03203 { 03204 TABLE *table= (TABLE *) ptable; 03205 handlerton *hton= (handlerton *)plugin->data; 03206 const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; 03207 CHARSET_INFO *scs= system_charset_info; 03208 DBUG_ENTER("iter_schema_engines"); 03209 03210 if (!(hton->flags & HTON_HIDDEN)) 03211 { 03212 if (!(wild && wild[0] && 03213 wild_case_compare(scs, plugin->name.str,wild))) 03214 { 03215 LEX_STRING state[2]= {{ C_STRING_WITH_LEN("ENABLED") }, 03216 { C_STRING_WITH_LEN("DISABLED") }}; 03217 LEX_STRING yesno[2]= {{ C_STRING_WITH_LEN("NO") }, 03218 { C_STRING_WITH_LEN("YES") }}; 03219 LEX_STRING *tmp; 03220 restore_record(table, s->default_values); 03221 03222 table->field[0]->store(plugin->name.str, plugin->name.length, scs); 03223 tmp= &state[test(hton->state)]; 03224 table->field[1]->store(tmp->str, tmp->length, scs); 03225 table->field[2]->store(plugin->plugin->descr, 03226 strlen(plugin->plugin->descr), scs); 03227 tmp= &yesno[test(hton->commit)]; 03228 table->field[3]->store(tmp->str, tmp->length, scs); 03229 tmp= &yesno[test(hton->prepare)]; 03230 table->field[4]->store(tmp->str, tmp->length, scs); 03231 tmp= &yesno[test(hton->savepoint_set)]; 03232 table->field[5]->store(tmp->str, tmp->length, scs); 03233 03234 if (schema_table_store_record(thd, table)) 03235 DBUG_RETURN(1); 03236 } 03237 } 03238 DBUG_RETURN(0); 03239 } 03240 03241 03242 int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond) 03243 { 03244 return plugin_foreach(thd, iter_schema_engines, 03245 MYSQL_STORAGE_ENGINE_PLUGIN, tables->table); 03246 } 03247 03248 03249 int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) 03250 { 03251 CHARSET_INFO **cs; 03252 const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; 03253 TABLE *table= tables->table; 03254 CHARSET_INFO *scs= system_charset_info; 03255 for (cs= all_charsets ; cs < all_charsets+255 ; cs++ ) 03256 { 03257 CHARSET_INFO **cl; 03258 CHARSET_INFO *tmp_cs= cs[0]; 03259 if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || 03260 (tmp_cs->state & MY_CS_HIDDEN) || 03261 !(tmp_cs->state & MY_CS_PRIMARY)) 03262 continue; 03263 for (cl= all_charsets; cl < all_charsets+255 ;cl ++) 03264 { 03265 CHARSET_INFO *tmp_cl= cl[0]; 03266 if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || 03267 !my_charset_same(tmp_cs, tmp_cl)) 03268 continue; 03269 if (!(wild && wild[0] && 03270 wild_case_compare(scs, tmp_cl->name,wild))) 03271 { 03272 const char *tmp_buff; 03273 restore_record(table, s->default_values); 03274 table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs); 03275 table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs); 03276 table->field[2]->store((longlong) tmp_cl->number, TRUE); 03277 tmp_buff= (tmp_cl->state & MY_CS_PRIMARY) ? "Yes" : ""; 03278 table->field[3]->store(tmp_buff, strlen(tmp_buff), scs); 03279 tmp_buff= (tmp_cl->state & MY_CS_COMPILED)? "Yes" : ""; 03280 table->field[4]->store(tmp_buff, strlen(tmp_buff), scs); 03281 table->field[5]->store((longlong) tmp_cl->strxfrm_multiply, TRUE); 03282 if (schema_table_store_record(thd, table)) 03283 return 1; 03284 } 03285 } 03286 } 03287 return 0; 03288 } 03289 03290 03291 int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond) 03292 { 03293 CHARSET_INFO **cs; 03294 TABLE *table= tables->table; 03295 CHARSET_INFO *scs= system_charset_info; 03296 for (cs= all_charsets ; cs < all_charsets+255 ; cs++ ) 03297 { 03298 CHARSET_INFO **cl; 03299 CHARSET_INFO *tmp_cs= cs[0]; 03300 if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || 03301 !(tmp_cs->state & MY_CS_PRIMARY)) 03302 continue; 03303 for (cl= all_charsets; cl < all_charsets+255 ;cl ++) 03304 { 03305 CHARSET_INFO *tmp_cl= cl[0]; 03306 if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || 03307 !my_charset_same(tmp_cs,tmp_cl)) 03308 continue; 03309 restore_record(table, s->default_values); 03310 table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs); 03311 table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs); 03312 if (schema_table_store_record(thd, table)) 03313 return 1; 03314 } 03315 } 03316 return 0; 03317 } 03318 03319 03320 bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, 03321 const char *wild, bool full_access, const char *sp_user) 03322 { 03323 String tmp_string; 03324 String sp_db, sp_name, definer; 03325 TIME time; 03326 LEX *lex= thd->lex; 03327 CHARSET_INFO *cs= system_charset_info; 03328 get_field(thd->mem_root, proc_table->field[0], &sp_db); 03329 get_field(thd->mem_root, proc_table->field[1], &sp_name); 03330 get_field(thd->mem_root, proc_table->field[11], &definer); 03331 if (!full_access) 03332 full_access= !strcmp(sp_user, definer.ptr()); 03333 if (!full_access && check_some_routine_access(thd, sp_db.ptr(), 03334 sp_name.ptr(), 03335 proc_table->field[2]-> 03336 val_int() == 03337 TYPE_ENUM_PROCEDURE)) 03338 return 0; 03339 03340 if (lex->sql_command == SQLCOM_SHOW_STATUS_PROC && 03341 proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE || 03342 lex->sql_command == SQLCOM_SHOW_STATUS_FUNC && 03343 proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION || 03344 (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0) 03345 { 03346 restore_record(table, s->default_values); 03347 if (!wild || !wild[0] || !wild_compare(sp_name.ptr(), wild, 0)) 03348 { 03349 int enum_idx= proc_table->field[5]->val_int(); 03350 table->field[3]->store(sp_name.ptr(), sp_name.length(), cs); 03351 get_field(thd->mem_root, proc_table->field[3], &tmp_string); 03352 table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs); 03353 table->field[2]->store(sp_db.ptr(), sp_db.length(), cs); 03354 get_field(thd->mem_root, proc_table->field[2], &tmp_string); 03355 table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs); 03356 if (proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION) 03357 { 03358 get_field(thd->mem_root, proc_table->field[9], &tmp_string); 03359 table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs); 03360 table->field[5]->set_notnull(); 03361 } 03362 if (full_access) 03363 { 03364 get_field(thd->mem_root, proc_table->field[10], &tmp_string); 03365 table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs); 03366 table->field[7]->set_notnull(); 03367 } 03368 table->field[6]->store(STRING_WITH_LEN("SQL"), cs); 03369 table->field[10]->store(STRING_WITH_LEN("SQL"), cs); 03370 get_field(thd->mem_root, proc_table->field[6], &tmp_string); 03371 table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs); 03372 table->field[12]->store(sp_data_access_name[enum_idx].str, 03373 sp_data_access_name[enum_idx].length , cs); 03374 get_field(thd->mem_root, proc_table->field[7], &tmp_string); 03375 table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs); 03376 bzero((char *)&time, sizeof(time)); 03377 ((Field_timestamp *) proc_table->field[12])->get_time(&time); 03378 table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); 03379 bzero((char *)&time, sizeof(time)); 03380 ((Field_timestamp *) proc_table->field[13])->get_time(&time); 03381 table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); 03382 get_field(thd->mem_root, proc_table->field[14], &tmp_string); 03383 table->field[17]->store(tmp_string.ptr(), tmp_string.length(), cs); 03384 get_field(thd->mem_root, proc_table->field[15], &tmp_string); 03385 table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs); 03386 table->field[19]->store(definer.ptr(), definer.length(), cs); 03387 return schema_table_store_record(thd, table); 03388 } 03389 } 03390 return 0; 03391 } 03392 03393 03394 int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) 03395 { 03396 TABLE *proc_table; 03397 TABLE_LIST proc_tables; 03398 const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; 03399 int res= 0; 03400 TABLE *table= tables->table; 03401 bool full_access; 03402 char definer[USER_HOST_BUFF_SIZE]; 03403 Open_tables_state open_tables_state_backup; 03404 DBUG_ENTER("fill_schema_proc"); 03405 03406 strxmov(definer, thd->security_ctx->priv_user, "@", 03407 thd->security_ctx->priv_host, NullS); 03408 /* We use this TABLE_LIST instance only for checking of privileges. */ 03409 bzero((char*) &proc_tables,sizeof(proc_tables)); 03410 proc_tables.db= (char*) "mysql"; 03411 proc_tables.db_length= 5; 03412 proc_tables.table_name= proc_tables.alias= (char*) "proc"; 03413 proc_tables.table_name_length= 4; 03414 proc_tables.lock_type= TL_READ; 03415 full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1); 03416 if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup))) 03417 { 03418 DBUG_RETURN(1); 03419 } 03420 proc_table->file->ha_index_init(0, 1); 03421 if ((res= proc_table->file->index_first(proc_table->record[0]))) 03422 { 03423 res= (res == HA_ERR_END_OF_FILE) ? 0 : 1; 03424 goto err; 03425 } 03426 if (store_schema_proc(thd, table, proc_table, wild, full_access, definer)) 03427 { 03428 res= 1; 03429 goto err; 03430 } 03431 while (!proc_table->file->index_next(proc_table->record[0])) 03432 { 03433 if (store_schema_proc(thd, table, proc_table, wild, full_access, definer)) 03434 { 03435 res= 1; 03436 goto err; 03437 } 03438 } 03439 03440 err: 03441 proc_table->file->ha_index_end(); 03442 close_proc_table(thd, &open_tables_state_backup); 03443 DBUG_RETURN(res); 03444 } 03445 03446 03447 static int get_schema_stat_record(THD *thd, struct st_table_list *tables, 03448 TABLE *table, bool res, 03449 const char *base_name, 03450 const char *file_name) 03451 { 03452 CHARSET_INFO *cs= system_charset_info; 03453 DBUG_ENTER("get_schema_stat_record"); 03454 if (res) 03455 { 03456 if (thd->lex->sql_command != SQLCOM_SHOW_KEYS) 03457 { 03458 /* 03459 I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS 03460 rather than in SHOW KEYS 03461 */ 03462 if (!tables->view) 03463 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 03464 thd->net.last_errno, thd->net.last_error); 03465 thd->clear_error(); 03466 res= 0; 03467 } 03468 DBUG_RETURN(res); 03469 } 03470 else if (!tables->view) 03471 { 03472 TABLE *show_table= tables->table; 03473 KEY *key_info=show_table->key_info; 03474 show_table->file->info(HA_STATUS_VARIABLE | 03475 HA_STATUS_NO_LOCK | 03476 HA_STATUS_TIME); 03477 for (uint i=0 ; i < show_table->s->keys ; i++,key_info++) 03478 { 03479 KEY_PART_INFO *key_part= key_info->key_part; 03480 const char *str; 03481 for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) 03482 { 03483 restore_record(table, s->default_values); 03484 table->field[1]->store(base_name, strlen(base_name), cs); 03485 table->field[2]->store(file_name, strlen(file_name), cs); 03486 table->field[3]->store((longlong) ((key_info->flags & 03487 HA_NOSAME) ? 0 : 1), TRUE); 03488 table->field[4]->store(base_name, strlen(base_name), cs); 03489 table->field[5]->store(key_info->name, strlen(key_info->name), cs); 03490 table->field[6]->store((longlong) (j+1), TRUE); 03491 str=(key_part->field ? key_part->field->field_name : 03492 "?unknown field?"); 03493 table->field[7]->store(str,

