Commit 755ae21b authored by unknown's avatar unknown

Bug#26277 User variable returns one type in SELECT @v and other for CREATE as SELECT @v

- Adding variable m_cached_result_type to keep the variable type consistent
  during the execution of a statement.
- Before each result set is returned to the client the description of each
  column is sent as meta data.
  Previously the result type for a column could change if the hash variable
  entry changed between statements. This caused the result set of the query
  to alternate column types in certain cases which is not supported by MySQL
  client-server protocol. Example:
  Previously this sequence:
    SET @A:=1;
    SELECT @A:="text", @A;
  would return "text", "text";
 
  After the change the SELECT returns "text", 0
  The reson for this is that previously the result set from 'SELECT @A;'
  would always be of the type STRING, whereas now the type of the variable
  is taken from the last SET statement. However, 'SELECT @A:="text"' will
  return type of STRING since the right side of the assignment is used.


mysql-test/r/ps_2myisam.result:
  Changed test result because SQL type of a user variable now
  more accurately represents its Item type: since Item type of a variable
  can be either STRING, INT, DECIMAL or DOUBLE, SQL type of the
  result set metadata now can be either MYSQL_TYPE_VARCHAR,
  MYSQL_TYPE_LONGLONG, MYSQL_TYPE_NEWDECIMAL or MYSQL_TYPE_DOUBLE.
  
  Previously it was always MYSQL_TYPE_VARCHAR.
  
  In particular, integer variables now have changed from
  MYSQL_TYPE_VARCHAR to MYSQL_TYPE_LONGLONG.
mysql-test/r/ps_3innodb.result:
  Changed test result because SQL type of a user variable now
  more accurately represents its Item type: since Item type of a variable
  can be either STRING, INT, DECIMAL or DOUBLE, SQL type of the
  result set metadata now can be either MYSQL_TYPE_VARCHAR,
  MYSQL_TYPE_LONGLONG, MYSQL_TYPE_NEWDECIMAL or MYSQL_TYPE_DOUBLE.
  
  Previously it was always MYSQL_TYPE_VARCHAR.
  
  In particular, integer variables now have changed from
  MYSQL_TYPE_VARCHAR to MYSQL_TYPE_LONGLONG.
mysql-test/r/ps_4heap.result:
  Changed test result because SQL type of a user variable now
  more accurately represents its Item type: since Item type of a variable
  can be either STRING, INT, DECIMAL or DOUBLE, SQL type of the
  result set metadata now can be either MYSQL_TYPE_VARCHAR,
  MYSQL_TYPE_LONGLONG, MYSQL_TYPE_NEWDECIMAL or MYSQL_TYPE_DOUBLE.
  
  Previously it was always MYSQL_TYPE_VARCHAR.
  
  In particular, integer variables now have changed from
  MYSQL_TYPE_VARCHAR to MYSQL_TYPE_LONGLONG.
mysql-test/r/ps_5merge.result:
  Changed test result because SQL type of a user variable now
  more accurately represents its Item type: since Item type of a variable
  can be either STRING, INT, DECIMAL or DOUBLE, SQL type of the
  result set metadata now can be either MYSQL_TYPE_VARCHAR,
  MYSQL_TYPE_LONGLONG, MYSQL_TYPE_NEWDECIMAL or MYSQL_TYPE_DOUBLE.
  
  Previously it was always MYSQL_TYPE_VARCHAR.
  
  In particular, integer variables now have changed from
  MYSQL_TYPE_VARCHAR to MYSQL_TYPE_LONGLONG.
mysql-test/r/ps_7ndb.result:
  Changed test result because SQL type of a user variable now
  more accurately represents its Item type: since Item type of a variable
  can be either STRING, INT, DECIMAL or DOUBLE, SQL type of the
  result set metadata now can be either MYSQL_TYPE_VARCHAR,
  MYSQL_TYPE_LONGLONG, MYSQL_TYPE_NEWDECIMAL or MYSQL_TYPE_DOUBLE.
  
  Previously it was always MYSQL_TYPE_VARCHAR.
  
  In particular, integer variables now have changed from
  MYSQL_TYPE_VARCHAR to MYSQL_TYPE_LONGLONG.
mysql-test/r/sp-vars.result:
  Added test case. Previously variables could change their variable type during 
  the execution of a statement.
  Which variable type to use in the statement is specified in
  any previous statement.
mysql-test/r/type_date.result:
  This test case result is changed because it is no longer allowed for user
  variables to change their variable type during the execution of a statement.
  The determination of which variable type to use in the statement is specified in
  any previous statement.
mysql-test/r/user_var.result:
  This test case result is changed because it is no longer allowed for user
  variables to change their variable type during the execution of a statement.
  The determination of which variable type to use in the statement is specified in
  any previous statement.
mysql-test/t/sp-vars.test:
  Added test case. Previously variables could change their variable type during 
  the execution of a statement.
  Which variable type to use in the statement is specified in
  any previous statement.
mysql-test/t/type_date.test:
  This test case result is changed because it is no longer allowed for user
  variables to change their variable type during the execution of a statement.
  The determination of which variable type to use in the statement is specified in
  any previous statement.
