diff options
author | unknown <timour@askmonty.org> | 2010-12-02 21:54:40 +0200 |
---|---|---|
committer | unknown <timour@askmonty.org> | 2010-12-02 21:54:40 +0200 |
commit | 620aea4fde7d40f3870bebdcfd66d2b0b556db2f (patch) | |
tree | 5c288f309731af09ad66a281b33039d1ca88f5c4 | |
parent | 1b3336dc30cf97283cca6071f089df992c425eb2 (diff) | |
download | mariadb-git-620aea4fde7d40f3870bebdcfd66d2b0b556db2f.tar.gz |
Fix LP BUG#682683
Analysis:
The fix for LP BUG#680846 avoids evaluation of constant expressions
with subqueries in the GROUP/ORDER clauses in the procedure
remove_const(). The purpose of remove_const is to remove constant
expressions in the GROUP/ORDER clauses.
In order delay until execution the evaluation of such subqueries,
they were not removed in the GROUP/ORDER clause. As a result temp
table creation during execution attempted to create a column in the
temp table for each constant GROUP/ORDER expression. However, the
logic in create_tmp_table is to not create temp table columns for
constant items. The crash was due to a group Item without a
corresponding column in the temp table for GROUP BY.
Solution:
The patch adds back removal of constant expressions with subqueries.
In order for such expressions to be evaluated, so that the server can
ensure that such subquries return 1 row, the evaluation of these
expressions is delayed until execution.
-rw-r--r-- | mysql-test/r/subselect4.result | 40 | ||||
-rw-r--r-- | mysql-test/t/subselect4.test | 30 | ||||
-rw-r--r-- | sql/sql_select.cc | 38 | ||||
-rw-r--r-- | sql/sql_select.h | 10 |
4 files changed, 111 insertions, 7 deletions
diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index bbbba8b073a..c18159295fb 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -605,6 +605,46 @@ COUNT(t2.f3) f9 0 NULL drop table t1,t2; # +# LP BUG#682683 Crash in create_tmp_table called from +# JOIN::init_execution +# +CREATE TABLE t2 (f1 int) ; +INSERT INTO t2 VALUES (1),(2); +CREATE TABLE t1 (f1 int) ; +EXPLAIN +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 GROUP BY field1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +2 SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 GROUP BY field1; +field1 +NULL +EXPLAIN +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 ORDER BY field1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +2 SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 ORDER BY field1; +field1 +NULL +NULL +INSERT INTO t1 VALUES (1),(2); +EXPLAIN +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 GROUP BY field1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 GROUP BY field1; +ERROR 21000: Subquery returns more than 1 row +EXPLAIN +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 ORDER BY field1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 ORDER BY field1; +ERROR 21000: Subquery returns more than 1 row +drop table t1,t2; +# # LP BUG#680943 Assertion `!table || (!table->read_set || # bitmap_is_set(table->read_set, field_index))' failed with subquery # diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index fea5d8a2106..cc183db8d87 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -559,6 +559,36 @@ ORDER BY f9; drop table t1,t2; --echo # +--echo # LP BUG#682683 Crash in create_tmp_table called from +--echo # JOIN::init_execution +--echo # + +CREATE TABLE t2 (f1 int) ; +INSERT INTO t2 VALUES (1),(2); + +CREATE TABLE t1 (f1 int) ; + +EXPLAIN +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 GROUP BY field1; +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 GROUP BY field1; +EXPLAIN +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 ORDER BY field1; +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 ORDER BY field1; + +INSERT INTO t1 VALUES (1),(2); + +EXPLAIN +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 GROUP BY field1; +--error ER_SUBQUERY_NO_1_ROW +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 GROUP BY field1; +EXPLAIN +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 ORDER BY field1; +--error ER_SUBQUERY_NO_1_ROW +SELECT (SELECT f1 FROM t1) AS field1 FROM t2 ORDER BY field1; + +drop table t1,t2; + +--echo # --echo # LP BUG#680943 Assertion `!table || (!table->read_set || --echo # bitmap_is_set(table->read_set, field_index))' failed with subquery --echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1d048075a5f..d682aa3e732 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1402,6 +1402,7 @@ setup_subq_exit: /** Create and initialize objects neeed for the execution of a query plan. + Evaluate constant expressions not evaluated during optimization. */ int JOIN::init_execution() @@ -1409,6 +1410,7 @@ int JOIN::init_execution() DBUG_ENTER("JOIN::init_execution"); DBUG_ASSERT(optimized); + DBUG_ASSERT(!(select_options & SELECT_DESCRIBE)); initialized= true; /* Create a tmp table if distinct or if the sort is too complicated */ @@ -1839,6 +1841,27 @@ JOIN::exec() DBUG_VOID_RETURN; } + /* + Evaluate all constant expressions with subqueries in the ORDER/GROUP clauses + to make sure that all subqueries return a single row. The evaluation itself + will trigger an error if that is not the case. + */ + if (exec_const_order_group_cond.elements && + !(select_options & SELECT_DESCRIBE)) + { + List_iterator_fast<Item> const_item_it(exec_const_order_group_cond); + Item *cur_const_item; + while ((cur_const_item= const_item_it++)) + { + cur_const_item->val_str(&cur_const_item->str_value); + if (thd->is_error()) + { + error= thd->is_error(); + DBUG_VOID_RETURN; + } + } + } + if ((this->select_lex->options & OPTION_SCHEMA_TABLE) && get_schema_tables_result(this, PROCESSED_BY_JOIN_EXEC)) DBUG_VOID_RETURN; @@ -8279,13 +8302,16 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, (join->tables > 1 && join->rollup.state == ROLLUP::STATE_INITED && join->outer_join)) *simple_order=0; // Must do a temp table to sort - else if (!(order_tables & not_const_tables) && - !order->item[0]->with_subselect) + else if (!(order_tables & not_const_tables)) { - /* - Skip constant expressions in the ORDER/GROUP clause, except when there - is a subquery in the expression. - */ + if (order->item[0]->with_subselect) + { + /* + Delay the evaluation of constant ORDER and/or GROUP expressions that + contain subqueries until the execution phase. + */ + join->exec_const_order_group_cond.push_back(order->item[0]); + } DBUG_PRINT("info",("removing: %s", order->item[0]->full_name())); continue; } diff --git a/sql/sql_select.h b/sql/sql_select.h index 7fcf18a5985..008530a4d94 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1599,6 +1599,13 @@ public: evaluated at optimization time. */ Item *exec_const_cond; + /* + Constant ORDER and/or GROUP expressions that contain subqueries. Such + expressions need to evaluated to verify that the subquery indeed + returns a single row. The evaluation of such expressions is delayed + until query execution. + */ + List<Item> exec_const_order_group_cond; SQL_SELECT *select; ///<created in optimisation phase JOIN_TAB *return_tab; ///<used only for outer joins Item **ref_pointer_array; ///<used pointer reference for this select @@ -1762,7 +1769,8 @@ public: bool send_row_on_empty_set() { return (do_send_rows && tmp_table_param.sum_func_count != 0 && - !group_list && having_value != Item::COND_FALSE); + !(group_list || group_optimized_away) && + having_value != Item::COND_FALSE); } bool change_result(select_result *result); bool is_top_level_join() const |