diff options
author | Igor Babaev <igor@askmonty.org> | 2020-03-19 21:52:52 -0700 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2020-03-20 09:36:25 -0700 |
commit | 2bde065525bfa1535bfc62ce1c428ad55d11839a (patch) | |
tree | 36d9178490d41640b26137a2f1abfe4f0920ad92 | |
parent | 9f7b8625e698da6b7eba7c26e765c66635571919 (diff) | |
download | mariadb-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.result | 12 | ||||
-rw-r--r-- | mysql-test/t/derived_cond_pushdown.test | 16 | ||||
-rw-r--r-- | sql/item.cc | 35 | ||||
-rw-r--r-- | sql/item_row.cc | 11 |
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; } |