mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Fixed Bug#12621017 - CRASH IF A SP VARIABLE IS USED IN THE LIMIT CLAUSE OF A
SET STATEMENT. Server built with debug asserts, without debug crashes if a user tries to run a stored procedure that constains query with subquery that include either LIMIT or LIMIT OFFSET clauses. The problem was that Item::fix_fields() was not called for the items representing LIMIT or OFFSET clauses. The solution is to call Item::fix_fields() right before evaluation in st_select_lex_unit::set_limit().
This commit is contained in:
@ -2599,7 +2599,47 @@ void st_select_lex_unit::set_limit(st_select_lex *sl)
|
||||
ulonglong val;
|
||||
|
||||
DBUG_ASSERT(! thd->stmt_arena->is_stmt_prepare());
|
||||
val= sl->select_limit ? sl->select_limit->val_uint() : HA_POS_ERROR;
|
||||
if (sl->select_limit)
|
||||
{
|
||||
Item *item = sl->select_limit;
|
||||
/*
|
||||
fix_fields() has not been called for sl->select_limit. That's due to the
|
||||
historical reasons -- this item could be only of type Item_int, and
|
||||
Item_int does not require fix_fields(). Thus, fix_fields() was never
|
||||
called for sl->select_limit.
|
||||
|
||||
Some time ago, Item_splocal was also allowed for LIMIT / OFFSET clauses.
|
||||
However, the fix_fields() behavior was not updated, which led to a crash
|
||||
in some cases.
|
||||
|
||||
There is no single place where to call fix_fields() for LIMIT / OFFSET
|
||||
items during the fix-fields-phase. Thus, for the sake of readability,
|
||||
it was decided to do it here, on the evaluation phase (which is a
|
||||
violation of design, but we chose the lesser of two evils).
|
||||
|
||||
We can call fix_fields() here, because sl->select_limit can be of two
|
||||
types only: Item_int and Item_splocal. Item_int::fix_fields() is trivial,
|
||||
and Item_splocal::fix_fields() (or rather Item_sp_variable::fix_fields())
|
||||
has the following specific:
|
||||
1) it does not affect other items;
|
||||
2) it does not fail.
|
||||
|
||||
Nevertheless DBUG_ASSERT was added to catch future changes in
|
||||
fix_fields() implementation. Also added runtime check against a result
|
||||
of fix_fields() in order to handle error condition in non-debug build.
|
||||
*/
|
||||
bool fix_fields_successful= true;
|
||||
if (!item->fixed)
|
||||
{
|
||||
fix_fields_successful= !item->fix_fields(thd, NULL);
|
||||
|
||||
DBUG_ASSERT(fix_fields_successful);
|
||||
}
|
||||
val= fix_fields_successful ? item->val_uint() : HA_POS_ERROR;
|
||||
}
|
||||
else
|
||||
val= HA_POS_ERROR;
|
||||
|
||||
select_limit_val= (ha_rows)val;
|
||||
#ifndef BIG_TABLES
|
||||
/*
|
||||
@ -2609,7 +2649,22 @@ void st_select_lex_unit::set_limit(st_select_lex *sl)
|
||||
if (val != (ulonglong)select_limit_val)
|
||||
select_limit_val= HA_POS_ERROR;
|
||||
#endif
|
||||
val= sl->offset_limit ? sl->offset_limit->val_uint() : ULL(0);
|
||||
if (sl->offset_limit)
|
||||
{
|
||||
Item *item = sl->offset_limit;
|
||||
// see comment for sl->select_limit branch.
|
||||
bool fix_fields_successful= true;
|
||||
if (!item->fixed)
|
||||
{
|
||||
fix_fields_successful= !item->fix_fields(thd, NULL);
|
||||
|
||||
DBUG_ASSERT(fix_fields_successful);
|
||||
}
|
||||
val= fix_fields_successful ? item->val_uint() : HA_POS_ERROR;
|
||||
}
|
||||
else
|
||||
val= ULL(0);
|
||||
|
||||
offset_limit_cnt= (ha_rows)val;
|
||||
#ifndef BIG_TABLES
|
||||
/* Check for truncation. */
|
||||
|
Reference in New Issue
Block a user