mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-5153: Server crashes in Item_ref::fix_fields on 2nd execution of PS with LEFT JOIN and MERGE view or SELECT SQ
1. Transformation of row IN subquery made the same as single value. 2. replace_where_subcondition() made working on several layers of OR/AND because it called on expression before fix_fields().
This commit is contained in:
@ -4709,6 +4709,37 @@ q 1 q
|
|||||||
q 1 q
|
q 1 q
|
||||||
drop view v1;
|
drop view v1;
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
#
|
||||||
|
# MDEV-5153: Server crashes in Item_ref::fix_fields on 2nd execution
|
||||||
|
# of PS with LEFT JOIN and MERGE view or SELECT SQ
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (i1 INT, c1 VARCHAR(6)) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
|
||||||
|
CREATE TABLE t2 (c2 VARCHAR(6)) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t2 VALUES ('foobar'),('qux');
|
||||||
|
CREATE ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1 WHERE ( c1 ) IN ( SELECT c2 FROM t2 ) AND i1 <= 2 ;
|
||||||
|
PREPARE stmt FROM 'SELECT * FROM t1 LEFT JOIN v1 ON (v1.i1 = t1.i1)';
|
||||||
|
EXECUTE stmt;
|
||||||
|
i1 c1 i1 c1
|
||||||
|
1 foo NULL NULL
|
||||||
|
2 bar NULL NULL
|
||||||
|
EXECUTE stmt;
|
||||||
|
i1 c1 i1 c1
|
||||||
|
1 foo NULL NULL
|
||||||
|
2 bar NULL NULL
|
||||||
|
drop view v1;
|
||||||
|
CREATE ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1 WHERE ( c1, c1 ) IN ( SELECT c2, c2 FROM t2 ) AND i1 <= 2 ;
|
||||||
|
EXECUTE stmt;
|
||||||
|
i1 c1 i1 c1
|
||||||
|
1 foo NULL NULL
|
||||||
|
2 bar NULL NULL
|
||||||
|
EXECUTE stmt;
|
||||||
|
i1 c1 i1 c1
|
||||||
|
1 foo NULL NULL
|
||||||
|
2 bar NULL NULL
|
||||||
|
deallocate prepare stmt;
|
||||||
|
drop view v1;
|
||||||
|
drop table t1,t2;
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
# -- End of 5.3 tests.
|
# -- End of 5.3 tests.
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
|
@ -4647,6 +4647,34 @@ SELECT * FROM t2 LEFT JOIN v1 ON ( c=b AND a IN ( 1,6 ) );
|
|||||||
drop view v1;
|
drop view v1;
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-5153: Server crashes in Item_ref::fix_fields on 2nd execution
|
||||||
|
--echo # of PS with LEFT JOIN and MERGE view or SELECT SQ
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (i1 INT, c1 VARCHAR(6)) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
|
||||||
|
|
||||||
|
CREATE TABLE t2 (c2 VARCHAR(6)) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t2 VALUES ('foobar'),('qux');
|
||||||
|
|
||||||
|
CREATE ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1 WHERE ( c1 ) IN ( SELECT c2 FROM t2 ) AND i1 <= 2 ;
|
||||||
|
|
||||||
|
PREPARE stmt FROM 'SELECT * FROM t1 LEFT JOIN v1 ON (v1.i1 = t1.i1)';
|
||||||
|
|
||||||
|
EXECUTE stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
drop view v1;
|
||||||
|
CREATE ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1 WHERE ( c1, c1 ) IN ( SELECT c2, c2 FROM t2 ) AND i1 <= 2 ;
|
||||||
|
|
||||||
|
EXECUTE stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
deallocate prepare stmt;
|
||||||
|
drop view v1;
|
||||||
|
drop table t1,t2;
|
||||||
|
|
||||||
--echo # -----------------------------------------------------------------
|
--echo # -----------------------------------------------------------------
|
||||||
--echo # -- End of 5.3 tests.
|
--echo # -- End of 5.3 tests.
|
||||||
--echo # -----------------------------------------------------------------
|
--echo # -----------------------------------------------------------------
|
||||||
|
@ -1436,9 +1436,11 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg)
|
|||||||
|
|
||||||
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
|
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
|
||||||
{
|
{
|
||||||
|
DBUG_ENTER("Item_in_optimizer::fix_left");
|
||||||
if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) ||
|
if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) ||
|
||||||
(!cache && !(cache= Item_cache::get_cache(args[0]))))
|
(!cache && !(cache= Item_cache::get_cache(args[0]))))
|
||||||
return 1;
|
DBUG_RETURN(1);
|
||||||
|
DBUG_PRINT("info", ("actual fix fields"));
|
||||||
|
|
||||||
cache->setup(args[0]);
|
cache->setup(args[0]);
|
||||||
if (cache->cols() == 1)
|
if (cache->cols() == 1)
|
||||||
@ -1460,10 +1462,13 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
|
|||||||
{
|
{
|
||||||
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
|
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
|
||||||
"SUBQUERY in ROW in left expression of IN/ALL/ANY");
|
"SUBQUERY in ROW in left expression of IN/ALL/ANY");
|
||||||
return 1;
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
if (args[0]->element_index(i)->used_tables())
|
if (args[0]->element_index(i)->used_tables())
|
||||||
|
{
|
||||||
((Item_cache *)cache->element_index(i))->set_used_tables(OUTER_REF_TABLE_BIT);
|
((Item_cache *)cache->element_index(i))->set_used_tables(OUTER_REF_TABLE_BIT);
|
||||||
|
cache->set_used_tables(OUTER_REF_TABLE_BIT);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
((Item_cache *)cache->element_index(i))->set_used_tables(0);
|
((Item_cache *)cache->element_index(i))->set_used_tables(0);
|
||||||
}
|
}
|
||||||
@ -1477,7 +1482,7 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
|
|||||||
cache->store(args[0]);
|
cache->store(args[0]);
|
||||||
cache->cache_value();
|
cache->cache_value();
|
||||||
}
|
}
|
||||||
return 0;
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2177,11 +2177,11 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
|
|||||||
DBUG_RETURN(true);
|
DBUG_RETURN(true);
|
||||||
Item *item_eq=
|
Item *item_eq=
|
||||||
new Item_func_eq(new
|
new Item_func_eq(new
|
||||||
Item_ref(&select_lex->context,
|
Item_direct_ref(&select_lex->context,
|
||||||
(*optimizer->get_cache())->
|
(*optimizer->get_cache())->
|
||||||
addr(i),
|
addr(i),
|
||||||
(char *)"<no matter>",
|
(char *)"<no matter>",
|
||||||
(char *)in_left_expr_name),
|
(char *)in_left_expr_name),
|
||||||
new
|
new
|
||||||
Item_ref(&select_lex->context,
|
Item_ref(&select_lex->context,
|
||||||
select_lex->ref_pointer_array + i,
|
select_lex->ref_pointer_array + i,
|
||||||
@ -2462,7 +2462,7 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg)
|
|||||||
bool
|
bool
|
||||||
Item_in_subselect::select_in_like_transformer(JOIN *join)
|
Item_in_subselect::select_in_like_transformer(JOIN *join)
|
||||||
{
|
{
|
||||||
Query_arena *arena, backup;
|
Query_arena *arena= 0, backup;
|
||||||
SELECT_LEX *current= thd->lex->current_select;
|
SELECT_LEX *current= thd->lex->current_select;
|
||||||
const char *save_where= thd->where;
|
const char *save_where= thd->where;
|
||||||
bool trans_res= true;
|
bool trans_res= true;
|
||||||
@ -2484,9 +2484,6 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed)
|
|
||||||
DBUG_RETURN(false);
|
|
||||||
|
|
||||||
thd->where= "IN/ALL/ANY subquery";
|
thd->where= "IN/ALL/ANY subquery";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2497,25 +2494,29 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
|
|||||||
note: we won't need Item_in_optimizer when handling degenerate cases
|
note: we won't need Item_in_optimizer when handling degenerate cases
|
||||||
like "... IN (SELECT 1)"
|
like "... IN (SELECT 1)"
|
||||||
*/
|
*/
|
||||||
|
arena= thd->activate_stmt_arena_if_needed(&backup);
|
||||||
if (!optimizer)
|
if (!optimizer)
|
||||||
{
|
{
|
||||||
arena= thd->activate_stmt_arena_if_needed(&backup);
|
|
||||||
result= (!(optimizer= new Item_in_optimizer(left_expr, this)));
|
result= (!(optimizer= new Item_in_optimizer(left_expr, this)));
|
||||||
if (arena)
|
|
||||||
thd->restore_active_arena(arena, &backup);
|
|
||||||
if (result)
|
if (result)
|
||||||
goto err;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->lex->current_select= current->return_after_parsing();
|
thd->lex->current_select= current->return_after_parsing();
|
||||||
result= (!left_expr->fixed &&
|
result= optimizer->fix_left(thd, optimizer->arguments());
|
||||||
left_expr->fix_fields(thd, optimizer->arguments()));
|
|
||||||
/* fix_fields can change reference to left_expr, we need reassign it */
|
/* fix_fields can change reference to left_expr, we need reassign it */
|
||||||
left_expr= optimizer->arguments()[0];
|
left_expr= optimizer->arguments()[0];
|
||||||
|
|
||||||
thd->lex->current_select= current;
|
thd->lex->current_select= current;
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
trans_res= false;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
goto err;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Both transformers call fix_fields() only for Items created inside them,
|
Both transformers call fix_fields() only for Items created inside them,
|
||||||
@ -2524,7 +2525,6 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
|
|||||||
of Item, we have to call fix_fields() for it only with original arena to
|
of Item, we have to call fix_fields() for it only with original arena to
|
||||||
avoid memory leack)
|
avoid memory leack)
|
||||||
*/
|
*/
|
||||||
arena= thd->activate_stmt_arena_if_needed(&backup);
|
|
||||||
if (left_expr->cols() == 1)
|
if (left_expr->cols() == 1)
|
||||||
trans_res= single_value_transformer(join);
|
trans_res= single_value_transformer(join);
|
||||||
else
|
else
|
||||||
@ -2539,9 +2539,9 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
|
|||||||
}
|
}
|
||||||
trans_res= row_value_transformer(join);
|
trans_res= row_value_transformer(join);
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
if (arena)
|
if (arena)
|
||||||
thd->restore_active_arena(arena, &backup);
|
thd->restore_active_arena(arena, &backup);
|
||||||
err:
|
|
||||||
thd->where= save_where;
|
thd->where= save_where;
|
||||||
DBUG_RETURN(trans_res);
|
DBUG_RETURN(trans_res);
|
||||||
}
|
}
|
||||||
|
@ -1252,11 +1252,11 @@ void get_delayed_table_estimates(TABLE *table,
|
|||||||
@brief Replaces an expression destructively inside the expression tree of
|
@brief Replaces an expression destructively inside the expression tree of
|
||||||
the WHERE clase.
|
the WHERE clase.
|
||||||
|
|
||||||
@note Because of current requirements for semijoin flattening, we do not
|
@note We substitute AND/OR structure because it was copied by
|
||||||
need to recurse here, hence this function will only examine the top-level
|
copy_andor_structure and some changes could be done in the copy but
|
||||||
AND conditions. (see JOIN::prepare, comment starting with "Check if the
|
should be left permanent, also there could be several layers of AND over
|
||||||
subquery predicate can be executed via materialization".
|
AND and OR over OR because ::fix_field() possibly is not called.
|
||||||
|
|
||||||
@param join The top-level query.
|
@param join The top-level query.
|
||||||
@param old_cond The expression to be replaced.
|
@param old_cond The expression to be replaced.
|
||||||
@param new_cond The expression to be substituted.
|
@param new_cond The expression to be substituted.
|
||||||
@ -1284,13 +1284,20 @@ static bool replace_where_subcondition(JOIN *join, Item **expr,
|
|||||||
Item *item;
|
Item *item;
|
||||||
while ((item= li++))
|
while ((item= li++))
|
||||||
{
|
{
|
||||||
if (item == old_cond)
|
if (item == old_cond)
|
||||||
{
|
{
|
||||||
li.replace(new_cond);
|
li.replace(new_cond);
|
||||||
if (do_fix_fields)
|
if (do_fix_fields)
|
||||||
new_cond->fix_fields(join->thd, li.ref());
|
new_cond->fix_fields(join->thd, li.ref());
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
else if (item->type() == Item::COND_ITEM)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(!(*expr)->fixed);
|
||||||
|
replace_where_subcondition(join, li.ref(),
|
||||||
|
old_cond, new_cond,
|
||||||
|
do_fix_fields);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user