summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormhansson/martin@linux-st28.site <>2007-12-11 20:15:03 +0100
committermhansson/martin@linux-st28.site <>2007-12-11 20:15:03 +0100
commit867a78654946c7c7ebed430b2b8437e837a0455d (patch)
tree9615a0eaca93ca19b59f1a93f0a77b7875a88468
parent7f67efccef94449ef6c797583a2695b27a9b7376 (diff)
downloadmariadb-git-867a78654946c7c7ebed430b2b8437e837a0455d.tar.gz
Bug#32848: Data type conversion bug in union subselects in MySQL 5.0.38
There were two problems when inferring the correct field types resulting from UNION queries. - If the type is NULL for all corresponding fields in the UNION, the resulting type would be NULL, while the type is BINARY(0) if there is just a single SELECT NULL. - If one SELECT in the UNION uses a subselect, a temporary table is created to represent the subselect, and the result type defaults to a STRING type, hiding the fact that the type was unknown(just a NULL value). Fixed by remembering whenever a field was created from a NULL value and pass type NULL to the type coercion if that is the case, and creating a string field as result of UNION only if the type would otherwise be NULL.
-rw-r--r--mysql-test/r/union.result24
-rw-r--r--mysql-test/t/union.test24
-rw-r--r--sql/field.cc3
-rw-r--r--sql/field.h10
-rw-r--r--sql/item.cc4
-rw-r--r--sql/sql_select.cc2
6 files changed, 66 insertions, 1 deletions
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index efdd8195fb5..0b77459e02f 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -1389,4 +1389,28 @@ select @var;
1
(select 2) union (select 1 into @var);
ERROR 42000: Result consisted of more than one row
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 SELECT * FROM (SELECT NULL) a UNION SELECT a FROM t1;
+DESC t2;
+Field Type Null Key Default Extra
+NULL int(11) YES NULL
+CREATE TABLE t3 SELECT a FROM t1 UNION SELECT * FROM (SELECT NULL) a;
+DESC t3;
+Field Type Null Key Default Extra
+a int(11) YES NULL
+CREATE TABLE t4 SELECT NULL;
+DESC t4;
+Field Type Null Key Default Extra
+NULL binary(0) YES NULL
+CREATE TABLE t5 SELECT NULL UNION SELECT NULL;
+DESC t5;
+Field Type Null Key Default Extra
+NULL binary(0) YES NULL
+CREATE TABLE t6
+SELECT * FROM (SELECT * FROM (SELECT NULL)a) b UNION SELECT a FROM t1;
+DESC t6;
+Field Type Null Key Default Extra
+NULL int(11) YES NULL
+DROP TABLE t1, t2, t3, t4, t5, t6;
End of 5.0 tests
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index 22f09466b1c..84616aa281d 100644
--- a/mysql-test/t/union.test
+++ b/mysql-test/t/union.test
@@ -877,4 +877,28 @@ DROP TABLE t1;
select @var;
--error 1172
(select 2) union (select 1 into @var);
+
+#
+# Bug#32848: Data type conversion bug in union subselects in MySQL 5.0.38
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+
+CREATE TABLE t2 SELECT * FROM (SELECT NULL) a UNION SELECT a FROM t1;
+DESC t2;
+
+CREATE TABLE t3 SELECT a FROM t1 UNION SELECT * FROM (SELECT NULL) a;
+DESC t3;
+
+CREATE TABLE t4 SELECT NULL;
+DESC t4;
+
+CREATE TABLE t5 SELECT NULL UNION SELECT NULL;
+DESC t5;
+
+CREATE TABLE t6
+SELECT * FROM (SELECT * FROM (SELECT NULL)a) b UNION SELECT a FROM t1;
+DESC t6;
+
+DROP TABLE t1, t2, t3, t4, t5, t6;
--echo End of 5.0 tests
diff --git a/sql/field.cc b/sql/field.cc
index e6e4195ba1e..1a0e93c82ac 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1304,7 +1304,8 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
field_name(field_name_arg),
query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0),
unireg_check(unireg_check_arg),
- field_length(length_arg), null_bit(null_bit_arg)
+ field_length(length_arg), null_bit(null_bit_arg),
+ is_created_from_null_item(FALSE)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
comment.str= (char*) "";
diff --git a/sql/field.h b/sql/field.h
index 4fcdb50f8c7..d9161d36dac 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -88,6 +88,16 @@ public:
uint field_index; // field number in fields array
uint16 flags;
uchar null_bit; // Bit used to test null bit
+ /**
+ If true, this field was created in create_tmp_field_from_item from a NULL
+ value. This means that the type of the field is just a guess, and the type
+ may be freely coerced to another type.
+
+ @see create_tmp_field_from_item
+ @see Item_type_holder::get_real_type
+
+ */
+ bool is_created_from_null_item;
Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uchar null_bit_arg,
utype unireg_check_arg, const char *field_name_arg,
diff --git a/sql/item.cc b/sql/item.cc
index 3177c0fb1e8..5df0f441619 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -6569,6 +6569,8 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
*/
Field *field= ((Item_field *) item)->field;
enum_field_types type= field->real_type();
+ if (field->is_created_from_null_item)
+ return MYSQL_TYPE_NULL;
/* work around about varchar type field detection */
if (type == MYSQL_TYPE_STRING && field->type() == MYSQL_TYPE_VAR_STRING)
return MYSQL_TYPE_VAR_STRING;
@@ -6820,6 +6822,8 @@ Field *Item_type_holder::make_field_by_type(TABLE *table)
Field::NONE, name,
table, get_set_pack_length(enum_set_typelib->count),
enum_set_typelib, collation.collation);
+ case MYSQL_TYPE_NULL:
+ return make_string_field(table);
default:
break;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3529de1c28a..74db7770c6f 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8974,6 +8974,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
*((*copy_func)++) = item; // Save for copy_funcs
if (modify_item)
item->set_result_field(new_field);
+ if (item->type() == MYSQL_TYPE_NULL)
+ new_field->is_created_from_null_item= TRUE;
return new_field;
}