Skip to content

Commit 42bb6d5

Browse files
authored
Add support of parsing ADD PROJECTION statement (#61)
1 parent 0d9ca44 commit 42bb6d5

File tree

6 files changed

+422
-1
lines changed

6 files changed

+422
-1
lines changed

parser/ast.go

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,178 @@ func (a *AlterTableAddIndex) Accept(visitor ASTVisitor) error {
493493
return visitor.VisitAlterTableAddIndex(a)
494494
}
495495

496+
type ProjectionOrderBy struct {
497+
OrderByPos Pos
498+
Columns *ColumnExprList
499+
}
500+
501+
func (p *ProjectionOrderBy) Pos() Pos {
502+
return p.OrderByPos
503+
}
504+
505+
func (p *ProjectionOrderBy) End() Pos {
506+
return p.Columns.End()
507+
}
508+
509+
func (p *ProjectionOrderBy) String(level int) string {
510+
var builder strings.Builder
511+
builder.WriteString("ORDER BY ")
512+
builder.WriteString(p.Columns.String(level))
513+
return builder.String()
514+
}
515+
516+
func (p *ProjectionOrderBy) Accept(visitor ASTVisitor) error {
517+
visitor.enter(p)
518+
defer visitor.leave(p)
519+
return visitor.VisitProjectionOrderBy(p)
520+
}
521+
522+
type ProjectionSelect struct {
523+
LeftParenPos Pos
524+
RightParenPos Pos
525+
With *WithExpr
526+
SelectColumns *ColumnExprList
527+
GroupBy *GroupByExpr
528+
OrderBy *ProjectionOrderBy
529+
}
530+
531+
func (p *ProjectionSelect) Pos() Pos {
532+
return p.LeftParenPos
533+
534+
}
535+
536+
func (p *ProjectionSelect) End() Pos {
537+
return p.RightParenPos
538+
}
539+
540+
func (p *ProjectionSelect) String(level int) string {
541+
var builder strings.Builder
542+
builder.WriteString("(")
543+
if p.With != nil {
544+
builder.WriteString(p.With.String(level))
545+
builder.WriteByte(' ')
546+
}
547+
builder.WriteString("SELECT ")
548+
builder.WriteString(p.SelectColumns.String(level))
549+
if p.GroupBy != nil {
550+
builder.WriteString(" ")
551+
builder.WriteString(p.GroupBy.String(level))
552+
}
553+
if p.OrderBy != nil {
554+
builder.WriteString(" ")
555+
builder.WriteString(p.OrderBy.String(level))
556+
}
557+
builder.WriteString(")")
558+
return builder.String()
559+
}
560+
561+
func (p *ProjectionSelect) Accept(visitor ASTVisitor) error {
562+
visitor.enter(p)
563+
defer visitor.leave(p)
564+
if p.With != nil {
565+
if err := p.With.Accept(visitor); err != nil {
566+
return err
567+
}
568+
}
569+
if err := p.SelectColumns.Accept(visitor); err != nil {
570+
return err
571+
}
572+
if p.GroupBy != nil {
573+
if err := p.GroupBy.Accept(visitor); err != nil {
574+
return err
575+
}
576+
}
577+
if p.OrderBy != nil {
578+
if err := p.OrderBy.Accept(visitor); err != nil {
579+
return err
580+
}
581+
}
582+
return visitor.VisitProjectionSelect(p)
583+
}
584+
585+
type TableProjection struct {
586+
ProjectionPos Pos
587+
Identifier *NestedIdentifier
588+
Select *ProjectionSelect
589+
}
590+
591+
func (t *TableProjection) Pos() Pos {
592+
return t.ProjectionPos
593+
}
594+
595+
func (t *TableProjection) End() Pos {
596+
return t.Select.End()
597+
}
598+
599+
func (t *TableProjection) String(level int) string {
600+
var builder strings.Builder
601+
builder.WriteString(t.Identifier.String(level))
602+
builder.WriteString(" ")
603+
builder.WriteString(t.Select.String(level))
604+
return builder.String()
605+
}
606+
607+
func (t *TableProjection) Accept(visitor ASTVisitor) error {
608+
visitor.enter(t)
609+
defer visitor.leave(t)
610+
if err := t.Identifier.Accept(visitor); err != nil {
611+
return err
612+
}
613+
if err := t.Select.Accept(visitor); err != nil {
614+
return err
615+
}
616+
return visitor.VisitTableProjection(t)
617+
}
618+
619+
type AlterTableAddProjection struct {
620+
AddPos Pos
621+
StatementEnd Pos
622+
623+
IfNotExists bool
624+
TableProjection *TableProjection
625+
After *NestedIdentifier
626+
}
627+
628+
func (a *AlterTableAddProjection) Pos() Pos {
629+
return a.AddPos
630+
}
631+
632+
func (a *AlterTableAddProjection) End() Pos {
633+
return a.StatementEnd
634+
}
635+
636+
func (a *AlterTableAddProjection) AlterType() string {
637+
return "ADD_PROJECTION"
638+
}
639+
640+
func (a *AlterTableAddProjection) String(level int) string {
641+
var builder strings.Builder
642+
builder.WriteString("ADD PROJECTION ")
643+
if a.IfNotExists {
644+
builder.WriteString("IF NOT EXISTS ")
645+
}
646+
builder.WriteString(a.TableProjection.String(level))
647+
if a.After != nil {
648+
builder.WriteString(" AFTER ")
649+
builder.WriteString(a.After.String(level))
650+
}
651+
return builder.String()
652+
}
653+
654+
func (a *AlterTableAddProjection) Accept(visitor ASTVisitor) error {
655+
visitor.enter(a)
656+
defer visitor.leave(a)
657+
if err := a.TableProjection.Accept(visitor); err != nil {
658+
return err
659+
}
660+
if a.After != nil {
661+
if err := a.After.Accept(visitor); err != nil {
662+
return err
663+
}
664+
}
665+
return visitor.VisitAlterTableAddProjection(a)
666+
}
667+
496668
type AlterTableDropColumn struct {
497669
DropPos Pos
498670
ColumnName *NestedIdentifier

parser/ast_visitor.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ type ASTVisitor interface {
1111
VisitAlterTableFreezePartition(expr *AlterTableFreezePartition) error
1212
VisitAlterTableAddColumn(expr *AlterTableAddColumn) error
1313
VisitAlterTableAddIndex(expr *AlterTableAddIndex) error
14+
VisitAlterTableAddProjection(expr *AlterTableAddProjection) error
15+
VisitTableProjection(expr *TableProjection) error
16+
VisitProjectionOrderBy(expr *ProjectionOrderBy) error
17+
VisitProjectionSelect(expr *ProjectionSelect) error
1418
VisitAlterTableDropColumn(expr *AlterTableDropColumn) error
1519
VisitAlterTableDropIndex(expr *AlterTableDropIndex) error
1620
VisitAlterTableRemoveTTL(expr *AlterTableRemoveTTL) error
@@ -232,6 +236,34 @@ func (v *DefaultASTVisitor) VisitAlterTableAddIndex(expr *AlterTableAddIndex) er
232236
return nil
233237
}
234238

239+
func (v *DefaultASTVisitor) VisitAlterTableAddProjection(expr *AlterTableAddProjection) error {
240+
if v.Visit != nil {
241+
return v.Visit(expr)
242+
}
243+
return nil
244+
}
245+
246+
func (v *DefaultASTVisitor) VisitProjectionOrderBy(expr *ProjectionOrderBy) error {
247+
if v.Visit != nil {
248+
return v.Visit(expr)
249+
}
250+
return nil
251+
}
252+
253+
func (v *DefaultASTVisitor) VisitProjectionSelect(expr *ProjectionSelect) error {
254+
if v.Visit != nil {
255+
return v.Visit(expr)
256+
}
257+
return nil
258+
}
259+
260+
func (v *DefaultASTVisitor) VisitTableProjection(expr *TableProjection) error {
261+
if v.Visit != nil {
262+
return v.Visit(expr)
263+
}
264+
return nil
265+
}
266+
235267
func (v *DefaultASTVisitor) VisitAlterTableDropColumn(expr *AlterTableDropColumn) error {
236268
if v.Visit != nil {
237269
return v.Visit(expr)

parser/parser_alter.go

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,10 @@ func (p *Parser) parseAlterTableAdd(pos Pos) (AlterTableExpr, error) {
7979
return p.parseAlterTableAddColumn(pos)
8080
case p.matchKeyword(KeywordIndex):
8181
return p.parseAlterTableAddIndex(pos)
82+
case p.matchKeyword(KeywordProjection):
83+
return p.parseAlterTableAddProjection(pos)
8284
default:
83-
return nil, errors.New("expected token: COLUMN|INDEX")
85+
return nil, errors.New("expected token: COLUMN|INDEX|PROJECTION")
8486
}
8587
}
8688

@@ -148,6 +150,106 @@ func (p *Parser) parseAlterTableAddIndex(pos Pos) (*AlterTableAddIndex, error) {
148150
}, nil
149151
}
150152

153+
func (p *Parser) parseProjectionOrderBy(pos Pos) (*ProjectionOrderBy, error) {
154+
if err := p.consumeKeyword(KeywordOrder); err != nil {
155+
return nil, err
156+
}
157+
if err := p.consumeKeyword(KeywordBy); err != nil {
158+
return nil, err
159+
}
160+
columns, err := p.parseColumnExprList(p.Pos())
161+
if err != nil {
162+
return nil, err
163+
}
164+
return &ProjectionOrderBy{
165+
OrderByPos: pos,
166+
Columns: columns,
167+
}, nil
168+
}
169+
170+
func (p *Parser) parseProjectionSelect(pos Pos) (*ProjectionSelect, error) {
171+
if _, err := p.consumeTokenKind("("); err != nil {
172+
return nil, err
173+
}
174+
withExpr, err := p.tryParseWithExpr(p.Pos())
175+
if err != nil {
176+
return nil, err
177+
}
178+
if err := p.consumeKeyword(KeywordSelect); err != nil {
179+
return nil, err
180+
}
181+
columns, err := p.parseColumnExprList(p.Pos())
182+
if err != nil {
183+
return nil, err
184+
}
185+
groupBy, err := p.tryParseGroupByExpr(p.Pos())
186+
if err != nil {
187+
return nil, err
188+
}
189+
orderBy, err := p.parseProjectionOrderBy(p.Pos())
190+
if err != nil {
191+
return nil, err
192+
}
193+
rightParen, err := p.consumeTokenKind(")")
194+
if err != nil {
195+
return nil, err
196+
}
197+
return &ProjectionSelect{
198+
LeftParenPos: pos,
199+
RightParenPos: rightParen.Pos,
200+
With: withExpr,
201+
SelectColumns: columns,
202+
GroupBy: groupBy,
203+
OrderBy: orderBy,
204+
}, nil
205+
}
206+
207+
func (p *Parser) parseTableProjection(pos Pos) (*TableProjection, error) {
208+
identifier, err := p.ParseNestedIdentifier(pos)
209+
if err != nil {
210+
return nil, err
211+
}
212+
selectExpr, err := p.parseProjectionSelect(p.Pos())
213+
if err != nil {
214+
return nil, err
215+
}
216+
return &TableProjection{
217+
ProjectionPos: pos,
218+
Identifier: identifier,
219+
Select: selectExpr,
220+
}, nil
221+
}
222+
223+
func (p *Parser) parseAlterTableAddProjection(pos Pos) (*AlterTableAddProjection, error) {
224+
if err := p.consumeKeyword(KeywordProjection); err != nil {
225+
return nil, err
226+
}
227+
228+
ifNotExists, err := p.tryParseIfNotExists()
229+
if err != nil {
230+
return nil, err
231+
}
232+
tableProjection, err := p.parseTableProjection(p.Pos())
233+
if err != nil {
234+
return nil, err
235+
}
236+
statementEnd := tableProjection.End()
237+
after, err := p.tryParseAfterClause()
238+
if err != nil {
239+
return nil, err
240+
}
241+
if after != nil {
242+
statementEnd = after.End()
243+
}
244+
return &AlterTableAddProjection{
245+
AddPos: pos,
246+
StatementEnd: statementEnd,
247+
IfNotExists: ifNotExists,
248+
TableProjection: tableProjection,
249+
After: after,
250+
}, nil
251+
}
252+
151253
func (p *Parser) parseTableIndex(pos Pos) (*TableIndex, error) {
152254
name, err := p.ParseNestedIdentifier(p.Pos())
153255
if err != nil {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ALTER TABLE visits_order
2+
ADD PROJECTION IF NOT EXISTS user_name_projection
3+
(SELECT * GROUP BY user_name ORDER BY user_name) AFTER a.user_id;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- Origin SQL:
2+
ALTER TABLE visits_order
3+
ADD PROJECTION IF NOT EXISTS user_name_projection
4+
(SELECT * GROUP BY user_name ORDER BY user_name) AFTER a.user_id;
5+
6+
7+
-- Format SQL:
8+
ALTER TABLE visits_order
9+
ADD PROJECTION IF NOT EXISTS user_name_projection (SELECT * GROUP BY user_name ORDER BY user_name) AFTER a.user_id;

0 commit comments

Comments
 (0)