github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/partition_binder.go (about)

     1  // Copyright 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 plan
    16  
    17  import (
    18  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    19  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    20  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    21  	"strings"
    22  )
    23  
    24  func NewPartitionBinder(builder *QueryBuilder, ctx *BindContext) *PartitionBinder {
    25  	p := &PartitionBinder{}
    26  	p.sysCtx = builder.GetContext()
    27  	p.builder = builder
    28  	p.ctx = ctx
    29  	p.impl = p
    30  	return p
    31  }
    32  
    33  // From: https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations-functions.html#partitioning-limitations-ceiling-floor
    34  var supportedFunctionsInPartitionExpr = map[string]int{
    35  	"abs":            0,
    36  	"ceiling":        0, //TODO: double check
    37  	"ceil":           0, //TODO: double check
    38  	"datediff":       0,
    39  	"day":            0,
    40  	"dayofmonth":     0,
    41  	"dayofweek":      0,
    42  	"dayofyear":      0,
    43  	"extract":        0,
    44  	"floor":          0, //TODO: double check
    45  	"hour":           0,
    46  	"microsecond":    0,
    47  	"minute":         0,
    48  	"mod":            0,
    49  	"month":          0,
    50  	"quarter":        0,
    51  	"second":         0,
    52  	"time_to_sec":    0,
    53  	"to_days":        0,
    54  	"to_seconds":     0,
    55  	"unix_timestamp": 0,
    56  	"weekday":        0,
    57  	"year":           0,
    58  	"yearweek":       0,
    59  	"hash_value":     0,
    60  }
    61  
    62  func functionIsSupported(funcName string) bool {
    63  	if _, ok := supportedFunctionsInPartitionExpr[funcName]; ok {
    64  		return ok
    65  	}
    66  	return false
    67  }
    68  
    69  func (p *PartitionBinder) BindExpr(expr tree.Expr, i int32, b bool) (*plan.Expr, error) {
    70  	/*
    71  		Base on reference:
    72  		https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations.html
    73  		https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations-functions.html#partitioning-limitations-ceiling-floor
    74  	*/
    75  	switch exprImpl := expr.(type) {
    76  	case *tree.BinaryExpr:
    77  		//unsupported operator
    78  		switch exprImpl.Op {
    79  		case tree.PLUS, tree.MINUS, tree.MULTI, tree.INTEGER_DIV, tree.MOD:
    80  			//suggested by Zhang Xiao, only support operator +,-,*,div in version 0.8
    81  		default:
    82  			return nil, moerr.NewInvalidInput(p.GetContext(), "operator %s is not allowed in the partition expression", exprImpl.Op.ToString())
    83  		}
    84  	case *tree.UnaryExpr:
    85  		switch exprImpl.Op {
    86  		case tree.UNARY_MINUS, tree.UNARY_PLUS:
    87  		default:
    88  			return nil, moerr.NewInvalidInput(p.GetContext(), "operator %s is not allowed in the partition expression", exprImpl.Op.ToString())
    89  		}
    90  	case *tree.FuncExpr:
    91  		//supported function
    92  		funcRef, ok := exprImpl.Func.FunctionReference.(*tree.UnresolvedName)
    93  		if !ok {
    94  			return nil, moerr.NewNYI(p.GetContext(), "invalid function expr '%v'", exprImpl)
    95  		}
    96  		funcName := strings.ToLower(funcRef.Parts[0])
    97  		if !functionIsSupported(funcName) {
    98  			return nil, moerr.NewInvalidInput(p.GetContext(), "function %s is not allowed in the partition expression", funcName)
    99  		}
   100  	}
   101  	return p.baseBindExpr(expr, i, b)
   102  }
   103  
   104  func (p *PartitionBinder) BindColRef(name *tree.UnresolvedName, i int32, b bool) (*plan.Expr, error) {
   105  	return p.baseBindColRef(name, i, b)
   106  }
   107  
   108  func (p *PartitionBinder) BindAggFunc(s string, expr *tree.FuncExpr, i int32, b bool) (*plan.Expr, error) {
   109  	return nil, moerr.NewSyntaxError(p.GetContext(), "aggregate functions not allowed in partition clause")
   110  }
   111  
   112  func (p *PartitionBinder) BindWinFunc(s string, expr *tree.FuncExpr, i int32, b bool) (*plan.Expr, error) {
   113  	return nil, moerr.NewSyntaxError(p.GetContext(), "window functions not allowed in partition clause")
   114  }
   115  
   116  func (p *PartitionBinder) BindSubquery(subquery *tree.Subquery, b bool) (*plan.Expr, error) {
   117  	return nil, moerr.NewSyntaxError(p.GetContext(), "subquery not allowed in partition clause")
   118  }
   119  
   120  func (p *PartitionBinder) BindTimeWindowFunc(funcName string, astExpr *tree.FuncExpr, depth int32, isRoot bool) (*plan.Expr, error) {
   121  	return nil, moerr.NewInvalidInput(p.GetContext(), "cannot bind time window functions '%s'", funcName)
   122  }