@@ -2569,8 +2569,21 @@ Item_func_nullif::fix_length_and_dec()
2569
2569
if (!args[2 ]) // Only false if EOM
2570
2570
return ;
2571
2571
2572
- DBUG_ASSERT (args[0 ] == args[2 ]);
2573
2572
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 ());
2574
2587
if (args[0 ]->type () == SUM_FUNC_ITEM)
2575
2588
{
2576
2589
/*
@@ -2586,49 +2599,90 @@ Item_func_nullif::fix_length_and_dec()
2586
2599
l_expr needs a special treatment, as it's referenced by both
2587
2600
args[0] and args[2] initially.
2588
2601
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:
2590
2612
2591
2613
- to Item_func_conv_charset by character set aggregation routines
2592
2614
- to a constant Item by equal field propagation routines
2593
2615
(in case of Item_field)
2594
2616
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
+
2595
2621
For aggregate functions we have to wrap the original args[0]/args[2]
2596
2622
into Item_cache (see MDEV-9181). In this case the Item_cache
2597
2623
instance becomes the subject to character set conversion instead of
2598
2624
the original args[0]/args[2], while the original args[0]/args[2] get
2599
2625
hidden inside the cache.
2600
2626
2601
2627
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):
2603
2629
2604
2630
1. l_expr is not an aggragate function:
2605
2631
2606
2632
a. No conversion happened.
2607
2633
args[0] and args[2] were not replaced to something else
2608
2634
(i.e. neither by character set conversion, nor by propagation):
2609
2635
2636
+ args[1] > r_expr
2610
2637
args[0] \
2611
- l_expr
2638
+ l_expr
2612
2639
args[2] /
2613
2640
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:
2616
2642
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);
2620
2647
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] > ----------------------/
2622
2652
2623
- args[0] >------------------------\
2624
- l_expr
2625
- args[2] > Item_func_conv_charset /
2653
+ c. Conversion of args[1] happened:
2626
2654
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);
2629
2659
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] /
2632
2686
2633
2687
2. In case if l_expr is an aggregate function:
2634
2688
@@ -2644,13 +2698,7 @@ Item_func_nullif::fix_length_and_dec()
2644
2698
Item_cache > l_expr
2645
2699
args[2] >------------------------/
2646
2700
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.
2654
2702
(e.g. by equal expression propagation)
2655
2703
TODO: check if it's possible (and add an example query if so).
2656
2704
*/
0 commit comments