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  }