[Commits] d80751b: MDEV-16090: Server crash in in Item_func_in::val_int or assertion `in_item'
revision-id: d80751bb532000b1a2be7a5a39fadccf4ae88b9e (mariadb-10.2.14-79-gd80751b) parent(s): bd1d152d05ba75bd1bdd2d9bc0358d8508df307a author: Galina Shalygina committer: Galina Shalygina timestamp: 2018-05-11 14:42:39 +0200 message: MDEV-16090: Server crash in in Item_func_in::val_int or assertion `in_item' failure upon SELECT with impossible condition The problem appears because of a wrong implementation of the Item_func_in::build_clone() method. It didn't clone 'array' and 'cmp_fields' fields for the cloned IN predicate and this could cause crashes. The Item_func_in::fix_length_and_dec() method was refactored and a new method named Item_func_in::create_array() was created. It allowed to create 'array' for a cloned IN predicate in a proper way. --- mysql-test/r/derived_cond_pushdown.result | 15 ++++ mysql-test/t/derived_cond_pushdown.test | 16 ++++ sql/item_cmpfunc.cc | 121 ++++++++++++++++++------------ sql/item_cmpfunc.h | 13 +--- sql/table.cc | 4 +- 5 files changed, 111 insertions(+), 58 deletions(-) diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result index 8e74e09..23b4a90 100644 --- a/mysql-test/r/derived_cond_pushdown.result +++ b/mysql-test/r/derived_cond_pushdown.result @@ -9045,3 +9045,18 @@ select * from (select date('2018-01-01') as d) as t where t.d between date ('2017-01-01') and date ('2019-01-01'); d 2018-01-01 +# +# MDEV-15765: pushing condition with IN subquery defined with constants +# using substitution +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM +( +SELECT DISTINCT * FROM t1 +) der_tab +WHERE (a>0 AND a<2 OR a IN (2,3)) AND +(a=2 OR 0); +a +2 +DROP TABLE t1; diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test index 0b87738..82b8953 100644 --- a/mysql-test/t/derived_cond_pushdown.test +++ b/mysql-test/t/derived_cond_pushdown.test @@ -1646,3 +1646,19 @@ select * from (select date('2018-01-01') as d select * from (select date('2018-01-01') as d) as t where t.d between date ('2017-01-01') and date ('2019-01-01'); + +--echo # +--echo # MDEV-15765: pushing condition with IN subquery defined with constants +--echo # using substitution +--echo # + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM +( + SELECT DISTINCT * FROM t1 +) der_tab +WHERE (a>0 AND a<2 OR a IN (2,3)) AND + (a=2 OR 0); + +DROP TABLE t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 44cc4f3..2116faf 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4114,6 +4114,67 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) (uchar *) y->ptr(),y->length()); } + +/* + Create 'array' for this IN predicate with the respect to its result type + and put in it values from <in value list>. +*/ + +bool Item_func_in::create_array(THD *thd) +{ + Item *date_arg= 0; + + switch (m_compare_type) { + case STRING_RESULT: + array=new (thd->mem_root) in_string(thd, arg_count - 1, + (qsort2_cmp) srtcmp_in, + cmp_collation.collation); + break; + case INT_RESULT: + array= new (thd->mem_root) in_longlong(thd, arg_count - 1); + break; + case REAL_RESULT: + array= new (thd->mem_root) in_double(thd, arg_count - 1); + break; + case ROW_RESULT: + /* + The row comparator was created at the beginning but only DATETIME + items comparators were initialized. Call store_value() to setup + others. + */ + ((in_row*)array)->tmp.store_value(args[0]); + break; + case DECIMAL_RESULT: + array= new (thd->mem_root) in_decimal(thd, arg_count - 1); + break; + case TIME_RESULT: + date_arg= find_date_time_item(thd, args, arg_count, 0, true); + array= new (thd->mem_root) in_datetime(thd, date_arg, arg_count - 1); + break; + } + if (!array || thd->is_fatal_error) // OOM + return true; + uint j=0; + for (uint i=1 ; i < arg_count ; i++) + { + array->set(j,args[i]); + if (!args[i]->null_value) + j++; // include this cell in the array. + else + { + /* + We don't put NULL values in array, to avoid erronous matches in + bisection. + */ + have_null= 1; + } + } + if ((array->used_count= j)) + array->sort(); + return false; +} + + void Item_func_in::fix_length_and_dec() { Item **arg, **arg_end; @@ -4241,53 +4302,8 @@ void Item_func_in::fix_length_and_dec() m_compare_type= INT_RESULT; } } - switch (m_compare_type) { - case STRING_RESULT: - array=new (thd->mem_root) in_string(thd, arg_count - 1, - (qsort2_cmp) srtcmp_in, - cmp_collation.collation); - break; - case INT_RESULT: - array= new (thd->mem_root) in_longlong(thd, arg_count - 1); - break; - case REAL_RESULT: - array= new (thd->mem_root) in_double(thd, arg_count - 1); - break; - case ROW_RESULT: - /* - The row comparator was created at the beginning but only DATETIME - items comparators were initialized. Call store_value() to setup - others. - */ - ((in_row*)array)->tmp.store_value(args[0]); - break; - case DECIMAL_RESULT: - array= new (thd->mem_root) in_decimal(thd, arg_count - 1); - break; - case TIME_RESULT: - date_arg= find_date_time_item(thd, args, arg_count, 0, true); - array= new (thd->mem_root) in_datetime(thd, date_arg, arg_count - 1); - break; - } - if (!array || thd->is_fatal_error) // OOM + if (create_array(thd)) return; - uint j=0; - for (uint i=1 ; i < arg_count ; i++) - { - array->set(j,args[i]); - if (!args[i]->null_value) - j++; // include this cell in the array. - else - { - /* - We don't put NULL values in array, to avoid erronous matches in - bisection. - */ - have_null= 1; - } - } - if ((array->used_count= j)) - array->sort(); } else { @@ -4396,6 +4412,19 @@ longlong Item_func_in::val_int() } +Item *Item_func_in::build_clone(THD *thd, MEM_ROOT *mem_root) +{ + Item_func_in *clone= (Item_func_in *) Item_func::build_clone(thd, mem_root); + if (clone) + { + if (array && clone->create_array(thd)) + return NULL; + memcpy(&clone->cmp_items, &cmp_items, sizeof(cmp_items)); + } + return clone; +} + + longlong Item_func_bit_or::val_int() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index de1b27c..78a9e38 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1648,6 +1648,7 @@ class Item_func_in :public Item_func_opt_neg } longlong val_int(); bool fix_fields(THD *, Item **); + bool create_array(THD *thd); void fix_length_and_dec(); void cleanup() { @@ -1693,16 +1694,7 @@ class Item_func_in :public Item_func_opt_neg bool count_sargable_conds(void *arg); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_in>(thd, mem_root, this); } - Item *build_clone(THD *thd, MEM_ROOT *mem_root) - { - Item_func_in *clone= (Item_func_in *) Item_func::build_clone(thd, mem_root); - if (clone) - { - clone->array= 0; - bzero(&clone->cmp_items, sizeof(cmp_items)); - } - return clone; - } + Item *build_clone(THD *thd, MEM_ROOT *mem_root); }; class cmp_item_row :public cmp_item @@ -1731,6 +1723,7 @@ class in_row :public in_vector ~in_row(); void set(uint pos,Item *item); uchar *get_value(Item *item); + friend bool Item_func_in::create_array(THD *thd); friend void Item_func_in::fix_length_and_dec(); Item_result result_type() { return ROW_RESULT; } cmp_item *get_cmp_item() { return &tmp; } diff --git a/sql/table.cc b/sql/table.cc index 4e9aa5c..c12a505 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8241,8 +8241,8 @@ Item* TABLE_LIST::build_pushable_cond_for_table(THD *thd, Item *cond) new_cond->argument_list()->push_back(fix, thd->mem_root); } - if (is_fix_needed) - new_cond->fix_fields(thd, 0); + if (is_fix_needed && new_cond->fix_fields(thd, 0)) + return 0; switch (new_cond->argument_list()->elements) {
participants (1)
-
galina.shalyginaï¼ mariadb.com