diff options
Diffstat (limited to 'sql/sql_show.cc')
-rw-r--r-- | sql/sql_show.cc | 435 |
1 files changed, 285 insertions, 150 deletions
diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ac1825d7c84..f500e3bf481 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -47,7 +47,7 @@ static void store_key_options(THD *thd, String *packet, TABLE *table, KEY *key_info); /*************************************************************************** -** List all table types supported +** List all table types supported ***************************************************************************/ static my_bool show_handlerton(THD *thd, st_plugin_int *plugin, @@ -55,25 +55,26 @@ static my_bool show_handlerton(THD *thd, st_plugin_int *plugin, { handlerton *default_type= (handlerton *) arg; Protocol *protocol= thd->protocol; - handlerton *hton= (handlerton *) plugin->plugin->info; + handlerton *hton= (handlerton *)plugin->data; if (!(hton->flags & HTON_HIDDEN)) { protocol->prepare_for_resend(); - protocol->store(hton->name, system_charset_info); + protocol->store(plugin->name.str, plugin->name.length, + system_charset_info); const char *option_name= show_comp_option_name[(int) hton->state]; if (hton->state == SHOW_OPTION_YES && default_type == hton) option_name= "DEFAULT"; protocol->store(option_name, system_charset_info); - protocol->store(hton->comment, system_charset_info); + protocol->store(plugin->plugin->descr, system_charset_info); protocol->store(hton->commit ? "YES" : "NO", system_charset_info); protocol->store(hton->prepare ? "YES" : "NO", system_charset_info); protocol->store(hton->savepoint_set ? "YES" : "NO", system_charset_info); - + return protocol->write() ? 1 : 0; } - return 0; + return 0; } bool mysqld_show_storage_engines(THD *thd) @@ -93,7 +94,7 @@ bool mysqld_show_storage_engines(THD *thd) Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - if (plugin_foreach(thd, show_handlerton, + if (plugin_foreach(thd, show_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, thd->variables.table_type)) DBUG_RETURN(TRUE); @@ -740,6 +741,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) field_list.push_back(new Item_field(field)); } restore_record(table, s->default_values); // Get empty record + table->use_all_columns(); if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS | Protocol::SEND_EOF)) DBUG_VOID_RETURN; @@ -953,9 +955,9 @@ static void append_directory(THD *thd, String *packet, const char *dir_type, RETURN 0 OK */ -int -store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, - HA_CREATE_INFO *create_info_arg) + +int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, + HA_CREATE_INFO *create_info_arg) { List<Item> field_list; char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end, uname[NAME_LEN*3+1]; @@ -968,6 +970,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, handler *file= table->file; TABLE_SHARE *share= table->s; HA_CREATE_INFO create_info; + bool show_table_options= FALSE; bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | MODE_ORACLE | MODE_MSSQL | @@ -977,6 +980,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 | MODE_MYSQL40)) != 0; + my_bitmap_map *old_map; DBUG_ENTER("store_create_info"); DBUG_PRINT("enter",("table: %s", table->s->table_name.str)); @@ -999,6 +1003,12 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, } append_identifier(thd, packet, alias, strlen(alias)); packet->append(STRING_WITH_LEN(" (\n")); + /* + We need this to get default values from the table + We have to restore the read_set if we are called from insert in case + of row based replication. + */ + old_map= tmp_use_all_columns(table, table->read_set); for (ptr=table->field ; (field= *ptr); ptr++) { @@ -1153,10 +1163,11 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, table->field[key_part->fieldnr-1]->key_length() && !(key_info->flags & HA_FULLTEXT))) { + char *end; buff[0] = '('; - char* end=int10_to_str((long) key_part->length / - key_part->field->charset()->mbmaxlen, - buff + 1,10); + end= int10_to_str((long) key_part->length / + key_part->field->charset()->mbmaxlen, + buff + 1,10); *end++ = ')'; packet->append(buff,(uint) (end-buff)); } @@ -1185,6 +1196,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN("\n)")); if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode) { + show_table_options= TRUE; /* Get possible table space definitions and append them to the CREATE TABLE statement @@ -1325,13 +1337,15 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, (!table->part_info->is_auto_partitioned) && ((part_syntax= generate_partition_syntax(table->part_info, &part_syntax_len, - FALSE,FALSE)))) + FALSE, + show_table_options)))) { packet->append(part_syntax, part_syntax_len); my_free(part_syntax, MYF(0)); } } #endif + tmp_restore_column_map(table->read_set, old_map); DBUG_RETURN(0); } @@ -2375,7 +2389,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) TABLE *table= tables->table; SELECT_LEX *select_lex= &lex->select_lex; SELECT_LEX *old_all_select_lex= lex->all_selects_list; - TABLE_LIST **save_query_tables_last= lex->query_tables_last; enum_sql_command save_sql_command= lex->sql_command; SELECT_LEX *lsel= tables->schema_select_lex; ST_SCHEMA_TABLE *schema_table= tables->schema_table; @@ -2394,6 +2407,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) enum legacy_db_type not_used; Open_tables_state open_tables_state_backup; bool save_view_prepare_mode= lex->view_prepare_mode; + Query_tables_list query_tables_list_backup; lex->view_prepare_mode= TRUE; DBUG_ENTER("get_all_tables"); @@ -2406,6 +2420,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) */ lex->sql_command= SQLCOM_SHOW_FIELDS; + lex->reset_n_backup_query_tables_list(&query_tables_list_backup); + /* We should not introduce deadlocks even if we already have some tables open and locked, since we won't lock tables which we will @@ -2446,8 +2462,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) show_table_list->db), show_table_list->alias)); thd->temporary_tables= 0; - close_thread_tables(thd); - show_table_list->table= 0; + close_tables_for_reopen(thd, &show_table_list); goto err; } @@ -2539,8 +2554,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) { int res; /* - Set the parent lex of 'sel' because it is needed by sel.init_query() - which is called inside make_table_list. + Set the parent lex of 'sel' because it is needed by + sel.init_query() which is called inside make_table_list. */ sel.parent_lex= lex; if (make_table_list(thd, &sel, base_name, file_name)) @@ -2558,9 +2573,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) in this case. */ res= schema_table->process_table(thd, show_table_list, table, - res, base_name, - show_table_list->alias); - close_thread_tables(thd); + res, base_name, + show_table_list->alias); + close_tables_for_reopen(thd, &show_table_list); + DBUG_ASSERT(!lex->query_tables_own_last); if (res) goto err; } @@ -2577,11 +2593,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) error= 0; err: thd->restore_backup_open_tables_state(&open_tables_state_backup); + lex->restore_backup_query_tables_list(&query_tables_list_backup); lex->derived_tables= derived_tables; lex->all_selects_list= old_all_select_lex; - lex->query_tables_last= save_query_tables_last; lex->view_prepare_mode= save_view_prepare_mode; - *save_query_tables_last= 0; lex->sql_command= save_sql_command; DBUG_RETURN(error); } @@ -2735,50 +2750,55 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, case ROW_TYPE_COMPACT: tmp_buff= "Compact"; break; + case ROW_TYPE_PAGES: + tmp_buff= "Paged"; + break; } table->field[6]->store(tmp_buff, strlen(tmp_buff), cs); if (!tables->schema_table) { - table->field[7]->store((longlong) file->records, TRUE); + table->field[7]->store((longlong) file->stats.records, TRUE); table->field[7]->set_notnull(); } - table->field[8]->store((longlong) file->mean_rec_length, TRUE); - table->field[9]->store((longlong) file->data_file_length, TRUE); - if (file->max_data_file_length) + table->field[8]->store((longlong) file->stats.mean_rec_length, TRUE); + table->field[9]->store((longlong) file->stats.data_file_length, TRUE); + if (file->stats.max_data_file_length) { - table->field[10]->store((longlong) file->max_data_file_length, TRUE); + table->field[10]->store((longlong) file->stats.max_data_file_length, + TRUE); } - table->field[11]->store((longlong) file->index_file_length, TRUE); - table->field[12]->store((longlong) file->delete_length, TRUE); + table->field[11]->store((longlong) file->stats.index_file_length, TRUE); + table->field[12]->store((longlong) file->stats.delete_length, TRUE); if (show_table->found_next_number_field) { - table->field[13]->store((longlong) file->auto_increment_value, TRUE); + table->field[13]->store((longlong) file->stats.auto_increment_value, + TRUE); table->field[13]->set_notnull(); } - if (file->create_time) + if (file->stats.create_time) { thd->variables.time_zone->gmt_sec_to_TIME(&time, - file->create_time); + file->stats.create_time); table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[14]->set_notnull(); } - if (file->update_time) + if (file->stats.update_time) { thd->variables.time_zone->gmt_sec_to_TIME(&time, - file->update_time); + file->stats.update_time); table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[15]->set_notnull(); } - if (file->check_time) + if (file->stats.check_time) { - thd->variables.time_zone->gmt_sec_to_TIME(&time, file->check_time); + thd->variables.time_zone->gmt_sec_to_TIME(&time, file->stats.check_time); table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[16]->set_notnull(); } tmp_buff= (share->table_charset ? share->table_charset->name : "default"); table->field[17]->store(tmp_buff, strlen(tmp_buff), cs); - if (file->table_flags() & (ulong) HA_HAS_CHECKSUM) + if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM) { table->field[18]->store((longlong) file->checksum(), TRUE); table->field[18]->set_notnull(); @@ -2875,6 +2895,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, restore_record(show_table, s->default_values); base_name_length= strlen(base_name); file_name_length= strlen(file_name); + show_table->use_all_columns(); // Required for default for (ptr=show_table->field; (field= *ptr) ; ptr++) { @@ -3091,7 +3112,7 @@ static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin, void *ptable) { TABLE *table= (TABLE *) ptable; - handlerton *hton= (handlerton *) plugin->plugin->info; + handlerton *hton= (handlerton *)plugin->data; const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; CHARSET_INFO *scs= system_charset_info; DBUG_ENTER("iter_schema_engines"); @@ -3099,21 +3120,26 @@ static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin, if (!(hton->flags & HTON_HIDDEN)) { if (!(wild && wild[0] && - wild_case_compare(scs, hton->name,wild))) + wild_case_compare(scs, plugin->name.str,wild))) { - const char *tmp; + LEX_STRING state[2]= {{(char*) STRING_WITH_LEN("ENABLED")}, + {(char*) STRING_WITH_LEN("DISABLED")}}; + LEX_STRING yesno[2]= {{(char*) STRING_WITH_LEN("NO")}, + {(char*) STRING_WITH_LEN("YES")}}; + LEX_STRING *tmp; restore_record(table, s->default_values); - table->field[0]->store(hton->name, strlen(hton->name), scs); - tmp= hton->state ? "DISABLED" : "ENABLED"; - table->field[1]->store( tmp, strlen(tmp), scs); - table->field[2]->store(hton->comment, strlen(hton->comment), scs); - tmp= hton->commit ? "YES" : "NO"; - table->field[3]->store( tmp, strlen(tmp), scs); - tmp= hton->prepare ? "YES" : "NO"; - table->field[4]->store( tmp, strlen(tmp), scs); - tmp= hton->savepoint_set ? "YES" : "NO"; - table->field[5]->store( tmp, strlen(tmp), scs); + table->field[0]->store(plugin->name.str, plugin->name.length, scs); + tmp= &state[test(hton->state)]; + table->field[1]->store(tmp->str, tmp->length, scs); + table->field[2]->store(plugin->plugin->descr, + strlen(plugin->plugin->descr), scs); + tmp= &yesno[test(hton->commit)]; + table->field[3]->store(tmp->str, tmp->length, scs); + tmp= &yesno[test(hton->prepare)]; + table->field[4]->store(tmp->str, tmp->length, scs); + tmp= &yesno[test(hton->savepoint_set)]; + table->field[5]->store(tmp->str, tmp->length, scs); if (schema_table_store_record(thd, table)) DBUG_RETURN(1); @@ -3125,7 +3151,7 @@ static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin, int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond) { - return plugin_foreach(thd, iter_schema_engines, + return plugin_foreach(thd, iter_schema_engines, MYSQL_STORAGE_ENGINE_PLUGIN, tables->table); } @@ -3140,7 +3166,7 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) { CHARSET_INFO **cl; CHARSET_INFO *tmp_cs= cs[0]; - if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || + if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || (tmp_cs->state & MY_CS_HIDDEN) || !(tmp_cs->state & MY_CS_PRIMARY)) continue; @@ -3382,7 +3408,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, KEY *key=show_table->key_info+i; if (key->rec_per_key[j]) { - ha_rows records=(show_table->file->records / + ha_rows records=(show_table->file->stats.records / key->rec_per_key[j]); table->field[9]->store((longlong) records, TRUE); table->field[9]->set_notnull(); @@ -3809,7 +3835,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *table, table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[20]->set_notnull(); } - if (file->table_flags() & (ulong) HA_HAS_CHECKSUM) + if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM) { table->field[21]->store((longlong) stat_info.check_sum, TRUE); table->field[21]->set_notnull(); @@ -3911,24 +3937,28 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables, { table->field[9]->store(part_info->part_func_string, part_info->part_func_len, cs); - table->field[9]->set_notnull(); } else if (part_info->list_of_part_fields) { collect_partition_expr(part_info->part_field_list, &tmp_str); table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs); - table->field[9]->set_notnull(); } + table->field[9]->set_notnull(); if (part_info->is_sub_partitioned()) { /* Subpartition method */ + tmp_res.length(0); + if (part_info->linear_hash_ind) + tmp_res.append(partition_keywords[PKW_LINEAR].str, + partition_keywords[PKW_LINEAR].length); if (part_info->list_of_subpart_fields) - table->field[8]->store(partition_keywords[PKW_KEY].str, - partition_keywords[PKW_KEY].length, cs); + tmp_res.append(partition_keywords[PKW_KEY].str, + partition_keywords[PKW_KEY].length); else - table->field[8]->store(partition_keywords[PKW_HASH].str, - partition_keywords[PKW_HASH].length, cs); + tmp_res.append(partition_keywords[PKW_HASH].str, + partition_keywords[PKW_HASH].length); + table->field[8]->store(tmp_res.ptr(), tmp_res.length(), cs); table->field[8]->set_notnull(); /* Subpartition expression */ @@ -3936,14 +3966,13 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables, { table->field[10]->store(part_info->subpart_func_string, part_info->subpart_func_len, cs); - table->field[10]->set_notnull(); } else if (part_info->list_of_subpart_fields) { collect_partition_expr(part_info->subpart_field_list, &tmp_str); table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs); - table->field[10]->set_notnull(); } + table->field[10]->set_notnull(); } while ((part_elem= part_it++)) @@ -4078,8 +4107,24 @@ static interval_type get_real_interval_type(interval_type i_type) extern LEX_STRING interval_type_to_name[]; + +/* + Loads an event from mysql.event and copies it's data to a row of + I_S.EVENTS + + Synopsis + copy_event_to_schema_table() + thd Thread + sch_table The schema table (information_schema.event) + event_table The event table to use for loading (mysql.event). + + Returns + 0 OK + 1 Error +*/ + static int -fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) +copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) { const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; CHARSET_INFO *scs= system_charset_info; @@ -4097,9 +4142,19 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0))) DBUG_RETURN(0); - + + /* + Skip events in schemas one does not have access to. The check is + optimized. It's guaranteed in case of SHOW EVENTS that the user + has access. + */ + if (thd->lex->orig_sql_command != SQLCOM_SHOW_EVENTS && + check_access(thd, EVENT_ACL, et.dbname.str, 0, 0, 1, + is_schema_db(et.dbname.str))) + DBUG_RETURN(0); + /* ->field[0] is EVENT_CATALOG and is by default NULL */ - + sch_table->field[1]->store(et.dbname.str, et.dbname.length, scs); sch_table->field[2]->store(et.name.str, et.name.length, scs); sch_table->field[3]->store(et.definer.str, et.definer.length, scs); @@ -4111,29 +4166,28 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) ulong sql_mode_len=0; sql_mode_str= sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode, - &sql_mode_len); + &sql_mode_len); sch_table->field[9]->store((const char*)sql_mode_str, sql_mode_len, scs); } - + if (et.expression) { String show_str; /* type */ sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs); - if (Events::reconstruct_interval_expression(&show_str, - et.interval, - et.expression)) + if (Events::reconstruct_interval_expression(&show_str, et.interval, + et.expression)) DBUG_RETURN(1); sch_table->field[7]->set_notnull(); - sch_table->field[7]->store(show_str.c_ptr(), show_str.length(), scs); + sch_table->field[7]->store(show_str.ptr(), show_str.length(), scs); LEX_STRING *ival= &interval_type_to_name[et.interval]; sch_table->field[8]->set_notnull(); sch_table->field[8]->store(ival->str, ival->length, scs); - //starts & ends + /* starts & ends */ sch_table->field[10]->set_notnull(); sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME); @@ -4152,13 +4206,13 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME); } - //status + /* status */ if (et.status == Event_timed::ENABLED) sch_table->field[12]->store(STRING_WITH_LEN("ENABLED"), scs); else sch_table->field[12]->store(STRING_WITH_LEN("DISABLED"), scs); - //on_completion + /* on_completion */ if (et.on_completion == Event_timed::ON_COMPLETION_DROP) sch_table->field[13]->store(STRING_WITH_LEN("NOT PRESERVE"), scs); else @@ -4188,98 +4242,179 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) } -int fill_schema_events(THD *thd, TABLE_LIST *tables, COND *cond) +/* + Performs an index scan of event_table (mysql.event) and fills schema_table. + + Synopsis + events_table_index_read_for_db() + thd Thread + schema_table The I_S.EVENTS table + event_table The event table to use for loading (mysql.event) + + Returns + 0 OK + 1 Error +*/ + +static +int events_table_index_read_for_db(THD *thd, TABLE *schema_table, + TABLE *event_table) { - TABLE *table= tables->table; - CHARSET_INFO *scs= system_charset_info; - TABLE *event_table= NULL; - Open_tables_state backup; int ret=0; - bool verbose= false; - char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; - bool use_prefix_scanning= true; - uint key_len= 0; + CHARSET_INFO *scs= system_charset_info; + KEY *key_info; + uint key_len; byte *key_buf= NULL; LINT_INIT(key_buf); - DBUG_ENTER("fill_schema_events"); - - strxmov(definer, thd->security_ctx->priv_user,"@",thd->security_ctx->priv_host, - NullS); - - DBUG_PRINT("info",("db=%s current_user=%s", thd->lex->select_lex.db, definer)); + DBUG_ENTER("schema_events_do_index_scan"); - thd->reset_n_backup_open_tables_state(&backup); + DBUG_PRINT("info", ("Using prefix scanning on PK")); + event_table->file->ha_index_init(0, 1); + event_table->field[Events::FIELD_DB]-> + store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs); + key_info= event_table->key_info; + key_len= key_info->key_part[0].store_length; - if ((ret= Events::open_event_table(thd, TL_READ, &event_table))) + if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len))) { - sql_print_error("Table mysql.event is damaged."); ret= 1; - goto err; - } - - event_table->file->ha_index_init(0, 1); - - /* see others' events only if you have PROCESS_ACL !! */ - verbose= ((thd->lex->verbose || - thd->lex->orig_sql_command != SQLCOM_SHOW_EVENTS) && - (thd->security_ctx->master_access & PROCESS_ACL)); - - if (verbose && thd->security_ctx->user) - { - ret= event_table->file->index_first(event_table->record[0]); - use_prefix_scanning= false; + /* don't send error, it would be done by sql_alloc_error_handler() */ } else { - event_table->field[Events::FIELD_DEFINER]-> - store(definer, strlen(definer), scs); - key_len= event_table->key_info->key_part[0].store_length; - - if (thd->lex->select_lex.db) + key_copy(key_buf, event_table->record[0], key_info, key_len); + if (!(ret= event_table->file->index_read(event_table->record[0], key_buf, + key_len, HA_READ_PREFIX))) { - event_table->field[Events::FIELD_DB]-> - store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs); - key_len+= event_table->key_info->key_part[1].store_length; - } - if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len))) - { - ret= 1; - goto err; + DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret)); + do + { + ret= copy_event_to_schema_table(thd, schema_table, event_table); + if (ret == 0) + ret= event_table->file->index_next_same(event_table->record[0], + key_buf, key_len); + } while (ret == 0); } - - key_copy(key_buf, event_table->record[0], event_table->key_info, key_len); - ret= event_table->file->index_read(event_table->record[0], key_buf, key_len, - HA_READ_PREFIX); + DBUG_PRINT("info", ("Scan finished. ret=%d", ret)); } + event_table->file->ha_index_end(); + /* ret is guaranteed to be != 0 */ + if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND) + DBUG_RETURN(0); + DBUG_RETURN(1); +} - if (ret) + +/* + Performs a table scan of event_table (mysql.event) and fills schema_table. + + Synopsis + events_table_scan_all() + thd Thread + schema_table The I_S.EVENTS in memory table + event_table The event table to use for loading. + + Returns + 0 OK + 1 Error +*/ + +static +int events_table_scan_all(THD *thd, TABLE *schema_table, + TABLE *event_table) +{ + int ret; + READ_RECORD read_record_info; + + DBUG_ENTER("schema_events_do_table_scan"); + init_read_record(&read_record_info, thd, event_table, NULL, 1, 0); + + /* + rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE, + but rr_handle_error returns -1 for that reason. Thus, read_record() + returns -1 eventually. + */ + do { - ret= (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND) ? 0 : 1; - goto err; + ret= read_record_info.read_record(&read_record_info); + if (ret == 0) + ret= copy_event_to_schema_table(thd, schema_table, event_table); } + while (ret == 0); - while (!ret) - { - if ((ret= fill_events_copy_to_schema_table(thd, table, event_table))) - goto err; + DBUG_PRINT("info", ("Scan finished. ret=%d", ret)); + end_read_record(&read_record_info); - if (use_prefix_scanning) - ret= event_table->file-> - index_next_same(event_table->record[0], key_buf, key_len); - else - ret= event_table->file->index_next(event_table->record[0]); + /* ret is guaranteed to be != 0 */ + DBUG_RETURN(ret == -1? 0:1); +} + + +/* + Fills I_S.EVENTS with data loaded from mysql.event. Also used by + SHOW EVENTS + + Synopsis + fill_schema_events() + thd Thread + tables The schema table + cond Unused + + Returns + 0 OK + 1 Error +*/ + +int fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) +{ + TABLE *schema_table= tables->table; + TABLE *event_table= NULL; + Open_tables_state backup; + int ret= 0; + + DBUG_ENTER("fill_schema_events"); + /* + If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to + be NULL. Let's do an assert anyway. + */ + if (thd->lex->orig_sql_command == SQLCOM_SHOW_EVENTS) + { + DBUG_ASSERT(thd->lex->select_lex.db); + if (check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0, + is_schema_db(thd->lex->select_lex.db))) + DBUG_RETURN(1); } - // ret is guaranteed to be != 0 - ret= (ret != HA_ERR_END_OF_FILE); -err: - if (event_table) + + DBUG_PRINT("info",("db=%s", thd->lex->select_lex.db? + thd->lex->select_lex.db:"(null)")); + + thd->reset_n_backup_open_tables_state(&backup); + if (Events::open_event_table(thd, TL_READ, &event_table)) { - event_table->file->ha_index_end(); - close_thread_tables(thd); + sql_print_error("Table mysql.event is damaged."); + thd->restore_backup_open_tables_state(&backup); + DBUG_RETURN(1); } + /* + 1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order + thus we won't order it. OTOH, SHOW EVENTS will be + ordered. + 2. SHOW EVENTS => PRIMARY KEY with prefix scanning on (db) + Reasoning: Events are per schema, therefore a scan over an index + will save use from doing a table scan and comparing + every single row's `db` with the schema which we show. + */ + if (thd->lex->orig_sql_command == SQLCOM_SHOW_EVENTS) + ret= events_table_index_read_for_db(thd, schema_table, event_table); + else + ret= events_table_scan_all(thd, schema_table, event_table); + + close_thread_tables(thd); thd->restore_backup_open_tables_state(&backup); + + DBUG_PRINT("info", ("Return code=%d", ret)); DBUG_RETURN(ret); } @@ -4502,7 +4637,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) field_count++; } TMP_TABLE_PARAM *tmp_table_param = - (TMP_TABLE_PARAM*) (thd->calloc(sizeof(TMP_TABLE_PARAM))); + (TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM))); tmp_table_param->init(); tmp_table_param->table_charset= cs; tmp_table_param->field_count= field_count; @@ -4874,7 +5009,7 @@ bool get_schema_tables_result(JOIN *join) filesort_free_buffers(table_list->table); } else - table_list->table->file->records= 0; + table_list->table->file->stats.records= 0; if (table_list->schema_table->fill_table(thd, table_list, tab->select_cond)) @@ -4897,7 +5032,7 @@ static my_bool run_hton_fill_schema_files(THD *thd, st_plugin_int *plugin, { struct run_hton_fill_schema_files_args *args= (run_hton_fill_schema_files_args *) arg; - handlerton *hton= (handlerton *) plugin->plugin->info; + handlerton *hton= (handlerton *)plugin->data; if(hton->fill_files_table) hton->fill_files_table(thd, args->tables, args->cond); return false; @@ -5241,7 +5376,7 @@ ST_FIELD_INFO partitions_fields_info[]= {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 1, 0}, {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 1, 0}, {"PARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0}, - {"SUBPARTITION_METHOD", 5, MYSQL_TYPE_STRING, 0, 1, 0}, + {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0}, {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0}, {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0}, {"PARTITION_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0}, @@ -5316,9 +5451,9 @@ ST_FIELD_INFO files_fields_info[]= {"FREE_EXTENTS", 4, MYSQL_TYPE_LONG, 0, 0, 0}, {"TOTAL_EXTENTS", 4, MYSQL_TYPE_LONG, 0, 0, 0}, {"EXTENT_SIZE", 4, MYSQL_TYPE_LONG, 0, 0, 0}, - {"INITIAL_SIZE", 8, MYSQL_TYPE_LONGLONG, 0, 0, 0}, - {"MAXIMUM_SIZE", 8, MYSQL_TYPE_LONGLONG, 0, 0, 0}, - {"AUTOEXTEND_SIZE", 8, MYSQL_TYPE_LONGLONG, 0, 0, 0}, + {"INITIAL_SIZE", 21, MYSQL_TYPE_LONG, 0, 0, 0}, + {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONG, 0, 0, 0}, + {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONG, 0, 0, 0}, {"CREATION_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, {"LAST_UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, {"LAST_ACCESS_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, |