github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/projection_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/container/batch" 20 "github.com/matrixorigin/matrixone/pkg/container/types" 21 "github.com/matrixorigin/matrixone/pkg/pb/plan" 22 "github.com/matrixorigin/matrixone/pkg/sql/colexec" 23 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" 24 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 25 "github.com/matrixorigin/matrixone/pkg/sql/plan/rule" 26 ) 27 28 func NewProjectionBinder(builder *QueryBuilder, ctx *BindContext, havingBinder *HavingBinder) *ProjectionBinder { 29 b := &ProjectionBinder{ 30 havingBinder: havingBinder, 31 } 32 b.sysCtx = builder.GetContext() 33 b.builder = builder 34 b.ctx = ctx 35 b.impl = b 36 37 return b 38 } 39 40 func (b *ProjectionBinder) BindExpr(astExpr tree.Expr, depth int32, isRoot bool) (*plan.Expr, error) { 41 astStr := tree.String(astExpr, dialect.MYSQL) 42 43 if colPos, ok := b.ctx.groupByAst[astStr]; ok { 44 return &plan.Expr{ 45 Typ: b.ctx.groups[colPos].Typ, 46 Expr: &plan.Expr_Col{ 47 Col: &plan.ColRef{ 48 RelPos: b.ctx.groupTag, 49 ColPos: colPos, 50 }, 51 }, 52 }, nil 53 } 54 55 if colPos, ok := b.ctx.aggregateByAst[astStr]; ok { 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 } 66 67 if colPos, ok := b.ctx.windowByAst[astStr]; ok { 68 return &plan.Expr{ 69 Typ: b.ctx.windows[colPos].Typ, 70 Expr: &plan.Expr_Col{ 71 Col: &plan.ColRef{ 72 RelPos: b.ctx.windowTag, 73 ColPos: colPos, 74 }, 75 }, 76 }, nil 77 } 78 79 if colPos, ok := b.ctx.sampleByAst[astStr]; ok { 80 return &plan.Expr{ 81 Typ: b.ctx.sampleFunc.columns[colPos].Typ, 82 Expr: &plan.Expr_Col{ 83 Col: &plan.ColRef{ 84 RelPos: b.ctx.sampleTag, 85 ColPos: colPos, 86 }, 87 }, 88 }, nil 89 } 90 91 if colPos, ok := b.ctx.timeByAst[astStr]; ok { 92 if astStr != TimeWindowEnd && astStr != TimeWindowStart { 93 b.ctx.timeAsts = append(b.ctx.timeAsts, astExpr) 94 } 95 return &plan.Expr{ 96 Typ: b.ctx.times[colPos].Typ, 97 Expr: &plan.Expr_Col{ 98 Col: &plan.ColRef{ 99 RelPos: b.ctx.timeTag, 100 ColPos: colPos, 101 }, 102 }, 103 }, nil 104 } 105 106 return b.baseBindExpr(astExpr, depth, isRoot) 107 } 108 109 func (b *ProjectionBinder) BindColRef(astExpr *tree.UnresolvedName, depth int32, isRoot bool) (*plan.Expr, error) { 110 return b.baseBindColRef(astExpr, depth, isRoot) 111 } 112 113 func (b *ProjectionBinder) BindAggFunc(funcName string, astExpr *tree.FuncExpr, depth int32, isRoot bool) (*plan.Expr, error) { 114 return b.havingBinder.BindAggFunc(funcName, astExpr, depth, isRoot) 115 } 116 117 func (b *ProjectionBinder) BindWinFunc(funcName string, astExpr *tree.FuncExpr, depth int32, isRoot bool) (*plan.Expr, error) { 118 if astExpr.Type == tree.FUNC_TYPE_DISTINCT { 119 return nil, moerr.NewNYI(b.GetContext(), "DISTINCT in window function") 120 } 121 122 colPos := int32(len(b.ctx.windows)) 123 astStr := tree.String(astExpr, dialect.MYSQL) 124 b.ctx.windowByAst[astStr] = colPos 125 w := &plan.WindowSpec{} 126 ws := astExpr.WindowSpec 127 var err error 128 129 // window function 130 w.WindowFunc, err = b.bindFuncExprImplByAstExpr(funcName, astExpr.Exprs, depth) 131 if err != nil { 132 return nil, err 133 } 134 w.Name = funcName 135 // partition by 136 for _, group := range ws.PartitionBy { 137 expr, err := b.BindExpr(group, depth, isRoot) 138 if err != nil { 139 return nil, err 140 } 141 w.PartitionBy = append(w.PartitionBy, expr) 142 } 143 // order by 144 if ws.OrderBy != nil { 145 w.OrderBy = make([]*plan.OrderBySpec, 0, len(ws.OrderBy)) 146 147 for _, order := range ws.OrderBy { 148 expr, err := b.BindExpr(order.Expr, depth, isRoot) 149 if err != nil { 150 return nil, err 151 } 152 153 orderBy := &plan.OrderBySpec{ 154 Expr: expr, 155 Flag: plan.OrderBySpec_INTERNAL, 156 } 157 158 switch order.Direction { 159 case tree.Ascending: 160 orderBy.Flag |= plan.OrderBySpec_ASC 161 case tree.Descending: 162 orderBy.Flag |= plan.OrderBySpec_DESC 163 } 164 165 switch order.NullsPosition { 166 case tree.NullsFirst: 167 orderBy.Flag |= plan.OrderBySpec_NULLS_FIRST 168 case tree.NullsLast: 169 orderBy.Flag |= plan.OrderBySpec_NULLS_LAST 170 } 171 172 w.OrderBy = append(w.OrderBy, orderBy) 173 } 174 } 175 // preceding and following 176 switch ws.Frame.Start.Type { 177 case tree.Following: 178 if ws.Frame.Start.UnBounded { 179 return nil, moerr.NewParseError(b.GetContext(), "Window '<unnamed window>': frame start cannot be UNBOUNDED FOLLOWING.") 180 } 181 if ws.Frame.End.Type == tree.Preceding || ws.Frame.End.Type == tree.CurrentRow { 182 return nil, moerr.NewParseError(b.GetContext(), "Window '<unnamed window>': frame start or end is negative, NULL or of non-integral type") 183 } 184 case tree.CurrentRow: 185 if ws.Frame.End.Type == tree.Preceding { 186 return nil, moerr.NewParseError(b.GetContext(), "Window '<unnamed window>': frame start or end is negative, NULL or of non-integral type") 187 } 188 } 189 190 if ws.Frame.End.Type == tree.Preceding && ws.Frame.End.UnBounded { 191 return nil, moerr.NewParseError(b.GetContext(), "Window '<unnamed window>': frame end cannot be UNBOUNDED PRECEDING.") 192 } 193 194 w.Frame = &plan.FrameClause{ 195 Type: plan.FrameClause_FrameType(ws.Frame.Type), 196 Start: &plan.FrameBound{ 197 Type: plan.FrameBound_BoundType(ws.Frame.Start.Type), 198 UnBounded: ws.Frame.Start.UnBounded, 199 }, 200 End: &plan.FrameBound{ 201 Type: plan.FrameBound_BoundType(ws.Frame.End.Type), 202 UnBounded: ws.Frame.End.UnBounded, 203 }, 204 } 205 var typ *plan.Type 206 switch ws.Frame.Type { 207 case tree.Rows: 208 typ = &plan.Type{Id: int32(types.T_uint64)} 209 case tree.Range: 210 if len(w.OrderBy) != 1 && isNRange(ws.Frame) { 211 return nil, moerr.NewParseError(b.GetContext(), "Window '<unnamed window>' with RANGE N PRECEDING/FOLLOWING frame requires exactly one ORDER BY expression, of numeric or temporal type") 212 } 213 if len(w.OrderBy) == 0 { 214 // not N range 215 break 216 } 217 typ = &w.OrderBy[0].Expr.Typ 218 t := types.Type{Oid: types.T(typ.Id)} 219 if !t.IsNumericOrTemporal() { 220 return nil, moerr.NewParseError(b.GetContext(), "Window '<unnamed window>' with RANGE N PRECEDING/FOLLOWING frame requires exactly one ORDER BY expression, of numeric or temporal type") 221 } 222 case tree.Groups: 223 return nil, moerr.NewNYI(b.GetContext(), "GROUPS in WINDOW FUNCTION condition") 224 } 225 if ws.Frame.Start.Expr != nil { 226 w.Frame.Start.Val, err = b.makeFrameConstValue(ws.Frame.Start.Expr, typ) 227 if err != nil { 228 return nil, err 229 } 230 } 231 if ws.Frame.End.Expr != nil { 232 w.Frame.End.Val, err = b.makeFrameConstValue(ws.Frame.End.Expr, typ) 233 if err != nil { 234 return nil, err 235 } 236 } 237 238 // append 239 b.ctx.windows = append(b.ctx.windows, &plan.Expr{ 240 Typ: w.WindowFunc.Typ, 241 Expr: &plan.Expr_W{W: w}, 242 }) 243 244 return &plan.Expr{ 245 Typ: w.WindowFunc.Typ, 246 Expr: &plan.Expr_Col{ 247 Col: &plan.ColRef{ 248 RelPos: b.ctx.windowTag, 249 ColPos: colPos, 250 }, 251 }, 252 }, nil 253 } 254 255 func isNRange(f *tree.FrameClause) bool { 256 if f.Start.Expr == nil && f.End.Expr == nil { 257 return false 258 } 259 return true 260 } 261 262 func (b *ProjectionBinder) makeFrameConstValue(expr tree.Expr, typ *plan.Type) (*plan.Expr, error) { 263 e, err := b.baseBindExpr(expr, 0, true) 264 if err != nil { 265 return nil, err 266 } 267 if e.Typ.Id == int32(types.T_interval) { 268 return b.resetInterval(e) 269 } 270 if typ == nil { 271 return e, nil 272 } 273 e, err = appendCastBeforeExpr(b.GetContext(), e, *typ) 274 if err != nil { 275 return nil, err 276 } 277 278 executor, err := colexec.NewExpressionExecutor(b.builder.compCtx.GetProcess(), e) 279 if err != nil { 280 return nil, err 281 } 282 defer executor.Free() 283 vec, err := executor.Eval(b.builder.compCtx.GetProcess(), []*batch.Batch{batch.EmptyForConstFoldBatch}) 284 if err != nil { 285 return nil, err 286 } 287 c := rule.GetConstantValue(vec, false, 0) 288 289 return &plan.Expr{ 290 Typ: *typ, 291 Expr: &plan.Expr_Lit{Lit: c}, 292 }, nil 293 } 294 295 func (b *ProjectionBinder) resetInterval(e *Expr) (*Expr, error) { 296 e1 := e.Expr.(*plan.Expr_List).List.List[0] 297 e2 := e.Expr.(*plan.Expr_List).List.List[1] 298 299 intervalTypeStr := e2.Expr.(*plan.Expr_Lit).Lit.Value.(*plan.Literal_Sval).Sval 300 intervalType, err := types.IntervalTypeOf(intervalTypeStr) 301 if err != nil { 302 return nil, err 303 } 304 305 if e1.Typ.Id == int32(types.T_varchar) || e1.Typ.Id == int32(types.T_char) { 306 s := e1.Expr.(*plan.Expr_Lit).Lit.Value.(*plan.Literal_Sval).Sval 307 returnNum, returnType, err := types.NormalizeInterval(s, intervalType) 308 if err != nil { 309 return nil, err 310 } 311 312 e.Expr.(*plan.Expr_List).List.List[0] = makePlan2Int64ConstExprWithType(returnNum) 313 e.Expr.(*plan.Expr_List).List.List[1] = makePlan2Int64ConstExprWithType(int64(returnType)) 314 return e, nil 315 } 316 317 typ := &plan.Type{Id: int32(types.T_int64)} 318 numberExpr, err := appendCastBeforeExpr(b.GetContext(), e1, *typ) 319 if err != nil { 320 return nil, err 321 } 322 323 executor, err := colexec.NewExpressionExecutor(b.builder.compCtx.GetProcess(), numberExpr) 324 if err != nil { 325 return nil, err 326 } 327 defer executor.Free() 328 vec, err := executor.Eval(b.builder.compCtx.GetProcess(), []*batch.Batch{batch.EmptyForConstFoldBatch}) 329 if err != nil { 330 return nil, err 331 } 332 c := rule.GetConstantValue(vec, false, 0) 333 334 e.Expr.(*plan.Expr_List).List.List[0] = &plan.Expr{Typ: *typ, Expr: &plan.Expr_Lit{Lit: c}} 335 e.Expr.(*plan.Expr_List).List.List[1] = makePlan2Int64ConstExprWithType(int64(intervalType)) 336 337 return e, nil 338 } 339 340 func (b *ProjectionBinder) BindSubquery(astExpr *tree.Subquery, isRoot bool) (*plan.Expr, error) { 341 return b.baseBindSubquery(astExpr, isRoot) 342 } 343 344 func (b *ProjectionBinder) BindTimeWindowFunc(funcName string, astExpr *tree.FuncExpr, depth int32, isRoot bool) (*plan.Expr, error) { 345 b.ctx.timeAsts = append(b.ctx.timeAsts, astExpr) 346 return b.havingBinder.BindTimeWindowFunc(funcName, astExpr, depth, isRoot) 347 }