Skip to content

Commit a96fbc3

Browse files
author
Alexander Barkov
committed
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.
1 parent dc50a3d commit a96fbc3

File tree

1 file changed

+72
-24
lines changed

1 file changed

+72
-24
lines changed

sql/item_cmpfunc.cc

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2569,8 +2569,21 @@ Item_func_nullif::fix_length_and_dec()
25692569
if (!args[2]) // Only false if EOM
25702570
return;
25712571

2572-
DBUG_ASSERT(args[0] == args[2]);
25732572
THD *thd= current_thd;
2573+
/*
2574+
At prepared statement EXECUTE time, args[0] can already
2575+
point to a different Item, created during PREPARE time fix_length_and_dec().
2576+
For example, if character set conversion was needed, arguments can look
2577+
like this:
2578+
2579+
args[0]= > Item_func_conv_charset \
2580+
l_expr
2581+
args[2]= >------------------------/
2582+
2583+
Otherwise (during PREPARE or convensional execution),
2584+
args[0] and args[2] should still point to the same original l_expr.
2585+
*/
2586+
DBUG_ASSERT(args[0] == args[2] || thd->stmt_arena->is_stmt_execute());
25742587
if (args[0]->type() == SUM_FUNC_ITEM)
25752588
{
25762589
/*
@@ -2586,49 +2599,90 @@ Item_func_nullif::fix_length_and_dec()
25862599
l_expr needs a special treatment, as it's referenced by both
25872600
args[0] and args[2] initially.
25882601
2589-
args[0] and args[2] can be replaced:
2602+
args[2] is used to return the value. Afrer all transformations
2603+
(e.g. in fix_length_and_dec(), equal field propagation, etc)
2604+
args[2] points to a an Item which preserves the exact data type and
2605+
attributes (e.g. collation) of the original l_expr.
2606+
It can point:
2607+
- to the original l_expr
2608+
- to an Item_cache pointing to l_expr
2609+
- to a constant of the same data type with l_expr.
2610+
2611+
args[0] is used for comparison. It can be replaced:
25902612
25912613
- to Item_func_conv_charset by character set aggregation routines
25922614
- to a constant Item by equal field propagation routines
25932615
(in case of Item_field)
25942616
2617+
The data type and/or the attributes of args[0] can differ from
2618+
the data type and the attributes of the original l_expr, to make
2619+
it comparable to args[1] (which points to r_expr or its replacement).
2620+
25952621
For aggregate functions we have to wrap the original args[0]/args[2]
25962622
into Item_cache (see MDEV-9181). In this case the Item_cache
25972623
instance becomes the subject to character set conversion instead of
25982624
the original args[0]/args[2], while the original args[0]/args[2] get
25992625
hidden inside the cache.
26002626
26012627
Some examples of what NULLIF can end up with after argument
2602-
substitution (we don't mention args[1] here for simplicity):
2628+
substitution (we don't mention args[1] in some cases for simplicity):
26032629
26042630
1. l_expr is not an aggragate function:
26052631
26062632
a. No conversion happened.
26072633
args[0] and args[2] were not replaced to something else
26082634
(i.e. neither by character set conversion, nor by propagation):
26092635
2636+
args[1] > r_expr
26102637
args[0] \
2611-
l_expr
2638+
l_expr
26122639
args[2] /
26132640
2614-
b. Conversion of args[0] happened.
2615-
args[0] was replaced, e.g. to Item_func_conv_charset:
2641+
b. Conversion of args[0] happened:
26162642
2617-
args[0] > Item_func_conv_charset \
2618-
l_expr
2619-
args[2] >------------------------/
2643+
CREATE OR REPLACE TABLE t1 (
2644+
a CHAR(10) CHARACTER SET latin1,
2645+
b CHAR(10) CHARACTER SET utf8);
2646+
SELECT * FROM t1 WHERE NULLIF(a,b);
26202647
2621-
c. Conversion of args[2] happened:
2648+
args[1] > r_expr (Item_field for t1.b)
2649+
args[0] > Item_func_conv_charset\
2650+
l_expr (Item_field for t1.a)
2651+
args[2] > ----------------------/
26222652
2623-
args[0] >------------------------\
2624-
l_expr
2625-
args[2] > Item_func_conv_charset /
2653+
c. Conversion of args[1] happened:
26262654
2627-
d. Conversion of both args[0] and args[2] happened
2628-
(e.g. by equal field propagation).
2655+
CREATE OR REPLACE TABLE t1 (
2656+
a CHAR(10) CHARACTER SET utf8,
2657+
b CHAR(10) CHARACTER SET latin1);
2658+
SELECT * FROM t1 WHERE NULLIF(a,b);
26292659
2630-
args[0] > Item_int
2631-
args[2] > Item_int
2660+
args[1] > Item_func_conv_charset -> r_expr (Item_field for t1.b)
2661+
args[0] \
2662+
l_expr (Item_field for t1.a)
2663+
args[2] /
2664+
2665+
d. Conversion of only args[0] happened (by equal field proparation):
2666+
2667+
CREATE OR REPLACE TABLE t1 (
2668+
a CHAR(10),
2669+
b CHAR(10));
2670+
SELECT * FROM t1 WHERE NULLIF(a,b) AND a='a';
2671+
2672+
args[1] > r_expr (Item_field for t1.b)
2673+
args[0] > Item_string('a') (constant replacement for t1.a)
2674+
args[2] > l_expr (Item_field for t1.a)
2675+
2676+
e. Conversion of both args[0] and args[2] happened
2677+
(by equal field propagation):
2678+
2679+
CREATE OR REPLACE TABLE t1 (a INT,b INT);
2680+
SELECT * FROM t1 WHERE NULLIF(a,b) AND a=5;
2681+
2682+
args[1] > r_expr (Item_field for "b")
2683+
args[0] \
2684+
Item_int (5) (constant replacement for "a")
2685+
args[2] /
26322686
26332687
2. In case if l_expr is an aggregate function:
26342688
@@ -2644,13 +2698,7 @@ Item_func_nullif::fix_length_and_dec()
26442698
Item_cache > l_expr
26452699
args[2] >------------------------/
26462700
2647-
c. Conversion of args[2] happened:
2648-
2649-
args[0] >------------------------\
2650-
Item_cache > l_expr
2651-
args[2] > Item_func_conv_charset /
2652-
2653-
d. Conversion of both args[0] and args[2] happened.
2701+
c. Conversion of both args[0] and args[2] happened.
26542702
(e.g. by equal expression propagation)
26552703
TODO: check if it's possible (and add an example query if so).
26562704
*/

0 commit comments

Comments
 (0)