mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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.
This commit is contained in:
@ -4749,4 +4749,15 @@ sum(a) sub
|
|||||||
1 3
|
1 3
|
||||||
deallocate prepare stmt1;
|
deallocate prepare stmt1;
|
||||||
drop table t1,t2;
|
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
|
End of 5.1 tests
|
||||||
|
@ -3759,4 +3759,19 @@ deallocate prepare stmt1;
|
|||||||
|
|
||||||
drop table t1,t2;
|
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
|
--echo End of 5.1 tests
|
||||||
|
11
sql/item.h
11
sql/item.h
@ -556,10 +556,17 @@ public:
|
|||||||
Field *make_string_field(TABLE *table);
|
Field *make_string_field(TABLE *table);
|
||||||
virtual bool fix_fields(THD *, Item **);
|
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.
|
complete fix_fields() procedure.
|
||||||
|
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.
|
||||||
*/
|
*/
|
||||||
inline void quick_fix_field() { fixed= 1; }
|
virtual inline void quick_fix_field() { fixed= 1; }
|
||||||
/* Function returns 1 on overflow and -1 on fatal errors */
|
/* Function returns 1 on overflow and -1 on fatal errors */
|
||||||
int save_in_field_no_warnings(Field *field, bool no_conversions);
|
int save_in_field_no_warnings(Field *field, bool no_conversions);
|
||||||
virtual int save_in_field(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;
|
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,
|
bool Item_func::walk(Item_processor processor, bool walk_subquery,
|
||||||
uchar *argument)
|
uchar *argument)
|
||||||
|
@ -117,6 +117,7 @@ public:
|
|||||||
// Constructor used for Item_cond_and/or (see Item comment)
|
// Constructor used for Item_cond_and/or (see Item comment)
|
||||||
Item_func(THD *thd, Item_func *item);
|
Item_func(THD *thd, Item_func *item);
|
||||||
bool fix_fields(THD *, Item **ref);
|
bool fix_fields(THD *, Item **ref);
|
||||||
|
void quick_fix_field();
|
||||||
table_map used_tables() const;
|
table_map used_tables() const;
|
||||||
table_map not_null_tables() const;
|
table_map not_null_tables() const;
|
||||||
void update_used_tables();
|
void update_used_tables();
|
||||||
|
Reference in New Issue
Block a user