Commit 68403eed authored by Alexander Barkov's avatar Alexander Barkov

MDEV-27207 Assertion `!m_null_value' failed in int...

MDEV-27207 Assertion `!m_null_value' failed in int FixedBinTypeBundle<FbtImpl>::cmp_item_fbt::compare or in cmp_item_inet6::compare

Also fixing:  MDEV-31719 Wrong result of: WHERE inet6_column IN ('','::1')

Problem:

When converting an Item value from string to INET6 it's possible
that the Item value itself is a not-NULL string value,
while the following result of the string-to-INET6 conversion returns NULL.

Methods cmp_item_xxx::set(), cmp_item_xxx::store_value_by_template(),
in_inet6::set() did not take this scenario into account and
tested source_item->null_value, which does not indicate if the conversion
failed.

Changing the return data type of the mentioned methods from "void" to "bool".

"true" means that:
- either the source Item was NULL
- or the source Item was not NULL, but the data type coversion to
  the destination data type (INET6 in this issue) returned NULL.

"false" means that the Item was not NULL and the data type conversion
to the destination data type worked without error.

This patches fixes the INET6 data type.
After merging to 10.9, this patch should also fix same problems in UUID.
parent 400c1013
......@@ -2229,3 +2229,29 @@ SELECT * FROM t1 WHERE d >= ALL (SELECT * FROM t1);
d
12::
DROP TABLE t1;
#
# MDEV-27207 Assertion `!m_null_value' failed in int FixedBinTypeBundle<FbtImpl>::cmp_item_fbt::compare or in cmp_item_inet6::compare
#
CREATE TABLE t1 (a CHAR,b INET6);
SELECT * FROM t1 WHERE (a,b) IN (('',''),('',''));
a b
Warnings:
Warning 1292 Incorrect inet6 value: ''
Warning 1292 Incorrect inet6 value: ''
INSERT INTO t1 VALUES ('','::'),('','::');
SELECT * FROM t1 WHERE (a,b) IN (('',''),('',''));
a b
Warnings:
Warning 1292 Incorrect inet6 value: ''
Warning 1292 Incorrect inet6 value: ''
DROP TABLE t1;
#
# MDEV-31719 Wrong result of: WHERE inet6_column IN ('','::1')
#
CREATE OR REPLACE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('::');
SELECT * FROM t1 WHERE a IN ('','::1');
a
Warnings:
Warning 1292 Incorrect inet6 value: ''
DROP TABLE t1;
......@@ -1641,3 +1641,22 @@ SELECT * FROM t1 ORDER BY d;
SELECT * FROM t1 WHERE d <= ALL (SELECT * FROM t1);
SELECT * FROM t1 WHERE d >= ALL (SELECT * FROM t1);
DROP TABLE t1;
--echo #
--echo # MDEV-27207 Assertion `!m_null_value' failed in int FixedBinTypeBundle<FbtImpl>::cmp_item_fbt::compare or in cmp_item_inet6::compare
--echo #
CREATE TABLE t1 (a CHAR,b INET6);
SELECT * FROM t1 WHERE (a,b) IN (('',''),('',''));
INSERT INTO t1 VALUES ('','::'),('','::');
SELECT * FROM t1 WHERE (a,b) IN (('',''),('',''));
DROP TABLE t1;
--echo #
--echo # MDEV-31719 Wrong result of: WHERE inet6_column IN ('','::1')
--echo #
CREATE OR REPLACE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('::');
SELECT * FROM t1 WHERE a IN ('','::1');
DROP TABLE t1;
......@@ -1303,14 +1303,22 @@ class in_inet6 :public in_vector
{
return &type_handler_inet6;
}
void set(uint pos, Item *item) override
bool set(uint pos, Item *item) override
{
/*
A 10.5->10.6 merge hint:
This method migrated to sql/sql_type_fixedbin.h,
to the class in_fbt.
*/
Inet6 *buff= &((Inet6 *) base)[pos];
Inet6_null value(item);
if (value.is_null())
{
*buff= Inet6_zero();
else
*buff= value;
return true;
}
*buff= value;
return false;
}
uchar *get_value(Item *item) override
{
......
......@@ -3702,7 +3702,7 @@ in_string::~in_string()
}
}
void in_string::set(uint pos,Item *item)
bool in_string::set(uint pos, Item *item)
{
String *str=((String*) base)+pos;
String *res=item->val_str(str);
......@@ -3722,6 +3722,7 @@ void in_string::set(uint pos,Item *item)
cs= &my_charset_bin; // Should never happen for STR items
str->set_charset(cs);
}
return res == NULL;
}
......@@ -3763,12 +3764,12 @@ uchar *in_row::get_value(Item *item)
return (uchar *)&tmp;
}
void in_row::set(uint pos, Item *item)
bool in_row::set(uint pos, Item *item)
{
DBUG_ENTER("in_row::set");
DBUG_PRINT("enter", ("pos: %u item: %p", pos,item));
((cmp_item_row*) base)[pos].store_value_by_template(current_thd, &tmp, item);
DBUG_VOID_RETURN;
DBUG_RETURN(((cmp_item_row*) base)[pos].store_value_by_template(current_thd,
&tmp, item));
}
in_longlong::in_longlong(THD *thd, uint elements)
......@@ -3776,12 +3777,13 @@ in_longlong::in_longlong(THD *thd, uint elements)
(qsort2_cmp) cmp_longlong, 0)
{}
void in_longlong::set(uint pos,Item *item)
bool in_longlong::set(uint pos, Item *item)
{
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
buff->val= item->val_int();
buff->unsigned_flag= item->unsigned_flag;
return item->null_value;
}
uchar *in_longlong::get_value(Item *item)
......@@ -3816,14 +3818,17 @@ in_timestamp::in_timestamp(THD *thd, uint elements)
{}
void in_timestamp::set(uint pos, Item *item)
bool in_timestamp::set(uint pos, Item *item)
{
Timestamp_or_zero_datetime *buff= &((Timestamp_or_zero_datetime *) base)[pos];
Timestamp_or_zero_datetime_native_null native(current_thd, item, true);
if (native.is_null())
{
*buff= Timestamp_or_zero_datetime();
else
*buff= Timestamp_or_zero_datetime(native);
return true;
}
*buff= Timestamp_or_zero_datetime(native);
return false;
}
......@@ -3850,20 +3855,22 @@ void in_timestamp::value_to_item(uint pos, Item *item)
}
void in_datetime::set(uint pos,Item *item)
bool in_datetime::set(uint pos, Item *item)
{
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
buff->val= item->val_datetime_packed(current_thd);
buff->unsigned_flag= 1L;
return item->null_value;
}
void in_time::set(uint pos,Item *item)
bool in_time::set(uint pos, Item *item)
{
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
buff->val= item->val_time_packed(current_thd);
buff->unsigned_flag= 1L;
return item->null_value;
}
uchar *in_datetime::get_value(Item *item)
......@@ -3894,9 +3901,10 @@ in_double::in_double(THD *thd, uint elements)
:in_vector(thd, elements, sizeof(double), (qsort2_cmp) cmp_double, 0)
{}
void in_double::set(uint pos,Item *item)
bool in_double::set(uint pos, Item *item)
{
((double*) base)[pos]= item->val_real();
return item->null_value;
}
uchar *in_double::get_value(Item *item)
......@@ -3918,7 +3926,7 @@ in_decimal::in_decimal(THD *thd, uint elements)
{}
void in_decimal::set(uint pos, Item *item)
bool in_decimal::set(uint pos, Item *item)
{
/* as far as 'item' is constant, we can store reference on my_decimal */
my_decimal *dec= ((my_decimal *)base) + pos;
......@@ -3928,6 +3936,7 @@ void in_decimal::set(uint pos, Item *item)
/* if item->val_decimal() is evaluated to NULL then res == 0 */
if (!item->null_value && res != dec)
my_decimal2decimal(res, dec);
return item->null_value;
}
......@@ -4103,15 +4112,16 @@ void cmp_item_row::store_value(Item *item)
}
void cmp_item_row::store_value_by_template(THD *thd, cmp_item *t, Item *item)
bool cmp_item_row::store_value_by_template(THD *thd, cmp_item *t, Item *item)
{
cmp_item_row *tmpl= (cmp_item_row*) t;
if (tmpl->n != item->cols())
{
my_error(ER_OPERAND_COLUMNS, MYF(0), tmpl->n);
return;
return 1;
}
n= tmpl->n;
bool rc= false;
if ((comparators= (cmp_item **) thd->alloc(sizeof(cmp_item *)*n)))
{
item->bring_value();
......@@ -4120,11 +4130,11 @@ void cmp_item_row::store_value_by_template(THD *thd, cmp_item *t, Item *item)
{
if (!(comparators[i]= tmpl->comparators[i]->make_same()))
break; // new failed
comparators[i]->store_value_by_template(thd, tmpl->comparators[i],
item->element_index(i));
item->null_value|= item->element_index(i)->null_value;
rc|= comparators[i]->store_value_by_template(thd, tmpl->comparators[i],
item->element_index(i));
}
}
return rc;
}
......@@ -4468,8 +4478,7 @@ void Item_func_in::fix_in_vector()
uint j=0;
for (uint i=1 ; i < arg_count ; i++)
{
array->set(j,args[i]);
if (!args[i]->null_value)
if (!array->set(j,args[i]))
j++; // include this cell in the array.
else
{
......
......@@ -1349,7 +1349,14 @@ class in_vector :public Sql_alloc
size(element_length), compare(cmp_func), collation(cmp_coll),
count(elements), used_count(elements) {}
virtual ~in_vector() = default;
virtual void set(uint pos,Item *item)=0;
/*
Store an Item value at the given position.
@returns false - the Item was not NULL, and the conversion from the
Item data type to the cmp_item data type went without
errors
@returns true - the Item was NULL, or data type conversion returned NULL
*/
virtual bool set(uint pos, Item *item)=0;
virtual uchar *get_value(Item *item)=0;
void sort()
{
......@@ -1404,7 +1411,7 @@ class in_string :public in_vector
public:
in_string(THD *thd, uint elements, qsort2_cmp cmp_func, CHARSET_INFO *cs);
~in_string();
void set(uint pos,Item *item);
bool set(uint pos, Item *item);
uchar *get_value(Item *item);
Item* create_item(THD *thd);
void value_to_item(uint pos, Item *item)
......@@ -1431,7 +1438,7 @@ class in_longlong :public in_vector
} tmp;
public:
in_longlong(THD *thd, uint elements);
void set(uint pos,Item *item);
bool set(uint pos, Item *item);
uchar *get_value(Item *item);
Item* create_item(THD *thd);
void value_to_item(uint pos, Item *item)
......@@ -1451,7 +1458,7 @@ class in_timestamp :public in_vector
Timestamp_or_zero_datetime tmp;
public:
in_timestamp(THD *thd, uint elements);
void set(uint pos,Item *item);
bool set(uint pos, Item *item);
uchar *get_value(Item *item);
Item* create_item(THD *thd);
void value_to_item(uint pos, Item *item);
......@@ -1486,7 +1493,7 @@ class in_datetime :public in_temporal
in_datetime(THD *thd, uint elements)
:in_temporal(thd, elements)
{}
void set(uint pos,Item *item);
bool set(uint pos, Item *item);
uchar *get_value(Item *item);
const Type_handler *type_handler() const { return &type_handler_datetime2; }
};
......@@ -1498,7 +1505,7 @@ class in_time :public in_temporal
in_time(THD *thd, uint elements)
:in_temporal(thd, elements)
{}
void set(uint pos,Item *item);
bool set(uint pos, Item *item);
uchar *get_value(Item *item);
const Type_handler *type_handler() const { return &type_handler_time2; }
};
......@@ -1509,7 +1516,7 @@ class in_double :public in_vector
double tmp;
public:
in_double(THD *thd, uint elements);
void set(uint pos,Item *item);
bool set(uint pos, Item *item);
uchar *get_value(Item *item);
Item *create_item(THD *thd);
void value_to_item(uint pos, Item *item)
......@@ -1525,7 +1532,7 @@ class in_decimal :public in_vector
my_decimal val;
public:
in_decimal(THD *thd, uint elements);
void set(uint pos, Item *item);
bool set(uint pos, Item *item);
uchar *get_value(Item *item);
Item *create_item(THD *thd);
void value_to_item(uint pos, Item *item)
......@@ -1558,10 +1565,14 @@ class cmp_item :public Sql_alloc
// for optimized IN with row
virtual int compare(cmp_item *item)= 0;
virtual cmp_item *make_same()= 0;
virtual void store_value_by_template(THD *thd, cmp_item *tmpl, Item *item)
{
store_value(item);
}
/*
Store a scalar or a ROW value into "this".
@returns false - the value (or every component in case of ROW) was
not NULL and the data type conversion went without errors.
@returns true - the value (or some of its components) was NULL, or the
data type conversion of a not-NULL value returned NULL.
*/
virtual bool store_value_by_template(THD *thd, cmp_item *tmpl, Item *item)=0;
};
/// cmp_item which stores a scalar (i.e. non-ROW).
......@@ -1569,6 +1580,11 @@ class cmp_item_scalar : public cmp_item
{
protected:
bool m_null_value; ///< If stored value is NULL
bool store_value_by_template(THD *thd, cmp_item *tmpl, Item *item) override
{
store_value(item);
return m_null_value;
}
};
class cmp_item_string : public cmp_item_scalar
......@@ -2504,18 +2520,18 @@ class cmp_item_row :public cmp_item
public:
cmp_item_row(): comparators(0), n(0) {}
~cmp_item_row();
void store_value(Item *item);
void store_value(Item *item) override;
bool prepare_comparators(THD *, const char *funcname,
const Item_args *args, uint level);
int cmp(Item *arg);
int cmp_not_null(const Value *val)
int cmp(Item *arg) override;
int cmp_not_null(const Value *val) override
{
DBUG_ASSERT(false);
return TRUE;
}
int compare(cmp_item *arg);
cmp_item *make_same();
void store_value_by_template(THD *thd, cmp_item *tmpl, Item *);
int compare(cmp_item *arg) override;
cmp_item *make_same() override;
bool store_value_by_template(THD *thd, cmp_item *tmpl, Item *) override;
friend class Item_func_in;
cmp_item *get_comparator(uint i) { return comparators[i]; }
};
......@@ -2527,7 +2543,7 @@ class in_row :public in_vector
public:
in_row(THD *thd, uint elements, Item *);
~in_row();
void set(uint pos,Item *item);
bool set(uint pos, Item *item);
uchar *get_value(Item *item);
friend class Item_func_in;
const Type_handler *type_handler() const { return &type_handler_row; }
......
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