Commit efbb3c6c authored by Igor Babaev's avatar Igor Babaev

Fixed LP bug #639935 (bug #58727).

When the optimizer creates items out of other items it does
not have to call the fix_fields method. Usually in these
cases it calls quick_fix_field() that just marks the 
created item as fixed. If the created item is an Item_func
object then calling quick_fix_field() works fine if the
arguments of the created functional item are already fixed.
Otherwise some unfixed nodes remain in the item tree and
it triggers an assertion failure whenever the item is 
evaluated.

Fixed the problem by making the method quick_fix_field
virtual and providing an implementation for the class
Item_func objects that recursively calls the method
for unfixed arguments of any functional item.
parent 46c7fb27
......@@ -4749,4 +4749,15 @@ sum(a) sub
1 3
deallocate prepare stmt1;
drop table t1,t2;
#
# Bug LP#693935/#58727: Assertion failure with
# a single row subquery returning more than one row
#
create table t1 (a char(1) charset utf8);
insert into t1 values ('a'), ('b');
create table t2 (a binary(1));
insert into t2 values ('x'), ('y');
select * from t2 where a=(select a from t1) and a='x';
ERROR 21000: Subquery returns more than 1 row
drop table t1,t2;
End of 5.1 tests
......@@ -3759,4 +3759,19 @@ deallocate prepare stmt1;
drop table t1,t2;
--echo #
--echo # Bug LP#693935/#58727: Assertion failure with
--echo # a single row subquery returning more than one row
--echo #
create table t1 (a char(1) charset utf8);
insert into t1 values ('a'), ('b');
create table t2 (a binary(1));
insert into t2 values ('x'), ('y');
-- error ER_SUBQUERY_NO_1_ROW
select * from t2 where a=(select a from t1) and a='x';
drop table t1,t2;
--echo End of 5.1 tests
......@@ -556,10 +556,17 @@ class Item {
Field *make_string_field(TABLE *table);
virtual bool fix_fields(THD *, Item **);
/*
should be used in case where we are sure that we do not need
This method should be used in case where we are sure that we do not need
complete fix_fields() procedure.
*/
inline void quick_fix_field() { fixed= 1; }
Usually this method is used by the optimizer when it has to create a new
item out of other already fixed items. For example, if the optimizer has
to create a new Item_func for an inferred equality whose left and right
parts are already fixed items. In some cases the optimizer cannot use
directly fixed items as the arguments of the created functional item,
but rather uses intermediate type conversion items. Then the method is
supposed to be applied recursively.
*/
virtual inline void quick_fix_field() { fixed= 1; }
/* Function returns 1 on overflow and -1 on fatal errors */
int save_in_field_no_warnings(Field *field, bool no_conversions);
virtual int save_in_field(Field *field, bool no_conversions);
......
......@@ -202,6 +202,21 @@ Item_func::fix_fields(THD *thd, Item **ref)
return FALSE;
}
void
Item_func::quick_fix_field()
{
Item **arg,**arg_end;
if (arg_count)
{
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
{
if (!(*arg)->fixed)
(*arg)->quick_fix_field();
}
}
fixed= 1;
}
bool Item_func::walk(Item_processor processor, bool walk_subquery,
uchar *argument)
......
......@@ -117,6 +117,7 @@ class Item_func :public Item_result_field
// Constructor used for Item_cond_and/or (see Item comment)
Item_func(THD *thd, Item_func *item);
bool fix_fields(THD *, Item **ref);
void quick_fix_field();
table_map used_tables() const;
table_map not_null_tables() const;
void update_used_tables();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment