diff options
Diffstat (limited to 'sql/sql_show.cc')
| -rw-r--r-- | sql/sql_show.cc | 2084 |
1 files changed, 1379 insertions, 705 deletions
diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e074461b452..6b24e3db7bc 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -9,28 +9,48 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Function with list databases, tables or fields */ -#include "mysql_priv.h" +#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "sql_priv.h" +#include "unireg.h" +#include "sql_acl.h" // fill_schema_*_privileges #include "sql_select.h" // For select_describe +#include "sql_base.h" // close_tables_for_reopen #include "sql_show.h" +#include "sql_table.h" // filename_to_tablename, + // primary_key_name, + // build_table_filename #include "repl_failsafe.h" +#include "sql_parse.h" // check_access, check_table_access +#include "sql_partition.h" // partition_element +#include "sql_db.h" // check_db_dir_existence, load_db_opt_by_name +#include "sql_time.h" // interval_type_to_name +#include "tztime.h" // struct Time_zone +#include "sql_acl.h" // TABLE_ACLS, check_grant, DB_ACLS, acl_get, + // check_grant_db +#include "filesort.h" // filesort_free_buffers #include "sp.h" #include "sp_head.h" +#include "sp_pcontext.h" +#include "set_var.h" #include "sql_trigger.h" #include "authors.h" #include "contributors.h" +#include "sql_partition.h" #ifdef HAVE_EVENT_SCHEDULER #include "events.h" #include "event_data_objects.h" #endif #include <my_dir.h> +#include "lock.h" // MYSQL_OPEN_IGNORE_FLUSH #include "debug_sync.h" +#include "datadict.h" // dd_frm_type() #define STR_OR_NIL(S) ((S) ? (S) : "<nil>") @@ -78,6 +98,12 @@ static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **), static void store_key_options(THD *thd, String *packet, TABLE *table, KEY *key_info); +static void get_cs_converted_string_value(THD *thd, + String *input_str, + String *output_str, + CHARSET_INFO *cs, + bool use_hex); + static void append_algorithm(TABLE_LIST *table, String *buff); @@ -217,7 +243,7 @@ bool mysqld_show_authors(THD *thd) field_list.push_back(new Item_empty_string("Location",40)); field_list.push_back(new Item_empty_string("Comment",80)); - if (protocol->send_fields(&field_list, + if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); @@ -251,7 +277,7 @@ bool mysqld_show_contributors(THD *thd) field_list.push_back(new Item_empty_string("Location",40)); field_list.push_back(new Item_empty_string("Comment",80)); - if (protocol->send_fields(&field_list, + if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); @@ -311,6 +337,7 @@ static struct show_privileges_st sys_privileges[]= {"Shutdown","Server Admin", "To shut down the server"}, {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."}, {"Trigger","Tables", "To use triggers"}, + {"Create tablespace", "Server Admin", "To create/alter/drop tablespaces"}, {"Update", "Tables", "To update existing rows"}, {"Usage","Server Admin","No privileges - allow connect only"}, {NullS, NullS, NullS} @@ -326,7 +353,7 @@ bool mysqld_show_privileges(THD *thd) field_list.push_back(new Item_empty_string("Context",15)); field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN)); - if (protocol->send_fields(&field_list, + if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); @@ -345,94 +372,6 @@ bool mysqld_show_privileges(THD *thd) } -/*************************************************************************** - List all column types -***************************************************************************/ - -struct show_column_type_st -{ - const char *type; - uint size; - const char *min_value; - const char *max_value; - uint precision; - uint scale; - const char *nullable; - const char *auto_increment; - const char *unsigned_attr; - const char *zerofill; - const char *searchable; - const char *case_sensitivity; - const char *default_value; - const char *comment; -}; - -/* TODO: Add remaning types */ - -static struct show_column_type_st sys_column_types[]= -{ - {"tinyint", - 1, "-128", "127", 0, 0, "YES", "YES", - "NO", "YES", "YES", "NO", "NULL,0", - "A very small integer"}, - {"tinyint unsigned", - 1, "0" , "255", 0, 0, "YES", "YES", - "YES", "YES", "YES", "NO", "NULL,0", - "A very small integer"}, -}; - -bool mysqld_show_column_types(THD *thd) -{ - List<Item> field_list; - Protocol *protocol= thd->protocol; - DBUG_ENTER("mysqld_show_column_types"); - - field_list.push_back(new Item_empty_string("Type",30)); - field_list.push_back(new Item_int("Size",(longlong) 1, - MY_INT64_NUM_DECIMAL_DIGITS)); - field_list.push_back(new Item_empty_string("Min_Value",20)); - field_list.push_back(new Item_empty_string("Max_Value",20)); - field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT)); - field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT)); - field_list.push_back(new Item_empty_string("Nullable",4)); - field_list.push_back(new Item_empty_string("Auto_Increment",4)); - field_list.push_back(new Item_empty_string("Unsigned",4)); - field_list.push_back(new Item_empty_string("Zerofill",4)); - field_list.push_back(new Item_empty_string("Searchable",4)); - field_list.push_back(new Item_empty_string("Case_Sensitive",4)); - field_list.push_back(new Item_empty_string("Default",NAME_CHAR_LEN)); - field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN)); - - if (protocol->send_fields(&field_list, - Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - DBUG_RETURN(TRUE); - - /* TODO: Change the loop to not use 'i' */ - for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++) - { - protocol->prepare_for_resend(); - protocol->store(sys_column_types[i].type, system_charset_info); - protocol->store((ulonglong) sys_column_types[i].size); - protocol->store(sys_column_types[i].min_value, system_charset_info); - protocol->store(sys_column_types[i].max_value, system_charset_info); - protocol->store_short((longlong) sys_column_types[i].precision); - protocol->store_short((longlong) sys_column_types[i].scale); - protocol->store(sys_column_types[i].nullable, system_charset_info); - protocol->store(sys_column_types[i].auto_increment, system_charset_info); - protocol->store(sys_column_types[i].unsigned_attr, system_charset_info); - protocol->store(sys_column_types[i].zerofill, system_charset_info); - protocol->store(sys_column_types[i].searchable, system_charset_info); - protocol->store(sys_column_types[i].case_sensitivity, system_charset_info); - protocol->store(sys_column_types[i].default_value, system_charset_info); - protocol->store(sys_column_types[i].comment, system_charset_info); - if (protocol->write()) - DBUG_RETURN(TRUE); - } - my_eof(thd); - DBUG_RETURN(FALSE); -} - - /* find_files() - find files in a given directory. @@ -513,7 +452,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, end= strend(buff); if (end != buff && end[-1] == FN_LIBCHAR) end[-1]= 0; // Remove end FN_LIBCHAR - if (!my_stat(buff, file->mystat, MYF(0))) + if (!mysql_file_stat(key_file_misc, buff, file->mystat, MYF(0))) continue; } #endif @@ -572,7 +511,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, table_list.table_name= uname; table_list.table_name_length= file_name_len; table_list.grant.privilege=col_access; - if (check_grant(thd, TABLE_ACLS, &table_list, 1, 1, 1)) + if (check_grant(thd, TABLE_ACLS, &table_list, TRUE, 1, TRUE)) continue; } #endif @@ -587,7 +526,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, DBUG_PRINT("info",("found: %d files", files->elements)); my_dirend(dirp); - VOID(ha_find_files(thd, db, path, wild, dir, files)); + (void) ha_find_files(thd, db, path, wild, dir, files); DBUG_RETURN(FIND_FILES_OK); } @@ -656,8 +595,10 @@ public: return m_view_access_denied_message_ptr; } - bool handle_error(uint sql_errno, const char *message, - MYSQL_ERROR::enum_warning_level level, THD *thd) { + bool handle_condition(THD *thd, uint sql_errno, const char */* sqlstate */, + MYSQL_ERROR::enum_warning_level level, + const char *message, MYSQL_ERROR **/* cond_hdl */) + { /* The handler does not handle the errors raised by itself. At this point we know if top_view is really a view. @@ -719,20 +660,30 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) Protocol *protocol= thd->protocol; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); + List<Item> field_list; + bool error= TRUE; DBUG_ENTER("mysqld_show_create"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->table_name)); + /* + Metadata locks taken during SHOW CREATE should be released when + the statmement completes as it is an information statement. + */ + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); + /* We want to preserve the tree for views. */ thd->lex->view_prepare_mode= TRUE; { Show_create_error_handler view_error_suppressor(thd, table_list); thd->push_internal_handler(&view_error_suppressor); - bool error= open_normal_and_derived_tables(thd, table_list, 0); + bool open_error= + open_normal_and_derived_tables(thd, table_list, + MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL); thd->pop_internal_handler(); - if (error && (thd->killed || thd->main_da.is_error())) - DBUG_RETURN(TRUE); + if (open_error && (thd->killed || thd->is_error())) + goto exit; } /* TODO: add environment variables show when it become possible */ @@ -740,7 +691,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) { my_error(ER_WRONG_OBJECT, MYF(0), table_list->db, table_list->table_name, "VIEW"); - DBUG_RETURN(TRUE); + goto exit; } buffer.length(0); @@ -752,9 +703,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) view_store_create_info(thd, table_list, &buffer) : store_create_info(thd, table_list, &buffer, NULL, FALSE /* show_database */))) - DBUG_RETURN(TRUE); + goto exit; - List<Item> field_list; if (table_list->view) { field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN)); @@ -773,9 +723,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) max(buffer.length(),1024))); } - if (protocol->send_fields(&field_list, + if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - DBUG_RETURN(TRUE); + goto exit; + protocol->prepare_for_resend(); if (table_list->view) protocol->store(table_list->view_name.str, system_charset_info); @@ -803,10 +754,16 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); if (protocol->write()) - DBUG_RETURN(TRUE); + goto exit; + error= FALSE; my_eof(thd); - DBUG_RETURN(FALSE); + +exit: + close_thread_tables(thd); + /* Release any metadata locks taken during SHOW CREATE. */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + DBUG_RETURN(error); } bool mysqld_show_create_db(THD *thd, char *dbname, @@ -838,7 +795,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname, DBUG_RETURN(TRUE); } #endif - if (is_schema_db(dbname)) + if (is_infoschema_db(dbname)) { dbname= INFORMATION_SCHEMA_NAME.str; create.default_table_charset= system_charset_info; @@ -857,7 +814,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname, field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN)); field_list.push_back(new Item_empty_string("Create Database",1024)); - if (protocol->send_fields(&field_list, + if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); @@ -903,7 +860,8 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) DBUG_ENTER("mysqld_list_fields"); DBUG_PRINT("enter",("table: %s",table_list->table_name)); - if (open_normal_and_derived_tables(thd, table_list, 0)) + if (open_normal_and_derived_tables(thd, table_list, + MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)) DBUG_VOID_RETURN; table= table_list->table; @@ -925,41 +883,12 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) } restore_record(table, s->default_values); // Get empty record table->use_all_columns(); - if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS)) + if (thd->protocol->send_result_set_metadata(&field_list, Protocol::SEND_DEFAULTS)) DBUG_VOID_RETURN; my_eof(thd); DBUG_VOID_RETURN; } - -int -mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd) -{ - Protocol *protocol= thd->protocol; - String *packet= protocol->storage_packet(); - DBUG_ENTER("mysqld_dump_create_info"); - DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name.str)); - - protocol->prepare_for_resend(); - if (store_create_info(thd, table_list, packet, NULL, - FALSE /* show_database */)) - DBUG_RETURN(-1); - - if (fd < 0) - { - if (protocol->write()) - DBUG_RETURN(-1); - protocol->flush(); - } - else - { - if (my_write(fd, (const uchar*) packet->ptr(), packet->length(), - MYF(MY_WME))) - DBUG_RETURN(-1); - } - DBUG_RETURN(0); -} - /* Go through all character combinations and ensure that sql_lex.cc can parse it as an identifier. @@ -1025,7 +954,7 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) it's a keyword */ - VOID(packet->reserve(length*2 + 2)); + (void) packet->reserve(length*2 + 2); quote_char= (char) q; packet->append("e_char, 1, system_charset_info); @@ -1078,7 +1007,7 @@ int get_quote_char_for_identifier(THD *thd, const char *name, uint length) if (length && !is_keyword(name,length) && !require_quotes(name, length) && - !(thd->options & OPTION_QUOTE_SHOW_CREATE)) + !(thd->variables.option_bits & OPTION_QUOTE_SHOW_CREATE)) return EOF; if (thd->variables.sql_mode & MODE_ANSI_QUOTES) return '"'; @@ -1116,20 +1045,21 @@ static void append_directory(THD *thd, String *packet, const char *dir_type, #define LIST_PROCESS_HOST_LEN 64 -static bool get_field_default_value(THD *thd, TABLE *table, +static bool get_field_default_value(THD *thd, Field *timestamp_field, Field *field, String *def_value, bool quoted) { bool has_default; bool has_now_default; enum enum_field_types field_type= field->type(); - /* + + /* We are using CURRENT_TIMESTAMP instead of NOW because it is more standard */ - has_now_default= table->timestamp_field == field && - field->unireg_check != Field::TIMESTAMP_UN_FIELD; - + has_now_default= (timestamp_field == field && + field->unireg_check != Field::TIMESTAMP_UN_FIELD); + has_default= (field_type != FIELD_TYPE_BLOB && !(field->flags & NO_DEFAULT_VALUE_FLAG) && field->unireg_check != Field::NEXT_NUMBER && @@ -1182,6 +1112,7 @@ static bool get_field_default_value(THD *thd, TABLE *table, return has_default; } + /* Build a CREATE TABLE statement for a table. @@ -1331,7 +1262,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(" NULL")); } - if (get_field_default_value(thd, table, field, &def_value, 1)) + if (get_field_default_value(thd, table->timestamp_field, + field, &def_value, 1)) { packet->append(STRING_WITH_LEN(" DEFAULT ")); packet->append(def_value.ptr(), def_value.length(), system_charset_info); @@ -1446,7 +1378,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(" /*!50100 TABLESPACE ")); packet->append(for_str, strlen(for_str)); packet->append(STRING_WITH_LEN(" STORAGE DISK */")); - my_free(for_str, MYF(0)); + my_free(for_str); } /* @@ -1489,7 +1421,6 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, end= longlong10_to_str(create_info.auto_increment_value, buff,10); packet->append(buff, (uint) (end - buff)); } - if (share->table_charset && !(thd->variables.sql_mode & MODE_MYSQL323) && @@ -1583,12 +1514,13 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, ((part_syntax= generate_partition_syntax(table->part_info, &part_syntax_len, FALSE, - show_table_options)))) + show_table_options, + NULL, NULL)))) { - packet->append(STRING_WITH_LEN("\n/*!50100")); + table->part_info->set_show_version_string(packet); packet->append(part_syntax, part_syntax_len); packet->append(STRING_WITH_LEN(" */")); - my_free(part_syntax, MYF(0)); + my_free(part_syntax); } } #endif @@ -1633,6 +1565,14 @@ static void store_key_options(THD *thd, String *packet, TABLE *table, end= longlong10_to_str(key_info->block_size, buff, 10); packet->append(buff, (uint) (end - buff)); } + DBUG_ASSERT(test(key_info->flags & HA_USES_COMMENT) == + (key_info->comment.length > 0)); + if (key_info->flags & HA_USES_COMMENT) + { + packet->append(STRING_WITH_LEN(" COMMENT ")); + append_unescaped(packet, key_info->comment.str, + key_info->comment.length); + } } } @@ -1793,6 +1733,30 @@ public: template class I_List<thread_info>; #endif +static const char *thread_state_info(THD *tmp) +{ +#ifndef EMBEDDED_LIBRARY + if (tmp->net.reading_or_writing) + { + if (tmp->net.reading_or_writing == 2) + return "Writing to net"; + else if (tmp->command == COM_SLEEP) + return ""; + else + return "Reading from net"; + } + else +#endif + { + if (tmp->proc_info) + return tmp->proc_info; + else if (tmp->mysys_var && tmp->mysys_var->current_cond) + return "Waiting on cond"; + else + return NULL; + } +} + void mysqld_list_processes(THD *thd,const char *user, bool verbose) { Item *field; @@ -1815,11 +1779,11 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) field->maybe_null=1; field_list.push_back(field=new Item_empty_string("Info",max_query_length)); field->maybe_null=1; - if (protocol->send_fields(&field_list, + if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_VOID_RETURN; - VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list if (!thd->killed) { I_List_iterator<THD> it(threads); @@ -1851,41 +1815,28 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if ((thd_info->db=tmp->db)) // Safe test thd_info->db=thd->strdup(thd_info->db); thd_info->command=(int) tmp->command; + mysql_mutex_lock(&tmp->LOCK_thd_data); if ((mysys_var= tmp->mysys_var)) - pthread_mutex_lock(&mysys_var->mutex); + mysql_mutex_lock(&mysys_var->mutex); thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0); -#ifndef EMBEDDED_LIBRARY - thd_info->state_info= (char*) (tmp->locked ? "Locked" : - tmp->net.reading_or_writing ? - (tmp->net.reading_or_writing == 2 ? - "Writing to net" : - thd_info->command == COM_SLEEP ? "" : - "Reading from net") : - tmp->proc_info ? tmp->proc_info : - tmp->mysys_var && - tmp->mysys_var->current_cond ? - "Waiting on cond" : NullS); -#else - thd_info->state_info= (char*)"Writing to net"; -#endif + thd_info->state_info= thread_state_info(tmp); if (mysys_var) - pthread_mutex_unlock(&mysys_var->mutex); + mysql_mutex_unlock(&mysys_var->mutex); - thd_info->start_time= tmp->start_time; thd_info->query=0; /* Lock THD mutex that protects its data when looking at it. */ - pthread_mutex_lock(&tmp->LOCK_thd_data); if (tmp->query()) { uint length= min(max_query_length, tmp->query_length()); thd_info->query= (char*) thd->strmake(tmp->query(),length); } - pthread_mutex_unlock(&tmp->LOCK_thd_data); + mysql_mutex_unlock(&tmp->LOCK_thd_data); + thd_info->start_time= tmp->start_time; thread_infos.append(thd_info); } } } - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + mysql_mutex_unlock(&LOCK_thread_count); thread_info *thd_info; time_t now= my_time(0); @@ -1924,7 +1875,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) user= thd->security_ctx->master_access & PROCESS_ACL ? NullS : thd->security_ctx->priv_user; - VOID(pthread_mutex_lock(&LOCK_thread_count)); + mysql_mutex_lock(&LOCK_thread_count); if (!thd->killed) { @@ -1967,8 +1918,9 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) table->field[3]->set_notnull(); } + mysql_mutex_lock(&tmp->LOCK_thd_data); if ((mysys_var= tmp->mysys_var)) - pthread_mutex_lock(&mysys_var->mutex); + mysql_mutex_lock(&mysys_var->mutex); /* COMMAND */ if ((val= (char *) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0))) table->field[4]->store(val, strlen(val), cs); @@ -1979,32 +1931,19 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) table->field[5]->store((longlong)(tmp->start_time ? now - tmp->start_time : 0), FALSE); /* STATE */ -#ifndef EMBEDDED_LIBRARY - val= (char*) (tmp->locked ? "Locked" : - tmp->net.reading_or_writing ? - (tmp->net.reading_or_writing == 2 ? - "Writing to net" : - tmp->command == COM_SLEEP ? "" : - "Reading from net") : - tmp->proc_info ? tmp->proc_info : - tmp->mysys_var && - tmp->mysys_var->current_cond ? - "Waiting on cond" : NullS); -#else - val= (char *) (tmp->proc_info ? tmp->proc_info : NullS); -#endif - if (val) + if ((val= thread_state_info(tmp))) { table->field[6]->store(val, strlen(val), cs); table->field[6]->set_notnull(); } if (mysys_var) - pthread_mutex_unlock(&mysys_var->mutex); + mysql_mutex_unlock(&mysys_var->mutex); + mysql_mutex_unlock(&tmp->LOCK_thd_data); /* INFO */ /* Lock THD mutex that protects its data when looking at it. */ - pthread_mutex_lock(&tmp->LOCK_thd_data); + mysql_mutex_lock(&tmp->LOCK_thd_data); if (tmp->query()) { table->field[7]->store(tmp->query(), @@ -2012,17 +1951,17 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) tmp->query_length()), cs); table->field[7]->set_notnull(); } - pthread_mutex_unlock(&tmp->LOCK_thd_data); + mysql_mutex_unlock(&tmp->LOCK_thd_data); if (schema_table_store_record(thd, table)) { - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + mysql_mutex_unlock(&LOCK_thread_count); DBUG_RETURN(1); } } } - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + mysql_mutex_unlock(&LOCK_thread_count); DBUG_RETURN(0); } @@ -2032,10 +1971,13 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) static DYNAMIC_ARRAY all_status_vars; static bool status_vars_inited= 0; + +C_MODE_START static int show_var_cmp(const void *var1, const void *var2) { return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name); } +C_MODE_END /* deletes all the SHOW_UNDEF elements from the array and calls @@ -2081,7 +2023,7 @@ int add_status_vars(SHOW_VAR *list) { int res= 0; if (status_vars_inited) - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); if (!all_status_vars.buffer && // array is not allocated yet - do it now my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 200, 20)) { @@ -2096,7 +2038,7 @@ int add_status_vars(SHOW_VAR *list) sort_dynamic(&all_status_vars, show_var_cmp); err: if (status_vars_inited) - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); return res; } @@ -2158,7 +2100,7 @@ void remove_status_vars(SHOW_VAR *list) { if (status_vars_inited) { - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *); int a= 0, b= all_status_vars.elements, c= (a+b)/2; @@ -2179,7 +2121,7 @@ void remove_status_vars(SHOW_VAR *list) all[c].type= SHOW_UNDEF; } shrink_var_array(&all_status_vars); - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); } else { @@ -2269,7 +2211,7 @@ static bool show_status_array(THD *thd, const char *wild, char *value=var->value; const char *pos, *end; // We assign a lot of const's - pthread_mutex_lock(&LOCK_global_system_variables); + mysql_mutex_lock(&LOCK_global_system_variables); if (show_type == SHOW_SYS) { @@ -2289,7 +2231,8 @@ static bool show_status_array(THD *thd, const char *wild, value= ((char *) status_var + (ulong) value); /* fall through */ case SHOW_DOUBLE: - end= buff + sprintf(buff, "%f", *(double*) value); + /* 6 is the default precision for '%f' in sprintf() */ + end= buff + my_fcvt(*(double *) value, 6, buff, NULL); break; case SHOW_LONG_STATUS: value= ((char *) status_var + (ulong) value); @@ -2337,6 +2280,15 @@ static bool show_status_array(THD *thd, const char *wild, end= strend(pos); break; } + case SHOW_LEX_STRING: + { + LEX_STRING *ls=(LEX_STRING*)value; + if (!(pos= ls->str)) + end= pos= ""; + else + end= pos + ls->length; + break; + } case SHOW_KEY_CACHE_LONG: value= (char*) dflt_key_cache + (ulong)value; end= int10_to_str(*(long*) value, buff, 10); @@ -2356,7 +2308,7 @@ static bool show_status_array(THD *thd, const char *wild, thd->count_cuted_fields= CHECK_FIELD_IGNORE; table->field[1]->set_notnull(); - pthread_mutex_unlock(&LOCK_global_system_variables); + mysql_mutex_unlock(&LOCK_global_system_variables); if (schema_table_store_record(thd, table)) { @@ -2379,7 +2331,7 @@ void calc_sum_of_all_status(STATUS_VAR *to) DBUG_ENTER("calc_sum_of_all_status"); /* Ensure that thread id not killed during loop */ - VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list I_List_iterator<THD> it(threads); THD *tmp; @@ -2391,7 +2343,7 @@ void calc_sum_of_all_status(STATUS_VAR *to) while ((tmp= it++)) add_to_status(to, &tmp->status_var); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + mysql_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; } @@ -2440,7 +2392,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel, Table_ident *table_ident; table_ident= new Table_ident(thd, *db_name, *table_name, 1); sel->init_query(); - if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ)) + if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ)) return 1; return 0; } @@ -2812,8 +2764,8 @@ int make_db_list(THD *thd, List<LEX_STRING> *files, */ if (lookup_field_vals->db_value.str) { - if (is_schema_db(lookup_field_vals->db_value.str, - lookup_field_vals->db_value.length)) + if (is_infoschema_db(lookup_field_vals->db_value.str, + lookup_field_vals->db_value.length)) { *with_i_schema= 1; if (files->push_back(i_s_name_copy)) @@ -2970,9 +2922,9 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex, Check that table is relevant in current transaction. (used for ndb engine, see ndbcluster_find_files(), ha_ndbcluster.cc) */ - VOID(ha_find_files(thd, db_name->str, path, + (void) ha_find_files(thd, db_name->str, path, lookup_field_vals->table_value.str, 0, - table_names)); + table_names); } return 0; } @@ -3014,7 +2966,11 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex, @param[in] thd thread handler @param[in] tables TABLE_LIST for I_S table @param[in] schema_table pointer to I_S structure - @param[in] open_tables_state_backup pointer to Open_tables_state object + @param[in] can_deadlock Indicates that deadlocks are possible + due to metadata locks, so to avoid + them we should not wait in case if + conflicting lock is present. + @param[in] open_tables_state_backup pointer to Open_tables_backup object which is used to save|restore original status of variables related to open tables state @@ -3027,7 +2983,8 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex, static int fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, ST_SCHEMA_TABLE *schema_table, - Open_tables_state *open_tables_state_backup) + bool can_deadlock, + Open_tables_backup *open_tables_state_backup) { LEX *lex= thd->lex; bool res; @@ -3054,8 +3011,14 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, */ lex->sql_command= SQLCOM_SHOW_FIELDS; res= open_normal_and_derived_tables(thd, show_table_list, - MYSQL_LOCK_IGNORE_FLUSH); + (MYSQL_OPEN_IGNORE_FLUSH | + MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL | + (can_deadlock ? + MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0))); lex->sql_command= save_sql_command; + + DEBUG_SYNC(thd, "after_open_table_ignore_flush"); + /* get_all_tables() returns 1 on failure and 0 on success thus return only these and not the result code of ::process_table() @@ -3080,7 +3043,8 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, table, res, db_name, table_name)); thd->temporary_tables= 0; - close_tables_for_reopen(thd, &show_table_list); + close_tables_for_reopen(thd, &show_table_list, + open_tables_state_backup->mdl_system_tables_svp); DBUG_RETURN(error); } @@ -3114,7 +3078,7 @@ static int fill_schema_table_names(THD *thd, TABLE *table, char path[FN_REFLEN + 1]; (void) build_table_filename(path, sizeof(path) - 1, db_name->str, table_name->str, reg_ext, 0); - switch (mysql_frm_type(thd, path, ¬_used)) { + switch (dd_frm_type(thd, path, ¬_used)) { case FRMTYPE_ERROR: table->field[3]->store(STRING_WITH_LEN("ERROR"), system_charset_info); @@ -3130,7 +3094,7 @@ static int fill_schema_table_names(THD *thd, TABLE *table, default: DBUG_ASSERT(0); } - if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) + if (thd->is_error() && thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE) { thd->clear_error(); return 0; @@ -3193,6 +3157,61 @@ uint get_table_open_method(TABLE_LIST *tables, /** + Try acquire high priority share metadata lock on a table (with + optional wait for conflicting locks to go away). + + @param thd Thread context. + @param mdl_request Pointer to memory to be used for MDL_request + object for a lock request. + @param table Table list element for the table + @param can_deadlock Indicates that deadlocks are possible due to + metadata locks, so to avoid them we should not + wait in case if conflicting lock is present. + + @note This is an auxiliary function to be used in cases when we want to + access table's description by looking up info in TABLE_SHARE without + going through full-blown table open. + @note This function assumes that there are no other metadata lock requests + in the current metadata locking context. + + @retval FALSE No error, if lock was obtained TABLE_LIST::mdl_request::ticket + is set to non-NULL value. + @retval TRUE Some error occured (probably thread was killed). +*/ + +static bool +try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table, + bool can_deadlock) +{ + bool error; + table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name, + MDL_SHARED_HIGH_PRIO); + + if (can_deadlock) + { + /* + When .FRM is being open in order to get data for an I_S table, + we might have some tables not only open but also locked. + E.g. this happens when a SHOW or I_S statement is run + under LOCK TABLES or inside a stored function. + By waiting for the conflicting metadata lock to go away we + might create a deadlock which won't entirely belong to the + MDL subsystem and thus won't be detectable by this subsystem's + deadlock detector. To avoid such situation, when there are + other locked tables, we prefer not to wait on a conflicting + lock. + */ + error= thd->mdl_context.try_acquire_lock(&table->mdl_request); + } + else + error= thd->mdl_context.acquire_lock(&table->mdl_request, + thd->variables.lock_wait_timeout); + + return error; +} + + +/** @brief Fill I_S table with data from FRM file only @param[in] thd thread handler @@ -3201,6 +3220,10 @@ uint get_table_open_method(TABLE_LIST *tables, @param[in] db_name database name @param[in] table_name table name @param[in] schema_table_idx I_S table index + @param[in] can_deadlock Indicates that deadlocks are possible + due to metadata locks, so to avoid + them we should not wait in case if + conflicting lock is present. @return Operation status @retval 0 Table is processed and we can continue @@ -3209,80 +3232,168 @@ uint get_table_open_method(TABLE_LIST *tables, open_tables function for this table */ -static int fill_schema_table_from_frm(THD *thd,TABLE *table, - ST_SCHEMA_TABLE *schema_table, +static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables, + ST_SCHEMA_TABLE *schema_table, LEX_STRING *db_name, LEX_STRING *table_name, - enum enum_schema_tables schema_table_idx) + enum enum_schema_tables schema_table_idx, + bool can_deadlock) { + TABLE *table= tables->table; TABLE_SHARE *share; TABLE tbl; TABLE_LIST table_list; uint res= 0; - int error; + int not_used; + my_hash_value_type hash_value; char key[MAX_DBKEY_LENGTH]; uint key_length; + char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1]; bzero((char*) &table_list, sizeof(TABLE_LIST)); bzero((char*) &tbl, sizeof(TABLE)); - table_list.table_name= table_name->str; - table_list.db= db_name->str; + if (lower_case_table_names) + { + /* + In lower_case_table_names > 0 metadata locking and table definition + cache subsystems require normalized (lowercased) database and table + names as input. + */ + strmov(db_name_buff, db_name->str); + strmov(table_name_buff, table_name->str); + my_casedn_str(files_charset_info, db_name_buff); + my_casedn_str(files_charset_info, table_name_buff); + table_list.db= db_name_buff; + table_list.table_name= table_name_buff; + } + else + { + table_list.table_name= table_name->str; + table_list.db= db_name->str; + } + + /* + TODO: investigate if in this particular situation we can get by + simply obtaining internal lock of the data-dictionary + instead of obtaining full-blown metadata lock. + */ + if (try_acquire_high_prio_shared_mdl_lock(thd, &table_list, can_deadlock)) + { + /* + Some error occured (most probably we have been killed while + waiting for conflicting locks to go away), let the caller to + handle the situation. + */ + return 1; + } + + if (! table_list.mdl_request.ticket) + { + /* + We are in situation when we have encountered conflicting metadata + lock and deadlocks can occur due to waiting for it to go away. + So instead of waiting skip this table with an appropriate warning. + */ + DBUG_ASSERT(can_deadlock); + + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_I_S_SKIPPED_TABLE, + ER(ER_WARN_I_S_SKIPPED_TABLE), + table_list.db, table_list.table_name); + return 0; + } + + if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY) + { + init_sql_alloc(&tbl.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); + if (!Table_triggers_list::check_n_load(thd, db_name->str, + table_name->str, &tbl, 1)) + { + table_list.table= &tbl; + res= schema_table->process_table(thd, &table_list, table, + res, db_name, table_name); + delete tbl.triggers; + } + free_root(&tbl.mem_root, MYF(0)); + goto end; + } + key_length= create_table_def_key(thd, key, &table_list, 0); - pthread_mutex_lock(&LOCK_open); + hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length); + mysql_mutex_lock(&LOCK_open); share= get_table_share(thd, &table_list, key, - key_length, OPEN_VIEW, &error); + key_length, OPEN_VIEW, ¬_used, hash_value); if (!share) { res= 0; - goto err; + goto end_unlock; } - + if (share->is_view) { if (schema_table->i_s_requested_object & OPEN_TABLE_ONLY) { /* skip view processing */ res= 0; - goto err1; + goto end_share; } else if (schema_table->i_s_requested_object & OPEN_VIEW_FULL) { /* - tell get_all_tables() to fall back to + tell get_all_tables() to fall back to open_normal_and_derived_tables() */ res= 1; - goto err1; + goto end_share; } } - if (share->is_view || - !open_table_from_share(thd, share, table_name->str, 0, - (READ_KEYINFO | COMPUTE_TYPES | - EXTRA_RECORD | OPEN_FRM_FILE_ONLY), + if (share->is_view) + { + if (open_new_frm(thd, share, table_name->str, + (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | + HA_GET_INDEX | HA_TRY_READ_ONLY), + READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD | + OPEN_VIEW_NO_PARSE, + thd->open_options, &tbl, &table_list, thd->mem_root)) + goto end_share; + table_list.view= (LEX*) share->is_view; + res= schema_table->process_table(thd, &table_list, table, + res, db_name, table_name); + goto end_share; + } + + if (!open_table_from_share(thd, share, table_name->str, 0, + (EXTRA_RECORD | OPEN_FRM_FILE_ONLY), thd->open_options, &tbl, FALSE)) { tbl.s= share; table_list.table= &tbl; - table_list.view= (st_lex*) share->is_view; + table_list.view= (LEX*) share->is_view; res= schema_table->process_table(thd, &table_list, table, res, db_name, table_name); - closefrm(&tbl, true); - goto err; + free_root(&tbl.mem_root, MYF(0)); + my_free((void *) tbl.alias); } -err1: - release_table_share(share, RELEASE_NORMAL); +end_share: + release_table_share(share); -err: - pthread_mutex_unlock(&LOCK_open); +end_unlock: + mysql_mutex_unlock(&LOCK_open); + /* + Don't release the MDL lock, it can be part of a transaction. + If it is not, it will be released by the call to + MDL_context::rollback_to_savepoint() in the caller. + */ + +end: thd->clear_error(); return res; } - /** @brief Fill I_S tables whose data are retrieved from frm files and storage engine @@ -3307,7 +3418,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) LEX *lex= thd->lex; TABLE *table= tables->table; SELECT_LEX *old_all_select_lex= lex->all_selects_list; - enum_sql_command save_sql_command= lex->sql_command; SELECT_LEX *lsel= tables->schema_select_lex; ST_SCHEMA_TABLE *schema_table= tables->schema_table; SELECT_LEX sel; @@ -3320,25 +3430,48 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) COND *partial_cond= 0; uint derived_tables= lex->derived_tables; int error= 1; - Open_tables_state open_tables_state_backup; + Open_tables_backup open_tables_state_backup; bool save_view_prepare_mode= lex->view_prepare_mode; Query_tables_list query_tables_list_backup; #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *sctx= thd->security_ctx; #endif uint table_open_method; + bool can_deadlock; DBUG_ENTER("get_all_tables"); + /* + In cases when SELECT from I_S table being filled by this call is + part of statement which also uses other tables or is being executed + under LOCK TABLES or is part of transaction which also uses other + tables waiting for metadata locks which happens below might result + in deadlocks. + To avoid them we don't wait if conflicting metadata lock is + encountered and skip table with emitting an appropriate warning. + */ + can_deadlock= thd->mdl_context.has_locks(); + lex->view_prepare_mode= TRUE; lex->reset_n_backup_query_tables_list(&query_tables_list_backup); + /* + Restore Query_tables_list::sql_command value, which was reset + above, as ST_SCHEMA_TABLE::process_table() functions often rely + that this value reflects which SHOW statement is executed. + */ + lex->sql_command= query_tables_list_backup.sql_command; /* We should not introduce deadlocks even if we already have some tables open and locked, since we won't lock tables which we will - open and will ignore possible name-locks for these tables. + open and will ignore pending exclusive metadata locks for these + tables by using high-priority requests for shared metadata locks. */ thd->reset_n_backup_open_tables_state(&open_tables_state_backup); + schema_table_idx= get_schema_table_idx(schema_table); + tables->table_open_method= table_open_method= + get_table_open_method(tables, schema_table, schema_table_idx); + DBUG_PRINT("open_method", ("%d", tables->table_open_method)); /* this branch processes SHOW FIELDS, SHOW INDEXES commands. see sql_parse.cc, prepare_schema_table() function where @@ -3347,11 +3480,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (lsel && lsel->table_list.first) { error= fill_schema_show_cols_or_idxs(thd, tables, schema_table, + can_deadlock, &open_tables_state_backup); goto err; } - schema_table_idx= get_schema_table_idx(schema_table); if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals)) { error= 0; @@ -3390,9 +3523,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) else partial_cond= make_cond_for_info_schema(cond, tables); - tables->table_open_method= table_open_method= - get_table_open_method(tables, schema_table, schema_table_idx); - if (lex->describe) { /* EXPLAIN SELECT */ @@ -3406,8 +3536,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) while ((db_name= it++)) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!(check_access(thd,SELECT_ACL, db_name->str, - &thd->col_access, 0, 1, with_i_schema) || + if (!(check_access(thd, SELECT_ACL, db_name->str, + &thd->col_access, NULL, 0, 1) || (!thd->col_access && check_grant_db(thd, db_name->str))) || sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0)) @@ -3444,6 +3574,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) (!lookup_field_vals.table_value.length || lookup_field_vals.wild_table_value)) { + table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info); if (schema_table_store_record(thd, table)) goto err; /* Out of space in temporary table */ continue; @@ -3458,11 +3589,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) } else { - if (!(table_open_method & ~OPEN_FRM_ONLY) && + if (!(table_open_method & ~OPEN_FRM_ONLY) && !with_i_schema) { - if (!fill_schema_table_from_frm(thd, table, schema_table, db_name, - table_name, schema_table_idx)) + if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name, + table_name, schema_table_idx, + can_deadlock)) continue; } @@ -3488,18 +3620,20 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) schema_table->i_s_requested_object; DEBUG_SYNC(thd, "before_open_in_get_all_tables"); res= open_normal_and_derived_tables(thd, show_table_list, - MYSQL_LOCK_IGNORE_FLUSH); - lex->sql_command= save_sql_command; + (MYSQL_OPEN_IGNORE_FLUSH | + MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL | + (can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0))); + lex->sql_command= query_tables_list_backup.sql_command; /* XXX: show_table_list has a flag i_is_requested, and when it's set, open_normal_and_derived_tables() can return an error without setting an error message in THD, which is a hack. This is why we have to check for res, then for thd->is_error() only then - for thd->main_da.sql_errno(). + for thd->stmt_da->sql_errno(). */ if (res && thd->is_error() && - thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) + thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE) { /* Hide error for not existing table. @@ -3524,7 +3658,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) res= schema_table->process_table(thd, show_table_list, table, res, &orig_db_name, &tmp_lex_string); - close_tables_for_reopen(thd, &show_table_list); + close_tables_for_reopen(thd, &show_table_list, + open_tables_state_backup.mdl_system_tables_svp); } DBUG_ASSERT(!lex->query_tables_own_last); if (res) @@ -3547,7 +3682,6 @@ err: lex->derived_tables= derived_tables; lex->all_selects_list= old_all_select_lex; lex->view_prepare_mode= save_view_prepare_mode; - lex->sql_command= save_sql_command; DBUG_RETURN(error); } @@ -3556,6 +3690,7 @@ bool store_schema_shemata(THD* thd, TABLE *table, LEX_STRING *db_name, CHARSET_INFO *cs) { restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info); table->field[1]->store(db_name->str, db_name->length, system_charset_info); table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info); table->field[3]->store(cs->name, strlen(cs->name), system_charset_info); @@ -3604,7 +3739,7 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond) path_len= build_table_filename(path, sizeof(path) - 1, lookup_field_vals.db_value.str, "", "", 0); path[path_len-1]= 0; - if (!my_stat(path,&stat_info,MYF(0))) + if (!mysql_file_stat(key_file_misc, path, &stat_info, MYF(0))) DBUG_RETURN(0); } @@ -3646,6 +3781,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, DBUG_ENTER("get_schema_tables_record"); restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(table_name->str, table_name->length, cs); if (res) @@ -3653,7 +3789,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, /* there was errors during opening tables */ - const char *error= thd->is_error() ? thd->main_da.message() : ""; + const char *error= thd->is_error() ? thd->stmt_da->message() : ""; if (tables->view) table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); else if (tables->schema_table) @@ -3693,7 +3829,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, } #ifdef WITH_PARTITION_STORAGE_ENGINE if (share->db_type() == partition_hton && - share->partition_info_len) + share->partition_info_str_len) { tmp_db_type= share->default_part_db_type; is_partitioned= TRUE; @@ -3836,6 +3972,131 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, } +/** + @brief Store field characteristics into appropriate I_S table columns + + @param[in] table I_S table + @param[in] field processed field + @param[in] cs I_S table charset + @param[in] offset offset from beginning of table + to DATE_TYPE column in I_S table + + @return void +*/ + +void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs, + uint offset) +{ + bool is_blob; + int decimals, field_length; + const char *tmp_buff; + char column_type_buff[MAX_FIELD_WIDTH]; + String column_type(column_type_buff, sizeof(column_type_buff), cs); + + field->sql_type(column_type); + /* DTD_IDENTIFIER column */ + table->field[offset + 7]->store(column_type.ptr(), column_type.length(), cs); + table->field[offset + 7]->set_notnull(); + /* + DATA_TYPE column: + MySQL column type has the following format: + base_type [(dimension)] [unsigned] [zerofill]. + For DATA_TYPE column we extract only base type. + */ + tmp_buff= strchr(column_type.ptr(), '('); + if (!tmp_buff) + /* + if there is no dimention part then check the presence of + [unsigned] [zerofill] attributes and cut them of if exist. + */ + tmp_buff= strchr(column_type.ptr(), ' '); + table->field[offset]->store(column_type.ptr(), + (tmp_buff ? tmp_buff - column_type.ptr() : + column_type.length()), cs); + + is_blob= (field->type() == MYSQL_TYPE_BLOB); + if (field->has_charset() || is_blob || + field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type + field->real_type() == MYSQL_TYPE_STRING) // For binary type + { + uint32 octet_max_length= field->max_display_length(); + if (is_blob && octet_max_length != (uint32) 4294967295U) + octet_max_length /= field->charset()->mbmaxlen; + longlong char_max_len= is_blob ? + (longlong) octet_max_length / field->charset()->mbminlen : + (longlong) octet_max_length / field->charset()->mbmaxlen; + /* CHARACTER_MAXIMUM_LENGTH column*/ + table->field[offset + 1]->store(char_max_len, TRUE); + table->field[offset + 1]->set_notnull(); + /* CHARACTER_OCTET_LENGTH column */ + table->field[offset + 2]->store((longlong) octet_max_length, TRUE); + table->field[offset + 2]->set_notnull(); + } + + /* + Calculate field_length and decimals. + They are set to -1 if they should not be set (we should return NULL) + */ + + decimals= field->decimals(); + switch (field->type()) { + case MYSQL_TYPE_NEWDECIMAL: + field_length= ((Field_new_decimal*) field)->precision; + break; + case MYSQL_TYPE_DECIMAL: + field_length= field->field_length - (decimals ? 2 : 1); + break; + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + field_length= field->max_display_length() - 1; + break; + case MYSQL_TYPE_LONGLONG: + field_length= field->max_display_length() - + ((field->flags & UNSIGNED_FLAG) ? 0 : 1); + break; + case MYSQL_TYPE_BIT: + field_length= field->max_display_length(); + decimals= -1; // return NULL + break; + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + field_length= field->field_length; + if (decimals == NOT_FIXED_DEC) + decimals= -1; // return NULL + break; + default: + field_length= decimals= -1; + break; + } + + /* NUMERIC_PRECISION column */ + if (field_length >= 0) + { + table->field[offset + 3]->store((longlong) field_length, TRUE); + table->field[offset + 3]->set_notnull(); + } + /* NUMERIC_SCALE column */ + if (decimals >= 0) + { + table->field[offset + 4]->store((longlong) decimals, TRUE); + table->field[offset + 4]->set_notnull(); + } + if (field->has_charset()) + { + /* CHARACTER_SET_NAME column*/ + tmp_buff= field->charset()->csname; + table->field[offset + 5]->store(tmp_buff, strlen(tmp_buff), cs); + table->field[offset + 5]->set_notnull(); + /* COLLATION_NAME column */ + tmp_buff= field->charset()->name; + table->field[offset + 6]->store(tmp_buff, strlen(tmp_buff), cs); + table->field[offset + 6]->set_notnull(); + } +} + + static int get_schema_column_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, LEX_STRING *db_name, @@ -3845,7 +4106,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, const char *wild= lex->wild ? lex->wild->ptr() : NullS; CHARSET_INFO *cs= system_charset_info; TABLE *show_table; - Field **ptr,*field; + Field **ptr, *field, *timestamp_field; int count; DBUG_ENTER("get_schema_column_record"); @@ -3856,10 +4117,10 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, /* I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS rather than in SHOW COLUMNS - */ + */ if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); res= 0; } @@ -3868,33 +4129,32 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, show_table= tables->table; count= 0; - restore_record(show_table, s->default_values); + ptr= show_table->field; + timestamp_field= show_table->timestamp_field; show_table->use_all_columns(); // Required for default + restore_record(show_table, s->default_values); - for (ptr= show_table->field; (field= *ptr) ; ptr++) + for (; (field= *ptr) ; ptr++) { - const char *tmp_buff; uchar *pos; - bool is_blob; - uint flags=field->flags; char tmp[MAX_FIELD_WIDTH]; String type(tmp,sizeof(tmp), system_charset_info); - int decimals, field_length; + + DEBUG_SYNC(thd, "get_schema_column"); if (wild && wild[0] && wild_case_compare(system_charset_info, field->field_name,wild)) continue; - flags= field->flags; count++; /* Get default row, with all NULL fields set to NULL */ restore_record(table, s->default_values); #ifndef NO_EMBEDDED_ACCESS_CHECKS uint col_access; - check_access(thd,SELECT_ACL | EXTRA_ACL, db_name->str, + check_access(thd,SELECT_ACL, db_name->str, &tables->grant.privilege, 0, 0, test(tables->schema_table)); - col_access= get_column_grant(thd, &tables->grant, + col_access= get_column_grant(thd, &tables->grant, db_name->str, table_name->str, field->field_name) & COL_ACLS; if (!tables->schema_table && !col_access) @@ -3911,6 +4171,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs); #endif + table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(table_name->str, table_name->length, cs); table->field[3]->store(field->field_name, strlen(field->field_name), @@ -3918,107 +4179,16 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, table->field[4]->store((longlong) count, TRUE); field->sql_type(type); table->field[14]->store(type.ptr(), type.length(), cs); - /* - MySQL column type has the following format: - base_type [(dimension)] [unsigned] [zerofill]. - For DATA_TYPE column we extract only base type. - */ - tmp_buff= strchr(type.ptr(), '('); - if (!tmp_buff) - /* - if there is no dimention part then check the presence of - [unsigned] [zerofill] attributes and cut them of if exist. - */ - tmp_buff= strchr(type.ptr(), ' '); - table->field[7]->store(type.ptr(), - (tmp_buff ? tmp_buff - type.ptr() : - type.length()), cs); - if (get_field_default_value(thd, show_table, field, &type, 0)) + if (get_field_default_value(thd, timestamp_field, field, &type, 0)) { table->field[5]->store(type.ptr(), type.length(), cs); table->field[5]->set_notnull(); } - pos=(uchar*) ((flags & NOT_NULL_FLAG) ? "NO" : "YES"); + pos=(uchar*) ((field->flags & NOT_NULL_FLAG) ? "NO" : "YES"); table->field[6]->store((const char*) pos, strlen((const char*) pos), cs); - is_blob= (field->type() == MYSQL_TYPE_BLOB); - if (field->has_charset() || is_blob || - field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type - field->real_type() == MYSQL_TYPE_STRING) // For binary type - { - uint32 octet_max_length= field->max_display_length(); - if (is_blob && octet_max_length != (uint32) 4294967295U) - octet_max_length /= field->charset()->mbmaxlen; - longlong char_max_len= is_blob ? - (longlong) octet_max_length / field->charset()->mbminlen : - (longlong) octet_max_length / field->charset()->mbmaxlen; - table->field[8]->store(char_max_len, TRUE); - table->field[8]->set_notnull(); - table->field[9]->store((longlong) octet_max_length, TRUE); - table->field[9]->set_notnull(); - } - - /* - Calculate field_length and decimals. - They are set to -1 if they should not be set (we should return NULL) - */ - - decimals= field->decimals(); - switch (field->type()) { - case MYSQL_TYPE_NEWDECIMAL: - field_length= ((Field_new_decimal*) field)->precision; - break; - case MYSQL_TYPE_DECIMAL: - field_length= field->field_length - (decimals ? 2 : 1); - break; - case MYSQL_TYPE_TINY: - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_INT24: - field_length= field->max_display_length() - 1; - break; - case MYSQL_TYPE_LONGLONG: - field_length= field->max_display_length() - - ((field->flags & UNSIGNED_FLAG) ? 0 : 1); - break; - case MYSQL_TYPE_BIT: - field_length= field->max_display_length(); - decimals= -1; // return NULL - break; - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - field_length= field->field_length; - if (decimals == NOT_FIXED_DEC) - decimals= -1; // return NULL - break; - default: - field_length= decimals= -1; - break; - } - - if (field_length >= 0) - { - table->field[10]->store((longlong) field_length, TRUE); - table->field[10]->set_notnull(); - } - if (decimals >= 0) - { - table->field[11]->store((longlong) decimals, TRUE); - table->field[11]->set_notnull(); - } - - if (field->has_charset()) - { - pos=(uchar*) field->charset()->csname; - table->field[12]->store((const char*) pos, - strlen((const char*) pos), cs); - table->field[12]->set_notnull(); - pos=(uchar*) field->charset()->name; - table->field[13]->store((const char*) pos, - strlen((const char*) pos), cs); - table->field[13]->set_notnull(); - } + store_column_type(table, field, cs, 7); pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" : (field->flags & UNIQUE_KEY_FLAG) ? "UNI" : (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":""); @@ -4027,7 +4197,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, if (field->unireg_check == Field::NEXT_NUMBER) table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs); - if (show_table->timestamp_field == field && + if (timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD) table->field[16]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"), cs); @@ -4040,7 +4210,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, } - int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) { CHARSET_INFO **cs; @@ -4048,7 +4217,9 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) TABLE *table= tables->table; CHARSET_INFO *scs= system_charset_info; - for (cs= all_charsets ; cs < all_charsets+255 ; cs++) + for (cs= all_charsets ; + cs < all_charsets + array_elements(all_charsets) ; + cs++) { CHARSET_INFO *tmp_cs= cs[0]; if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && @@ -4153,7 +4324,9 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; TABLE *table= tables->table; CHARSET_INFO *scs= system_charset_info; - for (cs= all_charsets ; cs < all_charsets+255 ; cs++ ) + for (cs= all_charsets ; + cs < all_charsets + array_elements(all_charsets) ; + cs++ ) { CHARSET_INFO **cl; CHARSET_INFO *tmp_cs= cs[0]; @@ -4161,7 +4334,9 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) (tmp_cs->state & MY_CS_HIDDEN) || !(tmp_cs->state & MY_CS_PRIMARY)) continue; - for (cl= all_charsets; cl < all_charsets+255 ;cl ++) + for (cl= all_charsets; + cl < all_charsets + array_elements(all_charsets) ; + cl ++) { CHARSET_INFO *tmp_cl= cl[0]; if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || @@ -4194,17 +4369,22 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond) CHARSET_INFO **cs; TABLE *table= tables->table; CHARSET_INFO *scs= system_charset_info; - for (cs= all_charsets ; cs < all_charsets+255 ; cs++ ) + for (cs= all_charsets ; + cs < all_charsets + array_elements(all_charsets) ; + cs++ ) { CHARSET_INFO **cl; CHARSET_INFO *tmp_cs= cs[0]; if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || !(tmp_cs->state & MY_CS_PRIMARY)) continue; - for (cl= all_charsets; cl < all_charsets+255 ;cl ++) + for (cl= all_charsets; + cl < all_charsets + array_elements(all_charsets) ; + cl ++) { CHARSET_INFO *tmp_cl= cl[0]; - if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || + if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || + (tmp_cl->state & MY_CS_HIDDEN) || !my_charset_same(tmp_cs,tmp_cl)) continue; restore_record(table, s->default_values); @@ -4227,6 +4407,169 @@ static inline void copy_field_as_string(Field *to_field, Field *from_field) } +/** + @brief Store record into I_S.PARAMETERS table + + @param[in] thd thread handler + @param[in] table I_S table + @param[in] proc_table 'mysql.proc' table + @param[in] wild wild string, not used for now, + will be useful + if we add 'SHOW PARAMETERs' + @param[in] full_access if 1 user has privileges on the routine + @param[in] sp_user user in 'user@host' format + + @return Operation status + @retval 0 ok + @retval 1 error +*/ + +bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table, + const char *wild, bool full_access, + const char *sp_user) +{ + TABLE_SHARE share; + TABLE tbl; + CHARSET_INFO *cs= system_charset_info; + char params_buff[MAX_FIELD_WIDTH], returns_buff[MAX_FIELD_WIDTH], + sp_db_buff[NAME_LEN], sp_name_buff[NAME_LEN], path[FN_REFLEN], + definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 1]; + String params(params_buff, sizeof(params_buff), cs); + String returns(returns_buff, sizeof(returns_buff), cs); + String sp_db(sp_db_buff, sizeof(sp_db_buff), cs); + String sp_name(sp_name_buff, sizeof(sp_name_buff), cs); + String definer(definer_buff, sizeof(definer_buff), cs); + sp_head *sp; + uint routine_type; + bool free_sp_head; + DBUG_ENTER("store_schema_params"); + + bzero((char*) &tbl, sizeof(TABLE)); + (void) build_table_filename(path, sizeof(path), "", "", "", 0); + init_tmp_table_share(thd, &share, "", 0, "", path); + + get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DB], &sp_db); + get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_NAME], &sp_name); + get_field(thd->mem_root,proc_table->field[MYSQL_PROC_FIELD_DEFINER],&definer); + routine_type= (uint) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int(); + + if (!full_access) + full_access= !strcmp(sp_user, definer.ptr()); + if (!full_access && + check_some_routine_access(thd, sp_db.ptr(),sp_name.ptr(), + routine_type == TYPE_ENUM_PROCEDURE)) + DBUG_RETURN(0); + + params.length(0); + get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST], + ¶ms); + returns.length(0); + if (routine_type == TYPE_ENUM_FUNCTION) + get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS], + &returns); + + sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name, + (ulong) proc_table-> + field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(), + routine_type, + returns.c_ptr_safe(), + params.c_ptr_safe(), + &free_sp_head); + + if (sp) + { + Field *field; + Create_field *field_def; + String tmp_string; + if (routine_type == TYPE_ENUM_FUNCTION) + { + restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), cs); + table->field[1]->store(sp_db.ptr(), sp_db.length(), cs); + table->field[2]->store(sp_name.ptr(), sp_name.length(), cs); + table->field[3]->store((longlong) 0, TRUE); + get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE], + &tmp_string); + table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs); + field_def= &sp->m_return_field_def; + field= make_field(&share, (uchar*) 0, field_def->length, + (uchar*) "", 0, field_def->pack_flag, + field_def->sql_type, field_def->charset, + field_def->geom_type, Field::NONE, + field_def->interval, ""); + + field->table= &tbl; + tbl.in_use= thd; + store_column_type(table, field, cs, 6); + if (schema_table_store_record(thd, table)) + { + free_table_share(&share); + if (free_sp_head) + delete sp; + DBUG_RETURN(1); + } + } + + sp_pcontext *spcont= sp->get_parse_context(); + uint params= spcont->context_var_count(); + for (uint i= 0 ; i < params ; i++) + { + const char *tmp_buff; + sp_variable_t *spvar= spcont->find_variable(i); + field_def= &spvar->field_def; + switch (spvar->mode) { + case sp_param_in: + tmp_buff= "IN"; + break; + case sp_param_out: + tmp_buff= "OUT"; + break; + case sp_param_inout: + tmp_buff= "INOUT"; + break; + default: + tmp_buff= ""; + break; + } + + restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), cs); + table->field[1]->store(sp_db.ptr(), sp_db.length(), cs); + table->field[2]->store(sp_name.ptr(), sp_name.length(), cs); + table->field[3]->store((longlong) i + 1, TRUE); + table->field[4]->store(tmp_buff, strlen(tmp_buff), cs); + table->field[4]->set_notnull(); + table->field[5]->store(spvar->name.str, spvar->name.length, cs); + table->field[5]->set_notnull(); + get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE], + &tmp_string); + table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs); + + field= make_field(&share, (uchar*) 0, field_def->length, + (uchar*) "", 0, field_def->pack_flag, + field_def->sql_type, field_def->charset, + field_def->geom_type, Field::NONE, + field_def->interval, spvar->name.str); + + field->table= &tbl; + tbl.in_use= thd; + store_column_type(table, field, cs, 6); + if (schema_table_store_record(thd, table)) + { + free_table_share(&share); + if (free_sp_head) + delete sp; + DBUG_RETURN(1); + } + } + if (free_sp_head) + delete sp; + } + free_table_share(&share); + DBUG_RETURN(0); +} + + bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, const char *wild, bool full_access, const char *sp_user) { @@ -4234,66 +4577,124 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, LEX *lex= thd->lex; CHARSET_INFO *cs= system_charset_info; char sp_db_buff[NAME_LEN + 1], sp_name_buff[NAME_LEN + 1], - definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 2]; + definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 2], + returns_buff[MAX_FIELD_WIDTH]; + String sp_db(sp_db_buff, sizeof(sp_db_buff), cs); String sp_name(sp_name_buff, sizeof(sp_name_buff), cs); String definer(definer_buff, sizeof(definer_buff), cs); + String returns(returns_buff, sizeof(returns_buff), cs); - proc_table->field[0]->val_str(&sp_db); - proc_table->field[1]->val_str(&sp_name); - proc_table->field[11]->val_str(&definer); + proc_table->field[MYSQL_PROC_FIELD_DB]->val_str(&sp_db); + proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str(&sp_name); + proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str(&definer); if (!full_access) full_access= !strcmp(sp_user, definer.c_ptr_safe()); if (!full_access && check_some_routine_access(thd, sp_db.c_ptr_safe(), sp_name.c_ptr_safe(), - proc_table->field[2]->val_int() == - TYPE_ENUM_PROCEDURE)) + proc_table->field[MYSQL_PROC_MYSQL_TYPE]-> + val_int() == TYPE_ENUM_PROCEDURE)) return 0; if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC && - proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE) || + proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() == + TYPE_ENUM_PROCEDURE) || (lex->sql_command == SQLCOM_SHOW_STATUS_FUNC && - proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION) || + proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() == + TYPE_ENUM_FUNCTION) || (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0) { restore_record(table, s->default_values); if (!wild || !wild[0] || !wild_compare(sp_name.c_ptr_safe(), wild, 0)) { - int enum_idx= (int) proc_table->field[5]->val_int(); + int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int(); table->field[3]->store(sp_name.ptr(), sp_name.length(), cs); - copy_field_as_string(table->field[0], proc_table->field[3]); + + copy_field_as_string(table->field[0], + proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]); + table->field[1]->store(STRING_WITH_LEN("def"), cs); table->field[2]->store(sp_db.ptr(), sp_db.length(), cs); - copy_field_as_string(table->field[4], proc_table->field[2]); - if (proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION) + copy_field_as_string(table->field[4], + proc_table->field[MYSQL_PROC_MYSQL_TYPE]); + + if (proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() == + TYPE_ENUM_FUNCTION) { - copy_field_as_string(table->field[5], proc_table->field[9]); - table->field[5]->set_notnull(); + sp_head *sp; + bool free_sp_head; + proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str(&returns); + sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name, + (ulong) proc_table-> + field[MYSQL_PROC_FIELD_SQL_MODE]-> + val_int(), + TYPE_ENUM_FUNCTION, + returns.c_ptr_safe(), + "", &free_sp_head); + + if (sp) + { + char path[FN_REFLEN]; + TABLE_SHARE share; + TABLE tbl; + Field *field; + Create_field *field_def= &sp->m_return_field_def; + + bzero((char*) &tbl, sizeof(TABLE)); + (void) build_table_filename(path, sizeof(path), "", "", "", 0); + init_tmp_table_share(thd, &share, "", 0, "", path); + field= make_field(&share, (uchar*) 0, field_def->length, + (uchar*) "", 0, field_def->pack_flag, + field_def->sql_type, field_def->charset, + field_def->geom_type, Field::NONE, + field_def->interval, ""); + + field->table= &tbl; + tbl.in_use= thd; + store_column_type(table, field, cs, 5); + free_table_share(&share); + if (free_sp_head) + delete sp; + } } + if (full_access) { - copy_field_as_string(table->field[7], proc_table->field[19]); - table->field[7]->set_notnull(); + copy_field_as_string(table->field[14], + proc_table->field[MYSQL_PROC_FIELD_BODY_UTF8]); + table->field[14]->set_notnull(); } - table->field[6]->store(STRING_WITH_LEN("SQL"), cs); - table->field[10]->store(STRING_WITH_LEN("SQL"), cs); - copy_field_as_string(table->field[11], proc_table->field[6]); - table->field[12]->store(sp_data_access_name[enum_idx].str, + table->field[13]->store(STRING_WITH_LEN("SQL"), cs); + table->field[17]->store(STRING_WITH_LEN("SQL"), cs); + copy_field_as_string(table->field[18], + proc_table->field[MYSQL_PROC_FIELD_DETERMINISTIC]); + table->field[19]->store(sp_data_access_name[enum_idx].str, sp_data_access_name[enum_idx].length , cs); - copy_field_as_string(table->field[14], proc_table->field[7]); + copy_field_as_string(table->field[21], + proc_table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]); bzero((char *)&time, sizeof(time)); - ((Field_timestamp *) proc_table->field[12])->get_time(&time); - table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); + ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_CREATED])-> + get_time(&time); + table->field[22]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); bzero((char *)&time, sizeof(time)); - ((Field_timestamp *) proc_table->field[13])->get_time(&time); - table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); - copy_field_as_string(table->field[17], proc_table->field[14]); - copy_field_as_string(table->field[18], proc_table->field[15]); - table->field[19]->store(definer.ptr(), definer.length(), cs); - copy_field_as_string(table->field[20], proc_table->field[16]); - copy_field_as_string(table->field[21], proc_table->field[17]); - copy_field_as_string(table->field[22], proc_table->field[18]); + ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_MODIFIED])-> + get_time(&time); + table->field[23]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); + copy_field_as_string(table->field[24], + proc_table->field[MYSQL_PROC_FIELD_SQL_MODE]); + copy_field_as_string(table->field[25], + proc_table->field[MYSQL_PROC_FIELD_COMMENT]); + + table->field[26]->store(definer.ptr(), definer.length(), cs); + copy_field_as_string(table->field[27], + proc_table-> + field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]); + copy_field_as_string(table->field[28], + proc_table-> + field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]); + copy_field_as_string(table->field[29], + proc_table->field[MYSQL_PROC_FIELD_DB_COLLATION]); return schema_table_store_record(thd, table); } @@ -4311,7 +4712,9 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) TABLE *table= tables->table; bool full_access; char definer[USER_HOST_BUFF_SIZE]; - Open_tables_state open_tables_state_backup; + Open_tables_backup open_tables_state_backup; + enum enum_schema_tables schema_table_idx= + get_schema_table_idx(tables->schema_table); DBUG_ENTER("fill_schema_proc"); strxmov(definer, thd->security_ctx->priv_user, "@", @@ -4323,7 +4726,8 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) proc_tables.table_name= proc_tables.alias= (char*) "proc"; proc_tables.table_name_length= 4; proc_tables.lock_type= TL_READ; - full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1, TRUE); + full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, FALSE, + 1, TRUE); if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup))) { DBUG_RETURN(1); @@ -4334,14 +4738,19 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) res= (res == HA_ERR_END_OF_FILE) ? 0 : 1; goto err; } - if (store_schema_proc(thd, table, proc_table, wild, full_access, definer)) + + if (schema_table_idx == SCH_PROCEDURES ? + store_schema_proc(thd, table, proc_table, wild, full_access, definer) : + store_schema_params(thd, table, proc_table, wild, full_access, definer)) { res= 1; goto err; } while (!proc_table->file->index_next(proc_table->record[0])) { - if (store_schema_proc(thd, table, proc_table, wild, full_access, definer)) + if (schema_table_idx == SCH_PROCEDURES ? + store_schema_proc(thd, table, proc_table, wild, full_access, definer): + store_schema_params(thd, table, proc_table, wild, full_access, definer)) { res= 1; goto err; @@ -4372,7 +4781,7 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, */ if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); res= 0; } @@ -4393,6 +4802,7 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) { restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(table_name->str, table_name->length, cs); table->field[3]->store((longlong) ((key_info->flags & @@ -4440,6 +4850,11 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, else table->field[14]->store("", 0, cs); table->field[14]->set_notnull(); + DBUG_ASSERT(test(key_info->flags & HA_USES_COMMENT) == + (key_info->comment.length > 0)); + if (key_info->flags & HA_USES_COMMENT) + table->field[15]->store(key_info->comment.str, + key_info->comment.length, cs); if (schema_table_store_record(thd, table)) DBUG_RETURN(1); } @@ -4455,24 +4870,15 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, LEX_STRING *table_name) { CHARSET_INFO *cs= system_charset_info; - DBUG_ENTER("get_schema_views_record"); - LEX_STRING *tmp_db_name, *tmp_table_name; char definer[USER_HOST_BUFF_SIZE]; uint definer_len; bool updatable_view; - /* - if SELECT FROM I_S.VIEWS uses only fields - which have OPEN_FRM_ONLY flag then 'tables' - structure is zeroed and only tables->view is set. - (see fill_schema_table_from_frm() function). - So we should disable other fields filling. - */ - bool only_share= !tables->definer.user.str; + DBUG_ENTER("get_schema_views_record"); if (tables->view) { Security_context *sctx= thd->security_ctx; - if (!only_share && !tables->allowed_show) + if (!tables->allowed_show) { if (!my_strcasecmp(system_charset_info, tables->definer.user.str, sctx->priv_user) && @@ -4490,46 +4896,42 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, TABLE_LIST table_list; uint view_access; memset(&table_list, 0, sizeof(table_list)); - table_list.db= tables->view_db.str; - table_list.table_name= tables->view_name.str; + table_list.db= tables->db; + table_list.table_name= tables->table_name; table_list.grant.privilege= thd->col_access; view_access= get_table_grant(thd, &table_list); - if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) == - (SHOW_VIEW_ACL|SELECT_ACL)) - tables->allowed_show= TRUE; + if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) == + (SHOW_VIEW_ACL|SELECT_ACL)) + tables->allowed_show= TRUE; } } #endif } restore_record(table, s->default_values); - tmp_db_name= &tables->view_db; - tmp_table_name= &tables->view_name; - if (only_share) + table->field[0]->store(STRING_WITH_LEN("def"), cs); + table->field[1]->store(db_name->str, db_name->length, cs); + table->field[2]->store(table_name->str, table_name->length, cs); + + if (tables->allowed_show) { - tmp_db_name= db_name; - tmp_table_name= table_name; + table->field[3]->store(tables->view_body_utf8.str, + tables->view_body_utf8.length, + cs); } - table->field[1]->store(tmp_db_name->str, tmp_db_name->length, cs); - table->field[2]->store(tmp_table_name->str, tmp_table_name->length, cs); - if (!only_share) - { - if (tables->allowed_show) - { - table->field[3]->store(tables->view_body_utf8.str, - tables->view_body_utf8.length, - cs); - } - if (tables->with_check != VIEW_CHECK_NONE) - { - if (tables->with_check == VIEW_CHECK_LOCAL) - table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs); - else - table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs); - } + if (tables->with_check != VIEW_CHECK_NONE) + { + if (tables->with_check == VIEW_CHECK_LOCAL) + table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs); else - table->field[4]->store(STRING_WITH_LEN("NONE"), cs); + table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs); + } + else + table->field[4]->store(STRING_WITH_LEN("NONE"), cs); + if (table->pos_in_table_list->table_open_method & + OPEN_FULL_TABLE) + { updatable_view= 0; if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE) { @@ -4563,31 +4965,33 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, table->field[5]->store(STRING_WITH_LEN("YES"), cs); else table->field[5]->store(STRING_WITH_LEN("NO"), cs); - definer_len= (strxmov(definer, tables->definer.user.str, "@", - tables->definer.host.str, NullS) - definer); - table->field[6]->store(definer, definer_len, cs); - if (tables->view_suid) - table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs); - else - table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs); + } - table->field[8]->store(tables->view_creation_ctx->get_client_cs()->csname, - strlen(tables->view_creation_ctx-> - get_client_cs()->csname), cs); + definer_len= (strxmov(definer, tables->definer.user.str, "@", + tables->definer.host.str, NullS) - definer); + table->field[6]->store(definer, definer_len, cs); + if (tables->view_suid) + table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs); + else + table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs); + + table->field[8]->store(tables->view_creation_ctx->get_client_cs()->csname, + strlen(tables->view_creation_ctx-> + get_client_cs()->csname), cs); + + table->field[9]->store(tables->view_creation_ctx-> + get_connection_cl()->name, + strlen(tables->view_creation_ctx-> + get_connection_cl()->name), cs); - table->field[9]->store(tables->view_creation_ctx-> - get_connection_cl()->name, - strlen(tables->view_creation_ctx-> - get_connection_cl()->name), cs); - } if (schema_table_store_record(thd, table)) DBUG_RETURN(1); if (res && thd->is_error()) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + thd->stmt_da->sql_errno(), thd->stmt_da->message()); } - if (res) + if (res) thd->clear_error(); DBUG_RETURN(0); } @@ -4599,6 +5003,7 @@ bool store_constraints(THD *thd, TABLE *table, LEX_STRING *db_name, { CHARSET_INFO *cs= system_charset_info; restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(key_name, key_len, cs); table->field[3]->store(db_name->str, db_name->length, cs); @@ -4618,7 +5023,7 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4683,10 +5088,12 @@ static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name, LEX_STRING sql_mode_rep; restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(trigger_name->str, trigger_name->length, cs); table->field[3]->store(trg_event_type_names[event].str, trg_event_type_names[event].length, cs); + table->field[4]->store(STRING_WITH_LEN("def"), cs); table->field[5]->store(db_name->str, db_name->length, cs); table->field[6]->store(table_name->str, table_name->length, cs); table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs); @@ -4696,8 +5103,7 @@ static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name, table->field[14]->store(STRING_WITH_LEN("OLD"), cs); table->field[15]->store(STRING_WITH_LEN("NEW"), cs); - sys_var_thd_sql_mode::symbolic_mode_representation(thd, sql_mode, - &sql_mode_rep); + sql_mode_string_representation(thd, sql_mode, &sql_mode_rep); table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs); table->field[18]->store(definer_buffer->str, definer_buffer->length, cs); table->field[19]->store(client_cs_name->str, client_cs_name->length, cs); @@ -4723,7 +5129,7 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4732,7 +5138,7 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables, Table_triggers_list *triggers= tables->table->triggers; int event, timing; - if (check_table_access(thd, TRIGGER_ACL, tables, 1, TRUE)) + if (check_table_access(thd, TRIGGER_ACL, tables, FALSE, 1, TRUE)) goto ret; for (event= 0; event < (int)TRG_EVENT_MAX; event++) @@ -4782,8 +5188,10 @@ void store_key_column_usage(TABLE *table, LEX_STRING *db_name, longlong idx) { CHARSET_INFO *cs= system_charset_info; + table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(key_name, key_len, cs); + table->field[3]->store(STRING_WITH_LEN("def"), cs); table->field[4]->store(db_name->str, db_name->length, cs); table->field[5]->store(table_name->str, table_name->length, cs); table->field[6]->store(con_type, con_len, cs); @@ -4802,7 +5210,7 @@ static int get_schema_key_column_usage_record(THD *thd, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4882,7 +5290,8 @@ static int get_schema_key_column_usage_record(THD *thd, #ifdef WITH_PARTITION_STORAGE_ENGINE -static void collect_partition_expr(List<char> &field_list, String *str) +static void collect_partition_expr(THD *thd, List<char> &field_list, + String *str) { List_iterator<char> part_it(field_list); ulong no_fields= field_list.elements; @@ -4890,12 +5299,63 @@ static void collect_partition_expr(List<char> &field_list, String *str) str->length(0); while ((field_str= part_it++)) { - str->append(field_str); + append_identifier(thd, str, field_str, strlen(field_str)); if (--no_fields != 0) str->append(","); } return; } + + +/* + Convert a string in a given character set to a string which can be + used for FRM file storage in which case use_hex is TRUE and we store + the character constants as hex strings in the character set encoding + their field have. In the case of SHOW CREATE TABLE and the + PARTITIONS information schema table we instead provide utf8 strings + to the user and convert to the utf8 character set. + + SYNOPSIS + get_cs_converted_part_value_from_string() + item Item from which constant comes + input_str String as provided by val_str after + conversion to character set + output_str Out value: The string created + cs Character set string is encoded in + NULL for INT_RESULT's here + use_hex TRUE => hex string created + FALSE => utf8 constant string created + + RETURN VALUES + TRUE Error + FALSE Ok +*/ + +int get_cs_converted_part_value_from_string(THD *thd, + Item *item, + String *input_str, + String *output_str, + CHARSET_INFO *cs, + bool use_hex) +{ + if (item->result_type() == INT_RESULT) + { + longlong value= item->val_int(); + output_str->set(value, system_charset_info); + return FALSE; + } + if (!input_str) + { + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); + return TRUE; + } + get_cs_converted_string_value(thd, + input_str, + output_str, + cs, + use_hex); + return FALSE; +} #endif @@ -4906,9 +5366,10 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table, { TABLE* table= schema_table; CHARSET_INFO *cs= system_charset_info; - PARTITION_INFO stat_info; + PARTITION_STATS stat_info; MYSQL_TIME time; file->get_dynamic_partition_info(&stat_info, part_id); + table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[12]->store((longlong) stat_info.records, TRUE); table->field[13]->store((longlong) stat_info.mean_rec_length, TRUE); table->field[14]->store((longlong) stat_info.data_file_length, TRUE); @@ -4967,7 +5428,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table, if(ts) { table->field[24]->store(ts, strlen(ts), cs); - my_free(ts, MYF(0)); + my_free(ts); } else table->field[24]->set_null(); @@ -4976,6 +5437,51 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table, return; } +#ifdef WITH_PARTITION_STORAGE_ENGINE +static int +get_partition_column_description(THD *thd, + partition_info *part_info, + part_elem_value *list_value, + String &tmp_str) +{ + uint num_elements= part_info->part_field_list.elements; + uint i; + DBUG_ENTER("get_partition_column_description"); + + for (i= 0; i < num_elements; i++) + { + part_column_list_val *col_val= &list_value->col_val_array[i]; + if (col_val->max_value) + tmp_str.append(partition_keywords[PKW_MAXVALUE].str); + else if (col_val->null_value) + tmp_str.append("NULL"); + else + { + char buffer[MAX_KEY_LENGTH]; + String str(buffer, sizeof(buffer), &my_charset_bin); + String val_conv; + Item *item= col_val->item_expression; + + if (!(item= part_info->get_column_item(item, + part_info->part_field_array[i]))) + { + DBUG_RETURN(1); + } + String *res= item->val_str(&str); + if (get_cs_converted_part_value_from_string(thd, item, res, &val_conv, + part_info->part_field_array[i]->charset(), + FALSE)) + { + DBUG_RETURN(1); + } + tmp_str.append(val_conv); + } + if (i != num_elements - 1) + tmp_str.append(","); + } + DBUG_RETURN(0); +} +#endif /* WITH_PARTITION_STORAGE_ENGINE */ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, @@ -4997,7 +5503,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } @@ -5011,6 +5517,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, uint part_pos= 0, part_id= 0; restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(table_name->str, table_name->length, cs); @@ -5018,12 +5525,18 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, /* Partition method*/ switch (part_info->part_type) { case RANGE_PARTITION: - table->field[7]->store(partition_keywords[PKW_RANGE].str, - partition_keywords[PKW_RANGE].length, cs); - break; case LIST_PARTITION: - table->field[7]->store(partition_keywords[PKW_LIST].str, - partition_keywords[PKW_LIST].length, cs); + tmp_res.length(0); + if (part_info->part_type == RANGE_PARTITION) + tmp_res.append(partition_keywords[PKW_RANGE].str, + partition_keywords[PKW_RANGE].length); + else + tmp_res.append(partition_keywords[PKW_LIST].str, + partition_keywords[PKW_LIST].length); + if (part_info->column_list) + tmp_res.append(partition_keywords[PKW_COLUMNS].str, + partition_keywords[PKW_COLUMNS].length); + table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs); break; case HASH_PARTITION: tmp_res.length(0); @@ -5040,8 +5553,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, break; default: DBUG_ASSERT(0); - my_error(ER_OUT_OF_RESOURCES, MYF(0)); - current_thd->fatal_error(); + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); DBUG_RETURN(1); } table->field[7]->set_notnull(); @@ -5054,7 +5566,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, } else if (part_info->list_of_part_fields) { - collect_partition_expr(part_info->part_field_list, &tmp_str); + collect_partition_expr(thd, part_info->part_field_list, &tmp_str); table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs); } table->field[9]->set_notnull(); @@ -5083,7 +5595,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, } else if (part_info->list_of_subpart_fields) { - collect_partition_expr(part_info->subpart_field_list, &tmp_str); + collect_partition_expr(thd, part_info->subpart_field_list, &tmp_str); table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs); } table->field[10]->set_notnull(); @@ -5101,36 +5613,70 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, /* Partition description */ if (part_info->part_type == RANGE_PARTITION) { - if (part_elem->range_value != LONGLONG_MAX) - table->field[11]->store((longlong) part_elem->range_value, FALSE); + if (part_info->column_list) + { + List_iterator<part_elem_value> list_val_it(part_elem->list_val_list); + part_elem_value *list_value= list_val_it++; + tmp_str.length(0); + if (get_partition_column_description(thd, + part_info, + list_value, + tmp_str)) + { + DBUG_RETURN(1); + } + table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs); + } else - table->field[11]->store(partition_keywords[PKW_MAXVALUE].str, + { + if (part_elem->range_value != LONGLONG_MAX) + table->field[11]->store((longlong) part_elem->range_value, FALSE); + else + table->field[11]->store(partition_keywords[PKW_MAXVALUE].str, partition_keywords[PKW_MAXVALUE].length, cs); + } table->field[11]->set_notnull(); } else if (part_info->part_type == LIST_PARTITION) { List_iterator<part_elem_value> list_val_it(part_elem->list_val_list); part_elem_value *list_value; - uint no_items= part_elem->list_val_list.elements; + uint num_items= part_elem->list_val_list.elements; tmp_str.length(0); tmp_res.length(0); if (part_elem->has_null_value) { tmp_str.append("NULL"); - if (no_items > 0) + if (num_items > 0) tmp_str.append(","); } while ((list_value= list_val_it++)) { - if (!list_value->unsigned_flag) - tmp_res.set(list_value->value, cs); + if (part_info->column_list) + { + if (part_info->part_field_list.elements > 1U) + tmp_str.append("("); + if (get_partition_column_description(thd, + part_info, + list_value, + tmp_str)) + { + DBUG_RETURN(1); + } + if (part_info->part_field_list.elements > 1U) + tmp_str.append(")"); + } else - tmp_res.set((ulonglong)list_value->value, cs); - tmp_str.append(tmp_res); - if (--no_items != 0) + { + if (!list_value->unsigned_flag) + tmp_res.set(list_value->value, cs); + else + tmp_res.set((ulonglong)list_value->value, cs); + tmp_str.append(tmp_res); + } + if (--num_items != 0) tmp_str.append(","); - }; + } table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs); table->field[11]->set_notnull(); } @@ -5179,52 +5725,6 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, } -#ifdef NOT_USED -static interval_type get_real_interval_type(interval_type i_type) -{ - switch (i_type) { - case INTERVAL_YEAR: - return INTERVAL_YEAR; - - case INTERVAL_QUARTER: - case INTERVAL_YEAR_MONTH: - case INTERVAL_MONTH: - return INTERVAL_MONTH; - - case INTERVAL_WEEK: - case INTERVAL_DAY: - return INTERVAL_DAY; - - case INTERVAL_DAY_HOUR: - case INTERVAL_HOUR: - return INTERVAL_HOUR; - - case INTERVAL_DAY_MINUTE: - case INTERVAL_HOUR_MINUTE: - case INTERVAL_MINUTE: - return INTERVAL_MINUTE; - - case INTERVAL_DAY_SECOND: - case INTERVAL_HOUR_SECOND: - case INTERVAL_MINUTE_SECOND: - case INTERVAL_SECOND: - return INTERVAL_SECOND; - - case INTERVAL_DAY_MICROSECOND: - case INTERVAL_HOUR_MICROSECOND: - case INTERVAL_MINUTE_MICROSECOND: - case INTERVAL_SECOND_MICROSECOND: - case INTERVAL_MICROSECOND: - return INTERVAL_MICROSECOND; - case INTERVAL_LAST: - DBUG_ASSERT(0); - } - DBUG_ASSERT(0); - return INTERVAL_SECOND; -} - -#endif - #ifdef HAVE_EVENT_SCHEDULER /* Loads an event from mysql.event and copies it's data to a row of @@ -5267,12 +5767,10 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) has access. */ if (thd->lex->sql_command != SQLCOM_SHOW_EVENTS && - check_access(thd, EVENT_ACL, et.dbname.str, 0, 0, 1, - is_schema_db(et.dbname.str, et.dbname.length))) + check_access(thd, EVENT_ACL, et.dbname.str, NULL, NULL, 0, 1)) DBUG_RETURN(0); - /* ->field[0] is EVENT_CATALOG and is by default NULL */ - + sch_table->field[ISE_EVENT_CATALOG]->store(STRING_WITH_LEN("def"), scs); sch_table->field[ISE_EVENT_SCHEMA]-> store(et.dbname.str, et.dbname.length,scs); sch_table->field[ISE_EVENT_NAME]-> @@ -5290,8 +5788,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) /* SQL_MODE */ { LEX_STRING sql_mode; - sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode, - &sql_mode); + sql_mode_string_representation(thd, et.sql_mode, &sql_mode); sch_table->field[ISE_SQL_MODE]-> store(sql_mode.str, sql_mode.length, scs); } @@ -5454,10 +5951,10 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) schema_table_idx == SCH_GLOBAL_VARIABLES) option_type= OPT_GLOBAL; - rw_rdlock(&LOCK_system_variables_hash); - res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars), + mysql_rwlock_rdlock(&LOCK_system_variables_hash); + res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type), option_type, NULL, "", tables->table, upper_case_names, cond); - rw_unlock(&LOCK_system_variables_hash); + mysql_rwlock_unlock(&LOCK_system_variables_hash); DBUG_RETURN(res); } @@ -5493,14 +5990,14 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) tmp1= &thd->status_var; } - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); if (option_type == OPT_GLOBAL) calc_sum_of_all_status(&tmp); res= show_status_array(thd, wild, (SHOW_VAR *)all_status_vars.buffer, option_type, tmp1, "", tables->table, upper_case_names, cond); - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); DBUG_RETURN(res); } @@ -5535,7 +6032,7 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } @@ -5553,10 +6050,12 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, while ((f_key_info= it++)) { restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); table->field[9]->store(table_name->str, table_name->length, cs); table->field[2]->store(f_key_info->forein_id->str, f_key_info->forein_id->length, cs); + table->field[3]->store(STRING_WITH_LEN("def"), cs); table->field[4]->store(f_key_info->referenced_db->str, f_key_info->referenced_db->length, cs); table->field[10]->store(f_key_info->referenced_table->str, @@ -5778,7 +6277,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) SELECT_LEX *select_lex= thd->lex->current_select; if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, 0, - (select_lex->options | thd->options | + (select_lex->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, table_list->alias))) DBUG_RETURN(0); @@ -5953,7 +6452,7 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { - int fields_arr[]= {2, 3, 4, 19, 16, 15, 14, 18, 20, 21, 22, -1}; + int fields_arr[]= {2, 3, 4, 26, 23, 22, 21, 25, 27, 28, 29, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; Name_resolution_context *context= &thd->lex->select_lex.context; @@ -6090,7 +6589,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, strlen(schema_table->table_name), 0); if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0), - 0, 0, TL_READ)) + 0, 0, TL_READ, MDL_SHARED_READ)) { DBUG_RETURN(1); } @@ -6188,32 +6687,33 @@ bool get_schema_tables_result(JOIN *join, DBUG_RETURN(result); } -struct run_hton_fill_schema_files_args +struct run_hton_fill_schema_table_args { TABLE_LIST *tables; COND *cond; }; -static my_bool run_hton_fill_schema_files(THD *thd, plugin_ref plugin, +static my_bool run_hton_fill_schema_table(THD *thd, plugin_ref plugin, void *arg) { - struct run_hton_fill_schema_files_args *args= - (run_hton_fill_schema_files_args *) arg; + struct run_hton_fill_schema_table_args *args= + (run_hton_fill_schema_table_args *) arg; handlerton *hton= plugin_data(plugin, handlerton *); - if(hton->fill_files_table && hton->state == SHOW_OPTION_YES) - hton->fill_files_table(hton, thd, args->tables, args->cond); + if (hton->fill_is_table && hton->state == SHOW_OPTION_YES) + hton->fill_is_table(hton, thd, args->tables, args->cond, + get_schema_table_idx(args->tables->schema_table)); return false; } -int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond) +int hton_fill_schema_table(THD *thd, TABLE_LIST *tables, COND *cond) { - DBUG_ENTER("fill_schema_files"); + DBUG_ENTER("hton_fill_schema_table"); - struct run_hton_fill_schema_files_args args; + struct run_hton_fill_schema_table_args args; args.tables= tables; args.cond= cond; - plugin_foreach(thd, run_hton_fill_schema_files, + plugin_foreach(thd, run_hton_fill_schema_table, MYSQL_STORAGE_ENGINE_PLUGIN, &args); DBUG_RETURN(0); @@ -6222,7 +6722,7 @@ int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond) ST_FIELD_INFO schema_fields_info[]= { - {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"SCHEMA_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database", SKIP_OPEN_TABLE}, {"DEFAULT_CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0, @@ -6236,7 +6736,7 @@ ST_FIELD_INFO schema_fields_info[]= ST_FIELD_INFO tables_fields_info[]= { - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name", SKIP_OPEN_TABLE}, @@ -6268,14 +6768,15 @@ ST_FIELD_INFO tables_fields_info[]= (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", OPEN_FULL_TABLE}, {"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options", OPEN_FRM_ONLY}, - {"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment", OPEN_FRM_ONLY}, + {"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, + "Comment", OPEN_FRM_ONLY}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; ST_FIELD_INFO columns_fields_info[]= { - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field", @@ -6302,7 +6803,8 @@ ST_FIELD_INFO columns_fields_info[]= {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY}, {"EXTRA", 27, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY}, {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY}, - {"COLUMN_COMMENT", 255, MYSQL_TYPE_STRING, 0, 0, "Comment", OPEN_FRM_ONLY}, + {"COLUMN_COMMENT", COLUMN_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, + "Comment", OPEN_FRM_ONLY}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; @@ -6349,7 +6851,7 @@ ST_FIELD_INFO engines_fields_info[]= ST_FIELD_INFO events_fields_info[]= { - {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"EVENT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db", SKIP_OPEN_TABLE}, {"EVENT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name", @@ -6398,13 +6900,20 @@ ST_FIELD_INFO coll_charset_app_fields_info[]= ST_FIELD_INFO proc_fields_info[]= { {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, - {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"ROUTINE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db", SKIP_OPEN_TABLE}, {"ROUTINE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name", SKIP_OPEN_TABLE}, {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE}, - {"DTD_IDENTIFIER", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, + {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE}, + {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE}, + {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE}, + {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE}, + {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, {"ROUTINE_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"ROUTINE_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, {"EXTERNAL_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, @@ -6420,7 +6929,7 @@ ST_FIELD_INFO proc_fields_info[]= {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Created", SKIP_OPEN_TABLE}, {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Modified", SKIP_OPEN_TABLE}, {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, - {"ROUTINE_COMMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Comment", + {"ROUTINE_COMMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Comment", SKIP_OPEN_TABLE}, {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE}, {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, @@ -6435,7 +6944,7 @@ ST_FIELD_INFO proc_fields_info[]= ST_FIELD_INFO stat_fields_info[]= { - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", OPEN_FRM_ONLY}, {"NON_UNIQUE", 1, MYSQL_TYPE_LONGLONG, 0, 0, "Non_unique", OPEN_FRM_ONLY}, @@ -6453,24 +6962,26 @@ ST_FIELD_INFO stat_fields_info[]= {"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null", OPEN_FRM_ONLY}, {"INDEX_TYPE", 16, MYSQL_TYPE_STRING, 0, 0, "Index_type", OPEN_FULL_TABLE}, {"COMMENT", 16, MYSQL_TYPE_STRING, 0, 1, "Comment", OPEN_FRM_ONLY}, + {"INDEX_COMMENT", INDEX_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, + "Index_comment", OPEN_FRM_ONLY}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; ST_FIELD_INFO view_fields_info[]= { - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, - {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, + {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, + {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, + {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, + {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0, - OPEN_FULL_TABLE}, + OPEN_FRM_ONLY}, {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0, - OPEN_FULL_TABLE}, + OPEN_FRM_ONLY}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; @@ -6478,7 +6989,7 @@ ST_FIELD_INFO view_fields_info[]= ST_FIELD_INFO user_privileges_fields_info[]= { {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} @@ -6488,7 +6999,7 @@ ST_FIELD_INFO user_privileges_fields_info[]= ST_FIELD_INFO schema_privileges_fields_info[]= { {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, @@ -6499,7 +7010,7 @@ ST_FIELD_INFO schema_privileges_fields_info[]= ST_FIELD_INFO table_privileges_fields_info[]= { {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, @@ -6511,7 +7022,7 @@ ST_FIELD_INFO table_privileges_fields_info[]= ST_FIELD_INFO column_privileges_fields_info[]= { {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, @@ -6523,7 +7034,7 @@ ST_FIELD_INFO column_privileges_fields_info[]= ST_FIELD_INFO table_constraints_fields_info[]= { - {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, @@ -6538,12 +7049,12 @@ ST_FIELD_INFO table_constraints_fields_info[]= ST_FIELD_INFO key_column_usage_fields_info[]= { - {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, @@ -6562,7 +7073,7 @@ ST_FIELD_INFO key_column_usage_fields_info[]= ST_FIELD_INFO table_names_fields_info[]= { - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Tables_in_", SKIP_OPEN_TABLE}, @@ -6585,45 +7096,45 @@ ST_FIELD_INFO open_tables_fields_info[]= ST_FIELD_INFO triggers_fields_info[]= { - {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, - {"TRIGGER_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, + {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, + {"TRIGGER_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"TRIGGER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger", - OPEN_FULL_TABLE}, - {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FULL_TABLE}, - {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, - OPEN_FULL_TABLE}, + OPEN_FRM_ONLY}, + {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FRM_ONLY}, + {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, + OPEN_FRM_ONLY}, {"EVENT_OBJECT_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, - OPEN_FULL_TABLE}, + OPEN_FRM_ONLY}, {"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", - OPEN_FULL_TABLE}, - {"ACTION_ORDER", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FULL_TABLE}, - {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + OPEN_FRM_ONLY}, + {"ACTION_ORDER", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FRM_ONLY}, + {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY}, {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement", - OPEN_FULL_TABLE}, - {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing", OPEN_FULL_TABLE}, + OPEN_FRM_ONLY}, + {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, + {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing", OPEN_FRM_ONLY}, {"ACTION_REFERENCE_OLD_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, - OPEN_FULL_TABLE}, + OPEN_FRM_ONLY}, {"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, - OPEN_FULL_TABLE}, - {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FULL_TABLE}, - {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FULL_TABLE}, - {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FULL_TABLE}, + OPEN_FRM_ONLY}, + {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, + {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, + {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FRM_ONLY}, + {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FRM_ONLY}, + {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FRM_ONLY}, {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, - "character_set_client", OPEN_FULL_TABLE}, + "character_set_client", OPEN_FRM_ONLY}, {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, - "collation_connection", OPEN_FULL_TABLE}, + "collation_connection", OPEN_FRM_ONLY}, {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, - "Database Collation", OPEN_FULL_TABLE}, + "Database Collation", OPEN_FRM_ONLY}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; ST_FIELD_INFO partitions_fields_info[]= { - {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"PARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, @@ -6633,7 +7144,7 @@ ST_FIELD_INFO partitions_fields_info[]= (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE}, {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE}, - {"PARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, @@ -6713,7 +7224,7 @@ ST_FIELD_INFO files_fields_info[]= {"FILE_TYPE", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, - {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, + {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, @@ -6774,12 +7285,12 @@ void init_fill_schema_files_row(TABLE* table) ST_FIELD_INFO referential_constraints_fields_info[]= { - {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, + {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, @@ -6795,6 +7306,51 @@ ST_FIELD_INFO referential_constraints_fields_info[]= }; +ST_FIELD_INFO parameters_fields_info[]= +{ + {"SPECIFIC_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, + {"SPECIFIC_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, + OPEN_FULL_TABLE}, + {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, + {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0, OPEN_FULL_TABLE}, + {"PARAMETER_MODE", 5, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"PARAMETER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, + {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE}, + {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE}, + {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE}, + {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE}, + {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, + {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE} +}; + + +ST_FIELD_INFO tablespaces_fields_info[]= +{ + {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, + SKIP_OPEN_TABLE}, + {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, + {"TABLESPACE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, + 0, SKIP_OPEN_TABLE}, + {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, + 0, SKIP_OPEN_TABLE}, + {"EXTENT_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, + MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE}, + {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, + MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE}, + {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, + MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE}, + {"NODEGROUP_ID", 21, MYSQL_TYPE_LONGLONG, 0, + MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE}, + {"TABLESPACE_COMMENT", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, + SKIP_OPEN_TABLE}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} +}; + + /* Description of ST_FIELD_INFO in table.h @@ -6825,18 +7381,21 @@ ST_SCHEMA_TABLE schema_tables[]= 0, make_old_format, 0, -1, -1, 0, 0}, #endif {"FILES", files_fields_info, create_schema_table, - fill_schema_files, 0, 0, -1, -1, 0, 0}, + hton_fill_schema_table, 0, 0, -1, -1, 0, 0}, {"GLOBAL_STATUS", variables_fields_info, create_schema_table, fill_status, make_old_format, 0, 0, -1, 0, 0}, {"GLOBAL_VARIABLES", variables_fields_info, create_schema_table, fill_variables, make_old_format, 0, 0, -1, 0, 0}, {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table, get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0, - OPEN_TABLE_ONLY}, + OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY}, {"OPEN_TABLES", open_tables_fields_info, create_schema_table, fill_open_tables, make_old_format, 0, -1, -1, 1, 0}, + {"PARAMETERS", parameters_fields_info, create_schema_table, + fill_schema_proc, 0, 0, -1, -1, 0, 0}, {"PARTITIONS", partitions_fields_info, create_schema_table, - get_all_tables, 0, get_schema_partitions_record, 1, 2, 0, OPEN_TABLE_ONLY}, + get_all_tables, 0, get_schema_partitions_record, 1, 2, 0, + OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY}, {"PLUGINS", plugin_fields_info, create_schema_table, fill_plugins, make_old_format, 0, -1, -1, 0, 0}, {"PROCESSLIST", processlist_fields_info, create_schema_table, @@ -6846,7 +7405,7 @@ ST_SCHEMA_TABLE schema_tables[]= NULL, -1, -1, false, 0}, {"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info, create_schema_table, get_all_tables, 0, get_referential_constraints_record, - 1, 9, 0, OPEN_TABLE_ONLY}, + 1, 9, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY}, {"ROUTINES", proc_fields_info, create_schema_table, fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0}, {"SCHEMATA", schema_fields_info, create_schema_table, @@ -6865,15 +7424,18 @@ ST_SCHEMA_TABLE schema_tables[]= {"TABLES", tables_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0, OPTIMIZE_I_S_TABLE}, + {"TABLESPACES", tablespaces_fields_info, create_schema_table, + hton_fill_schema_table, 0, 0, -1, -1, 0, 0}, {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table, - get_all_tables, 0, get_schema_constraints_record, 3, 4, 0, OPEN_TABLE_ONLY}, + get_all_tables, 0, get_schema_constraints_record, 3, 4, 0, + OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY}, {"TABLE_NAMES", table_names_fields_info, create_schema_table, get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0}, {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table, fill_schema_table_privileges, 0, 0, -1, -1, 0, 0}, {"TRIGGERS", triggers_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0, - OPEN_TABLE_ONLY}, + OPEN_TRIGGER_ONLY|OPTIMIZE_I_S_TABLE}, {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, fill_schema_user_privileges, 0, 0, -1, -1, 0, 0}, {"VARIABLES", variables_fields_info, create_schema_table, fill_variables, @@ -6915,7 +7477,7 @@ int initialize_schema_table(st_plugin_int *plugin) sql_print_error("Plugin '%s' init function returned error.", plugin->name.str); plugin->data= NULL; - my_free(schema_table, MYF(0)); + my_free(schema_table); DBUG_RETURN(1); } @@ -6941,7 +7503,7 @@ int finalize_schema_table(st_plugin_int *plugin) plugin->name.str)); } } - my_free(schema_table, MYF(0)); + my_free(schema_table); } DBUG_RETURN(0); } @@ -6999,9 +7561,7 @@ static bool show_create_trigger_impl(THD *thd, &trg_connection_cl_name, &trg_db_cl_name); - sys_var_thd_sql_mode::symbolic_mode_representation(thd, - trg_sql_mode, - &trg_sql_mode_str); + sql_mode_string_representation(thd, trg_sql_mode, &trg_sql_mode_str); /* Resolve trigger client character set. */ @@ -7037,7 +7597,7 @@ static bool show_create_trigger_impl(THD *thd, fields.push_back(new Item_empty_string("Database Collation", MY_CS_NAME_SIZE)); - if (p->send_fields(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + if (p->send_result_set_metadata(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) return TRUE; /* Send data. */ @@ -7101,14 +7661,14 @@ static bool show_create_trigger_impl(THD *thd, - do not update Lex::query_tables in add_table_to_list(). */ -static TABLE_LIST *get_trigger_table_impl( - THD *thd, - const sp_name *trg_name) +static +TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name) { char trn_path_buff[FN_REFLEN]; - LEX_STRING trn_path= { trn_path_buff, 0 }; + LEX_STRING db; LEX_STRING tbl_name; + TABLE_LIST *table; build_trn_path(thd, trg_name, &trn_path); @@ -7122,61 +7682,23 @@ static TABLE_LIST *get_trigger_table_impl( return NULL; /* We need to reset statement table list to be PS/SP friendly. */ - - TABLE_LIST *table; - - if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST)))) - { - my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST)); + if (!(table= (TABLE_LIST*) thd->alloc(sizeof(TABLE_LIST)))) return NULL; - } - table->db_length= trg_name->m_db.length; - table->db= thd->strmake(trg_name->m_db.str, trg_name->m_db.length); + db= trg_name->m_db; - table->table_name_length= tbl_name.length; - table->table_name= thd->strmake(tbl_name.str, tbl_name.length); + db.str= thd->strmake(db.str, db.length); + tbl_name.str= thd->strmake(tbl_name.str, tbl_name.length); - table->alias= thd->strmake(tbl_name.str, tbl_name.length); + if (db.str == NULL || tbl_name.str == NULL) + return NULL; - table->lock_type= TL_IGNORE; - table->cacheable_table= 0; + table->init_one_table(db.str, db.length, tbl_name.str, tbl_name.length, + tbl_name.str, TL_IGNORE); return table; } -/** - Read TRN and TRG files to obtain base table name for the specified - trigger name and construct TABE_LIST object for the base table. Acquire - LOCK_open when doing this. - - @param thd Thread context. - @param trg_name Trigger name. - - @return TABLE_LIST object corresponding to the base table. -*/ - -static TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name) -{ - /* Acquire LOCK_open (stop the server). */ - - pthread_mutex_lock(&LOCK_open); - - /* - Load base table name from the TRN-file and create TABLE_LIST object. - */ - - TABLE_LIST *lst= get_trigger_table_impl(thd, trg_name); - - /* Release LOCK_open (continue the server). */ - - pthread_mutex_unlock(&LOCK_open); - - /* That's it. */ - - return lst; -} - /** SHOW CREATE TRIGGER high-level implementation. @@ -7192,46 +7714,50 @@ static TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name) bool show_create_trigger(THD *thd, const sp_name *trg_name) { TABLE_LIST *lst= get_trigger_table(thd, trg_name); + uint num_tables; /* NOTE: unused, only to pass to open_tables(). */ + Table_triggers_list *triggers; + int trigger_idx; + bool error= TRUE; if (!lst) return TRUE; - if (check_table_access(thd, TRIGGER_ACL, lst, 1, TRUE)) + if (check_table_access(thd, TRIGGER_ACL, lst, FALSE, 1, TRUE)) { my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "TRIGGER"); return TRUE; } /* - Open the table by name in order to load Table_triggers_list object. - - NOTE: there is race condition here -- the table can be dropped after - LOCK_open is released. It will be fixed later by introducing - acquire-shared-table-name-lock functionality. + Metadata locks taken during SHOW CREATE TRIGGER should be released when + the statement completes as it is an information statement. */ + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); - uint num_tables; /* NOTE: unused, only to pass to open_tables(). */ - - if (open_tables(thd, &lst, &num_tables, 0)) + /* + Open the table by name in order to load Table_triggers_list object. + */ + if (open_tables(thd, &lst, &num_tables, + MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)) { my_error(ER_TRG_CANT_OPEN_TABLE, MYF(0), (const char *) trg_name->m_db.str, (const char *) lst->table_name); - return TRUE; + goto exit; /* Perform closing actions and return error status. */ } - Table_triggers_list *triggers= lst->table->triggers; + triggers= lst->table->triggers; if (!triggers) { my_error(ER_TRG_DOES_NOT_EXIST, MYF(0)); - return TRUE; + goto exit; } - int trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name); + trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name); if (trigger_idx < 0) { @@ -7239,14 +7765,162 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) (const char *) trg_name->m_db.str, (const char *) lst->table_name); - return TRUE; + goto exit; } - return show_create_trigger_impl(thd, triggers, trigger_idx); + error= show_create_trigger_impl(thd, triggers, trigger_idx); /* NOTE: if show_create_trigger_impl() failed, that means we could not send data to the client. In this case we simply raise the error status and client connection will be closed. */ + +exit: + close_thread_tables(thd); + /* Release any metadata locks taken during SHOW CREATE TRIGGER. */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + return error; +} + +class IS_internal_schema_access : public ACL_internal_schema_access +{ +public: + IS_internal_schema_access() + {} + + ~IS_internal_schema_access() + {} + + ACL_internal_access_result check(ulong want_access, + ulong *save_priv) const; + + const ACL_internal_table_access *lookup(const char *name) const; +}; + +ACL_internal_access_result +IS_internal_schema_access::check(ulong want_access, + ulong *save_priv) const +{ + want_access &= ~SELECT_ACL; + + /* + We don't allow any simple privileges but SELECT_ACL on + the information_schema database. + */ + if (unlikely(want_access & DB_ACLS)) + return ACL_INTERNAL_ACCESS_DENIED; + + /* Always grant SELECT for the information schema. */ + *save_priv|= SELECT_ACL; + + return want_access ? ACL_INTERNAL_ACCESS_CHECK_GRANT : + ACL_INTERNAL_ACCESS_GRANTED; +} + +const ACL_internal_table_access * +IS_internal_schema_access::lookup(const char *name) const +{ + /* There are no per table rules for the information schema. */ + return NULL; +} + +static IS_internal_schema_access is_internal_schema_access; + +void initialize_information_schema_acl() +{ + ACL_internal_schema_registry::register_schema(&INFORMATION_SCHEMA_NAME, + &is_internal_schema_access); +} + +/* + Convert a string in character set in column character set format + to utf8 character set if possible, the utf8 character set string + will later possibly be converted to character set used by client. + Thus we attempt conversion from column character set to both + utf8 and to character set client. + + Examples of strings that should fail conversion to utf8 are unassigned + characters as e.g. 0x81 in cp1250 (Windows character set for for countries + like Czech and Poland). Example of string that should fail conversion to + character set on client (e.g. if this is latin1) is 0x2020 (daggger) in + ucs2. + + If the conversion fails we will as a fall back convert the string to + hex encoded format. The caller of the function can also ask for hex + encoded format of output string unconditionally. + + SYNOPSIS + get_cs_converted_string_value() + thd Thread object + input_str Input string in cs character set + output_str Output string to be produced in utf8 + cs Character set of input string + use_hex Use hex string unconditionally + + + RETURN VALUES + No return value +*/ + +static void get_cs_converted_string_value(THD *thd, + String *input_str, + String *output_str, + CHARSET_INFO *cs, + bool use_hex) +{ + + output_str->length(0); + if (input_str->length() == 0) + { + output_str->append("''"); + return; + } + if (!use_hex) + { + String try_val; + uint try_conv_error= 0; + + try_val.copy(input_str->ptr(), input_str->length(), cs, + thd->variables.character_set_client, &try_conv_error); + if (!try_conv_error) + { + String val; + uint conv_error= 0; + + val.copy(input_str->ptr(), input_str->length(), cs, + system_charset_info, &conv_error); + if (!conv_error) + { + append_unescaped(output_str, val.ptr(), val.length()); + return; + } + } + /* We had a conversion error, use hex encoded string for safety */ + } + { + const uchar *ptr; + uint i, len; + char buf[3]; + + output_str->append("_"); + output_str->append(cs->csname); + output_str->append(" "); + output_str->append("0x"); + len= input_str->length(); + ptr= (uchar*)input_str->ptr(); + for (i= 0; i < len; i++) + { + uint high, low; + + high= (*ptr) >> 4; + low= (*ptr) & 0x0F; + buf[0]= _dig_vec_upper[high]; + buf[1]= _dig_vec_upper[low]; + buf[2]= 0; + output_str->append((const char*)buf); + ptr++; + } + } + return; } |
