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  }