diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 566dac07fd5..cdba113ae40 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -622,3 +622,22 @@ execute stmt using @user_id, @id; partner_id deallocate prepare stmt; drop table t1, t2, t3, t4; +prepare stmt from 'select ?=?'; +set @a='CHRISTINE '; +set @b='CHRISTINE'; +execute stmt using @a, @b; +?=? +1 +execute stmt using @a, @b; +?=? +1 +set @a=1, @b=2; +execute stmt using @a, @b; +?=? +0 +set @a='CHRISTINE '; +set @b='CHRISTINE'; +execute stmt using @a, @b; +?=? +1 +deallocate prepare stmt; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index a25d4447c20..0fa14024d11 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -650,3 +650,19 @@ execute stmt using @user_id, @id; execute stmt using @user_id, @id; deallocate prepare stmt; drop table t1, t2, t3, t4; + +# +# Bug#9379: make sure that Item::collation is reset when one sets +# a parameter marker from a string variable. +# +prepare stmt from 'select ?=?'; +set @a='CHRISTINE '; +set @b='CHRISTINE'; +execute stmt using @a, @b; +execute stmt using @a, @b; +set @a=1, @b=2; +execute stmt using @a, @b; +set @a='CHRISTINE '; +set @b='CHRISTINE'; +execute stmt using @a, @b; +deallocate prepare stmt; diff --git a/sql/item.cc b/sql/item.cc index 19b88c115b9..ed39fe177cd 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1089,6 +1089,7 @@ void Item_param::reset() to the binary log. */ str_value.set_charset(&my_charset_bin); + collation.set(&my_charset_bin, DERIVATION_COERCIBLE); state= NO_VALUE; maybe_null= 1; null_value= 0; @@ -1336,6 +1337,8 @@ bool Item_param::convert_str_value(THD *thd) */ str_value_ptr.set(str_value.ptr(), str_value.length(), str_value.charset()); + /* Synchronize item charset with value charset */ + collation.set(str_value.charset(), DERIVATION_COERCIBLE); } return rc; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 442ef15bba8..4e0b6d8813f 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -188,7 +188,20 @@ bool Item_func::agg_arg_charsets(DTCollation &coll, break; // we cannot return here, we need to restore "arena". } conv->fix_fields(thd, 0, &conv); - *arg= conv; + /* + If in statement prepare, then we create a converter for two + constant items, do it once and then reuse it. + If we're in execution of a prepared statement, arena is NULL, + and the conv was created in runtime memory. This can be + the case only if the argument is a parameter marker ('?'), + because for all true constants the charset converter has already + been created in prepare. In this case register the change for + rollback. + */ + if (arena) + *arg= conv; + else + thd->change_item_tree(arg, conv); } if (arena) thd->restore_backup_item_arena(arena, &backup);