mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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.
This commit is contained in:
@ -605,6 +605,46 @@ COUNT(t2.f3) f9
|
|||||||
0 NULL
|
0 NULL
|
||||||
drop table t1,t2;
|
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 ||
|
# LP BUG#680943 Assertion `!table || (!table->read_set ||
|
||||||
# bitmap_is_set(table->read_set, field_index))' failed with subquery
|
# bitmap_is_set(table->read_set, field_index))' failed with subquery
|
||||||
#
|
#
|
||||||
|
@ -558,6 +558,36 @@ ORDER BY f9;
|
|||||||
|
|
||||||
drop table t1,t2;
|
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 #
|
||||||
--echo # LP BUG#680943 Assertion `!table || (!table->read_set ||
|
--echo # LP BUG#680943 Assertion `!table || (!table->read_set ||
|
||||||
--echo # bitmap_is_set(table->read_set, field_index))' failed with subquery
|
--echo # bitmap_is_set(table->read_set, field_index))' failed with subquery
|
||||||
|
@ -1402,6 +1402,7 @@ setup_subq_exit:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Create and initialize objects neeed for the execution of a query plan.
|
Create and initialize objects neeed for the execution of a query plan.
|
||||||
|
Evaluate constant expressions not evaluated during optimization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int JOIN::init_execution()
|
int JOIN::init_execution()
|
||||||
@ -1409,6 +1410,7 @@ int JOIN::init_execution()
|
|||||||
DBUG_ENTER("JOIN::init_execution");
|
DBUG_ENTER("JOIN::init_execution");
|
||||||
|
|
||||||
DBUG_ASSERT(optimized);
|
DBUG_ASSERT(optimized);
|
||||||
|
DBUG_ASSERT(!(select_options & SELECT_DESCRIBE));
|
||||||
initialized= true;
|
initialized= true;
|
||||||
|
|
||||||
/* Create a tmp table if distinct or if the sort is too complicated */
|
/* Create a tmp table if distinct or if the sort is too complicated */
|
||||||
@ -1839,6 +1841,27 @@ JOIN::exec()
|
|||||||
DBUG_VOID_RETURN;
|
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) &&
|
if ((this->select_lex->options & OPTION_SCHEMA_TABLE) &&
|
||||||
get_schema_tables_result(this, PROCESSED_BY_JOIN_EXEC))
|
get_schema_tables_result(this, PROCESSED_BY_JOIN_EXEC))
|
||||||
DBUG_VOID_RETURN;
|
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->tables > 1 && join->rollup.state == ROLLUP::STATE_INITED &&
|
||||||
join->outer_join))
|
join->outer_join))
|
||||||
*simple_order=0; // Must do a temp table to sort
|
*simple_order=0; // Must do a temp table to sort
|
||||||
else if (!(order_tables & not_const_tables) &&
|
else if (!(order_tables & not_const_tables))
|
||||||
!order->item[0]->with_subselect)
|
|
||||||
{
|
{
|
||||||
/*
|
if (order->item[0]->with_subselect)
|
||||||
Skip constant expressions in the ORDER/GROUP clause, except when there
|
{
|
||||||
is a subquery in the expression.
|
/*
|
||||||
*/
|
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()));
|
DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1599,6 +1599,13 @@ public:
|
|||||||
evaluated at optimization time.
|
evaluated at optimization time.
|
||||||
*/
|
*/
|
||||||
Item *exec_const_cond;
|
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
|
SQL_SELECT *select; ///<created in optimisation phase
|
||||||
JOIN_TAB *return_tab; ///<used only for outer joins
|
JOIN_TAB *return_tab; ///<used only for outer joins
|
||||||
Item **ref_pointer_array; ///<used pointer reference for this select
|
Item **ref_pointer_array; ///<used pointer reference for this select
|
||||||
@ -1762,7 +1769,8 @@ public:
|
|||||||
bool send_row_on_empty_set()
|
bool send_row_on_empty_set()
|
||||||
{
|
{
|
||||||
return (do_send_rows && tmp_table_param.sum_func_count != 0 &&
|
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 change_result(select_result *result);
|
||||||
bool is_top_level_join() const
|
bool is_top_level_join() const
|
||||||
|
Reference in New Issue
Block a user