From 0973b7a8d20751b56c8ca3f861ea2fbf060e5ab3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 15 Jun 2013 19:10:00 +0200 Subject: [PATCH] partitioning frm bugs: 1. default db type for partitions was stored as 1-byte DB_TYPE code, which doesn't work for dynamically generated codes. 2. storage engine plugin for default db type wasn't locked at all, which could trivially crash for dynamic plugins. Now the storage engine name is stored in the extra2 section, and the plugin is correctly locked. --- sql/sql_show.cc | 2 +- sql/table.cc | 26 +++++++++++++++++----- sql/table.h | 2 +- sql/unireg.cc | 59 +++++++++++++++++++++++++++++++++++-------------- sql/unireg.h | 1 + 5 files changed, 65 insertions(+), 25 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e0b3de07305..83303da1c71 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4914,7 +4914,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, if (share->db_type() == partition_hton && share->partition_info_str_len) { - tmp_db_type= share->default_part_db_type; + tmp_db_type= plugin_hton(share->default_part_plugin); is_partitioned= TRUE; } #endif diff --git a/sql/table.cc b/sql/table.cc index 01b7ae3445e..b5550e090a1 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -454,6 +454,7 @@ void TABLE_SHARE::destroy() 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); @@ -798,6 +799,16 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, options= extra2; options_len= length; break; + case EXTRA2_DEFAULT_PART_ENGINE: +#ifdef WITH_PARTITION_STORAGE_ENGINE + { + LEX_STRING name= { (char*)extra2, length }; + share->default_part_plugin= ha_resolve_by_name(NULL, &name); + if (!share->default_part_plugin) + goto err; + } +#endif + break; default: /* abort frm parsing if it's an unknown but important extra2 value */ if (type >= EXTRA2_ENGINE_IMPORTANT) @@ -828,11 +839,14 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, share->frm_version= FRM_VER_TRUE_VARCHAR; #ifdef WITH_PARTITION_STORAGE_ENGINE - if (frm_image[61] && - !(share->default_part_db_type= - ha_checktype(thd, (enum legacy_db_type) (uint) frm_image[61], 1, 0))) - goto err; - DBUG_PRINT("info", ("default_part_db_type = %u", frm_image[61])); + if (frm_image[61] && !share->default_part_plugin) + { + enum legacy_db_type db_type= (enum legacy_db_type) (uint) frm_image[61]; + share->default_part_plugin= + ha_lock_engine(NULL, ha_checktype(thd, db_type, 1, 0)); + if (!share->default_part_plugin) + goto err; + } #endif legacy_db_type= (enum legacy_db_type) (uint) frm_image[3]; /* @@ -2697,7 +2711,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, tmp= mysql_unpack_partition(thd, share->partition_info_str, share->partition_info_str_len, outparam, is_create_table, - share->default_part_db_type, + plugin_hton(share->default_part_plugin), &work_part_info_used); if (tmp) { diff --git a/sql/table.h b/sql/table.h index e376ee2ad2f..068cbe9a763 100644 --- a/sql/table.h +++ b/sql/table.h @@ -741,7 +741,7 @@ struct TABLE_SHARE char *partition_info_str; uint partition_info_str_len; uint partition_info_buffer_size; - handlerton *default_part_db_type; + plugin_ref default_part_plugin; #endif /** diff --git a/sql/unireg.cc b/sql/unireg.cc index 099f8ccbc78..d90db0ebab8 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -46,6 +46,38 @@ static bool pack_fields(uchar *, List &, ulong); static size_t packed_fields_length(List &); static bool make_empty_rec(THD *, uchar *, uint, List &, uint, ulong); +static uchar *extra2_write_len(uchar *pos, size_t len) +{ + if (len < 255) + *pos++= len; + else + { + /* + At the moment we support options_len up to 64K. + We can easily extend it in the future, if the need arises. + */ + DBUG_ASSERT(len <= 65535); + int2store(pos + 1, len); + pos+= 3; + } + return pos; +} + +static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type, + LEX_STRING *str) +{ + *pos++ = type; + pos= extra2_write_len(pos, str->length); + memcpy(pos, str->str, str->length); + return pos + str->length; +} + +static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type, + LEX_CUSTRING *str) +{ + return extra2_write(pos, type, reinterpret_cast(str)); +} + /** Create a frm (table definition) file @@ -200,6 +232,9 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, if (options_len) extra2_size+= 1 + (options_len > 255 ? 3 : 1) + options_len; + if (part_info) + extra2_size+= 1 + 1 + hton_name(part_info->default_engine_type)->length; + key_buff_length= uint4korr(fileinfo+47); frm.length= FRM_HEADER_SIZE; // fileinfo; @@ -223,27 +258,17 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, /* write the extra2 segment */ pos = frm_ptr + 64; compile_time_assert(EXTRA2_TABLEDEF_VERSION != '/'); - *pos++ = EXTRA2_TABLEDEF_VERSION; // old servers write '/' here - *pos++ = create_info->tabledef_version.length; - memcpy(pos, create_info->tabledef_version.str, - create_info->tabledef_version.length); - pos+= create_info->tabledef_version.length; + pos= extra2_write(pos, EXTRA2_TABLEDEF_VERSION, + &create_info->tabledef_version); + + if (part_info) + pos= extra2_write(pos, EXTRA2_DEFAULT_PART_ENGINE, + hton_name(part_info->default_engine_type)); if (options_len) { *pos++= EXTRA2_ENGINE_TABLEOPTS; - if (options_len < 255) - *pos++= options_len; - else - { - /* - At the moment we support options_len up to 64K. - We can easily extend it in the future, if the need arises. - */ - DBUG_ASSERT(options_len <= 65535); - int2store(pos + 1, options_len); - pos+= 3; - } + pos= extra2_write_len(pos, options_len); pos= engine_table_options_frm_image(pos, create_info->option_list, create_fields, keys, key_info); } diff --git a/sql/unireg.h b/sql/unireg.h index 5e232becbb2..6662c63871e 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -181,6 +181,7 @@ */ enum extra2_frm_value_type { EXTRA2_TABLEDEF_VERSION=0, + EXTRA2_DEFAULT_PART_ENGINE=1, #define EXTRA2_ENGINE_IMPORTANT 128