From ca5c122adcd39c34b1bd7059903668586496caf6 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 11 Aug 2023 17:59:40 +0300 Subject: [PATCH] MDEV-9938 Prepared statement return wrong result (missing row) The problem is that the first execution of the prepared statement makes a permanent optimization of converting the LEFT JOIN to an INNER JOIN. This is based on the assumption that all the user parameters (?) are always constants and that parameters to Item_cond() will not change value from true and false between different executions. (The example was using IS NULL, which will change value if parameter depending on if the parameter is NULL or not). The fix is to change Item_cond::fix_fields() and Item_cond::eval_not_null_tables() to not threat user parameters as constants. This will ensure that we don't do the LEFT_JOIN -> INNER JOIN conversion that causes problems. There is also some things that needs to be improved regarding calculations of not_null_tables_cache as we get a different value for WHERE 1 or t1.a=1 compared to WHERE t1.a= or 1 Changes done: - Mark Item_param with the PARAM flag to be able to quickly check in Item_cond::eval_not_null_tables() if an item contains a prepared statement parameter (just like we check for stored procedure parameters). - Fixed that Item_cond::not_null_tables_cache is not depending on order of arguments. - Don't call item->eval_const_cond() for items that are NOT on the top level of the WHERE clause. This removed a lot of unnecessary warnings in the test suite! - Do not reset not_null_tables_cache for not top level items. - Simplified Item_cond::fix_fields by calling eval_not_null_tables() instead of having duplication of all the code in eval_not_null_tables(). - Return an error if Item_cond::fix_field() generates an error The old code did generate an error in some cases, but not in all cases. - Fixed all handling of the above error in make_cond_for_tables(). The error handling by the callers did not exists before which could lead to asserts in many different places in the old code). - All changes in sql_select.cc are just checking the return value of fix_fields() and make_cond_for_tables() and returning an error value if fix_fields() returns true or make_cond_for_tables() returns NULL and is_error() is set. - Mark Item_cond as const_item if all arguments returns true for can_eval_in_optimize(). Reviewer: Sergei Petrunia --- mysql-test/main/having_cond_pushdown.result | 4 -- mysql-test/main/prepare.result | 35 ++++++++++ mysql-test/main/prepare.test | 36 ++++++++++ mysql-test/main/ps.result | 7 ++ mysql-test/main/ps.test | 8 ++- mysql-test/main/range.result | 2 - mysql-test/main/range_mrr_icp.result | 2 - mysql-test/main/subselect_exists2in.result | 4 +- mysql-test/main/view.result | 4 +- mysql-test/suite/vcol/r/vcol_syntax.result | 10 ++- mysql-test/suite/vcol/t/vcol_syntax.test | 2 + sql/item.cc | 1 + sql/item.h | 11 +-- sql/item_cmpfunc.cc | 74 ++++++++------------- sql/sql_select.cc | 74 ++++++++++++++++----- 15 files changed, 190 insertions(+), 84 deletions(-) diff --git a/mysql-test/main/having_cond_pushdown.result b/mysql-test/main/having_cond_pushdown.result index fea8f83f9a1..fb73cf789b5 100644 --- a/mysql-test/main/having_cond_pushdown.result +++ b/mysql-test/main/having_cond_pushdown.result @@ -4932,12 +4932,8 @@ SELECT * FROM t1 GROUP BY i HAVING i IN ( i IS NULL); i SELECT * FROM t1 GROUP BY i HAVING i IN ( i IS NULL AND 'x' = 0); i -Warnings: -Warning 1292 Truncated incorrect DECIMAL value: 'x' SELECT * FROM t1 GROUP BY i HAVING i='1' IN ( i IS NULL AND 'x' = 0); i -Warnings: -Warning 1292 Truncated incorrect DECIMAL value: 'x' DROP TABLE t1; # # MDEV-28080: HAVING with NOT EXIST predicate in an equality diff --git a/mysql-test/main/prepare.result b/mysql-test/main/prepare.result index 7c730bff0c5..a9ac531280c 100644 --- a/mysql-test/main/prepare.result +++ b/mysql-test/main/prepare.result @@ -80,3 +80,38 @@ drop table t1, t2, t3; # # End of 10.4 tests # +# +# MDEV-9938 Prepared statement return wrong result (missing row) +# +CREATE TABLE t1 (a_id INT AUTO_INCREMENT PRIMARY KEY, a_text VARCHAR(20)); +CREATE TABLE t2 (b_id INT AUTO_INCREMENT PRIMARY KEY, b_a_id INT); +INSERT INTO t1 VALUES (NULL, 'word1'); +INSERT INTO t2 VALUES (NULL, 1), (NULL, NULL); +PREPARE q FROM 'SELECT * FROM t2 + LEFT JOIN t1 ON (t1.a_id = t2.b_a_id) +WHERE ((? IS NULL) OR (t1.a_text = ?))'; +SET @var = 'word1'; +expect row count 1 +EXECUTE q USING @var, @var; +b_id b_a_id a_id a_text +1 1 1 word1 +expect row count = 2 +EXECUTE q USING @nul, @nul; +b_id b_a_id a_id a_text +1 1 1 word1 +2 NULL NULL NULL +PREPARE q2 FROM 'SELECT * FROM t2 + LEFT JOIN t1 ON (t1.a_id = t2.b_a_id) +WHERE ((? IS NULL) OR (t1.a_text = ?))'; +expect row count 2 +SET @var = 'word1'; +EXECUTE q2 USING @nul, @nul; +b_id b_a_id a_id a_text +1 1 1 word1 +2 NULL NULL NULL +deallocate prepare q; +deallocate prepare q2; +drop table t1,t2; +# +# End of 10.6 tests +# diff --git a/mysql-test/main/prepare.test b/mysql-test/main/prepare.test index bf37f6dc8d1..b8ee5ad6b6d 100644 --- a/mysql-test/main/prepare.test +++ b/mysql-test/main/prepare.test @@ -69,3 +69,39 @@ drop table t1, t2, t3; --echo # --echo # End of 10.4 tests --echo # + +--echo # +--echo # MDEV-9938 Prepared statement return wrong result (missing row) +--echo # + +CREATE TABLE t1 (a_id INT AUTO_INCREMENT PRIMARY KEY, a_text VARCHAR(20)); +CREATE TABLE t2 (b_id INT AUTO_INCREMENT PRIMARY KEY, b_a_id INT); + +INSERT INTO t1 VALUES (NULL, 'word1'); +INSERT INTO t2 VALUES (NULL, 1), (NULL, NULL); + +PREPARE q FROM 'SELECT * FROM t2 + LEFT JOIN t1 ON (t1.a_id = t2.b_a_id) +WHERE ((? IS NULL) OR (t1.a_text = ?))'; + +SET @var = 'word1'; +--echo expect row count 1 +EXECUTE q USING @var, @var; +--echo expect row count = 2 +EXECUTE q USING @nul, @nul; + +PREPARE q2 FROM 'SELECT * FROM t2 + LEFT JOIN t1 ON (t1.a_id = t2.b_a_id) +WHERE ((? IS NULL) OR (t1.a_text = ?))'; + +--echo expect row count 2 +SET @var = 'word1'; +EXECUTE q2 USING @nul, @nul; + +deallocate prepare q; +deallocate prepare q2; +drop table t1,t2; + +--echo # +--echo # End of 10.6 tests +--echo # diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index fc982fba4e5..d96fcbe2dcc 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -4094,9 +4094,16 @@ DROP TABLE t1, t2; # CREATE TABLE t1 (a INT); PREPARE stmt FROM "SELECT 1 FROM t1 GROUP BY 0 OR 18446744073709551615+1"; +execute stmt; +1 +SELECT 1 FROM t1 GROUP BY 0 OR 18446744073709551615+1; +1 +insert into t1 values(1),(2); +execute stmt; ERROR 22003: BIGINT UNSIGNED value is out of range in '18446744073709551615 + 1' SELECT 1 FROM t1 GROUP BY 0 OR 18446744073709551615+1; ERROR 22003: BIGINT UNSIGNED value is out of range in '18446744073709551615 + 1' +deallocate prepare stmt; drop table t1; # End of 5.3 tests # diff --git a/mysql-test/main/ps.test b/mysql-test/main/ps.test index ebf646eadf3..0043d3aa141 100644 --- a/mysql-test/main/ps.test +++ b/mysql-test/main/ps.test @@ -3632,12 +3632,16 @@ DROP TABLE t1, t2; --echo # with out of range in GROUP BY --echo # CREATE TABLE t1 (a INT); - ---error ER_DATA_OUT_OF_RANGE PREPARE stmt FROM "SELECT 1 FROM t1 GROUP BY 0 OR 18446744073709551615+1"; +execute stmt; +SELECT 1 FROM t1 GROUP BY 0 OR 18446744073709551615+1; +insert into t1 values(1),(2); +--error ER_DATA_OUT_OF_RANGE +execute stmt; --error ER_DATA_OUT_OF_RANGE SELECT 1 FROM t1 GROUP BY 0 OR 18446744073709551615+1; +deallocate prepare stmt; drop table t1; --echo # End of 5.3 tests diff --git a/mysql-test/main/range.result b/mysql-test/main/range.result index 31777773240..8b4eafa3682 100644 --- a/mysql-test/main/range.result +++ b/mysql-test/main/range.result @@ -1625,8 +1625,6 @@ NULL Warnings: Warning 1411 Incorrect datetime value: '2007-20-00' for function str_to_date Warning 1411 Incorrect datetime value: '2007-20-00' for function str_to_date -Warning 1411 Incorrect datetime value: '2007-20-00' for function str_to_date -Warning 1411 Incorrect datetime value: '2007-20-00' for function str_to_date SELECT str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20'; str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20' 1 diff --git a/mysql-test/main/range_mrr_icp.result b/mysql-test/main/range_mrr_icp.result index 6817edd30cd..4fb717b0b51 100644 --- a/mysql-test/main/range_mrr_icp.result +++ b/mysql-test/main/range_mrr_icp.result @@ -1628,8 +1628,6 @@ NULL Warnings: Warning 1411 Incorrect datetime value: '2007-20-00' for function str_to_date Warning 1411 Incorrect datetime value: '2007-20-00' for function str_to_date -Warning 1411 Incorrect datetime value: '2007-20-00' for function str_to_date -Warning 1411 Incorrect datetime value: '2007-20-00' for function str_to_date SELECT str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20'; str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20' 1 diff --git a/mysql-test/main/subselect_exists2in.result b/mysql-test/main/subselect_exists2in.result index 6ff518b5a29..78f5457012f 100644 --- a/mysql-test/main/subselect_exists2in.result +++ b/mysql-test/main/subselect_exists2in.result @@ -333,7 +333,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Note 1276 Field or reference 'test.t2.b' of SELECT #3 was resolved in SELECT #2 -Note 1003 /* select#1 */ select (/* select#2 */ select 1 from dual where !(1 is not null and (1,1 in ((1 in on distinct_key where 1 = ``.`c`))))) AS `( SELECT b FROM t2 WHERE NOT EXISTS ( SELECT c FROM t3 WHERE c = b ) )` from `test`.`t1` +Note 1003 /* select#1 */ select (/* select#2 */ select 1 from dual where !(1 is not null and (1,1 in ( (/* select#3 */ select `test`.`t3`.`c` from `test`.`t3` where `test`.`t3`.`c` is not null ), (1 in on distinct_key where 1 = ``.`c`))))) AS `( SELECT b FROM t2 WHERE NOT EXISTS ( SELECT c FROM t3 WHERE c = b ) )` from `test`.`t1` SELECT ( SELECT b FROM t2 WHERE NOT EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1; ( SELECT b FROM t2 WHERE NOT EXISTS ( SELECT c FROM t3 WHERE c = b ) ) 1 @@ -347,7 +347,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Note 1276 Field or reference 'test.t2.b' of SELECT #3 was resolved in SELECT #2 -Note 1003 /* select#1 */ select (/* select#2 */ select 1 from dual where !(1 is not null and (1,1 in ((1 in on distinct_key where 1 = ``.`c`))))) AS `( SELECT b FROM t2 WHERE NOT EXISTS ( SELECT c FROM t3 WHERE c = b ) )` from `test`.`t1` +Note 1003 /* select#1 */ select (/* select#2 */ select 1 from dual where !(1 is not null and (1,1 in ( (/* select#3 */ select `test`.`t3`.`c` from `test`.`t3` where `test`.`t3`.`c` is not null ), (1 in on distinct_key where 1 = ``.`c`))))) AS `( SELECT b FROM t2 WHERE NOT EXISTS ( SELECT c FROM t3 WHERE c = b ) )` from `test`.`t1` SELECT ( SELECT b FROM t2 WHERE NOT EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1; ( SELECT b FROM t2 WHERE NOT EXISTS ( SELECT c FROM t3 WHERE c = b ) ) 1 diff --git a/mysql-test/main/view.result b/mysql-test/main/view.result index 329f367844e..75cfd55f47c 100644 --- a/mysql-test/main/view.result +++ b/mysql-test/main/view.result @@ -4630,7 +4630,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DEPENDENT SUBQUERY t4 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 -Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,10 AS `a` from `test`.`t1` where !<10,`test`.`t1`.`a`>((10,(/* select#2 */ select NULL from `test`.`t4` where `test`.`t4`.`a` >= `test`.`t1`.`a` and trigcond((10) = NULL or 1) having trigcond(NULL is null)))) +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,10 AS `a` from `test`.`t1` where !<10,`test`.`t1`.`a`>((10,(/* select#2 */ select NULL from `test`.`t4` where `test`.`t4`.`a` >= `test`.`t1`.`a` and trigcond((10) = NULL or (NULL is null)) having trigcond(NULL is null)))) SELECT * FROM t1, t2 WHERE t2.a NOT IN (SELECT t3.b FROM t3 RIGHT JOIN t4 ON (t4.a = t3.a) WHERE t4.a >= t1.a); @@ -4646,7 +4646,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DEPENDENT SUBQUERY t4 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Note 1276 Field or reference 'v1.a' of SELECT #2 was resolved in SELECT #1 -Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,10 AS `a` from `test`.`t1` where !<10,`test`.`t1`.`a`>((10,(/* select#2 */ select NULL from `test`.`t4` where `test`.`t4`.`a` >= `test`.`t1`.`a` and trigcond((10) = NULL or 1) having trigcond(NULL is null)))) +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,10 AS `a` from `test`.`t1` where !<10,`test`.`t1`.`a`>((10,(/* select#2 */ select NULL from `test`.`t4` where `test`.`t4`.`a` >= `test`.`t1`.`a` and trigcond((10) = NULL or (NULL is null)) having trigcond(NULL is null)))) SELECT * FROM v1, t2 WHERE t2.a NOT IN (SELECT t3.b FROM t3 RIGHT JOIN t4 ON (t4.a = t3.a) WHERE t4.a >= v1.a); diff --git a/mysql-test/suite/vcol/r/vcol_syntax.result b/mysql-test/suite/vcol/r/vcol_syntax.result index 144d4ab335d..7725d59f59c 100644 --- a/mysql-test/suite/vcol/r/vcol_syntax.result +++ b/mysql-test/suite/vcol/r/vcol_syntax.result @@ -201,18 +201,22 @@ drop table t1; # MDEV-31319 Assertion const_item_cache == true failed in Item_func::fix_fields # create table t (f1 int, f2 int, fv int generated always as (case user() when 'foo' or 'bar' then f1 else f2 end) virtual); -Warnings: -Warning 1292 Truncated incorrect DOUBLE value: 'foo' -Warning 1292 Truncated incorrect DOUBLE value: 'bar' select * from t; f1 f2 fv +insert into t (f1,f2) values(1,1); +select * from t; +f1 f2 fv +1 1 1 Warnings: +Warning 1292 Truncated incorrect DECIMAL value: 'root@localhost' Warning 1292 Truncated incorrect DOUBLE value: 'foo' Warning 1292 Truncated incorrect DOUBLE value: 'bar' create table tmp as select * from information_schema.tables where table_name = 't'; select * from t; f1 f2 fv +1 1 1 Warnings: +Warning 1292 Truncated incorrect DECIMAL value: 'root@localhost' Warning 1292 Truncated incorrect DOUBLE value: 'foo' Warning 1292 Truncated incorrect DOUBLE value: 'bar' drop table t, tmp; diff --git a/mysql-test/suite/vcol/t/vcol_syntax.test b/mysql-test/suite/vcol/t/vcol_syntax.test index da2ad27d37d..c26c4897833 100644 --- a/mysql-test/suite/vcol/t/vcol_syntax.test +++ b/mysql-test/suite/vcol/t/vcol_syntax.test @@ -168,6 +168,8 @@ drop table t1; --echo # create table t (f1 int, f2 int, fv int generated always as (case user() when 'foo' or 'bar' then f1 else f2 end) virtual); select * from t; +insert into t (f1,f2) values(1,1); +select * from t; create table tmp as select * from information_schema.tables where table_name = 't'; select * from t; diff --git a/sql/item.cc b/sql/item.cc index ce1ba00bd5b..9f964ed019a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4068,6 +4068,7 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg, value is set. */ set_maybe_null(); + with_flags= with_flags | item_with_t::PARAM; } diff --git a/sql/item.h b/sql/item.h index 0f59b38cd38..3be7cd7283a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -787,7 +787,8 @@ enum class item_with_t : item_flags_t FIELD= (1<<2), // If any item except Item_sum contains a field. SUM_FUNC= (1<<3), // If item contains a sum func SUBQUERY= (1<<4), // If item containts a sub query - ROWNUM_FUNC= (1<<5) + ROWNUM_FUNC= (1<<5), // If ROWNUM function was used + PARAM= (1<<6) // If user parameter was used }; @@ -1087,6 +1088,8 @@ public: { return (bool) (with_flags & item_with_t::SUBQUERY); } inline bool with_rownum_func() const { return (bool) (with_flags & item_with_t::ROWNUM_FUNC); } + inline bool with_param() const + { return (bool) (with_flags & item_with_t::PARAM); } inline void copy_flags(const Item *org, item_base_t mask) { base_flags= (item_base_t) (((item_flags_t) base_flags & @@ -5304,17 +5307,17 @@ public: :used_tables_cache(other->used_tables_cache), const_item_cache(other->const_item_cache) { } - void used_tables_and_const_cache_init() + inline void used_tables_and_const_cache_init() { used_tables_cache= 0; const_item_cache= true; } - void used_tables_and_const_cache_join(const Item *item) + inline void used_tables_and_const_cache_join(const Item *item) { used_tables_cache|= item->used_tables(); const_item_cache&= item->const_item(); } - void used_tables_and_const_cache_update_and_join(Item *item) + inline void used_tables_and_const_cache_update_and_join(Item *item) { item->update_used_tables(); used_tables_and_const_cache_join(item); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 1e7209ad37c..1ef5d3c9d0c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4915,7 +4915,7 @@ Item_cond::fix_fields(THD *thd, Item **ref) List_iterator li(list); Item *item; uchar buff[sizeof(char*)]; // Max local vars in function - bool is_and_cond= functype() == Item_func::COND_AND_FUNC; + not_null_tables_cache= 0; used_tables_and_const_cache_init(); @@ -4957,52 +4957,24 @@ Item_cond::fix_fields(THD *thd, Item **ref) merge_sub_condition(li); item= *li.ref(); // may be substituted in fix_fields/merge_item_if_possible - used_tables_cache|= item->used_tables(); - if (item->can_eval_in_optimize() && !item->with_sp_var() && - !cond_has_datetime_is_null(item)) - { - if (item->eval_const_cond() == is_and_cond && top_level()) - { - /* - a. This is "... AND true_cond AND ..." - In this case, true_cond has no effect on cond_and->not_null_tables() - b. This is "... OR false_cond/null cond OR ..." - In this case, false_cond has no effect on cond_or->not_null_tables() - */ - } - else - { - /* - a. This is "... AND false_cond/null_cond AND ..." - The whole condition is FALSE/UNKNOWN. - b. This is "... OR const_cond OR ..." - In this case, cond_or->not_null_tables()=0, because the condition - const_cond might evaluate to true (regardless of whether some tables - were NULL-complemented). - */ - not_null_tables_cache= (table_map) 0; - and_tables_cache= (table_map) 0; - } - if (thd->is_error()) - return TRUE; - } - else - { - table_map tmp_table_map= item->not_null_tables(); - not_null_tables_cache|= tmp_table_map; - and_tables_cache&= tmp_table_map; - - const_item_cache= FALSE; - } + used_tables_and_const_cache_join(item); base_flags|= item->base_flags & item_base_t::MAYBE_NULL; with_flags|= item->with_flags; } - if (fix_length_and_dec()) - return TRUE; + (void) eval_not_null_tables((void*) 0); + + /* + We have to set fixed as some other items will check it and fail if we + do not. This can be changed when we properly check if fix_fields() + fails in call cases. + */ base_flags|= item_base_t::FIXED; + if (fix_length_and_dec() || thd->is_error()) + return TRUE; return FALSE; } + /** @brief Merge a lower-level condition pointed by the iterator into this Item_cond @@ -5052,6 +5024,9 @@ void Item_cond::merge_sub_condition(List_iterator& li) } } +/* + Calculate not_null_tables_cache and and_tables_cache. +*/ bool Item_cond::eval_not_null_tables(void *opt_arg) @@ -5059,15 +5034,17 @@ Item_cond::eval_not_null_tables(void *opt_arg) Item *item; bool is_and_cond= functype() == Item_func::COND_AND_FUNC; List_iterator li(list); + bool found= 0; + not_null_tables_cache= (table_map) 0; and_tables_cache= ~(table_map) 0; while ((item=li++)) { - table_map tmp_table_map; - if (item->can_eval_in_optimize() && !item->with_sp_var() && - !cond_has_datetime_is_null(item)) + if (item->can_eval_in_optimize() && + !item->with_sp_var() && !item->with_param() && + !cond_has_datetime_is_null(item) && top_level()) { - if (item->eval_const_cond() == is_and_cond && top_level()) + if (item->eval_const_cond() == is_and_cond) { /* a. This is "... AND true_cond AND ..." @@ -5086,14 +5063,19 @@ Item_cond::eval_not_null_tables(void *opt_arg) const_cond might evaluate to true (regardless of whether some tables were NULL-complemented). */ + found= 1; not_null_tables_cache= (table_map) 0; and_tables_cache= (table_map) 0; } } else { - tmp_table_map= item->not_null_tables(); - not_null_tables_cache|= tmp_table_map; + table_map tmp_table_map= item->not_null_tables(); + if (!found) + { + /* We should not depend on the order of items */ + not_null_tables_cache|= tmp_table_map; + } and_tables_cache&= tmp_table_map; } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ae68d84b30f..9ae356e0749 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2479,6 +2479,8 @@ JOIN::optimize_inner() COND *table_independent_conds= make_cond_for_table(thd, conds, PSEUDO_TABLE_BITS, 0, -1, FALSE, FALSE); + if (!table_independent_conds && thd->is_error()) + DBUG_RETURN(1); DBUG_EXECUTE("where", print_where(table_independent_conds, "where after opt_sum_query()", @@ -2819,6 +2821,8 @@ int JOIN::optimize_stage2() if (make_join_select(this, select, conds)) { + if (thd->is_error()) + DBUG_RETURN(1); zero_result_cause= "Impossible WHERE noticed after reading const tables"; select_lex->mark_const_derived(zero_result_cause); @@ -3423,9 +3427,13 @@ bool JOIN::add_having_as_table_cond(JOIN_TAB *tab) having= make_cond_for_table(thd, tmp_having, ~ (table_map) 0, ~used_tables, 0, false, false); + if (!having && thd->is_error()) + DBUG_RETURN(true); DBUG_EXECUTE("where", print_where(having, "having after sort", QT_ORDINARY);); } + else if (thd->is_error()) + DBUG_RETURN(true); DBUG_RETURN(false); } @@ -10625,17 +10633,22 @@ int JOIN_TAB::make_scan_filter() Item *cond= is_inner_table_of_outer_join() ? *get_first_inner_table()->on_expr_ref : join->conds; - if (cond && - (tmp= make_cond_for_table(join->thd, cond, - join->const_table_map | table->map, - table->map, -1, FALSE, TRUE))) + if (cond) { - DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY);); - if (!(cache_select= - (SQL_SELECT*) join->thd->memdup((uchar*) select, sizeof(SQL_SELECT)))) - DBUG_RETURN(1); - cache_select->cond= tmp; - cache_select->read_tables=join->const_table_map; + if ((tmp= make_cond_for_table(join->thd, cond, + join->const_table_map | table->map, + table->map, -1, FALSE, TRUE))) + { + DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY);); + if (!(cache_select= + (SQL_SELECT*) join->thd->memdup((uchar*) select, + sizeof(SQL_SELECT)))) + DBUG_RETURN(1); + cache_select->cond= tmp; + cache_select->read_tables=join->const_table_map; + } + else if (join->thd->is_error()) + DBUG_RETURN(1); } DBUG_RETURN(0); } @@ -12215,6 +12228,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) const_cond= make_cond_for_table(thd, cond, join->const_table_map, (table_map) 0, -1, FALSE, FALSE); + if (!const_cond && thd->is_error()) + DBUG_RETURN(1); + /* Add conditions added by add_not_null_conds(). */ for (uint i= 0 ; i < join->const_tables ; i++) add_cond_and_fix(thd, &const_cond, @@ -12263,6 +12279,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) add_cond_and_fix(thd, &outer_ref_cond, join->outer_ref_cond); join->outer_ref_cond= outer_ref_cond; } + else if (thd->is_error()) + DBUG_RETURN(1); } else { @@ -12278,6 +12296,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) join->pseudo_bits_cond); join->pseudo_bits_cond= pseudo_bits_cond; } + else if (thd->is_error()) + DBUG_RETURN(1); } } } @@ -12381,6 +12401,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) { tmp= make_cond_for_table(thd, cond, used_tables, current_map, i, FALSE, FALSE); + if (!tmp && thd->is_error()) + DBUG_RETURN(1); + if (tab == join->join_tab + last_top_base_tab_idx) { /* @@ -12393,7 +12416,10 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) COND *rand_cond= make_cond_for_table(thd, cond, used_tables, rand_table_bit, -1, FALSE, FALSE); - add_cond_and_fix(thd, &tmp, rand_cond); + if (rand_cond) + add_cond_and_fix(thd, &tmp, rand_cond); + else if (thd->is_error()) + DBUG_RETURN(1); } } /* Add conditions added by add_not_null_conds(). */ @@ -12478,8 +12504,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) trace_cp.add_table_name(tab->table); COND *push_cond= - make_cond_for_table(thd, tmp_cond, current_map, current_map, - -1, FALSE, FALSE); + make_cond_for_table(thd, tmp_cond, current_map, current_map, + -1, FALSE, FALSE); if (push_cond) { trace_cp.add("push_cond", push_cond); @@ -12487,6 +12513,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) if (!tab->table->file->cond_push(push_cond)) tab->table->file->pushed_cond= push_cond; } + else if (thd->is_error()) + DBUG_RETURN(1); } } } @@ -12695,7 +12723,11 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) join->const_table_map, (table_map) 0, -1, FALSE, FALSE); if (!tmp_cond) - continue; + { + if (!thd->is_error()) + continue; + DBUG_RETURN(1); + } tmp_cond= new (thd->mem_root) Item_func_trig_cond(thd, tmp_cond, &cond_tab->not_null_compl); if (!tmp_cond) @@ -12749,6 +12781,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) current_map, /*(inner_tab - first_tab)*/ -1, FALSE, FALSE); + if (!tmp_cond && thd->is_error()) + DBUG_RETURN(1); if (tab == last_tab) { /* @@ -12762,7 +12796,10 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) COND *rand_cond= make_cond_for_table(thd, on_expr, used_tables2, rand_table_bit, -1, FALSE, FALSE); - add_cond_and_fix(thd, &tmp_cond, rand_cond); + if (rand_cond) + add_cond_and_fix(thd, &tmp_cond, rand_cond); + else if (thd->is_error()) + DBUG_RETURN(1); } bool is_sjm_lookup_tab= FALSE; if (inner_tab->bush_children) @@ -23676,6 +23713,8 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond, retain_ref_cond, false); if (fix) new_cond->argument_list()->push_back(fix, thd->mem_root); + else if (thd->is_error()) + return ((COND*) 0); } switch (new_cond->argument_list()->elements) { case 0: @@ -23718,7 +23757,7 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond, exclude_expensive_cond, retain_ref_cond, false); if (!fix) - return (COND*) 0; // Always true + return (COND*) 0; // Always true or error new_cond->argument_list()->push_back(fix, thd->mem_root); } /* @@ -23726,7 +23765,8 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond, the new parent Item. This should not be expensive because all children of Item_cond_and should be fixed by now. */ - new_cond->fix_fields(thd, 0); + if (new_cond->fix_fields(thd, 0)) + return (COND*) 0; new_cond->used_tables_cache= ((Item_cond_or*) cond)->used_tables_cache; new_cond->top_level_item(); return new_cond;