Commit a96fbc3c authored by Alexander Barkov's avatar Alexander Barkov

MDEV-9503 Server crashes in fix_fields, main.null fails with ps-protocol

DBUG_ASSERT() added in the patch for MDEV-9181 did not take into account
special circumstances for the prepared statement EXECUTE. Fixig the assert.
Also, extending and fixing comments made during MDEV-9181.
parent dc50a3dd
...@@ -2569,8 +2569,21 @@ Item_func_nullif::fix_length_and_dec() ...@@ -2569,8 +2569,21 @@ Item_func_nullif::fix_length_and_dec()
if (!args[2]) // Only false if EOM if (!args[2]) // Only false if EOM
return; return;
DBUG_ASSERT(args[0] == args[2]);
THD *thd= current_thd; THD *thd= current_thd;
/*
At prepared statement EXECUTE time, args[0] can already
point to a different Item, created during PREPARE time fix_length_and_dec().
For example, if character set conversion was needed, arguments can look
like this:
args[0]= > Item_func_conv_charset \
l_expr
args[2]= >------------------------/
Otherwise (during PREPARE or convensional execution),
args[0] and args[2] should still point to the same original l_expr.
*/
DBUG_ASSERT(args[0] == args[2] || thd->stmt_arena->is_stmt_execute());
if (args[0]->type() == SUM_FUNC_ITEM) if (args[0]->type() == SUM_FUNC_ITEM)
{ {
/* /*
...@@ -2586,12 +2599,25 @@ Item_func_nullif::fix_length_and_dec() ...@@ -2586,12 +2599,25 @@ Item_func_nullif::fix_length_and_dec()
l_expr needs a special treatment, as it's referenced by both l_expr needs a special treatment, as it's referenced by both
args[0] and args[2] initially. args[0] and args[2] initially.
args[0] and args[2] can be replaced: args[2] is used to return the value. Afrer all transformations
(e.g. in fix_length_and_dec(), equal field propagation, etc)
args[2] points to a an Item which preserves the exact data type and
attributes (e.g. collation) of the original l_expr.
It can point:
- to the original l_expr
- to an Item_cache pointing to l_expr
- to a constant of the same data type with l_expr.
args[0] is used for comparison. It can be replaced:
- to Item_func_conv_charset by character set aggregation routines - to Item_func_conv_charset by character set aggregation routines
- to a constant Item by equal field propagation routines - to a constant Item by equal field propagation routines
(in case of Item_field) (in case of Item_field)
The data type and/or the attributes of args[0] can differ from
the data type and the attributes of the original l_expr, to make
it comparable to args[1] (which points to r_expr or its replacement).
For aggregate functions we have to wrap the original args[0]/args[2] For aggregate functions we have to wrap the original args[0]/args[2]
into Item_cache (see MDEV-9181). In this case the Item_cache into Item_cache (see MDEV-9181). In this case the Item_cache
instance becomes the subject to character set conversion instead of instance becomes the subject to character set conversion instead of
...@@ -2599,7 +2625,7 @@ Item_func_nullif::fix_length_and_dec() ...@@ -2599,7 +2625,7 @@ Item_func_nullif::fix_length_and_dec()
hidden inside the cache. hidden inside the cache.
Some examples of what NULLIF can end up with after argument Some examples of what NULLIF can end up with after argument
substitution (we don't mention args[1] here for simplicity): substitution (we don't mention args[1] in some cases for simplicity):
1. l_expr is not an aggragate function: 1. l_expr is not an aggragate function:
...@@ -2607,28 +2633,56 @@ Item_func_nullif::fix_length_and_dec() ...@@ -2607,28 +2633,56 @@ Item_func_nullif::fix_length_and_dec()
args[0] and args[2] were not replaced to something else args[0] and args[2] were not replaced to something else
(i.e. neither by character set conversion, nor by propagation): (i.e. neither by character set conversion, nor by propagation):
args[1] > r_expr
args[0] \ args[0] \
l_expr l_expr
args[2] / args[2] /
b. Conversion of args[0] happened. b. Conversion of args[0] happened:
args[0] was replaced, e.g. to Item_func_conv_charset:
args[0] > Item_func_conv_charset \ CREATE OR REPLACE TABLE t1 (
l_expr a CHAR(10) CHARACTER SET latin1,
args[2] >------------------------/ b CHAR(10) CHARACTER SET utf8);
SELECT * FROM t1 WHERE NULLIF(a,b);
c. Conversion of args[2] happened: args[1] > r_expr (Item_field for t1.b)
args[0] > Item_func_conv_charset\
l_expr (Item_field for t1.a)
args[2] > ----------------------/
args[0] >------------------------\ c. Conversion of args[1] happened:
l_expr
args[2] > Item_func_conv_charset /
d. Conversion of both args[0] and args[2] happened CREATE OR REPLACE TABLE t1 (
(e.g. by equal field propagation). a CHAR(10) CHARACTER SET utf8,
b CHAR(10) CHARACTER SET latin1);
SELECT * FROM t1 WHERE NULLIF(a,b);
args[0] > Item_int args[1] > Item_func_conv_charset -> r_expr (Item_field for t1.b)
args[2] > Item_int args[0] \
l_expr (Item_field for t1.a)
args[2] /
d. Conversion of only args[0] happened (by equal field proparation):
CREATE OR REPLACE TABLE t1 (
a CHAR(10),
b CHAR(10));
SELECT * FROM t1 WHERE NULLIF(a,b) AND a='a';
args[1] > r_expr (Item_field for t1.b)
args[0] > Item_string('a') (constant replacement for t1.a)
args[2] > l_expr (Item_field for t1.a)
e. Conversion of both args[0] and args[2] happened
(by equal field propagation):
CREATE OR REPLACE TABLE t1 (a INT,b INT);
SELECT * FROM t1 WHERE NULLIF(a,b) AND a=5;
args[1] > r_expr (Item_field for "b")
args[0] \
Item_int (5) (constant replacement for "a")
args[2] /
2. In case if l_expr is an aggregate function: 2. In case if l_expr is an aggregate function:
...@@ -2644,13 +2698,7 @@ Item_func_nullif::fix_length_and_dec() ...@@ -2644,13 +2698,7 @@ Item_func_nullif::fix_length_and_dec()
Item_cache > l_expr Item_cache > l_expr
args[2] >------------------------/ args[2] >------------------------/
c. Conversion of args[2] happened: c. Conversion of both args[0] and args[2] happened.
args[0] >------------------------\
Item_cache > l_expr
args[2] > Item_func_conv_charset /
d. Conversion of both args[0] and args[2] happened.
(e.g. by equal expression propagation) (e.g. by equal expression propagation)
TODO: check if it's possible (and add an example query if so). TODO: check if it's possible (and add an example query if so).
*/ */
......
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