@@ -75,6 +75,7 @@ func splitSetGetVarFunc(filters []expression.Expression) ([]expression.Expressio
75
75
func (p * LogicalSelection ) PredicatePushDown (predicates []expression.Expression ) ([]expression.Expression , LogicalPlan ) {
76
76
var child LogicalPlan
77
77
var retConditions []expression.Expression
78
+ << << << < HEAD
78
79
if p .buildByHaving {
79
80
retConditions , child = p .children [0 ].PredicatePushDown (predicates )
80
81
retConditions = append (retConditions , p .Conditions ... )
@@ -83,6 +84,13 @@ func (p *LogicalSelection) PredicatePushDown(predicates []expression.Expression)
83
84
retConditions , child = p .children [0 ].PredicatePushDown (append (canBePushDown , predicates ... ))
84
85
retConditions = append (retConditions , canNotBePushDown ... )
85
86
}
87
+ == == == =
88
+ var originConditions []expression.Expression
89
+ canBePushDown , canNotBePushDown := splitSetGetVarFunc (p .Conditions )
90
+ originConditions = canBePushDown
91
+ retConditions , child = p .children [0 ].PredicatePushDown (append (canBePushDown , predicates ... ), opt )
92
+ retConditions = append (retConditions , canNotBePushDown ... )
93
+ >> >> >> > 47e4 b5bf3 ... * : revert #27021 to fix a bug that selection can not be pushed down when having clause above aggregation (#33168 )
86
94
if len (retConditions ) > 0 {
87
95
p .Conditions = expression .PropagateConstant (p .ctx , retConditions )
88
96
// Return table dual when filter is constant false or null.
@@ -597,3 +605,196 @@ func (p *LogicalMemTable) PredicatePushDown(predicates []expression.Expression)
597
605
func (* ppdSolver ) name () string {
598
606
return "predicate_push_down"
599
607
}
608
+ << << << < HEAD
609
+ == == == =
610
+
611
+ func appendTableDualTraceStep (replaced LogicalPlan , dual LogicalPlan , conditions []expression.Expression , opt * logicalOptimizeOp ) {
612
+ action := func () string {
613
+ return fmt .Sprintf ("%v_%v is replaced by %v_%v" , replaced .TP (), replaced .ID (), dual .TP (), dual .ID ())
614
+ }
615
+ reason := func () string {
616
+ buffer := bytes .NewBufferString ("The conditions[" )
617
+ for i , cond := range conditions {
618
+ if i > 0 {
619
+ buffer .WriteString ("," )
620
+ }
621
+ buffer .WriteString (cond .String ())
622
+ }
623
+ buffer .WriteString ("] are constant false or null" )
624
+ return buffer .String ()
625
+ }
626
+ opt .appendStepToCurrent (dual .ID (), dual .TP (), reason , action )
627
+ }
628
+
629
+ func appendSelectionPredicatePushDownTraceStep (p * LogicalSelection , conditions []expression.Expression , opt * logicalOptimizeOp ) {
630
+ action := func () string {
631
+ return fmt .Sprintf ("%v_%v is removed" , p .TP (), p .ID ())
632
+ }
633
+ reason := func () string {
634
+ return ""
635
+ }
636
+ if len (conditions ) > 0 {
637
+ reason = func () string {
638
+ buffer := bytes .NewBufferString ("The conditions[" )
639
+ for i , cond := range conditions {
640
+ if i > 0 {
641
+ buffer .WriteString ("," )
642
+ }
643
+ buffer .WriteString (cond .String ())
644
+ }
645
+ buffer .WriteString (fmt .Sprintf ("] in %v_%v are pushed down" , p .TP (), p .ID ()))
646
+ return buffer .String ()
647
+ }
648
+ }
649
+ opt .appendStepToCurrent (p .ID (), p .TP (), reason , action )
650
+ }
651
+
652
+ func appendDataSourcePredicatePushDownTraceStep (ds * DataSource , opt * logicalOptimizeOp ) {
653
+ if len (ds .pushedDownConds ) < 1 {
654
+ return
655
+ }
656
+ reason := func () string {
657
+ return ""
658
+ }
659
+ action := func () string {
660
+ buffer := bytes .NewBufferString ("The conditions[" )
661
+ for i , cond := range ds .pushedDownConds {
662
+ if i > 0 {
663
+ buffer .WriteString ("," )
664
+ }
665
+ buffer .WriteString (cond .String ())
666
+ }
667
+ buffer .WriteString (fmt .Sprintf ("] are pushed down across %v_%v" , ds .TP (), ds .ID ()))
668
+ return buffer .String ()
669
+ }
670
+ opt .appendStepToCurrent (ds .ID (), ds .TP (), reason , action )
671
+ }
672
+
673
+ func appendAddSelectionTraceStep (p LogicalPlan , child LogicalPlan , sel * LogicalSelection , opt * logicalOptimizeOp ) {
674
+ reason := func () string {
675
+ return ""
676
+ }
677
+ action := func () string {
678
+ return fmt .Sprintf ("add %v_%v to connect %v_%v and %v_%v" , sel .TP (), sel .ID (), p .TP (), p .ID (), child .TP (), child .ID ())
679
+ }
680
+ opt .appendStepToCurrent (sel .ID (), sel .TP (), reason , action )
681
+ }
682
+
683
+ // AddPrefix4ShardIndexes add expression prefix for shard index. e.g. an index is test.uk(tidb_shard(a), a).
684
+ // It transforms the sql "SELECT * FROM test WHERE a = 10" to
685
+ // "SELECT * FROM test WHERE tidb_shard(a) = val AND a = 10", val is the value of tidb_shard(10).
686
+ // It also transforms the sql "SELECT * FROM test WHERE a IN (10, 20, 30)" to
687
+ // "SELECT * FROM test WHERE tidb_shard(a) = val1 AND a = 10 OR tidb_shard(a) = val2 AND a = 20"
688
+ // @param[in] conds the original condtion of this datasource
689
+ // @retval - the new condition after adding expression prefix
690
+ func (ds * DataSource ) AddPrefix4ShardIndexes (sc sessionctx.Context , conds []expression.Expression ) []expression.Expression {
691
+ if ! ds .containExprPrefixUk {
692
+ return conds
693
+ }
694
+
695
+ var err error
696
+ newConds := conds
697
+
698
+ for _ , path := range ds .possibleAccessPaths {
699
+ if ! path .IsUkShardIndexPath {
700
+ continue
701
+ }
702
+ newConds , err = ds .addExprPrefixCond (sc , path , newConds )
703
+ if err != nil {
704
+ logutil .BgLogger ().Error ("Add tidb_shard expression failed" ,
705
+ zap .Error (err ),
706
+ zap .Uint64 ("connection id" , sc .GetSessionVars ().ConnectionID ),
707
+ zap .String ("database name" , ds .DBName .L ),
708
+ zap .String ("table name" , ds .tableInfo .Name .L ),
709
+ zap .String ("index name" , path .Index .Name .L ))
710
+ return conds
711
+ }
712
+ }
713
+
714
+ return newConds
715
+ }
716
+
717
+ func (ds * DataSource ) addExprPrefixCond (sc sessionctx.Context , path * util.AccessPath ,
718
+ conds []expression.Expression ) ([]expression.Expression , error ) {
719
+ IdxCols , IdxColLens :=
720
+ expression .IndexInfo2PrefixCols (ds .Columns , ds .schema .Columns , path .Index )
721
+ if len (IdxCols ) == 0 {
722
+ return conds , nil
723
+ }
724
+
725
+ adder := & exprPrefixAdder {
726
+ sctx : sc ,
727
+ OrigConds : conds ,
728
+ cols : IdxCols ,
729
+ lengths : IdxColLens ,
730
+ }
731
+
732
+ return adder .addExprPrefix4ShardIndex ()
733
+ }
734
+
735
+ // AddExprPrefix4ShardIndex
736
+ // if original condition is a LogicOr expression, such as `WHERE a = 1 OR a = 10`,
737
+ // call the function AddExprPrefix4DNFCond to add prefix expression tidb_shard(a) = xxx for shard index.
738
+ // Otherwise, if the condition is `WHERE a = 1`, `WHERE a = 1 AND b = 10`, `WHERE a IN (1, 2, 3)`......,
739
+ // call the function AddExprPrefix4CNFCond to add prefix expression for shard index.
740
+ func (adder * exprPrefixAdder ) addExprPrefix4ShardIndex () ([]expression.Expression , error ) {
741
+ if len (adder .OrigConds ) == 1 {
742
+ if sf , ok := adder .OrigConds [0 ].(* expression.ScalarFunction ); ok && sf .FuncName .L == ast .LogicOr {
743
+ return adder .addExprPrefix4DNFCond (sf )
744
+ }
745
+ }
746
+ return adder .addExprPrefix4CNFCond (adder .OrigConds )
747
+ }
748
+
749
+ // AddExprPrefix4CNFCond
750
+ // add the prefix expression for CNF condition, e.g. `WHERE a = 1`, `WHERE a = 1 AND b = 10`, ......
751
+ // @param[in] conds the original condtion of the datasoure. e.g. `WHERE t1.a = 1 AND t1.b = 10 AND t2.a = 20`.
752
+ // if current datasource is `t1`, conds is {t1.a = 1, t1.b = 10}. if current datasource is
753
+ // `t2`, conds is {t2.a = 20}
754
+ // @return - the new condition after adding expression prefix
755
+ func (adder * exprPrefixAdder ) addExprPrefix4CNFCond (conds []expression.Expression ) ([]expression.Expression , error ) {
756
+ newCondtionds , err := ranger .AddExpr4EqAndInCondition (adder .sctx ,
757
+ conds , adder .cols )
758
+
759
+ return newCondtionds , err
760
+ }
761
+
762
+ // AddExprPrefix4DNFCond
763
+ // add the prefix expression for DNF condition, e.g. `WHERE a = 1 OR a = 10`, ......
764
+ // The condition returned is `WHERE (tidb_shard(a) = 214 AND a = 1) OR (tidb_shard(a) = 142 AND a = 10)`
765
+ // @param[in] condition the original condtion of the datasoure. e.g. `WHERE a = 1 OR a = 10`.
766
+ // condtion is `a = 1 OR a = 10`
767
+ // @return - the new condition after adding expression prefix. It's still a LogicOr expression.
768
+ func (adder * exprPrefixAdder ) addExprPrefix4DNFCond (condition * expression.ScalarFunction ) ([]expression.Expression , error ) {
769
+ var err error
770
+ dnfItems := expression .FlattenDNFConditions (condition )
771
+ newAccessItems := make ([]expression.Expression , 0 , len (dnfItems ))
772
+
773
+ for _ , item := range dnfItems {
774
+ if sf , ok := item .(* expression.ScalarFunction ); ok {
775
+ var accesses []expression.Expression
776
+ if sf .FuncName .L == ast .LogicAnd {
777
+ cnfItems := expression .FlattenCNFConditions (sf )
778
+ accesses , err = adder .addExprPrefix4CNFCond (cnfItems )
779
+ if err != nil {
780
+ return []expression.Expression {condition }, err
781
+ }
782
+ newAccessItems = append (newAccessItems , expression .ComposeCNFCondition (adder .sctx , accesses ... ))
783
+ } else if sf .FuncName .L == ast .EQ || sf .FuncName .L == ast .In {
784
+ // only add prefix expression for EQ or IN function
785
+ accesses , err = adder .addExprPrefix4CNFCond ([]expression.Expression {sf })
786
+ if err != nil {
787
+ return []expression.Expression {condition }, err
788
+ }
789
+ newAccessItems = append (newAccessItems , expression .ComposeCNFCondition (adder .sctx , accesses ... ))
790
+ } else {
791
+ newAccessItems = append (newAccessItems , item )
792
+ }
793
+ } else {
794
+ newAccessItems = append (newAccessItems , item )
795
+ }
796
+ }
797
+
798
+ return []expression.Expression {expression .ComposeDNFCondition (adder .sctx , newAccessItems ... )}, nil
799
+ }
800
+ >> >> >> > 47e4 b5bf3 ... * : revert #27021 to fix a bug that selection can not be pushed down when having clause above aggregation (#33168 )
0 commit comments