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 }