Commit 50563d39 authored by unknown's avatar unknown

Bug #27084 partitioning by list seems failing when using case

creation of the partitioned table could fail as we created Item-s for
it's list function in thd->mem_root, and then do Item->fix_fields
in the context of other table->mem_root (so that memory alloced
there was alloced in this table->mem_root). As we freed the
table->mem_root before we do thd->free_items, our Item-s had
pointers to the freed memory, that caused the crash


mysql-test/r/partition.result:
  result
mysql-test/t/partition.test:
  testcase
sql/item_cmpfunc.cc:
  here is better place for the implementation
sql/item_cmpfunc.h:
  implementation moved to .cc file
sql/sql_partition.cc:
  work_part_info_used parameter added to mysql_unpack_partition
sql/sql_partition.h:
  work_part_info_used parameter added to mysql_unpack_partition
sql/table.cc:
  we do 'fix_partition_func' using the proper arena now.
  It's necessary as Item_*::fix_fields can alloc memory
  using thd->mem_root and this has to be same mem_root that
  we used to alloc these Item-s
parent 7bc01344
...@@ -1219,4 +1219,14 @@ SELECT t2.id FROM t2 WHERE t2.id IN (SELECT id FROM t1 WHERE status = 'Verified' ...@@ -1219,4 +1219,14 @@ SELECT t2.id FROM t2 WHERE t2.id IN (SELECT id FROM t1 WHERE status = 'Verified'
id id
22589 22589
drop table t1, t2; drop table t1, t2;
CREATE TABLE `t1` ( `a` varchar(1)) ENGINE=MyISAM
PARTITION BY LIST (CASE a WHEN 'a' THEN 1
WHEN 'b' THEN 2
WHEN 'c' THEN 3
END) (
PARTITION a VALUES IN (1),
PARTITION b VALUES IN (2),
PARTITION c VALUES IN (3)
);
DROP TABLE t1;
End of 5.1 tests End of 5.1 tests
...@@ -1463,4 +1463,19 @@ SELECT t2.id FROM t2 WHERE t2.id IN (SELECT id FROM t1 WHERE status = 'Verified' ...@@ -1463,4 +1463,19 @@ SELECT t2.id FROM t2 WHERE t2.id IN (SELECT id FROM t1 WHERE status = 'Verified'
drop table t1, t2; drop table t1, t2;
#
# Bug #27084 partitioning by list seems failing when using case
#
CREATE TABLE `t1` ( `a` varchar(1)) ENGINE=MyISAM
PARTITION BY LIST (CASE a WHEN 'a' THEN 1
WHEN 'b' THEN 2
WHEN 'c' THEN 3
END) (
PARTITION a VALUES IN (1),
PARTITION b VALUES IN (2),
PARTITION c VALUES IN (3)
);
DROP TABLE t1;
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -2099,6 +2099,21 @@ void Item_func_case::print(String *str) ...@@ -2099,6 +2099,21 @@ void Item_func_case::print(String *str)
str->append(STRING_WITH_LEN("end)")); str->append(STRING_WITH_LEN("end)"));
} }
void Item_func_case::cleanup()
{
uint i;
DBUG_ENTER("Item_func_case::cleanup");
Item_func::cleanup();
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
}
DBUG_VOID_RETURN;
}
/* /*
Coalesce - return first not NULL argument. Coalesce - return first not NULL argument.
*/ */
......
...@@ -1106,18 +1106,7 @@ public: ...@@ -1106,18 +1106,7 @@ public:
Item *find_item(String *str); Item *find_item(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
bool check_partition_func_processor(byte *bool_arg) { return FALSE;} bool check_partition_func_processor(byte *bool_arg) { return FALSE;}
void cleanup() void cleanup();
{
uint i;
DBUG_ENTER("Item_func_case::cleanup");
Item_func::cleanup();
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
}
DBUG_VOID_RETURN;
}
}; };
/* /*
......
...@@ -3684,6 +3684,8 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index, ...@@ -3684,6 +3684,8 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
table Table object of partitioned table table Table object of partitioned table
create_table_ind Is it called from CREATE TABLE create_table_ind Is it called from CREATE TABLE
default_db_type What is the default engine of the table default_db_type What is the default engine of the table
work_part_info_used Flag is raised if we don't create new
part_info, but used thd->work_part_info
RETURN VALUE RETURN VALUE
TRUE Error TRUE Error
...@@ -3704,7 +3706,8 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf, ...@@ -3704,7 +3706,8 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
uint part_info_len, uint part_info_len,
uchar *part_state, uint part_state_len, uchar *part_state, uint part_state_len,
TABLE* table, bool is_create_table_ind, TABLE* table, bool is_create_table_ind,
handlerton *default_db_type) handlerton *default_db_type,
bool *work_part_info_used)
{ {
bool result= TRUE; bool result= TRUE;
partition_info *part_info; partition_info *part_info;
...@@ -3716,6 +3719,7 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf, ...@@ -3716,6 +3719,7 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
thd->lex= &lex; thd->lex= &lex;
thd->variables.character_set_client= system_charset_info; thd->variables.character_set_client= system_charset_info;
lex_start(thd, part_buf, part_info_len); lex_start(thd, part_buf, part_info_len);
*work_part_info_used= false;
/* /*
We need to use the current SELECT_LEX since I need to keep the We need to use the current SELECT_LEX since I need to keep the
Name_resolution_context object which is referenced from the Name_resolution_context object which is referenced from the
...@@ -3805,6 +3809,7 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf, ...@@ -3805,6 +3809,7 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
thd->free_items(); thd->free_items();
part_info= thd->work_part_info; part_info= thd->work_part_info;
table->s->version= 0UL; table->s->version= 0UL;
*work_part_info_used= true;
} }
} }
table->part_info= part_info; table->part_info= part_info;
......
...@@ -81,7 +81,8 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf, ...@@ -81,7 +81,8 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
uint part_info_len, uint part_info_len,
uchar *part_state, uint part_state_len, uchar *part_state, uint part_state_len,
TABLE *table, bool is_create_table_ind, TABLE *table, bool is_create_table_ind,
handlerton *default_db_type); handlerton *default_db_type,
bool *work_part_info_used);
void make_used_partitions_str(partition_info *part_info, String *parts_str); void make_used_partitions_str(partition_info *part_info, String *parts_str);
uint32 get_list_array_idx_for_endpoint(partition_info *part_info, uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
bool left_endpoint, bool left_endpoint,
......
...@@ -1525,21 +1525,30 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, ...@@ -1525,21 +1525,30 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
thd->set_n_backup_active_arena(&part_func_arena, &backup_arena); thd->set_n_backup_active_arena(&part_func_arena, &backup_arena);
thd->stmt_arena= &part_func_arena; thd->stmt_arena= &part_func_arena;
bool tmp; bool tmp;
bool work_part_info_used;
tmp= mysql_unpack_partition(thd, share->partition_info, tmp= mysql_unpack_partition(thd, share->partition_info,
share->partition_info_len, share->partition_info_len,
(uchar*)share->part_state, (uchar*)share->part_state,
share->part_state_len, share->part_state_len,
outparam, is_create_table, outparam, is_create_table,
share->default_part_db_type); share->default_part_db_type,
&work_part_info_used);
outparam->part_info->is_auto_partitioned= share->auto_partitioned; outparam->part_info->is_auto_partitioned= share->auto_partitioned;
DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned)); DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned));
if (!tmp) /* we should perform the fix_partition_func in either local or
caller's arena depending on work_part_info_used value
*/
if (!tmp && !work_part_info_used)
tmp= fix_partition_func(thd, outparam, is_create_table); tmp= fix_partition_func(thd, outparam, is_create_table);
thd->stmt_arena= backup_stmt_arena_ptr; thd->stmt_arena= backup_stmt_arena_ptr;
thd->restore_active_arena(&part_func_arena, &backup_arena); thd->restore_active_arena(&part_func_arena, &backup_arena);
if (!tmp) if (!tmp)
{
if (work_part_info_used)
tmp= fix_partition_func(thd, outparam, is_create_table);
outparam->part_info->item_free_list= part_func_arena.free_list; outparam->part_info->item_free_list= part_func_arena.free_list;
}
if (tmp) if (tmp)
{ {
if (is_create_table) if (is_create_table)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment