github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/rule/predicate_pushdown.go (about) 1 // Copyright 2021 - 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package rule 16 17 import ( 18 "github.com/matrixorigin/matrixone/pkg/pb/plan" 19 "github.com/matrixorigin/matrixone/pkg/sql/plan/function" 20 ) 21 22 type PredicatePushdown struct { 23 } 24 25 func NewPredicatePushdown() *PredicatePushdown { 26 return &PredicatePushdown{} 27 } 28 29 func (r *PredicatePushdown) Match(n *plan.Node) bool { 30 return n.NodeType != plan.Node_TABLE_SCAN && n.NodeType != plan.Node_EXTERNAL_SCAN && n.NodeType != plan.Node_FUNCTION_SCAN && len(n.FilterList) > 0 31 } 32 33 func (r *PredicatePushdown) Apply(n *plan.Node, qry *plan.Query) { 34 es := n.FilterList 35 n.FilterList = make([]*plan.Expr, 0, len(es)) 36 for i := range es { 37 r.pushdown(es[i], n, qry) 38 } 39 } 40 41 func (r *PredicatePushdown) pushdown(e *plan.Expr, n *plan.Node, qry *plan.Query) bool { 42 var ne *plan.Expr // new expr 43 44 if _, ok := e.Expr.(*plan.Expr_F); !ok { 45 n.FilterList = append(n.FilterList, e) 46 return false 47 } 48 if n.NodeType == plan.Node_TABLE_SCAN || n.NodeType == plan.Node_AGG || n.NodeType == plan.Node_FUNCTION_SCAN { 49 n.FilterList = append(n.FilterList, e) 50 return false 51 } 52 if len(n.Children) > 0 && (qry.Nodes[n.Children[0]].NodeType == plan.Node_JOIN || qry.Nodes[n.Children[0]].NodeType == plan.Node_AGG || qry.Nodes[n.Children[0]].NodeType == plan.Node_FUNCTION_SCAN) { 53 n.FilterList = append(n.FilterList, e) 54 return false 55 } 56 relPos := int32(-1) 57 relPos, ne = r.newExpr(relPos, e, n, qry) 58 if ne == nil { 59 n.FilterList = append(n.FilterList, e) 60 return false 61 } 62 if !r.pushdown(ne, qry.Nodes[relPos], qry) { 63 n.FilterList = append(n.FilterList, e) 64 return false 65 } 66 return true 67 } 68 69 func (r *PredicatePushdown) newExpr(relPos int32, expr *plan.Expr, n *plan.Node, qry *plan.Query) (int32, *plan.Expr) { 70 switch e := expr.Expr.(type) { 71 case *plan.Expr_C: 72 return relPos, expr 73 case *plan.Expr_F: 74 overloadID := e.F.Func.GetObj() 75 f, exists := function.GetFunctionByIDWithoutError(overloadID) 76 if !exists { 77 return relPos, nil 78 } 79 if f.TestFlag(plan.Function_AGG) { 80 return relPos, nil 81 } 82 args := make([]*plan.Expr, len(e.F.Args)) 83 for i := range e.F.Args { 84 relPos, args[i] = r.newExpr(relPos, e.F.Args[i], n, qry) 85 if args[i] == nil { 86 return relPos, nil 87 } 88 } 89 return relPos, expr 90 case *plan.Expr_Col: 91 if relPos < 0 { 92 relPos = e.Col.RelPos 93 } 94 if relPos < 0 { 95 return relPos, nil 96 } 97 if relPos != e.Col.RelPos { 98 return relPos, nil 99 } 100 return relPos, qry.Nodes[n.Children[relPos]].ProjectList[e.Col.ColPos] 101 default: 102 return relPos, nil 103 } 104 }