github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/having_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/dialect" 21 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 22 "github.com/matrixorigin/matrixone/pkg/sql/plan/function" 23 ) 24 25 func NewHavingBinder(builder *QueryBuilder, ctx *BindContext) *HavingBinder { 26 b := &HavingBinder{ 27 insideAgg: false, 28 } 29 b.sysCtx = builder.GetContext() 30 b.builder = builder 31 b.ctx = ctx 32 b.impl = b 33 34 return b 35 } 36 37 func (b *HavingBinder) BindExpr(astExpr tree.Expr, depth int32, isRoot bool) (*plan.Expr, error) { 38 astStr := tree.String(astExpr, dialect.MYSQL) 39 40 if !b.insideAgg { 41 if colPos, ok := b.ctx.groupByAst[astStr]; ok { 42 return &plan.Expr{ 43 Typ: b.ctx.groups[colPos].Typ, 44 Expr: &plan.Expr_Col{ 45 Col: &plan.ColRef{ 46 RelPos: b.ctx.groupTag, 47 ColPos: colPos, 48 }, 49 }, 50 }, nil 51 } 52 } 53 54 if colPos, ok := b.ctx.aggregateByAst[astStr]; ok { 55 if !b.insideAgg { 56 return &plan.Expr{ 57 Typ: b.ctx.aggregates[colPos].Typ, 58 Expr: &plan.Expr_Col{ 59 Col: &plan.ColRef{ 60 RelPos: b.ctx.aggregateTag, 61 ColPos: colPos, 62 }, 63 }, 64 }, nil 65 } else { 66 return nil, moerr.NewInvalidInput(b.GetContext(), "nestted aggregate function") 67 } 68 } 69 70 return b.baseBindExpr(astExpr, depth, isRoot) 71 } 72 73 func (b *HavingBinder) BindColRef(astExpr *tree.UnresolvedName, depth int32, isRoot bool) (*plan.Expr, error) { 74 if b.insideAgg { 75 expr, err := b.baseBindColRef(astExpr, depth, isRoot) 76 if err != nil { 77 return nil, err 78 } 79 80 if _, ok := expr.Expr.(*plan.Expr_Corr); ok { 81 return nil, moerr.NewNYI(b.GetContext(), "correlated columns in aggregate function") 82 } 83 84 return expr, nil 85 } else if b.builder.mysqlCompatible { 86 expr, err := b.baseBindColRef(astExpr, depth, isRoot) 87 if err != nil { 88 return nil, err 89 } 90 91 if _, ok := expr.Expr.(*plan.Expr_Corr); ok { 92 return nil, moerr.NewNYI(b.GetContext(), "correlated columns in aggregate function") 93 } 94 95 newExpr, _ := bindFuncExprImplByPlanExpr(b.builder.compCtx.GetContext(), "any_value", []*plan.Expr{expr}) 96 colPos := len(b.ctx.aggregates) 97 b.ctx.aggregates = append(b.ctx.aggregates, newExpr) 98 return &plan.Expr{ 99 Typ: b.ctx.aggregates[colPos].Typ, 100 Expr: &plan.Expr_Col{ 101 Col: &plan.ColRef{ 102 RelPos: b.ctx.aggregateTag, 103 ColPos: int32(colPos), 104 }, 105 }, 106 }, nil 107 } else { 108 return nil, moerr.NewSyntaxError(b.GetContext(), "column %q must appear in the GROUP BY clause or be used in an aggregate function", tree.String(astExpr, dialect.MYSQL)) 109 } 110 } 111 112 func (b *HavingBinder) BindAggFunc(funcName string, astExpr *tree.FuncExpr, depth int32, isRoot bool) (*plan.Expr, error) { 113 if b.insideAgg { 114 return nil, moerr.NewSyntaxError(b.GetContext(), "aggregate function %s calls cannot be nested", funcName) 115 } 116 117 b.insideAgg = true 118 expr, err := b.bindFuncExprImplByAstExpr(funcName, astExpr.Exprs, depth) 119 if err != nil { 120 return nil, err 121 } 122 if astExpr.Type == tree.FUNC_TYPE_DISTINCT { 123 expr.GetF().Func.Obj = int64(int64(uint64(expr.GetF().Func.Obj) | function.Distinct)) 124 } 125 b.insideAgg = false 126 127 colPos := int32(len(b.ctx.aggregates)) 128 astStr := tree.String(astExpr, dialect.MYSQL) 129 b.ctx.aggregateByAst[astStr] = colPos 130 b.ctx.aggregates = append(b.ctx.aggregates, expr) 131 132 return &plan.Expr{ 133 Typ: expr.Typ, 134 Expr: &plan.Expr_Col{ 135 Col: &plan.ColRef{ 136 RelPos: b.ctx.aggregateTag, 137 ColPos: colPos, 138 }, 139 }, 140 }, nil 141 } 142 143 func (b *HavingBinder) BindWinFunc(funcName string, astExpr *tree.FuncExpr, depth int32, isRoot bool) (*plan.Expr, error) { 144 if b.insideAgg { 145 return nil, moerr.NewSyntaxError(b.GetContext(), "aggregate function calls cannot contain window function calls") 146 } else { 147 return nil, moerr.NewSyntaxError(b.GetContext(), "window %s functions not allowed in having clause", funcName) 148 } 149 } 150 151 func (b *HavingBinder) BindSubquery(astExpr *tree.Subquery, isRoot bool) (*plan.Expr, error) { 152 return b.baseBindSubquery(astExpr, isRoot) 153 }