summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2016-11-03 22:02:24 +0400
committerAlexander Barkov <bar@mariadb.org>2016-11-03 22:02:24 +0400
commitf0d8a4d29e3dbd713dc13fb052acd0a96ab47522 (patch)
treea1b1c7bfb38ffc43d48dabb060f7d0bc4f3b48f8
parent82780a7c0031af3fe6d8b9bc9f46ace2876c33f6 (diff)
downloadmariadb-git-f0d8a4d29e3dbd713dc13fb052acd0a96ab47522.tar.gz
MDEV-11219 main.null fails in buldbot and outside with ps-protocol
-rw-r--r--sql/item_cmpfunc.cc42
-rw-r--r--sql/item_cmpfunc.h4
2 files changed, 44 insertions, 2 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index a222335cf97..1a2c85f66a6 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2553,7 +2553,7 @@ Item_func_nullif::fix_length_and_dec()
See also class Item_func_nullif declaration.
*/
if (arg_count == 2)
- args[arg_count++]= args[0];
+ args[arg_count++]= m_arg0 ? m_arg0 : args[0];
THD *thd= current_thd;
/*
@@ -2704,7 +2704,47 @@ Item_func_nullif::fix_length_and_dec()
unsigned_flag= args[2]->unsigned_flag;
fix_char_length(args[2]->max_char_length());
maybe_null=1;
+ m_arg0= args[0];
setup_args_and_comparator(thd, &cmp);
+ /*
+ A special code for EXECUTE..PREPARE.
+
+ If args[0] did not change, then we don't remember it, as it can point
+ to a temporary Item object which will be destroyed between PREPARE
+ and EXECUTE. EXECUTE time fix_length_and_dec() will correctly set args[2]
+ from args[0] again.
+
+ If args[0] changed, then it can be Item_func_conv_charset() for the
+ original args[0], which was permanently installed during PREPARE time
+ into the item tree as a wrapper for args[0], using change_item_tree(), i.e.
+
+ NULLIF(latin1_field, 'a' COLLATE utf8_bin)
+
+ was "rewritten" to:
+
+ CASE WHEN CONVERT(latin1_field USING utf8) = 'a' COLLATE utf8_bin
+ THEN NULL
+ ELSE latin1_field
+
+ - m_args0 points to Item_field corresponding to latin1_field
+ - args[0] points to Item_func_conv_charset
+ - args[0]->args[0] is equal to m_args0
+ - args[1] points to Item_func_set_collation
+ - args[2] points is eqial to m_args0
+
+ In this case we remember and reuse m_arg0 during EXECUTE time as args[2].
+
+ QQ: How to make sure that m_args0 does not point
+ to something temporary which will be destoyed between PREPARE and EXECUTE.
+ The condition below should probably be more strict and somehow check that:
+ - change_item_tree() was called for the new args[0]
+ - m_args0 is referenced from inside args[0], e.g. as a function argument,
+ and therefore it is also something that won't be destroyed between
+ PREPARE and EXECUTE.
+ Any ideas?
+ */
+ if (args[0] == m_arg0)
+ m_arg0= NULL;
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 9a9d0e65ff6..9149f25b1b1 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1009,6 +1009,7 @@ class Item_func_nullif :public Item_func_hybrid_field_type
*/
Item_cache *m_cache;
int compare();
+ Item *m_arg0;
public:
/*
Here we pass three arguments to the parent constructor, as NULLIF
@@ -1020,7 +1021,8 @@ public:
*/
Item_func_nullif(THD *thd, Item *a, Item *b):
Item_func_hybrid_field_type(thd, a, b, a),
- m_cache(NULL)
+ m_cache(NULL),
+ m_arg0(NULL)
{ arg_count--; }
void cleanup()
{