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.
This commit is contained in:
Sergei Golubchik 2013-06-15 19:10:00 +02:00
parent 54b3472ef1
commit 0973b7a8d2
5 changed files with 65 additions and 25 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -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
/**

View File

@ -46,6 +46,38 @@ static bool pack_fields(uchar *, List<Create_field> &, ulong);
static size_t packed_fields_length(List<Create_field> &);
static bool make_empty_rec(THD *, uchar *, uint, List<Create_field> &, 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<LEX_STRING *>(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);
}

View File

@ -181,6 +181,7 @@
*/
enum extra2_frm_value_type {
EXTRA2_TABLEDEF_VERSION=0,
EXTRA2_DEFAULT_PART_ENGINE=1,
#define EXTRA2_ENGINE_IMPORTANT 128