MDEV-16722: Assertion `type() != NULL_ITEM' failed
We hit this assert during the create of a temporary table field because the current code does not handle the case when the value of the NAME_CONST function is NULL. Fixed this by allowing creation of temporary table fields even for the case when NAME_CONST returns NULL value. Introduced tmp_table_field_from_field_type_maybe_null() function in Item class so both Item_basic_value and Item_name_const can use it. Introduced a virtual method get_func_item() in the Item class.
This commit is contained in:
parent
b05ee14d95
commit
befc09f002
@ -3334,3 +3334,14 @@ d x
|
|||||||
00:00:01 00:00:02
|
00:00:01 00:00:02
|
||||||
00:00:02 NULL
|
00:00:02 NULL
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# MDEV-16722: Assertion `type() != NULL_ITEM' failed
|
||||||
|
#
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
SELECT row_number() OVER (order by a) FROM t1 order by NAME_CONST('myname',NULL);
|
||||||
|
row_number() OVER (order by a)
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
drop table t1;
|
||||||
|
@ -2100,3 +2100,12 @@ CREATE TABLE t1 (d time);
|
|||||||
INSERT INTO t1 VALUES ('00:00:01'),('00:00:02');
|
INSERT INTO t1 VALUES ('00:00:01'),('00:00:02');
|
||||||
SELECT *, LEAD(d) OVER (ORDER BY d) AS x FROM t1;
|
SELECT *, LEAD(d) OVER (ORDER BY d) AS x FROM t1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-16722: Assertion `type() != NULL_ITEM' failed
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
SELECT row_number() OVER (order by a) FROM t1 order by NAME_CONST('myname',NULL);
|
||||||
|
drop table t1;
|
||||||
|
20
sql/item.cc
20
sql/item.cc
@ -1960,7 +1960,6 @@ Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val):
|
|||||||
Item_fixed_hybrid(thd), value_item(val), name_item(name_arg)
|
Item_fixed_hybrid(thd), value_item(val), name_item(name_arg)
|
||||||
{
|
{
|
||||||
Item::maybe_null= TRUE;
|
Item::maybe_null= TRUE;
|
||||||
valid_args= true;
|
|
||||||
if (!name_item->basic_const_item())
|
if (!name_item->basic_const_item())
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -1979,7 +1978,6 @@ Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val):
|
|||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
valid_args= false;
|
|
||||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST");
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1987,24 +1985,16 @@ err:
|
|||||||
Item::Type Item_name_const::type() const
|
Item::Type Item_name_const::type() const
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
As
|
|
||||||
1. one can try to create the Item_name_const passing non-constant
|
|
||||||
arguments, although it's incorrect and
|
|
||||||
2. the type() method can be called before the fix_fields() to get
|
|
||||||
type information for a further type cast, e.g.
|
|
||||||
if (item->type() == FIELD_ITEM)
|
|
||||||
((Item_field *) item)->...
|
|
||||||
we return NULL_ITEM in the case to avoid wrong casting.
|
|
||||||
|
|
||||||
valid_args guarantees value_item->basic_const_item(); if type is
|
We are guarenteed that value_item->basic_const_item(), if not
|
||||||
FUNC_ITEM, then we have a fudged item_func_neg() on our hands
|
an error is thrown that WRONG ARGUMENTS are supplied to
|
||||||
and return the underlying type.
|
NAME_CONST function.
|
||||||
|
If type is FUNC_ITEM, then we have a fudged item_func_neg()
|
||||||
|
on our hands and return the underlying type.
|
||||||
For Item_func_set_collation()
|
For Item_func_set_collation()
|
||||||
e.g. NAME_CONST('name', 'value' COLLATE collation) we return its
|
e.g. NAME_CONST('name', 'value' COLLATE collation) we return its
|
||||||
'value' argument type.
|
'value' argument type.
|
||||||
*/
|
*/
|
||||||
if (!valid_args)
|
|
||||||
return NULL_ITEM;
|
|
||||||
Item::Type value_type= value_item->type();
|
Item::Type value_type= value_item->type();
|
||||||
if (value_type == FUNC_ITEM)
|
if (value_type == FUNC_ITEM)
|
||||||
{
|
{
|
||||||
|
24
sql/item.h
24
sql/item.h
@ -820,6 +820,10 @@ protected:
|
|||||||
return tmp_table_field_from_field_type(table);
|
return tmp_table_field_from_field_type(table);
|
||||||
}
|
}
|
||||||
Field *create_tmp_field_int(TABLE *table, uint convert_int_length);
|
Field *create_tmp_field_int(TABLE *table, uint convert_int_length);
|
||||||
|
Field *tmp_table_field_from_field_type_maybe_null(TABLE *table,
|
||||||
|
Tmp_field_src *src,
|
||||||
|
const Tmp_field_param *param,
|
||||||
|
bool is_explicit_null);
|
||||||
|
|
||||||
void push_note_converted_to_negative_complement(THD *thd);
|
void push_note_converted_to_negative_complement(THD *thd);
|
||||||
void push_note_converted_to_positive_complement(THD *thd);
|
void push_note_converted_to_positive_complement(THD *thd);
|
||||||
@ -876,6 +880,7 @@ public:
|
|||||||
expressions with subqueries in the ORDER/GROUP clauses.
|
expressions with subqueries in the ORDER/GROUP clauses.
|
||||||
*/
|
*/
|
||||||
String *val_str() { return val_str(&str_value); }
|
String *val_str() { return val_str(&str_value); }
|
||||||
|
virtual Item_func *get_item_func() { return NULL; }
|
||||||
|
|
||||||
const MY_LOCALE *locale_from_val_str();
|
const MY_LOCALE *locale_from_val_str();
|
||||||
|
|
||||||
@ -2574,7 +2579,20 @@ protected:
|
|||||||
Item_basic_value(THD *thd): Item(thd) {}
|
Item_basic_value(THD *thd): Item(thd) {}
|
||||||
public:
|
public:
|
||||||
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
|
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
|
||||||
const Tmp_field_param *param);
|
const Tmp_field_param *param)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
create_tmp_field_ex() for this type of Items is called for:
|
||||||
|
- CREATE TABLE ... SELECT
|
||||||
|
- In ORDER BY: SELECT max(a) FROM t1 GROUP BY a ORDER BY 'const';
|
||||||
|
- In CURSORS:
|
||||||
|
DECLARE c CURSOR FOR SELECT 'test';
|
||||||
|
OPEN c;
|
||||||
|
*/
|
||||||
|
return tmp_table_field_from_field_type_maybe_null(table, src, param,
|
||||||
|
type() == Item::NULL_ITEM);
|
||||||
|
}
|
||||||
bool eq(const Item *item, bool binary_cmp) const;
|
bool eq(const Item *item, bool binary_cmp) const;
|
||||||
const Type_all_attributes *get_type_all_attributes_from_const() const
|
const Type_all_attributes *get_type_all_attributes_from_const() const
|
||||||
{ return this; }
|
{ return this; }
|
||||||
@ -2915,7 +2933,6 @@ class Item_name_const : public Item_fixed_hybrid
|
|||||||
{
|
{
|
||||||
Item *value_item;
|
Item *value_item;
|
||||||
Item *name_item;
|
Item *name_item;
|
||||||
bool valid_args;
|
|
||||||
public:
|
public:
|
||||||
Item_name_const(THD *thd, Item *name_arg, Item *val);
|
Item_name_const(THD *thd, Item *name_arg, Item *val);
|
||||||
|
|
||||||
@ -2948,7 +2965,8 @@ public:
|
|||||||
DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1;
|
DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1;
|
||||||
OPEN c;
|
OPEN c;
|
||||||
*/
|
*/
|
||||||
return create_tmp_field_ex_simple(table, src, param);
|
return tmp_table_field_from_field_type_maybe_null(table, src, param,
|
||||||
|
type() == Item::NULL_ITEM);
|
||||||
}
|
}
|
||||||
int save_in_field(Field *field, bool no_conversions)
|
int save_in_field(Field *field, bool no_conversions)
|
||||||
{
|
{
|
||||||
|
@ -3313,11 +3313,8 @@ public:
|
|||||||
|
|
||||||
inline bool is_cond_and(Item *item)
|
inline bool is_cond_and(Item *item)
|
||||||
{
|
{
|
||||||
if (item->type() != Item::COND_ITEM)
|
Item_func *func_item= item->get_item_func();
|
||||||
return FALSE;
|
return func_item && func_item->functype() == Item_func::COND_AND_FUNC;
|
||||||
|
|
||||||
Item_cond *cond_item= (Item_cond*) item;
|
|
||||||
return (cond_item->functype() == Item_func::COND_AND_FUNC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Item_cond_or :public Item_cond
|
class Item_cond_or :public Item_cond
|
||||||
@ -3418,11 +3415,8 @@ public:
|
|||||||
|
|
||||||
inline bool is_cond_or(Item *item)
|
inline bool is_cond_or(Item *item)
|
||||||
{
|
{
|
||||||
if (item->type() != Item::COND_ITEM)
|
Item_func *func_item= item->get_item_func();
|
||||||
return FALSE;
|
return func_item && func_item->functype() == Item_func::COND_OR_FUNC;
|
||||||
|
|
||||||
Item_cond *cond_item= (Item_cond*) item;
|
|
||||||
return (cond_item->functype() == Item_func::COND_OR_FUNC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item *and_expressions(Item *a, Item *b, Item **org_item);
|
Item *and_expressions(Item *a, Item *b, Item **org_item);
|
||||||
|
@ -393,6 +393,7 @@ public:
|
|||||||
|
|
||||||
bool with_sum_func() const { return m_with_sum_func; }
|
bool with_sum_func() const { return m_with_sum_func; }
|
||||||
With_sum_func_cache* get_with_sum_func_cache() { return this; }
|
With_sum_func_cache* get_with_sum_func_cache() { return this; }
|
||||||
|
Item_func *get_item_func() { return this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -16616,6 +16616,22 @@ Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length)
|
|||||||
*this, table);
|
*this, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table,
|
||||||
|
Tmp_field_src *src,
|
||||||
|
const Tmp_field_param *param,
|
||||||
|
bool is_explicit_null)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(!param->make_copy_field());
|
||||||
|
DBUG_ASSERT(!is_result_field());
|
||||||
|
Field *result;
|
||||||
|
if ((result= tmp_table_field_from_field_type(table)))
|
||||||
|
{
|
||||||
|
if (result && is_explicit_null)
|
||||||
|
result->is_created_from_null_item= true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Field *Item_sum::create_tmp_field(bool group, TABLE *table)
|
Field *Item_sum::create_tmp_field(bool group, TABLE *table)
|
||||||
{
|
{
|
||||||
@ -16847,31 +16863,6 @@ Field *Item_func_sp::create_tmp_field_ex(TABLE *table,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Field *Item_basic_value::create_tmp_field_ex(TABLE *table,
|
|
||||||
Tmp_field_src *src,
|
|
||||||
const Tmp_field_param *param)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
create_tmp_field_ex() for this type of Items is called for:
|
|
||||||
- CREATE TABLE ... SELECT
|
|
||||||
- In ORDER BY: SELECT max(a) FROM t1 GROUP BY a ORDER BY 'const';
|
|
||||||
- In CURSORS:
|
|
||||||
DECLARE c CURSOR FOR SELECT 'test';
|
|
||||||
OPEN c;
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(!param->make_copy_field());
|
|
||||||
DBUG_ASSERT(!is_result_field());
|
|
||||||
Field *result;
|
|
||||||
if ((result= tmp_table_field_from_field_type(table)))
|
|
||||||
{
|
|
||||||
if (type() == Item::NULL_ITEM) // Item_null or Item_param
|
|
||||||
result->is_created_from_null_item= true;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create field for temporary table.
|
Create field for temporary table.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user