summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/subselect4.result27
-rw-r--r--mysql-test/t/subselect4.test24
-rw-r--r--sql/item.cc27
-rw-r--r--sql/item.h10
-rw-r--r--sql/item_cmpfunc.cc2
-rw-r--r--sql/item_subselect.cc49
-rw-r--r--sql/item_subselect.h6
7 files changed, 129 insertions, 16 deletions
diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result
index 25937373e5e..2e24cbcb40c 100644
--- a/mysql-test/r/subselect4.result
+++ b/mysql-test/r/subselect4.result
@@ -2694,4 +2694,31 @@ INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4), (5,5);
SELECT a, b FROM t1 WHERE a IN (SELECT A.a FROM t1 A GROUP BY s.id);
ERROR 42S22: Unknown column 's.id' in 'group statement'
DROP TABLE t1;
+#
+# MDEV-24519: Server crashes in Charset::set_charset upon SELECT
+#
+CREATE TABLE t1 (a VARBINARY(8));
+INSERT INTO t1 VALUES ('foo'),('bar');
+CREATE TABLE t2 (b VARBINARY(8));
+EXPLAIN
+SELECT a FROM t1 WHERE (a, a) IN (SELECT 'qux', 'qux') AND a = (SELECT MIN(b) FROM t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used
+SELECT a FROM t1 WHERE (a, a) IN (SELECT 'qux', 'qux') AND a = (SELECT MIN(b) FROM t2);
+a
+DROP TABLE t1,t2;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 (b VARBINARY(8));
+EXPLAIN
+SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used
+SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2);
+a
+DROP TABLE t1,t2;
# End of 10.2 tests
diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test
index fd36023435f..f19a654de64 100644
--- a/mysql-test/t/subselect4.test
+++ b/mysql-test/t/subselect4.test
@@ -2212,4 +2212,28 @@ INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4), (5,5);
SELECT a, b FROM t1 WHERE a IN (SELECT A.a FROM t1 A GROUP BY s.id);
DROP TABLE t1;
+--echo #
+--echo # MDEV-24519: Server crashes in Charset::set_charset upon SELECT
+--echo #
+
+CREATE TABLE t1 (a VARBINARY(8));
+INSERT INTO t1 VALUES ('foo'),('bar');
+CREATE TABLE t2 (b VARBINARY(8));
+
+EXPLAIN
+SELECT a FROM t1 WHERE (a, a) IN (SELECT 'qux', 'qux') AND a = (SELECT MIN(b) FROM t2);
+SELECT a FROM t1 WHERE (a, a) IN (SELECT 'qux', 'qux') AND a = (SELECT MIN(b) FROM t2);
+
+DROP TABLE t1,t2;
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 (b VARBINARY(8));
+
+EXPLAIN
+SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2);
+SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2);
+
+DROP TABLE t1,t2;
+
--echo # End of 10.2 tests
diff --git a/sql/item.cc b/sql/item.cc
index e633964270b..45f40874ddb 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -9690,7 +9690,7 @@ bool Item_cache_int::cache_value()
return FALSE;
value_cached= TRUE;
value= example->val_int_result();
- null_value= example->null_value;
+ null_value_inside= null_value= example->null_value;
unsigned_flag= example->unsigned_flag;
return TRUE;
}
@@ -9860,7 +9860,7 @@ bool Item_cache_temporal::cache_value()
return true;
value= pack_time(&ltime);
}
- null_value= example->null_value;
+ null_value_inside= null_value= example->null_value;
return true;
}
@@ -9955,7 +9955,7 @@ bool Item_cache_real::cache_value()
return FALSE;
value_cached= TRUE;
value= example->val_result();
- null_value= example->null_value;
+ null_value_inside= null_value= example->null_value;
return TRUE;
}
@@ -10017,7 +10017,8 @@ bool Item_cache_decimal::cache_value()
return FALSE;
value_cached= TRUE;
my_decimal *val= example->val_decimal_result(&decimal_value);
- if (!(null_value= example->null_value) && val != &decimal_value)
+ if (!(null_value_inside= null_value= example->null_value) &&
+ val != &decimal_value)
my_decimal2decimal(val, &decimal_value);
return TRUE;
}
@@ -10083,11 +10084,14 @@ Item *Item_cache_decimal::convert_to_basic_const_item(THD *thd)
bool Item_cache_str::cache_value()
{
if (!example)
+ {
+ DBUG_ASSERT(value_cached == FALSE);
return FALSE;
+ }
value_cached= TRUE;
value_buff.set(buffer, sizeof(buffer), example->collation.collation);
value= example->str_result(&value_buff);
- if ((null_value= example->null_value))
+ if ((null_value= null_value_inside= example->null_value))
value= 0;
else if (value != &value_buff)
{
@@ -10186,6 +10190,8 @@ Item *Item_cache_str::convert_to_basic_const_item(THD *thd)
bool Item_cache_row::setup(THD *thd, Item *item)
{
example= item;
+ null_value= true;
+
if (!values && allocate(thd, item->cols()))
return 1;
for (uint i= 0; i < item_count; i++)
@@ -10218,12 +10224,19 @@ bool Item_cache_row::cache_value()
if (!example)
return FALSE;
value_cached= TRUE;
- null_value= 0;
+ null_value= TRUE;
+ null_value_inside= false;
example->bring_value();
+
+ /*
+ For Item_cache_row null_value is set to TRUE only when ALL the values
+ inside the cache are NULL
+ */
for (uint i= 0; i < item_count; i++)
{
values[i]->cache_value();
- null_value|= values[i]->null_value;
+ null_value&= values[i]->null_value;
+ null_value_inside|= values[i]->null_value;
}
return TRUE;
}
diff --git a/sql/item.h b/sql/item.h
index 823ffd873b6..cb1e8519b27 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -5658,6 +5658,14 @@ protected:
*/
bool value_cached;
public:
+ /*
+ This is set if at least one of the values of a sub query is NULL
+ Item_cache_row returns this with null_inside().
+ For not row items, it's set to the value of null_value
+ It is set after cache_value() is called.
+ */
+ bool null_value_inside;
+
Item_cache(THD *thd):
Item_basic_constant(thd),
Type_handler_hybrid_field_type(MYSQL_TYPE_STRING),
@@ -5667,6 +5675,7 @@ public:
fixed= 1;
maybe_null= 1;
null_value= 1;
+ null_value_inside= true;
}
protected:
Item_cache(THD *thd, enum_field_types field_type_arg):
@@ -5678,6 +5687,7 @@ protected:
fixed= 1;
maybe_null= 1;
null_value= 1;
+ null_value_inside= true;
}
public:
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index d5b89f13f04..7b7604053e3 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1598,7 +1598,7 @@ longlong Item_in_optimizer::val_int()
DBUG_RETURN(res);
}
- if (cache->null_value)
+ if (cache->null_value_inside)
{
DBUG_PRINT("info", ("Left NULL..."));
/*
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 3424df1eb91..4b8f118ca43 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -851,7 +851,7 @@ bool Item_subselect::expr_cache_is_needed(THD *thd)
inline bool Item_in_subselect::left_expr_has_null()
{
- return (*(optimizer->get_cache()))->null_value;
+ return (*(optimizer->get_cache()))->null_value_inside;
}
@@ -1319,7 +1319,17 @@ bool Item_singlerow_subselect::null_inside()
void Item_singlerow_subselect::bring_value()
{
if (!exec() && assigned())
- null_value= 0;
+ {
+ null_value= true;
+ for (uint i= 0; i < max_columns ; i++)
+ {
+ if (!row[i]->null_value)
+ {
+ null_value= false;
+ return;
+ }
+ }
+ }
else
reset();
}
@@ -1345,7 +1355,11 @@ longlong Item_singlerow_subselect::val_int()
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->val_int();
+ {
+ longlong val= value->val_int();
+ null_value= value->null_value;
+ return val;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1354,6 +1368,7 @@ longlong Item_singlerow_subselect::val_int()
else
{
reset();
+ DBUG_ASSERT(null_value);
return 0;
}
}
@@ -1362,7 +1377,11 @@ String *Item_singlerow_subselect::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->val_str(str);
+ {
+ String *res= value->val_str(str);
+ null_value= value->null_value;
+ return res;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1371,6 +1390,7 @@ String *Item_singlerow_subselect::val_str(String *str)
else
{
reset();
+ DBUG_ASSERT(null_value);
return 0;
}
}
@@ -1380,7 +1400,11 @@ my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->val_decimal(decimal_value);
+ {
+ my_decimal *val= value->val_decimal(decimal_value);
+ null_value= value->null_value;
+ return val;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1389,6 +1413,7 @@ my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
else
{
reset();
+ DBUG_ASSERT(null_value);
return 0;
}
}
@@ -1398,7 +1423,11 @@ bool Item_singlerow_subselect::val_bool()
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->val_bool();
+ {
+ bool val= value->val_bool();
+ null_value= value->null_value;
+ return val;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1407,6 +1436,7 @@ bool Item_singlerow_subselect::val_bool()
else
{
reset();
+ DBUG_ASSERT(null_value);
return 0;
}
}
@@ -1416,7 +1446,11 @@ bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->get_date(ltime, fuzzydate);
+ {
+ bool val= value->get_date(ltime, fuzzydate);
+ null_value= value->null_value;
+ return val;
+ }
if (!exec() && !value->null_value)
{
null_value= FALSE;
@@ -1425,6 +1459,7 @@ bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
else
{
reset();
+ DBUG_ASSERT(null_value);
return 1;
}
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 9116238c640..130f90839e3 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -48,7 +48,11 @@ class Cached_item;
class Item_subselect :public Item_result_field,
protected Used_tables_and_const_cache
{
- bool value_assigned; /* value already assigned to subselect */
+ /*
+ Set to TRUE if the value is assigned for the subselect
+ FALSE: subquery not executed or the subquery returns an empty result
+ */
+ bool value_assigned;
bool own_engine; /* the engine was not taken from other Item_subselect */
protected:
/* thread handler, will be assigned in fix_fields only */