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)
DROP VIEW v1;
DROP TABLE t1, t2;
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
......@@ -2168,4 +2168,20 @@ DROP TABLE t1, t2;
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
......@@ -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
@details
This method gets copy of the current item and also
build clones for its referencies. For the referencies
build_copy is called again.
This method fisrt builds clones of the arguments. If it is successful with
buiding the clones then it constructs a copy of this Item_func_or_sum object
and attaches to it the built clones of the arguments.
@retval
clone of the item
0 if an error occured
clone of the item on success
0 on a failure
*/
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);
if (!copy)
return 0;
Item *copy_tmp_args[2]= {0,0};
Item **copy_args= copy_tmp_args;
if (arg_count > 2)
{
copy->args=
(Item**) alloc_root(mem_root, sizeof(Item*) * arg_count);
if (!copy->args)
if (!(copy_args= (Item**) alloc_root(mem_root, sizeof(Item*) * arg_count)))
return 0;
}
else if (arg_count > 0)
copy->args= copy->tmp_arg;
for (uint i= 0; i < arg_count; i++)
{
Item *arg_clone= args[i]->build_clone(thd, mem_root);
if (!arg_clone)
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;
}
......
......@@ -166,17 +166,20 @@ void Item_row::bring_value()
Item* Item_row::build_clone(THD *thd, MEM_ROOT *mem_root)
{
Item_row *copy= (Item_row *) get_copy(thd, mem_root);
if (!copy)
Item **copy_args= 0;
if (!(copy_args= (Item**) alloc_root(mem_root, sizeof(Item*) * arg_count)))
return 0;
copy->args= (Item**) alloc_root(mem_root, sizeof(Item*) * arg_count);
for (uint i= 0; i < arg_count; i++)
{
Item *arg_clone= args[i]->build_clone(thd, mem_root);
if (!arg_clone)
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;
}
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