summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <timour@askmonty.org>2010-12-02 21:54:40 +0200
committerunknown <timour@askmonty.org>2010-12-02 21:54:40 +0200
commit620aea4fde7d40f3870bebdcfd66d2b0b556db2f (patch)
tree5c288f309731af09ad66a281b33039d1ca88f5c4
parent1b3336dc30cf97283cca6071f089df992c425eb2 (diff)
downloadmariadb-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.result40
-rw-r--r--mysql-test/t/subselect4.test30
-rw-r--r--sql/sql_select.cc38
-rw-r--r--sql/sql_select.h10
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