diff --git a/parser/ast/dml.go b/parser/ast/dml.go index 2046f3ad24eb9..e7fbc19019679 100644 --- a/parser/ast/dml.go +++ b/parser/ast/dml.go @@ -43,6 +43,10 @@ var ( _ Node = &TableSource{} _ Node = &UnionSelectList{} _ Node = &WildCardField{} + _ Node = &WindowSpec{} + _ Node = &PartitionByClause{} + _ Node = &FrameClause{} + _ Node = &FrameBound{} ) // JoinType is join type, including cross/left/right/full. @@ -468,6 +472,8 @@ type SelectStmt struct { GroupBy *GroupByClause // Having is the having condition. Having *HavingClause + // WindowSpecs is the window specification list. + WindowSpecs []WindowSpec // OrderBy is the ordering expression list. OrderBy *OrderByClause // Limit is the limit clause. @@ -542,6 +548,14 @@ func (n *SelectStmt) Accept(v Visitor) (Node, bool) { n.Having = node.(*HavingClause) } + for i, spec := range n.WindowSpecs { + node, ok := spec.Accept(v) + if !ok { + return n, false + } + n.WindowSpecs[i] = *node.(*WindowSpec) + } + if n.OrderBy != nil { node, ok := n.OrderBy.Accept(v) if !ok { @@ -1035,3 +1049,163 @@ func (n *ShowStmt) Accept(v Visitor) (Node, bool) { } return v.Leave(n) } + +// WindowSpec is the specification of a window. +type WindowSpec struct { + node + + Name model.CIStr + // Ref is the reference window of this specification. For example, in `w2 as (w1 order by a)`, + // the definition of `w2` references `w1`. + Ref model.CIStr + + PartitionBy *PartitionByClause + OrderBy *OrderByClause + Frame *FrameClause +} + +// Accept implements Node Accept interface. +func (n *WindowSpec) Accept(v Visitor) (Node, bool) { + newNode, skipChildren := v.Enter(n) + if skipChildren { + return v.Leave(newNode) + } + n = newNode.(*WindowSpec) + if n.PartitionBy != nil { + node, ok := n.PartitionBy.Accept(v) + if !ok { + return n, false + } + n.PartitionBy = node.(*PartitionByClause) + } + if n.OrderBy != nil { + node, ok := n.OrderBy.Accept(v) + if !ok { + return n, false + } + n.OrderBy = node.(*OrderByClause) + } + if n.Frame != nil { + node, ok := n.Frame.Accept(v) + if !ok { + return n, false + } + n.Frame = node.(*FrameClause) + } + return v.Leave(n) +} + +// PartitionByClause represents partition by clause. +type PartitionByClause struct { + node + + Items []*ByItem +} + +// Accept implements Node Accept interface. +func (n *PartitionByClause) Accept(v Visitor) (Node, bool) { + newNode, skipChildren := v.Enter(n) + if skipChildren { + return v.Leave(newNode) + } + n = newNode.(*PartitionByClause) + for i, val := range n.Items { + node, ok := val.Accept(v) + if !ok { + return n, false + } + n.Items[i] = node.(*ByItem) + } + return v.Leave(n) +} + +// FrameType is the type of window function frame. +type FrameType int + +// Window function frame types. +// MySQL only supports `ROWS` and `RANGES`. +const ( + Rows = iota + Ranges + Groups +) + +// FrameClause represents frame clause. +type FrameClause struct { + node + + Type FrameType + Extent FrameExtent +} + +// Accept implements Node Accept interface. +func (n *FrameClause) Accept(v Visitor) (Node, bool) { + newNode, skipChildren := v.Enter(n) + if skipChildren { + return v.Leave(newNode) + } + n = newNode.(*FrameClause) + node, ok := n.Extent.Start.Accept(v) + if !ok { + return n, false + } + n.Extent.Start = *node.(*FrameBound) + node, ok = n.Extent.End.Accept(v) + if !ok { + return n, false + } + n.Extent.End = *node.(*FrameBound) + return v.Leave(n) +} + +// FrameExtent represents frame extent. +type FrameExtent struct { + Start FrameBound + End FrameBound +} + +// FrameType is the type of window function frame bound. +type BoundType int + +// Frame bound types. +const ( + Following = iota + Preceding + CurrentRow +) + +// FrameBound represents frame bound. +type FrameBound struct { + node + + Type BoundType + UnBounded bool + Expr ExprNode + // `Unit` is used to indicate the units in which the `Expr` should be interpreted. + // For example: '2:30' MINUTE_SECOND. + Unit ExprNode +} + +// Accept implements Node Accept interface. +func (n *FrameBound) Accept(v Visitor) (Node, bool) { + newNode, skipChildren := v.Enter(n) + if skipChildren { + return v.Leave(newNode) + } + n = newNode.(*FrameBound) + if n.Expr != nil { + node, ok := n.Expr.Accept(v) + if !ok { + return n, false + } + n.Expr = node.(ExprNode) + } + if n.Unit != nil { + node, ok := n.Expr.Accept(v) + if !ok { + return n, false + } + n.Unit = node.(ExprNode) + } + return v.Leave(n) +} diff --git a/parser/ast/dml_test.go b/parser/ast/dml_test.go index 6553c3254b281..d703784886113 100644 --- a/parser/ast/dml_test.go +++ b/parser/ast/dml_test.go @@ -58,6 +58,10 @@ func (ts *testDMLSuite) TestDMLVisitorCover(c *C) { {&SelectStmt{}, 0, 0}, {&FieldList{}, 0, 0}, {&UnionSelectList{}, 0, 0}, + {&WindowSpec{}, 0, 0}, + {&PartitionByClause{}, 0, 0}, + {&FrameClause{}, 0, 0}, + {&FrameBound{}, 0, 0}, } for _, v := range stmts { diff --git a/parser/ast/functions.go b/parser/ast/functions.go index bf5edfd767c14..0fb862eb575c0 100644 --- a/parser/ast/functions.go +++ b/parser/ast/functions.go @@ -25,6 +25,7 @@ var ( _ FuncNode = &AggregateFuncExpr{} _ FuncNode = &FuncCallExpr{} _ FuncNode = &FuncCastExpr{} + _ FuncNode = &WindowFuncExpr{} ) // List scalar function names. @@ -522,3 +523,76 @@ func (n *AggregateFuncExpr) Accept(v Visitor) (Node, bool) { } return v.Leave(n) } + +const ( + // WindowFuncRowNumber is the name of row_number function. + WindowFuncRowNumber = "row_number" + // WindowFuncRank is the name of rank function. + WindowFuncRank = "rank" + // WindowFuncDenseRank is the name of dense_rank function. + WindowFuncDenseRank = "dense_rank" + // WindowFuncCumeDist is the name of cume_dist function. + WindowFuncCumeDist = "cume_dist" + // WindowFuncPercentRank is the name of percent_rank function. + WindowFuncPercentRank = "percent_rank" + // WindowFuncNtile is the name of ntile function. + WindowFuncNtile = "ntile" + // WindowFuncLead is the name of lead function. + WindowFuncLead = "lead" + // WindowFuncLag is the name of lag function. + WindowFuncLag = "lag" + // WindowFuncFirstValue is the name of first_value function. + WindowFuncFirstValue = "first_value" + // WindowFuncLastValue is the name of last_value function. + WindowFuncLastValue = "last_value" + // WindowFuncNthValue is the name of nth_value function. + WindowFuncNthValue = "nth_value" +) + +// WindowFuncExpr represents window function expression. +type WindowFuncExpr struct { + funcNode + + // F is the function name. + F string + // Args is the function args. + Args []ExprNode + // Distinct cannot be true for most window functions, except `max` and `min`. + // We need to raise error if it is not allowed to be true. + Distinct bool + // IgnoreNull indicates how to handle null value. + // MySQL only supports `RESPECT NULLS`, so we need to raise error if it is true. + IgnoreNull bool + // FromLast indicates the calculation direction of this window function. + // MySQL only supports calculation from first, so we need to raise error if it is true. + FromLast bool + // Spec is the specification of this window. + Spec WindowSpec +} + +// Format formats the window function expression into a Writer. +func (n *WindowFuncExpr) Format(w io.Writer) { + panic("Not implemented") +} + +// Accept implements Node Accept interface. +func (n *WindowFuncExpr) Accept(v Visitor) (Node, bool) { + newNode, skipChildren := v.Enter(n) + if skipChildren { + return v.Leave(newNode) + } + n = newNode.(*WindowFuncExpr) + for i, val := range n.Args { + node, ok := val.Accept(v) + if !ok { + return n, false + } + n.Args[i] = node.(ExprNode) + } + node, ok := n.Spec.Accept(v) + if !ok { + return n, false + } + n.Spec = *node.(*WindowSpec) + return v.Leave(n) +} diff --git a/parser/ast/functions_test.go b/parser/ast/functions_test.go index d07db759b337c..1586d71f4d12f 100644 --- a/parser/ast/functions_test.go +++ b/parser/ast/functions_test.go @@ -29,6 +29,7 @@ func (ts *testFunctionsSuite) TestFunctionsVisitorCover(c *C) { &AggregateFuncExpr{Args: []ExprNode{valueExpr}}, &FuncCallExpr{Args: []ExprNode{valueExpr}}, &FuncCastExpr{Expr: valueExpr}, + &WindowFuncExpr{Spec: WindowSpec{}}, } for _, stmt := range stmts { diff --git a/parser/parser.go b/parser/parser.go index 5012b607a296d..e5f3a675f5992 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -8849,8 +8849,7 @@ yynewstate: } case 637: { - // TODO: Remove this fake ast placeholder. - parser.yyVAL.expr = ast.NewParamMarkerExpr(yyS[yypt].offset) + parser.yyVAL.expr = yyS[yypt-0].item.(*ast.WindowFuncExpr) } case 639: { @@ -9248,31 +9247,59 @@ yynewstate: } case 755: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + } } case 756: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + } } case 757: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + } } case 758: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + } } case 759: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + } } case 760: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + } } case 761: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + } } case 762: { @@ -9280,16 +9307,28 @@ yynewstate: } case 763: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + } } case 764: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}} + } } case 765: { args := []ast.ExprNode{ast.NewValueExpr(1)} - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: args} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: args, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: args} + } } case 766: { @@ -9299,23 +9338,43 @@ yynewstate: } case 767: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + } } case 768: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + } } case 769: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + } } case 770: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: ast.AggFuncStddevPop, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + } } case 771: { - parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + if yyS[yypt-0].item != nil { + parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} + } else { + parser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)} + } } case 772: { @@ -9718,6 +9777,9 @@ yynewstate: if yyS[yypt-1].item != nil { st.Having = yyS[yypt-1].item.(*ast.HavingClause) } + if yyS[yypt-0].item != nil { + st.WindowSpecs = (yyS[yypt-0].item.([]ast.WindowSpec)) + } parser.yyVAL.item = st } case 847: @@ -9780,39 +9842,51 @@ yynewstate: } case 852: { - parser.yyVAL.item = nil + parser.yyVAL.item = yyS[yypt-0].item.([]ast.WindowSpec) } case 853: { - parser.yyVAL.item = nil + parser.yyVAL.item = []ast.WindowSpec{yyS[yypt-0].item.(ast.WindowSpec)} } case 854: { - parser.yyVAL.item = nil + parser.yyVAL.item = append(yyS[yypt-2].item.([]ast.WindowSpec), yyS[yypt-0].item.(ast.WindowSpec)) } case 855: { - parser.yyVAL.item = nil + var spec = yyS[yypt-0].item.(ast.WindowSpec) + spec.Name = yyS[yypt-2].item.(model.CIStr) + parser.yyVAL.item = spec } case 856: { - parser.yyVAL.item = nil + parser.yyVAL.item = model.NewCIStr(yyS[yypt-0].ident) } case 857: { - parser.yyVAL.item = nil + parser.yyVAL.item = yyS[yypt-1].item.(ast.WindowSpec) } case 858: { - parser.yyVAL.item = nil + spec := ast.WindowSpec{Ref: yyS[yypt-3].item.(model.CIStr)} + if yyS[yypt-2].item != nil { + spec.PartitionBy = yyS[yypt-2].item.(*ast.PartitionByClause) + } + if yyS[yypt-1].item != nil { + spec.OrderBy = yyS[yypt-1].item.(*ast.OrderByClause) + } + if yyS[yypt-0].item != nil { + spec.Frame = yyS[yypt-0].item.(*ast.FrameClause) + } + parser.yyVAL.item = spec } case 859: { - parser.yyVAL.item = nil + parser.yyVAL.item = model.CIStr{} } case 860: { - parser.yyVAL.item = nil + parser.yyVAL.item = yyS[yypt-0].item.(model.CIStr) } case 861: { @@ -9820,7 +9894,7 @@ yynewstate: } case 862: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.PartitionByClause{Items: yyS[yypt-0].item.([]*ast.ByItem)} } case 863: { @@ -9828,7 +9902,7 @@ yynewstate: } case 864: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.OrderByClause{Items: yyS[yypt-0].item.([]*ast.ByItem)} } case 865: { @@ -9836,71 +9910,77 @@ yynewstate: } case 866: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.FrameClause{ + Type: yyS[yypt-1].item.(ast.FrameType), + Extent: yyS[yypt-0].item.(ast.FrameExtent), + } } case 867: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameType(ast.Rows) } case 868: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameType(ast.Ranges) } case 869: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameType(ast.Groups) } case 870: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameExtent{ + Start: yyS[yypt-0].item.(ast.FrameBound), + End: ast.FrameBound{Type: ast.CurrentRow}, + } } case 871: { - parser.yyVAL.item = nil + parser.yyVAL.item = yyS[yypt-0].item.(ast.FrameExtent) } case 872: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, UnBounded: true} } case 873: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr(yyS[yypt-1].item)} } case 874: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr(yyS[yypt-1].item)} } case 875: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr(yyS[yypt-2].expr), Unit: ast.NewValueExpr(yyS[yypt-1].ident)} } case 876: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameBound{Type: ast.CurrentRow} } case 877: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameExtent{Start: yyS[yypt-2].item.(ast.FrameBound), End: yyS[yypt-0].item.(ast.FrameBound)} } case 878: { - parser.yyVAL.item = nil + parser.yyVAL.item = yyS[yypt-0].item.(ast.FrameBound) } case 879: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameBound{Type: ast.Following, UnBounded: true} } case 880: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr(yyS[yypt-1].item)} } case 881: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr(yyS[yypt-1].item)} } case 882: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr(yyS[yypt-2].expr), Unit: ast.NewValueExpr(yyS[yypt-1].ident)} } case 883: { @@ -9908,63 +9988,72 @@ yynewstate: } case 884: { - parser.yyVAL.item = nil + spec := yyS[yypt-0].item.(ast.WindowSpec) + parser.yyVAL.item = &spec } case 885: { - parser.yyVAL.item = nil + parser.yyVAL.item = yyS[yypt-0].item.(ast.WindowSpec) } case 886: { - parser.yyVAL.item = nil + parser.yyVAL.item = ast.WindowSpec{Ref: yyS[yypt-0].item.(model.CIStr)} } case 887: { - parser.yyVAL.item = nil + parser.yyVAL.item = yyS[yypt-0].item.(ast.WindowSpec) } case 888: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 889: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 890: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 891: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 892: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 893: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 894: { - parser.yyVAL.item = nil + args := []ast.ExprNode{yyS[yypt-4].expr} + if yyS[yypt-3].item != nil { + args = append(args, yyS[yypt-3].item.([]ast.ExprNode)...) + } + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-6].ident, Args: args, IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 895: { - parser.yyVAL.item = nil + args := []ast.ExprNode{yyS[yypt-4].expr} + if yyS[yypt-3].item != nil { + args = append(args, yyS[yypt-3].item.([]ast.ExprNode)...) + } + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-6].ident, Args: args, IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 896: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-3].expr}, IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 897: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-3].expr}, IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 898: { - parser.yyVAL.item = nil + parser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-8].ident, Args: []ast.ExprNode{yyS[yypt-6].expr, yyS[yypt-4].expr}, FromLast: yyS[yypt-2].item.(bool), IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)} } case 899: { @@ -9972,11 +10061,19 @@ yynewstate: } case 900: { - parser.yyVAL.item = nil + args := []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item)} + if yyS[yypt-0].item != nil { + args = append(args, yyS[yypt-0].item.(ast.ExprNode)) + } + parser.yyVAL.item = args } case 901: { - parser.yyVAL.item = nil + args := []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item)} + if yyS[yypt-0].item != nil { + args = append(args, yyS[yypt-0].item.(ast.ExprNode)) + } + parser.yyVAL.item = args } case 902: { @@ -9984,31 +10081,31 @@ yynewstate: } case 903: { - parser.yyVAL.item = nil + parser.yyVAL.item = yyS[yypt-0].expr } case 904: { - parser.yyVAL.item = nil + parser.yyVAL.item = false } case 905: { - parser.yyVAL.item = nil + parser.yyVAL.item = false } case 906: { - parser.yyVAL.item = nil + parser.yyVAL.item = true } case 907: { - parser.yyVAL.item = nil + parser.yyVAL.item = false } case 908: { - parser.yyVAL.item = nil + parser.yyVAL.item = false } case 909: { - parser.yyVAL.item = nil + parser.yyVAL.item = true } case 910: { diff --git a/parser/parser.y b/parser/parser.y index ef491bb943c7d..f06f33eddfaf2 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -3373,8 +3373,7 @@ SimpleExpr: } | WindowFuncCall { - // TODO: Remove this fake ast placeholder. - $$ = ast.NewParamMarkerExpr(yyS[yypt].offset) + $$ = $1.(*ast.WindowFuncExpr) } | Literal | paramMarker @@ -3857,31 +3856,59 @@ TrimDirection: SumExpr: "AVG" '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + } } | builtinBitAnd '(' Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3}} + if $5 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: *($5.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3},} + } } | builtinBitAnd '(' "ALL" Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4},} + } } | builtinBitOr '(' Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3}} + if $5 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: *($5.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3},} + } } | builtinBitOr '(' "ALL" Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4},} + } } | builtinBitXor '(' Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3}} + if $5 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: *($5.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3},} + } } | builtinBitXor '(' "ALL" Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4},} + } } | builtinCount '(' DistinctKwd ExpressionList ')' { @@ -3889,16 +3916,28 @@ SumExpr: } | builtinCount '(' "ALL" Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4},} + } } | builtinCount '(' Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3}} + if $5 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: *($5.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3},} + } } | builtinCount '(' '*' ')' OptWindowingClause { args := []ast.ExprNode{ast.NewValueExpr(1)} - $$ = &ast.AggregateFuncExpr{F: $1, Args: args} + if $5 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: args, Spec: *($5.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: args,} + } } | builtinGroupConcat '(' BuggyDefaultFalseDistinctOpt ExpressionList OrderByOptional OptGConcatSeparator ')' { @@ -3908,23 +3947,43 @@ SumExpr: } | builtinMax '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + } } | builtinMin '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + } } | builtinSum '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + } } | builtinStddevPop '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: ast.AggFuncStddevPop, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + } } | builtinStddevSamp '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause { - $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + if $6 != nil { + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec)),} + } else { + $$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)} + } } OptGConcatSeparator: @@ -4398,6 +4457,9 @@ SelectStmtFromTable: if $6 != nil { st.Having = $6.(*ast.HavingClause) } + if $7 != nil { + st.WindowSpecs = ($7.([]ast.WindowSpec)) + } $$ = st } @@ -4466,50 +4528,62 @@ WindowClauseOptional: } | "WINDOW" WindowDefinitionList { - $$ = nil + $$ = $2.([]ast.WindowSpec) } WindowDefinitionList: WindowDefinition { - $$ = nil + $$ = []ast.WindowSpec{$1.(ast.WindowSpec)} } | WindowDefinitionList ',' WindowDefinition { - $$ = nil + $$ = append($1.([]ast.WindowSpec), $3.(ast.WindowSpec)) } WindowDefinition: WindowName "AS" WindowSpec { - $$ = nil + var spec = $3.(ast.WindowSpec) + spec.Name = $1.(model.CIStr) + $$ = spec } WindowName: Identifier { - $$ = nil + $$ = model.NewCIStr($1) } WindowSpec: '(' WindowSpecDetails ')' { - $$ = nil + $$ = $2.(ast.WindowSpec) } WindowSpecDetails: OptExistingWindowName OptPartitionClause OptWindowOrderByClause OptWindowFrameClause { - $$ = nil + spec := ast.WindowSpec{Ref: $1.(model.CIStr),} + if $2 != nil { + spec.PartitionBy = $2.(*ast.PartitionByClause) + } + if $3 != nil { + spec.OrderBy = $3.(*ast.OrderByClause) + } + if $4 != nil { + spec.Frame = $4.(*ast.FrameClause) + } + $$ = spec } OptExistingWindowName: { - $$ = nil + $$ = model.CIStr{} } | WindowName { - $$ = nil + $$ = $1.(model.CIStr) } OptPartitionClause: @@ -4518,7 +4592,7 @@ OptPartitionClause: } | "PARTITION" "BY" ByList { - $$ = nil + $$ = &ast.PartitionByClause{Items: $3.([]*ast.ByItem)} } OptWindowOrderByClause: @@ -4527,7 +4601,7 @@ OptWindowOrderByClause: } | "ORDER" "BY" ByList { - $$ = nil + $$ = &ast.OrderByClause{Items: $3.([]*ast.ByItem)} } OptWindowFrameClause: @@ -4536,81 +4610,87 @@ OptWindowFrameClause: } | WindowFrameUnits WindowFrameExtent { - $$ = nil + $$ = &ast.FrameClause{ + Type: $1.(ast.FrameType), + Extent: $2.(ast.FrameExtent), + } } WindowFrameUnits: "ROWS" { - $$ = nil + $$ = ast.FrameType(ast.Rows) } | "RANGE" { - $$ = nil + $$ = ast.FrameType(ast.Ranges) } | "GROUPS" { - $$ = nil + $$ = ast.FrameType(ast.Groups) } WindowFrameExtent: WindowFrameStart { - $$ = nil + $$ = ast.FrameExtent { + Start: $1.(ast.FrameBound), + End: ast.FrameBound{Type: ast.CurrentRow,}, + } } | WindowFrameBetween { - $$ = nil + $$ = $1.(ast.FrameExtent) } WindowFrameStart: "UNBOUNDED" "PRECEDING" { - $$ = nil + $$ = ast.FrameBound{Type: ast.Preceding, UnBounded: true,} } | NumLiteral "PRECEDING" { - $$ = nil + $$ = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr($1),} } | paramMarker "PRECEDING" { - $$ = nil + $$ = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr($1),} } | "INTERVAL" Expression TimeUnit "PRECEDING" { - $$ = nil + $$ = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr($2), Unit: ast.NewValueExpr($3),} } | "CURRENT" "ROW" { - $$ = nil + $$ = ast.FrameBound{Type: ast.CurrentRow,} } WindowFrameBetween: "BETWEEN" WindowFrameBound "AND" WindowFrameBound { - $$ = nil + $$ = ast.FrameExtent{Start: $2.(ast.FrameBound), End: $4.(ast.FrameBound),} } WindowFrameBound: WindowFrameStart { - $$ = nil + $$ = $1.(ast.FrameBound) } | "UNBOUNDED" "FOLLOWING" { - $$ = nil + $$ = ast.FrameBound{Type: ast.Following, UnBounded: true,} } | NumLiteral "FOLLOWING" { - $$ = nil + $$ = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr($1),} } | paramMarker "FOLLOWING" { - $$ = nil + $$ = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr($1),} } | "INTERVAL" Expression TimeUnit "FOLLOWING" { - $$ = nil + $$ = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr($2), Unit: ast.NewValueExpr($3),} } OptWindowingClause: @@ -4619,69 +4699,78 @@ OptWindowingClause: } | WindowingClause { - $$ = nil + spec := $1.(ast.WindowSpec) + $$ = &spec } WindowingClause: "OVER" WindowNameOrSpec { - $$ = nil + $$ = $2.(ast.WindowSpec) } WindowNameOrSpec: WindowName { - $$ = nil + $$ = ast.WindowSpec{Ref: $1.(model.CIStr)} } | WindowSpec { - $$ = nil + $$ = $1.(ast.WindowSpec) } WindowFuncCall: "ROW_NUMBER" '(' ')' WindowingClause { - $$ = nil + $$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec),} } | "RANK" '(' ')' WindowingClause { - $$ = nil + $$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec),} } | "DENSE_RANK" '(' ')' WindowingClause { - $$ = nil + $$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec),} } | "CUME_DIST" '(' ')' WindowingClause { - $$ = nil + $$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec),} } | "PERCENT_RANK" '(' ')' WindowingClause { - $$ = nil + $$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec),} } | "NTILE" '(' SimpleExpr ')' WindowingClause { - $$ = nil + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: $5.(ast.WindowSpec),} } | "LEAD" '(' Expression OptLeadLagInfo ')' OptNullTreatment WindowingClause { - $$ = nil + args := []ast.ExprNode{$3} + if $4 != nil { + args = append(args, $4.([]ast.ExprNode)...) + } + $$ = &ast.WindowFuncExpr{F: $1, Args: args, IgnoreNull: $6.(bool), Spec: $7.(ast.WindowSpec),} } | "LAG" '(' Expression OptLeadLagInfo ')' OptNullTreatment WindowingClause { - $$ = nil + args := []ast.ExprNode{$3} + if $4 != nil { + args = append(args, $4.([]ast.ExprNode)...) + } + $$ = &ast.WindowFuncExpr{F: $1, Args: args, IgnoreNull: $6.(bool), Spec: $7.(ast.WindowSpec),} } | "FIRST_VALUE" '(' Expression ')' OptNullTreatment WindowingClause { - $$ = nil + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, IgnoreNull: $5.(bool), Spec: $6.(ast.WindowSpec),} } | "LAST_VALUE" '(' Expression ')' OptNullTreatment WindowingClause { - $$ = nil + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, IgnoreNull: $5.(bool), Spec: $6.(ast.WindowSpec),} } | "NTH_VALUE" '(' Expression ',' SimpleExpr ')' OptFromFirstLast OptNullTreatment WindowingClause { - $$ = nil + $$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3, $5}, FromLast: $7.(bool), IgnoreNull: $8.(bool), Spec: $9.(ast.WindowSpec),} } OptLeadLagInfo: @@ -4690,11 +4779,19 @@ OptLeadLagInfo: } | ',' NumLiteral OptLLDefault { - $$ = nil + args := []ast.ExprNode{ast.NewValueExpr($2)} + if $3 != nil { + args = append(args, $3.(ast.ExprNode)) + } + $$ = args } | ',' paramMarker OptLLDefault { - $$ = nil + args := []ast.ExprNode{ast.NewValueExpr($2)} + if $3 != nil { + args = append(args, $3.(ast.ExprNode)) + } + $$ = args } OptLLDefault: @@ -4703,33 +4800,33 @@ OptLLDefault: } | ',' Expression { - $$ = nil + $$ = $2 } OptNullTreatment: { - $$ = nil + $$ = false } | "RESPECT" "NULLS" { - $$ = nil + $$ = false } | "IGNORE" "NULLS" { - $$ = nil + $$ = true } OptFromFirstLast: { - $$ = nil + $$ = false } | "FROM" "FIRST" { - $$ = nil + $$ = false } | "FROM" "LAST" { - $$ = nil + $$ = true } TableRefsClause: