diff options
Diffstat (limited to 'sql/table.cc')
-rw-r--r-- | sql/table.cc | 438 |
1 files changed, 244 insertions, 194 deletions
diff --git a/sql/table.cc b/sql/table.cc index f6bea7221ce..a4065f2c393 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -31,7 +31,7 @@ #include "sql_partition.h" // mysql_unpack_partition, // fix_partition_func, partition_info #include "sql_acl.h" // *_ACL, acl_getroot_no_password -#include "sql_base.h" // release_table_share +#include "sql_base.h" #include "create_options.h" #include <m_ctype.h> #include "my_md5.h" @@ -148,7 +148,7 @@ View_creation_ctx * View_creation_ctx::create(THD *thd, if (!view->view_client_cs_name.str || !view->view_connection_cl_name.str) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_VIEW_NO_CREATION_CTX, ER(ER_VIEW_NO_CREATION_CTX), (const char *) view->db, @@ -182,7 +182,7 @@ View_creation_ctx * View_creation_ctx::create(THD *thd, (const char *) view->view_client_cs_name.str, (const char *) view->view_connection_cl_name.str); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_VIEW_INVALID_CREATION_CTX, ER(ER_VIEW_INVALID_CREATION_CTX), (const char *) view->db, @@ -273,7 +273,7 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name) /* - Allocate a setup TABLE_SHARE structure + Allocate and setup a TABLE_SHARE structure SYNOPSIS alloc_table_share() @@ -287,7 +287,7 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name) */ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, - char *key, uint key_length) + const char *key, uint key_length) { MEM_ROOT mem_root; TABLE_SHARE *share; @@ -315,29 +315,20 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, strmov(share->path.str, path); share->normalized_path.str= share->path.str; share->normalized_path.length= path_length; + /* TEMPORARY FIX: if true, this means this is mysql.gtid_slave_pos table */ + share->is_gtid_slave_pos= FALSE; share->table_category= get_table_category(& share->db, & share->table_name); - share->set_refresh_version(); share->open_errno= ENOENT; - - /* - Since alloc_table_share() can be called without any locking (for - example, ha_create_table... functions), we do not assign a table - map id here. Instead we assign a value that is not used - elsewhere, and then assign a table map id inside open_table() - under the protection of the LOCK_open mutex. - */ - share->table_map_id= ~0UL; share->cached_row_logging_check= -1; - share->used_tables.empty(); - share->free_tables.empty(); - share->m_flush_tickets.empty(); - init_sql_alloc(&share->stats_cb.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0)); memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root)); + mysql_mutex_init(key_TABLE_SHARE_LOCK_share, + &share->LOCK_share, MY_MUTEX_INIT_SLOW); mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data, &share->LOCK_ha_data, MY_MUTEX_INIT_FAST); + tdc_init_share(share); } DBUG_RETURN(share); } @@ -350,7 +341,7 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, init_tmp_table_share() thd thread handle share Share to fill - key Table_cache_key, as generated from create_table_def_key. + key Table_cache_key, as generated from tdc_create_key. must start with db name. key_length Length of key table_name Table name @@ -400,11 +391,6 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key, compatibility checks. */ share->table_map_id= (ulong) thd->query_id; - - share->used_tables.empty(); - share->free_tables.empty(); - share->m_flush_tickets.empty(); - DBUG_VOID_RETURN; } @@ -419,20 +405,28 @@ void TABLE_SHARE::destroy() { uint idx; KEY *info_it; + DBUG_ENTER("TABLE_SHARE::destroy"); + DBUG_PRINT("info", ("db: %s table: %s", db.str, table_name.str)); + + if (ha_share) + { + delete ha_share; + ha_share= NULL; // Safety + } - if (tmp_table == NO_TMP_TABLE) - mysql_mutex_lock(&LOCK_ha_data); free_root(&stats_cb.mem_root, MYF(0)); stats_cb.stats_can_be_read= FALSE; stats_cb.stats_is_read= FALSE; stats_cb.histograms_can_be_read= FALSE; stats_cb.histograms_are_read= FALSE; - if (tmp_table == NO_TMP_TABLE) - mysql_mutex_unlock(&LOCK_ha_data); - /* The mutex is initialized only for shares that are part of the TDC */ + /* The mutexes are initialized only for shares that are part of the TDC */ if (tmp_table == NO_TMP_TABLE) + { + mysql_mutex_destroy(&LOCK_share); mysql_mutex_destroy(&LOCK_ha_data); + tdc_deinit_share(this); + } my_hash_free(&name_hash); plugin_unlock(NULL, db_plugin); @@ -448,25 +442,20 @@ void TABLE_SHARE::destroy() info_it->flags= 0; } } - if (ha_data_destroy) - { - ha_data_destroy(ha_data); - ha_data_destroy= NULL; - } + #ifdef WITH_PARTITION_STORAGE_ENGINE plugin_unlock(NULL, default_part_plugin); - if (ha_part_data_destroy) - { - ha_part_data_destroy(ha_part_data); - ha_part_data_destroy= NULL; - } #endif /* WITH_PARTITION_STORAGE_ENGINE */ + + PSI_CALL_release_table_share(m_psi); + /* Make a copy since the share is allocated in its own root, and free_root() updates its argument after freeing the memory. */ MEM_ROOT own_root= mem_root; free_root(&own_root, MYF(0)); + DBUG_VOID_RETURN; } /* @@ -481,37 +470,7 @@ void free_table_share(TABLE_SHARE *share) { DBUG_ENTER("free_table_share"); DBUG_PRINT("enter", ("table: %s.%s", share->db.str, share->table_name.str)); - DBUG_ASSERT(share->ref_count == 0); - - if (share->m_flush_tickets.is_empty()) - { - /* - No threads are waiting for this share to be flushed (the - share is not old, is for a temporary table, or just nobody - happens to be waiting for it). Destroy it. - */ - share->destroy(); - } - else - { - Wait_for_flush_list::Iterator it(share->m_flush_tickets); - Wait_for_flush *ticket; - /* - We're about to iterate over a list that is used - concurrently. Make sure this never happens without a lock. - */ - mysql_mutex_assert_owner(&LOCK_open); - - while ((ticket= it++)) - (void) ticket->get_ctx()->m_wait.set_status(MDL_wait::GRANTED); - /* - If there are threads waiting for this share to be flushed, - the last one to receive the notification will destroy the - share. At this point the share is removed from the table - definition cache, so is OK to proceed here without waiting - for this thread to do the work. - */ - } + share->destroy(); DBUG_VOID_RETURN; } @@ -556,12 +515,16 @@ inline bool is_system_table_name(const char *name, uint length) my_tolower(ci, name[2]) == 'm' && my_tolower(ci, name[3]) == 'e') || - /* one of mysql.*_stat tables */ - (my_tolower(ci, name[length-5]) == 's' && - my_tolower(ci, name[length-4]) == 't' && - my_tolower(ci, name[length-3]) == 'a' && - my_tolower(ci, name[length-2]) == 't' && - my_tolower(ci, name[length-1]) == 's') || + /* one of mysql.*_stat tables, but not mysql.innodb* tables*/ + ((my_tolower(ci, name[length-5]) == 's' && + my_tolower(ci, name[length-4]) == 't' && + my_tolower(ci, name[length-3]) == 'a' && + my_tolower(ci, name[length-2]) == 't' && + my_tolower(ci, name[length-1]) == 's') && + !(my_tolower(ci, name[0]) == 'i' && + my_tolower(ci, name[1]) == 'n' && + my_tolower(ci, name[2]) == 'n' && + my_tolower(ci, name[3]) == 'o')) || /* mysql.event table */ (my_tolower(ci, name[0]) == 'e' && @@ -586,7 +549,7 @@ inline bool is_system_table_name(const char *name, uint length) NOTES This function is called when the table definition is not cached in - table_def_cache + table definition cache The data is returned in 'share', which is alloced by alloc_table_share().. The code assumes that share is initialized. */ @@ -732,7 +695,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, return 1; keyinfo->flags= (uint) uint2korr(strpos) ^ HA_NOSAME; keyinfo->key_length= (uint) uint2korr(strpos+2); - keyinfo->key_parts= (uint) strpos[4]; + keyinfo->user_defined_key_parts= (uint) strpos[4]; keyinfo->algorithm= (enum ha_key_alg) strpos[5]; keyinfo->block_size= uint2korr(strpos+6); strpos+=8; @@ -743,14 +706,14 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, return 1; keyinfo->flags= ((uint) strpos[0]) ^ HA_NOSAME; keyinfo->key_length= (uint) uint2korr(strpos+1); - keyinfo->key_parts= (uint) strpos[3]; + keyinfo->user_defined_key_parts= (uint) strpos[3]; keyinfo->algorithm= HA_KEY_ALG_UNDEF; strpos+=4; } if (i == 0) { - ext_key_parts+= (share->use_ext_keys ? first_keyinfo->key_parts*(keys-1) : 0); + ext_key_parts+= (share->use_ext_keys ? first_keyinfo->user_defined_key_parts*(keys-1) : 0); n_length=keys * sizeof(KEY) + ext_key_parts * sizeof(KEY_PART_INFO); if (!(keyinfo= (KEY*) alloc_root(&share->mem_root, n_length + len))) @@ -763,10 +726,10 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, sizeof(ulong) * ext_key_parts))) return 1; first_key_part= key_part; - first_key_parts= first_keyinfo->key_parts; + first_key_parts= first_keyinfo->user_defined_key_parts; keyinfo->flags= first_keyinfo->flags; keyinfo->key_length= first_keyinfo->key_length; - keyinfo->key_parts= first_keyinfo->key_parts; + keyinfo->user_defined_key_parts= first_keyinfo->user_defined_key_parts; keyinfo->algorithm= first_keyinfo->algorithm; if (new_frm_ver >= 3) keyinfo->block_size= first_keyinfo->block_size; @@ -774,7 +737,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, keyinfo->key_part= key_part; keyinfo->rec_per_key= rec_per_key; - for (j=keyinfo->key_parts ; j-- ; key_part++) + for (j=keyinfo->user_defined_key_parts ; j-- ; key_part++) { if (strpos + (new_frm_ver >= 1 ? 9 : 7) >= frm_image_end) return 1; @@ -802,17 +765,22 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, } key_part->store_length=key_part->length; } - keyinfo->ext_key_parts= keyinfo->key_parts; + + /* + Add primary key to end of extended keys for non unique keys for + storage engines that supports it. + */ + keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; keyinfo->ext_key_flags= keyinfo->flags; keyinfo->ext_key_part_map= 0; - if (share->use_ext_keys && i) + if (share->use_ext_keys && i && !(keyinfo->flags & HA_NOSAME)) { keyinfo->ext_key_part_map= 0; for (j= 0; j < first_key_parts && keyinfo->ext_key_parts < MAX_REF_PARTS; j++) { - uint key_parts= keyinfo->key_parts; + uint key_parts= keyinfo->user_defined_key_parts; KEY_PART_INFO* curr_key_part= keyinfo->key_part; KEY_PART_INFO* curr_key_part_end= curr_key_part+key_parts; for ( ; curr_key_part < curr_key_part_end; curr_key_part++) @@ -865,6 +833,42 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, /** + Check if a collation has changed number + + @param mysql_version + @param current collation number + + @retval new collation number (same as current collation number of no change) +*/ + +static uint +upgrade_collation(ulong mysql_version, uint cs_number) +{ + if (mysql_version >= 50300 && mysql_version <= 50399) + { + switch (cs_number) { + case 149: return MY_PAGE2_COLLATION_ID_UCS2; // ucs2_crotian_ci + case 213: return MY_PAGE2_COLLATION_ID_UTF8; // utf8_crotian_ci + } + } + if ((mysql_version >= 50500 && mysql_version <= 50599) || + (mysql_version >= 100000 && mysql_version <= 100005)) + { + switch (cs_number) { + case 149: return MY_PAGE2_COLLATION_ID_UCS2; // ucs2_crotian_ci + case 213: return MY_PAGE2_COLLATION_ID_UTF8; // utf8_crotian_ci + case 214: return MY_PAGE2_COLLATION_ID_UTF32; // utf32_croatian_ci + case 215: return MY_PAGE2_COLLATION_ID_UTF16; // utf16_croatian_ci + case 245: return MY_PAGE2_COLLATION_ID_UTF8MB4;// utf8mb4_croatian_ci + } + } + return cs_number; +} + + + + +/** Read data from a binary .frm file image into a TABLE_SHARE @note @@ -1041,13 +1045,21 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, share->null_field_first= 0; if (!frm_image[32]) // New frm file in 3.23 { + uint cs_org= (((uint) frm_image[41]) << 8) + (uint) frm_image[38]; + uint cs_new= upgrade_collation(share->mysql_version, cs_org); + if (cs_org != cs_new) + share->incompatible_version|= HA_CREATE_USED_CHARSET; + share->avg_row_length= uint4korr(frm_image+34); share->transactional= (ha_choice) (frm_image[39] & 3); share->page_checksum= (ha_choice) ((frm_image[39] >> 2) & 3); share->row_type= (enum row_type) frm_image[40]; - share->table_charset= get_charset((((uint) frm_image[41]) << 8) + - (uint) frm_image[38],MYF(0)); + + if (cs_new && !(share->table_charset= get_charset(cs_new, MYF(MY_WME)))) + goto err; share->null_field_first= 1; + share->stats_sample_pages= uint2korr(frm_image+42); + share->stats_auto_recalc= (enum_stats_auto_recalc)(frm_image[44]); } if (!share->table_charset) { @@ -1062,9 +1074,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } share->table_charset= default_charset_info; } + share->db_record_offset= 1; - if (db_create_options & HA_OPTION_LONG_BLOB_PTR) - share->blob_ptr_size= portable_sizeof_char_ptr; share->max_rows= uint4korr(frm_image+18); share->min_rows= uint4korr(frm_image+22); @@ -1383,6 +1394,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, plugin_hton(se_plugin)))) goto err; + if (handler_file->set_ha_share_ref(&share->ha_share)) + goto err; + record= share->default_values-1; /* Fieldstart = 1 */ null_bits_are_used= share->null_fields != 0; if (share->null_field_first) @@ -1447,16 +1461,19 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } else { - uint csid= strpos[14] + (((uint) strpos[11]) << 8); - if (!csid) + uint cs_org= strpos[14] + (((uint) strpos[11]) << 8); + uint cs_new= upgrade_collation(share->mysql_version, cs_org); + if (cs_org != cs_new) + share->incompatible_version|= HA_CREATE_USED_CHARSET; + if (!cs_new) charset= &my_charset_bin; - else if (!(charset= get_charset(csid, MYF(0)))) + else if (!(charset= get_charset(cs_new, MYF(0)))) { - const char *csname= get_charset_name((uint) csid); + const char *csname= get_charset_name((uint) cs_new); char tmp[10]; if (!csname || csname[0] =='?') { - my_snprintf(tmp, sizeof(tmp), "#%d", csid); + my_snprintf(tmp, sizeof(tmp), "#%d", cs_new); csname= tmp; } my_printf_error(ER_UNKNOWN_COLLATION, @@ -1580,7 +1597,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, "Please do \"ALTER TABLE '%s' FORCE\" to fix it!", share->fieldnames.type_names[i], share->table_name.str, share->table_name.str); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_CRASHED_ON_USAGE, "Found incompatible DECIMAL field '%s' in %s; " "Please do \"ALTER TABLE '%s' FORCE\" to fix it!", @@ -1667,12 +1684,12 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } else { - add_first_key_parts= first_keyinfo.key_parts; + add_first_key_parts= first_keyinfo.user_defined_key_parts; /* Do not add components of the primary key starting from the major component defined over the beginning of a field. */ - for (i= 0; i < first_keyinfo.key_parts; i++) + for (i= 0; i < first_keyinfo.user_defined_key_parts; i++) { uint fieldnr= keyinfo[0].key_part[i].fieldnr; if (share->field[fieldnr-1]->key_length() != @@ -1711,7 +1728,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, Do not extend the key that contains a component defined over the beginning of a field. */ - for (i= 0; i < keyinfo->key_parts; i++) + for (i= 0; i < keyinfo->user_defined_key_parts; i++) { uint fieldnr= keyinfo->key_part[i].fieldnr; if (share->field[fieldnr-1]->key_length() != @@ -1722,11 +1739,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } } - if (add_first_key_parts < keyinfo->ext_key_parts-keyinfo->key_parts) + if (add_first_key_parts < keyinfo->ext_key_parts-keyinfo->user_defined_key_parts) { share->ext_key_parts-= keyinfo->ext_key_parts; key_part_map ext_key_part_map= keyinfo->ext_key_part_map; - keyinfo->ext_key_parts= keyinfo->key_parts; + keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; keyinfo->ext_key_flags= keyinfo->flags; keyinfo->ext_key_part_map= 0; for (i= 0; i < add_first_key_parts; i++) @@ -1759,7 +1776,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, */ primary_key=key; key_part= keyinfo->key_part; - for (i=0 ; i < keyinfo->key_parts ;i++) + for (i=0 ; i < keyinfo->user_defined_key_parts ;i++) { uint fieldnr= key_part[i].fieldnr; if (!fieldnr || @@ -1775,7 +1792,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, key_part= keyinfo->key_part; uint key_parts= share->use_ext_keys ? keyinfo->ext_key_parts : - keyinfo->key_parts; + keyinfo->user_defined_key_parts; for (i=0; i < key_parts; key_part++, i++) { Field *field; @@ -1815,7 +1832,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (i == 0 && key != primary_key) field->flags |= (((keyinfo->flags & HA_NOSAME) && - (keyinfo->key_parts == 1)) ? + (keyinfo->user_defined_key_parts == 1)) ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG); if (i == 0) field->key_start.set_bit(key); @@ -1826,7 +1843,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, { share->keys_for_keyread.set_bit(key); field->part_of_key.set_bit(key); - if (i < keyinfo->key_parts) + if (i < keyinfo->user_defined_key_parts) field->part_of_key_not_clustered.set_bit(key); } if (handler_file->index_flags(key, i, 1) & HA_READ_ORDER) @@ -1872,7 +1889,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, "Please do \"ALTER TABLE '%s' FORCE \" to fix it!", share->table_name.str, share->table_name.str); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_CRASHED_ON_USAGE, "Found wrong key definition in %s; " "Please do \"ALTER TABLE '%s' FORCE\" to fix " @@ -1900,7 +1917,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, keyinfo->usable_key_parts= usable_parts; // Filesort set_if_bigger(share->max_key_length,keyinfo->key_length+ - keyinfo->key_parts); + keyinfo->user_defined_key_parts); share->total_key_length+= keyinfo->key_length; /* MERGE tables do not have unique indexes. But every key could be @@ -1918,7 +1935,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, If we are using an integer as the primary key then allow the user to refer to it as '_rowid' */ - if (share->key_info[primary_key].key_parts == 1) + if (share->key_info[primary_key].user_defined_key_parts == 1) { Field *field= share->key_info[primary_key].key_part[0].field; if (field && field->result_type() == INT_RESULT) @@ -2017,18 +2034,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, delete handler_file; plugin_unlock(0, se_plugin); my_hash_free(&share->name_hash); - if (share->ha_data_destroy) - { - share->ha_data_destroy(share->ha_data); - share->ha_data_destroy= NULL; - } -#ifdef WITH_PARTITION_STORAGE_ENGINE - if (share->ha_part_data_destroy) - { - share->ha_part_data_destroy(share->ha_part_data); - share->ha_data_destroy= NULL; - } -#endif /* WITH_PARTITION_STORAGE_ENGINE */ if (!thd->is_error()) open_table_error(share, OPEN_FRM_CORRUPTED, share->open_errno); @@ -2038,7 +2043,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } -static bool sql_unusable_for_discovery(THD *thd, const char *sql) +static bool sql_unusable_for_discovery(THD *thd, handlerton *engine, + const char *sql) { LEX *lex= thd->lex; HA_CREATE_INFO *create_info= &lex->create_info; @@ -2053,7 +2059,7 @@ static bool sql_unusable_for_discovery(THD *thd, const char *sql) if (lex->select_lex.item_list.elements) return 1; // ... temporary - if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + if (create_info->tmp_table()) return 1; // ... if exists if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) @@ -2070,7 +2076,7 @@ static bool sql_unusable_for_discovery(THD *thd, const char *sql) if (create_info->data_file_name || create_info->index_file_name) return 1; // ... engine - if (create_info->used_fields & HA_CREATE_USED_ENGINE) + if (create_info->db_type && create_info->db_type != engine) return 1; return 0; @@ -2088,6 +2094,9 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write, LEX *old_lex; Query_arena *arena, backup; LEX tmp_lex; + KEY *unused1; + uint unused2; + handlerton *hton= plugin_hton(db_plugin); LEX_CUSTRING frm= {0,0}; DBUG_ENTER("TABLE_SHARE::init_from_sql_statement_string"); @@ -2119,17 +2128,18 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write, lex_start(thd); if ((error= parse_sql(thd, & parser_state, NULL) || - sql_unusable_for_discovery(thd, sql_copy))) + sql_unusable_for_discovery(thd, hton, sql_copy))) goto ret; - thd->lex->create_info.db_type= plugin_hton(db_plugin); + thd->lex->create_info.db_type= hton; if (tabledef_version.str) thd->lex->create_info.tabledef_version= tabledef_version; + promote_first_timestamp_column(&thd->lex->alter_info.create_list); file= mysql_create_frm_image(thd, db.str, table_name.str, &thd->lex->create_info, &thd->lex->alter_info, - C_ORDINARY_CREATE, &frm); + C_ORDINARY_CREATE, &unused1, &unused2, &frm); error|= file == 0; delete file; @@ -2528,6 +2538,13 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, outparam->db_stat= db_stat; outparam->write_row_record= NULL; + if (share->incompatible_version && + !(ha_open_flags & (HA_OPEN_FOR_ALTER | HA_OPEN_FOR_REPAIR))) + { + /* one needs to run mysql_upgrade on the table */ + error= OPEN_FRM_NEEDS_REBUILD; + goto err; + } init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0)); if (outparam->alias.copy(alias, strlen(alias), table_alias_charset)) @@ -2544,6 +2561,9 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, if (!(outparam->file= get_new_handler(share, &outparam->mem_root, share->db_type()))) goto err; + + if (outparam->file->set_ha_share_ref(&share->ha_share)) + goto err; } else { @@ -2643,7 +2663,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, key_info->key_part= key_part; key_part_end= key_part + (share->use_ext_keys ? key_info->ext_key_parts : - key_info->key_parts) ; + key_info->user_defined_key_parts) ; for ( ; key_part < key_part_end; key_part++) { Field *field= key_part->field= outparam->field[key_part->fieldnr - 1]; @@ -2661,7 +2681,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, } } if (!share->use_ext_keys) - key_part+= key_info->ext_key_parts - key_info->key_parts; + key_part+= key_info->ext_key_parts - key_info->user_defined_key_parts; } } @@ -2754,8 +2774,9 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, } outparam->part_info->is_auto_partitioned= share->auto_partitioned; DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned)); - /* we should perform the fix_partition_func in either local or - caller's arena depending on work_part_info_used value + /* + We should perform the fix_partition_func in either local or + caller's arena depending on work_part_info_used value. */ if (!work_part_info_used) tmp= fix_partition_func(thd, outparam, is_create_table); @@ -2864,9 +2885,22 @@ partititon_err: bzero((char*) bitmaps, bitmap_size*3); #endif - outparam->no_replicate= outparam->file && - test(outparam->file->ha_table_flags() & - HA_HAS_OWN_BINLOGGING); + if (share->table_category == TABLE_CATEGORY_LOG) + { + outparam->no_replicate= TRUE; + } + else if (outparam->file) + { + handler::Table_flags flags= outparam->file->ha_table_flags(); + outparam->no_replicate= ! test(flags & (HA_BINLOG_STMT_CAPABLE + | HA_BINLOG_ROW_CAPABLE)) + || test(flags & HA_HAS_OWN_BINLOGGING); + } + else + { + outparam->no_replicate= FALSE; + } + thd->status_var.opened_tables++; thd->lex->context_analysis_only= save_context_analysis_only; @@ -2926,6 +2960,7 @@ int closefrm(register TABLE *table, bool free_share) #ifdef WITH_PARTITION_STORAGE_ENGINE if (table->part_info) { + /* Allocated through table->mem_root, freed below */ free_items(table->part_info->item_free_list); table->part_info->item_free_list= 0; table->part_info= 0; @@ -2934,7 +2969,7 @@ int closefrm(register TABLE *table, bool free_share) if (free_share) { if (table->s->tmp_table == NO_TMP_TABLE) - release_table_share(table->s); + tdc_release_share(table->s); else free_table_share(table->s); } @@ -3033,6 +3068,11 @@ void open_table_error(TABLE_SHARE *share, enum open_frm_error error, strxmov(buff, share->normalized_path.str, reg_ext, NullS); my_error(ER_ERROR_ON_READ, errortype, buff, db_errno); break; + case OPEN_FRM_NEEDS_REBUILD: + strxnmov(buff, sizeof(buff)-1, + share->db.str, ".", share->table_name.str, NullS); + my_error(ER_TABLE_NEEDS_REBUILD, errortype, buff); + break; } DBUG_VOID_RETURN; } /* open_table_error */ @@ -3264,11 +3304,10 @@ void prepare_frm_header(THD *thd, uint reclength, uchar *fileinfo, fileinfo[39]= (uchar) ((uint) create_info->transactional | ((uint) create_info->page_checksum << 2)); fileinfo[40]= (uchar) create_info->row_type; - /* Next few bytes where for RAID support */ + /* Bytes 41-46 were for RAID support; now reused for other purposes */ fileinfo[41]= (uchar) (csid >> 8); - fileinfo[42]= 0; - fileinfo[43]= 0; - fileinfo[44]= 0; + int2store(fileinfo+42, create_info->stats_sample_pages & 0xffff); + fileinfo[44]= (uchar) create_info->stats_auto_recalc; fileinfo[45]= 0; fileinfo[46]= 0; int4store(fileinfo+47, key_length); @@ -3342,7 +3381,7 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res) } if (!(to= strmake_root(mem, str.ptr(), length))) length= 0; // Safety fix - res->set(to, length, ((Field_str*)field)->charset()); + res->set(to, length, field->charset()); return 0; } @@ -3579,9 +3618,9 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) } else if (MYSQL_VERSION_ID == table->s->mysql_version) { - report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED, - ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), - table->alias.c_ptr(), + report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2, + ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2), + table->s->db.str, table->s->table_name.str, table_def->count, table->s->fields); DBUG_RETURN(TRUE); } @@ -3693,18 +3732,18 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) else { KEY *pk= &table->s->key_info[table->s->primary_key]; - if (pk->key_parts != table_def->primary_key_parts) + if (pk->user_defined_key_parts != table_def->primary_key_parts) { report_error(0, "Incorrect definition of table %s.%s: " "Expected primary key to have %u columns, but instead " "found %u columns.", table->s->db.str, table->alias.c_ptr(), table_def->primary_key_parts, - pk->key_parts); + pk->user_defined_key_parts); error= TRUE; } else { - for (i= 0; i < pk->key_parts; ++i) + for (i= 0; i < pk->user_defined_key_parts; ++i) { if (table_def->primary_key_columns[i] + 1 != pk->key_part[i].fieldnr) { @@ -3778,7 +3817,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush, if (gvisitor->m_lock_open_count++ == 0) mysql_mutex_lock(&LOCK_open); - I_P_List_iterator <TABLE, TABLE_share> tables_it(used_tables); + All_share_tables_list::Iterator tables_it(tdc.all_tables); /* In case of multiple searches running in parallel, avoid going @@ -3796,7 +3835,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush, while ((table= tables_it++)) { - if (gvisitor->inspect_edge(&table->in_use->mdl_context)) + if (table->in_use && gvisitor->inspect_edge(&table->in_use->mdl_context)) { goto end_leave_node; } @@ -3805,7 +3844,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush, tables_it.rewind(); while ((table= tables_it++)) { - if (table->in_use->mdl_context.visit_subgraph(gvisitor)) + if (table->in_use && table->in_use->mdl_context.visit_subgraph(gvisitor)) { goto end_leave_node; } @@ -3832,10 +3871,15 @@ end: @param abstime Timeout for waiting as absolute time value. @param deadlock_weight Weight of this wait for deadlock detector. - @pre LOCK_open is write locked, the share is used (has - non-zero reference count), is marked for flush and + @pre LOCK_table_share is locked, the share is marked for flush and this connection does not reference the share. - LOCK_open will be unlocked temporarily during execution. + LOCK_table_share will be unlocked temporarily during execution. + + It may happen that another FLUSH TABLES thread marked this share + for flush, but didn't yet purge it from table definition cache. + In this case we may start waiting for a table share that has no + references (ref_count == 0). We do this with assumption that this + another FLUSH TABLES thread is about to purge this share. @retval FALSE - Success. @retval TRUE - Error (OOM, deadlock, timeout, etc...). @@ -3848,41 +3892,40 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime, Wait_for_flush ticket(mdl_context, this, deadlock_weight); MDL_wait::enum_wait_status wait_status; - mysql_mutex_assert_owner(&LOCK_open); - /* - We should enter this method only when share's version is not - up to date and the share is referenced. Otherwise our - thread will never be woken up from wait. - */ - DBUG_ASSERT(version != refresh_version && ref_count != 0); + mysql_mutex_assert_owner(&tdc.LOCK_table_share); + DBUG_ASSERT(has_old_version()); - m_flush_tickets.push_front(&ticket); + tdc.m_flush_tickets.push_front(&ticket); mdl_context->m_wait.reset_status(); - mysql_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&tdc.LOCK_table_share); mdl_context->will_wait_for(&ticket); mdl_context->find_deadlock(); wait_status= mdl_context->m_wait.timed_wait(thd, abstime, TRUE, - "Waiting for table flush"); + &stage_waiting_for_table_flush); mdl_context->done_waiting_for(); - mysql_mutex_lock(&LOCK_open); + mysql_mutex_lock(&tdc.LOCK_table_share); - m_flush_tickets.remove(&ticket); + tdc.m_flush_tickets.remove(&ticket); - if (m_flush_tickets.is_empty() && ref_count == 0) + if (tdc.m_flush_tickets.is_empty() && tdc.ref_count == 0) { /* If our thread was the last one using the share, we must destroy it here. */ + mysql_mutex_unlock(&tdc.LOCK_table_share); destroy(); } + else + mysql_mutex_unlock(&tdc.LOCK_table_share); + /* In cases when our wait was aborted by KILL statement, @@ -3927,7 +3970,7 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime, void TABLE::init(THD *thd, TABLE_LIST *tl) { - DBUG_ASSERT(s->ref_count > 0 || s->tmp_table != NO_TMP_TABLE); + DBUG_ASSERT(s->tdc.ref_count > 0 || s->tmp_table != NO_TMP_TABLE); if (thd->lex->need_correct_ident()) alias_name_used= my_strcasecmp(table_alias_charset, @@ -4054,7 +4097,8 @@ void TABLE::reset_item_list(List<Item> *item_list) const void TABLE_LIST::calc_md5(char *buffer) { uchar digest[16]; - MY_MD5_HASH(digest, (uchar *) select_stmt.str, select_stmt.length); + compute_md5_hash((char*) digest, select_stmt.str, + select_stmt.length); sprintf((char *) buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], @@ -4445,27 +4489,32 @@ void TABLE_LIST::hide_view_error(THD *thd) return; /* Hide "Unknown column" or "Unknown function" error */ DBUG_ASSERT(thd->is_error()); + switch (thd->get_stmt_da()->sql_errno()) { + case ER_BAD_FIELD_ERROR: + case ER_SP_DOES_NOT_EXIST: + case ER_FUNC_INEXISTENT_NAME_COLLISION: + case ER_PROCACCESS_DENIED_ERROR: + case ER_COLUMNACCESS_DENIED_ERROR: + case ER_TABLEACCESS_DENIED_ERROR: + case ER_TABLE_NOT_LOCKED: + case ER_NO_SUCH_TABLE: + { + TABLE_LIST *top= top_table(); + thd->clear_error(); + my_error(ER_VIEW_INVALID, MYF(0), + top->view_db.str, top->view_name.str); + break; + } - if (thd->stmt_da->sql_errno() == ER_BAD_FIELD_ERROR || - thd->stmt_da->sql_errno() == ER_SP_DOES_NOT_EXIST || - thd->stmt_da->sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION || - thd->stmt_da->sql_errno() == ER_PROCACCESS_DENIED_ERROR || - thd->stmt_da->sql_errno() == ER_COLUMNACCESS_DENIED_ERROR || - thd->stmt_da->sql_errno() == ER_TABLEACCESS_DENIED_ERROR || - thd->stmt_da->sql_errno() == ER_TABLE_NOT_LOCKED || - thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE) - { - TABLE_LIST *top= top_table(); - thd->clear_error(); - my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str); - } - else if (thd->stmt_da->sql_errno() == ER_NO_DEFAULT_FOR_FIELD) - { - TABLE_LIST *top= top_table(); - thd->clear_error(); - // TODO: make correct error message - my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), - top->view_db.str, top->view_name.str); + case ER_NO_DEFAULT_FOR_FIELD: + { + TABLE_LIST *top= top_table(); + thd->clear_error(); + // TODO: make correct error message + my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), + top->view_db.str, top->view_name.str); + break; + } } } @@ -4541,7 +4590,7 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure) TABLE_LIST *main_view= top_table(); if (ignore_failure) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED), main_view->view_db.str, main_view->view_name.str); return(VIEW_CHECK_SKIP); @@ -4834,7 +4883,7 @@ bool TABLE_LIST::prepare_view_security_context(THD *thd) if ((thd->lex->sql_command == SQLCOM_SHOW_CREATE) || (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_NO_SUCH_USER, ER(ER_NO_SUCH_USER), definer.user.str, definer.host.str); @@ -4863,6 +4912,7 @@ bool TABLE_LIST::prepare_view_security_context(THD *thd) } } DBUG_RETURN(FALSE); + } #endif @@ -5627,7 +5677,7 @@ void TABLE::mark_columns_used_by_index_no_reset(uint index, { KEY_PART_INFO *key_part= key_info[index].key_part; KEY_PART_INFO *key_part_end= (key_part + - key_info[index].key_parts); + key_info[index].user_defined_key_parts); for (;key_part != key_part_end; key_part++) { bitmap_set_bit(bitmap, key_part->fieldnr-1); @@ -6057,8 +6107,8 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, return TRUE; keyinfo= key_info + key; keyinfo->key_part= key_part_info; - keyinfo->usable_key_parts= keyinfo->key_parts = key_parts; - keyinfo->ext_key_parts= keyinfo->key_parts; + keyinfo->usable_key_parts= keyinfo->user_defined_key_parts = key_parts; + keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; keyinfo->key_length=0; keyinfo->algorithm= HA_KEY_ALG_UNDEF; keyinfo->flags= HA_GENERATED_KEY; @@ -6157,7 +6207,7 @@ bool TABLE::is_filled_at_execution() uint TABLE::actual_n_key_parts(KEY *keyinfo) { return optimizer_flag(in_use, OPTIMIZER_SWITCH_EXTENDED_KEYS) ? - keyinfo->ext_key_parts : keyinfo->key_parts; + keyinfo->ext_key_parts : keyinfo->user_defined_key_parts; } @@ -6474,7 +6524,7 @@ bool TABLE::update_const_key_parts(COND *conds) for (uint index= 0; index < s->keys; index++) { KEY_PART_INFO *keyinfo= key_info[index].key_part; - KEY_PART_INFO *keyinfo_end= keyinfo + key_info[index].key_parts; + KEY_PART_INFO *keyinfo_end= keyinfo + key_info[index].user_defined_key_parts; for (key_part_map part_map= (key_part_map)1; keyinfo < keyinfo_end; |