Commit 2bde0655 authored by Igor Babaev's avatar Igor Babaev

MDEV-17177 Crash in Item_func_in::cleanup() for SELECT executed via

           prepared statement

The method Item_func_in::build_clone() that builds a clone item for an
Item_func_in item first calls a generic method Item_func::build_item()
that builds the the clones for the arguments of the Item_func_in item
to be cloned, creates a copy of the Item_func_in object and attaches the
clones for the arguments to this copy. Then the method Item_func_in::build_clone()
makes the copy fully independent on the copied object in order to
guarantee a proper destruction of the clone. The fact is the copy of the
Item_func_in object is registered as any other item object and should be
destructed as any other item object.
If the method Item_func::build_item fails to build a clone of an argument
then it returns 0. In this case no copy of the Item_func_in object should
be created. Otherwise the finalizing actions for this copy would not be
performed and the copy would remain in a state that would prevent its
proper destruction.

The code of Item_func_in::build_clone() before this patch created the copy
of the Item_func_in object before cloning the argument items. If this
cloning failed the server crashed when trying to destruct the copy item.

The code of Item_row::build_clone() was changed similarly to the code of
Item_func::build_clone though this code could not cause any problems.
parent 9f7b8625
...@@ -10581,4 +10581,16 @@ a b max_c a b dayname(v1.b) ...@@ -10581,4 +10581,16 @@ a b max_c a b dayname(v1.b)
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
SET optimizer_switch=DEFAULT; SET optimizer_switch=DEFAULT;
#
# MDEV-17177: an attempt to push down IN predicate when one of
# the arguments is too complex to be cloned
#
CREATE TABLE t1 (a VARCHAR(8));
INSERT INTO t1 VALUES ('abc'),('def');
CREATE VIEW v1 AS SELECT * FROM t1 GROUP BY a;
SELECT * FROM v1 WHERE IF( a REGEXP 'def', 'foo', a ) IN ('abc', 'foobar');
a
abc
DROP VIEW v1;
DROP TABLE t1;
# End of 10.2 tests # End of 10.2 tests
...@@ -2168,4 +2168,20 @@ DROP TABLE t1, t2; ...@@ -2168,4 +2168,20 @@ DROP TABLE t1, t2;
SET optimizer_switch=DEFAULT; SET optimizer_switch=DEFAULT;
--echo #
--echo # MDEV-17177: an attempt to push down IN predicate when one of
--echo # the arguments is too complex to be cloned
--echo #
CREATE TABLE t1 (a VARCHAR(8));
INSERT INTO t1 VALUES ('abc'),('def');
CREATE VIEW v1 AS SELECT * FROM t1 GROUP BY a;
SELECT * FROM v1 WHERE IF( a REGEXP 'def', 'foo', a ) IN ('abc', 'foobar');
DROP VIEW v1;
DROP TABLE t1;
--echo # End of 10.2 tests --echo # End of 10.2 tests
...@@ -2389,37 +2389,40 @@ bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll, ...@@ -2389,37 +2389,40 @@ bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll,
@param mem_root part of the memory for the clone @param mem_root part of the memory for the clone
@details @details
This method gets copy of the current item and also This method fisrt builds clones of the arguments. If it is successful with
build clones for its referencies. For the referencies buiding the clones then it constructs a copy of this Item_func_or_sum object
build_copy is called again. and attaches to it the built clones of the arguments.
@retval @retval
clone of the item clone of the item on success
0 if an error occured 0 on a failure
*/ */
Item* Item_func_or_sum::build_clone(THD *thd, MEM_ROOT *mem_root) Item* Item_func_or_sum::build_clone(THD *thd, MEM_ROOT *mem_root)
{ {
Item_func_or_sum *copy= (Item_func_or_sum *) get_copy(thd, mem_root); Item *copy_tmp_args[2]= {0,0};
if (!copy) Item **copy_args= copy_tmp_args;
return 0;
if (arg_count > 2) if (arg_count > 2)
{ {
copy->args= if (!(copy_args= (Item**) alloc_root(mem_root, sizeof(Item*) * arg_count)))
(Item**) alloc_root(mem_root, sizeof(Item*) * arg_count);
if (!copy->args)
return 0; return 0;
} }
else if (arg_count > 0)
copy->args= copy->tmp_arg;
for (uint i= 0; i < arg_count; i++) for (uint i= 0; i < arg_count; i++)
{ {
Item *arg_clone= args[i]->build_clone(thd, mem_root); Item *arg_clone= args[i]->build_clone(thd, mem_root);
if (!arg_clone) if (!arg_clone)
return 0; return 0;
copy->args[i]= arg_clone; copy_args[i]= arg_clone;
}
Item_func_or_sum *copy= (Item_func_or_sum *) get_copy(thd, mem_root);
if (!copy)
return 0;
if (arg_count > 2)
copy->args= copy_args;
else if (arg_count > 0)
{
copy->args= copy->tmp_arg;
memcpy(copy->args, copy_args, sizeof(Item *) * arg_count);
} }
return copy; return copy;
} }
......
...@@ -166,17 +166,20 @@ void Item_row::bring_value() ...@@ -166,17 +166,20 @@ void Item_row::bring_value()
Item* Item_row::build_clone(THD *thd, MEM_ROOT *mem_root) Item* Item_row::build_clone(THD *thd, MEM_ROOT *mem_root)
{ {
Item_row *copy= (Item_row *) get_copy(thd, mem_root); Item **copy_args= 0;
if (!copy) if (!(copy_args= (Item**) alloc_root(mem_root, sizeof(Item*) * arg_count)))
return 0; return 0;
copy->args= (Item**) alloc_root(mem_root, sizeof(Item*) * arg_count);
for (uint i= 0; i < arg_count; i++) for (uint i= 0; i < arg_count; i++)
{ {
Item *arg_clone= args[i]->build_clone(thd, mem_root); Item *arg_clone= args[i]->build_clone(thd, mem_root);
if (!arg_clone) if (!arg_clone)
return 0; return 0;
copy->args[i]= arg_clone; copy_args[i]= arg_clone;
} }
Item_row *copy= (Item_row *) get_copy(thd, mem_root);
if (!copy)
return 0;
copy->args= copy_args;
return copy; return copy;
} }
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