sql/item_func.cc:
  Adding variable m_cached_result_type to keep the variable type consistent
  during the execution of a statement.
  Previously the result type could change if the hash variable entry changed
  between statements. This caused the result set of the query to alternate
  column types in certain cases.
sql/item_func.h:
  Adding variable m_cached_result_type to keep the variable type consistent
  during the execution of a statement.
  Previously the result type could change if the hash variable entry changed
  between statements. This caused the result set of the query to alternate
  column types in certain cases.
parent 1513cd09
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -1161,3 +1161,29 @@ CALL p1(); ...@@ -1161,3 +1161,29 @@ CALL p1();
v_text v_text
abc|def abc|def
DROP PROCEDURE p1; DROP PROCEDURE p1;
drop function if exists f1;
drop table if exists t1;
create function f1() returns int
begin
if @a=1 then set @b='abc';
else set @b=1;
end if;
set @a=1;
return 0;
end|
create table t1 (a int)|
insert into t1 (a) values (1), (2)|
set @b=1|
set @a=0|
select f1(), @b from t1|
f1() @b
0 1
0 0
set @b:='test'|
set @a=0|
select f1(), @b from t1|
f1() @b
0 1
0 abc
drop function f1;
drop table t1;
...@@ -110,15 +110,24 @@ select 1 from t1 where cast('2000-01-01 12:01:01' as datetime) between start_dat ...@@ -110,15 +110,24 @@ select 1 from t1 where cast('2000-01-01 12:01:01' as datetime) between start_dat
1 1
1 1
drop table t1; drop table t1;
select @d:=1111, year(@d), month(@d), day(@d), cast(@d as date); select @d:=1111;
@d:=1111 year(@d) month(@d) day(@d) cast(@d as date) @d:=1111
1111 2000 11 11 2000-11-11 1111
select @d:=011111, year(@d), month(@d), day(@d), cast(@d as date); select year(@d), month(@d), day(@d), cast(@d as date);
@d:=011111 year(@d) month(@d) day(@d) cast(@d as date) year(@d) month(@d) day(@d) cast(@d as date)
11111 2001 11 11 2001-11-11 2000 11 11 2000-11-11
select @d:=1311, year(@d), month(@d), day(@d), cast(@d as date); select @d:=011111;
@d:=1311 year(@d) month(@d) day(@d) cast(@d as date) @d:=011111
1311 NULL NULL NULL NULL 11111
select year(@d), month(@d), day(@d), cast(@d as date);
year(@d) month(@d) day(@d) cast(@d as date)
2001 11 11 2001-11-11
select @d:=1311;
@d:=1311
1311
select year(@d), month(@d), day(@d), cast(@d as date);
year(@d) month(@d) day(@d) cast(@d as date)
NULL NULL NULL NULL
Warnings: Warnings:
Warning 1292 Incorrect datetime value: '1311' Warning 1292 Incorrect datetime value: '1311'
Warning 1292 Incorrect datetime value: '1311' Warning 1292 Incorrect datetime value: '1311'
......
...@@ -91,7 +91,7 @@ NULL test test ...@@ -91,7 +91,7 @@ NULL test test
set @g=1; set @g=1;
select @g,(@g:=c),@g from t1; select @g,(@g:=c),@g from t1;
@g (@g:=c) @g @g (@g:=c) @g
1 test test 1 test 0
select @c, @d, @e, @f; select @c, @d, @e, @f;
@c @d @e @f @c @d @e @f
1 1 2 test 1 1 2 test
......
...@@ -1368,3 +1368,39 @@ CALL p1(); ...@@ -1368,3 +1368,39 @@ CALL p1();
DROP PROCEDURE p1; DROP PROCEDURE p1;
# End of 5.0 tests. # End of 5.0 tests.
#
# Bug #26277 User variable returns one type in SELECT @v and other for CREATE as SELECT @v
#
--disable_warnings
drop function if exists f1;
drop table if exists t1;
--enable_warnings
delimiter |;
create function f1() returns int
begin
if @a=1 then set @b='abc';
else set @b=1;
end if;
set @a=1;
return 0;
end|
create table t1 (a int)|
insert into t1 (a) values (1), (2)|
set @b=1|
set @a=0|
select f1(), @b from t1|
set @b:='test'|
set @a=0|
select f1(), @b from t1|
delimiter ;|
drop function f1;
drop table t1;
# End of 5.1 tests.
...@@ -128,9 +128,12 @@ drop table t1; ...@@ -128,9 +128,12 @@ drop table t1;
# Bug #23093: Implicit conversion of 9912101 to date does not match # Bug #23093: Implicit conversion of 9912101 to date does not match
# cast(9912101 as date) # cast(9912101 as date)
# #
select @d:=1111, year(@d), month(@d), day(@d), cast(@d as date); select @d:=1111;
select @d:=011111, year(@d), month(@d), day(@d), cast(@d as date); select year(@d), month(@d), day(@d), cast(@d as date);
select @d:=1311, year(@d), month(@d), day(@d), cast(@d as date); select @d:=011111;
select year(@d), month(@d), day(@d), cast(@d as date);
select @d:=1311;
select year(@d), month(@d), day(@d), cast(@d as date);
create table t1 (d date , dt datetime , ts timestamp); create table t1 (d date , dt datetime , ts timestamp);
insert into t1 values (9912101,9912101,9912101); insert into t1 values (9912101,9912101,9912101);
insert into t1 values (11111,11111,11111); insert into t1 values (11111,11111,11111);
......
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#define sp_restore_security_context(A,B) while (0) {} #define sp_restore_security_context(A,B) while (0) {}
#endif #endif
bool check_reserved_words(LEX_STRING *name) bool check_reserved_words(LEX_STRING *name)
{ {
if (!my_strcasecmp(system_charset_info, name->str, "GLOBAL") || if (!my_strcasecmp(system_charset_info, name->str, "GLOBAL") ||
...@@ -4380,7 +4379,6 @@ err: ...@@ -4380,7 +4379,6 @@ err:
return 1; return 1;
} }
void Item_func_get_user_var::fix_length_and_dec() void Item_func_get_user_var::fix_length_and_dec()
{ {
THD *thd=current_thd; THD *thd=current_thd;
...@@ -4391,10 +4389,19 @@ void Item_func_get_user_var::fix_length_and_dec() ...@@ -4391,10 +4389,19 @@ void Item_func_get_user_var::fix_length_and_dec()
error= get_var_with_binlog(thd, thd->lex->sql_command, name, &var_entry); error= get_var_with_binlog(thd, thd->lex->sql_command, name, &var_entry);
/*
If the variable didn't exist it has been created as a STRING-type.
'var_entry' is NULL only if there occured an error during the call to
get_var_with_binlog.
*/
if (var_entry) if (var_entry)
{ {
m_cached_result_type= var_entry->type;
unsigned_flag= var_entry->unsigned_flag;
max_length= var_entry->length;
collation.set(var_entry->collation); collation.set(var_entry->collation);
switch (var_entry->type) { switch(m_cached_result_type) {
case REAL_RESULT: case REAL_RESULT:
max_length= DBL_DIG + 8; max_length= DBL_DIG + 8;
break; break;
...@@ -4419,6 +4426,8 @@ void Item_func_get_user_var::fix_length_and_dec() ...@@ -4419,6 +4426,8 @@ void Item_func_get_user_var::fix_length_and_dec()
{ {
collation.set(&my_charset_bin, DERIVATION_IMPLICIT); collation.set(&my_charset_bin, DERIVATION_IMPLICIT);
null_value= 1; null_value= 1;
m_cached_result_type= STRING_RESULT;
max_length= MAX_BLOB_WIDTH;
} }
if (error) if (error)
...@@ -4436,12 +4445,7 @@ bool Item_func_get_user_var::const_item() const ...@@ -4436,12 +4445,7 @@ bool Item_func_get_user_var::const_item() const
enum Item_result Item_func_get_user_var::result_type() const enum Item_result Item_func_get_user_var::result_type() const
{ {
user_var_entry *entry; return m_cached_result_type;
if (!(entry = (user_var_entry*) hash_search(&current_thd->user_vars,
(byte*) name.str,
name.length)))
return STRING_RESULT;
return entry->type;
} }
......
...@@ -1247,11 +1247,12 @@ class Item_func_get_user_var :public Item_func, ...@@ -1247,11 +1247,12 @@ class Item_func_get_user_var :public Item_func,
private Settable_routine_parameter private Settable_routine_parameter
{ {
user_var_entry *var_entry; user_var_entry *var_entry;
Item_result m_cached_result_type;
public: public:
LEX_STRING name; // keep it public LEX_STRING name; // keep it public
Item_func_get_user_var(LEX_STRING a): Item_func_get_user_var(LEX_STRING a):
Item_func(), name(a) {} Item_func(), name(a), m_cached_result_type(STRING_RESULT) {}
enum Functype functype() const { return GUSERVAR_FUNC; } enum Functype functype() const { return GUSERVAR_FUNC; }
LEX_STRING get_name() { return name; } LEX_STRING get_name() { return name; }
double val_real(); double val_real();
...@@ -1265,13 +1266,11 @@ public: ...@@ -1265,13 +1266,11 @@ public:
We must always return variables as strings to guard against selects of type We must always return variables as strings to guard against selects of type
select @t1:=1,@t1,@t:="hello",@t from foo where (@t1:= t2.b) select @t1:=1,@t1,@t:="hello",@t from foo where (@t1:= t2.b)
*/ */
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
const char *func_name() const { return "get_user_var"; } const char *func_name() const { return "get_user_var"; }
bool const_item() const; bool const_item() const;
table_map used_tables() const table_map used_tables() const
{ return const_item() ? 0 : RAND_TABLE_BIT; } { return const_item() ? 0 : RAND_TABLE_BIT; }
bool eq(const Item *item, bool binary_cmp) const; bool eq(const Item *item, bool binary_cmp) const;
private: private:
bool set_value(THD *thd, sp_rcontext *ctx, Item **it); bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
......
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