summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2020-03-19 21:52:52 -0700
committerIgor Babaev <igor@askmonty.org>2020-03-20 09:36:25 -0700
commit2bde065525bfa1535bfc62ce1c428ad55d11839a (patch)
tree36d9178490d41640b26137a2f1abfe4f0920ad92
parent9f7b8625e698da6b7eba7c26e765c66635571919 (diff)
downloadmariadb-git-2bde065525bfa1535bfc62ce1c428ad55d11839a.tar.gz
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.
-rw-r--r--mysql-test/r/derived_cond_pushdown.result12
-rw-r--r--mysql-test/t/derived_cond_pushdown.test16
-rw-r--r--sql/item.cc35
-rw-r--r--sql/item_row.cc11
4 files changed, 54 insertions, 20 deletions
diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result
index 1010ed6eccb..e2c24639cc7 100644
--- a/mysql-test/r/derived_cond_pushdown.result
+++ b/mysql-test/r/derived_cond_pushdown.result
@@ -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
diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test
index ec15791ddbd..a7df65f2951 100644
--- a/mysql-test/t/derived_cond_pushdown.test
+++ b/mysql-test/t/derived_cond_pushdown.test
@@ -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
diff --git a/sql/item.cc b/sql/item.cc
index 4f8433c28c0..ab7340a4689 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -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;
}
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 000253ece07..6ae049dbfe5 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -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;
}