Skip to content

Commit

Permalink
Add the support of OPTIMIZE expression
Browse files Browse the repository at this point in the history
  • Loading branch information
git-hulk committed Sep 25, 2023
1 parent ab2211d commit 1ad6389
Show file tree
Hide file tree
Showing 7 changed files with 578 additions and 0 deletions.
72 changes: 72 additions & 0 deletions parser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -3049,6 +3049,78 @@ func (f *FormatExpr) String(level int) string {
return "FORMAT " + f.Format.String(level)
}

type OptimizeExpr struct {
OptimizePos Pos
StatementEnd Pos
Table *TableIdentifier
OnCluster *OnClusterExpr
Partition *PartitionExpr
HasFinal bool
Deduplicate *DeduplicateExpr
}

func (o *OptimizeExpr) Pos() Pos {
return o.OptimizePos
}

func (o *OptimizeExpr) End() Pos {
return o.StatementEnd
}

func (o *OptimizeExpr) String(level int) string {
var builder strings.Builder
builder.WriteString("OPTIMIZE TABLE ")
builder.WriteString(o.Table.String(level))
if o.OnCluster != nil {
builder.WriteString(NewLine(level))
builder.WriteString(o.OnCluster.String(level))
}
if o.Partition != nil {
builder.WriteString(NewLine(level))
builder.WriteString(o.Partition.String(level))
}
if o.HasFinal {
builder.WriteString(" FINAL")
}
if o.Deduplicate != nil {
builder.WriteString(o.Deduplicate.String(level))
}
return builder.String()
}

type DeduplicateExpr struct {
DeduplicatePos Pos
By *ColumnExprList
Except *ColumnExprList
}

func (d *DeduplicateExpr) Pos() Pos {
return d.DeduplicatePos
}

func (d *DeduplicateExpr) End() Pos {
if d.By != nil {
return d.By.End()
} else if d.Except != nil {
return d.Except.End()
}
return d.DeduplicatePos + Pos(len(KeywordDeduplicate))
}

func (d *DeduplicateExpr) String(level int) string {
var builder strings.Builder
builder.WriteString(" DEDUPLICATE")
if d.By != nil {
builder.WriteString(" BY ")
builder.WriteString(d.By.String(level))
}
if d.Except != nil {
builder.WriteString(" EXCEPT ")
builder.WriteString(d.Except.String(level))
}
return builder.String()
}

type SystemExpr struct {
SystemPos Pos
Expr Expr
Expand Down
2 changes: 2 additions & 0 deletions parser/keyword.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const (
KeywordEnd = "END"
KeywordEngine = "ENGINE"
KeywordEvents = "EVENTS"
KeywordExcept = "EXCEPT"
KeywordExists = "EXISTS"
KeywordExplain = "EXPLAIN"
KeywordExpression = "EXPRESSION"
Expand Down Expand Up @@ -261,6 +262,7 @@ var keywords = NewSet(
KeywordEnd,
KeywordEngine,
KeywordEvents,
KeywordExcept,
KeywordExists,
KeywordExplain,
KeywordExpression,
Expand Down
84 changes: 84 additions & 0 deletions parser/parse_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,90 @@ func (p *Parser) parseSystemDropExpr(pos Pos) (*SystemDropExpr, error) {
}
}

func (p *Parser) tryParseDeduplicateExpr(pos Pos) (*DeduplicateExpr, error) {
if !p.matchKeyword(KeywordDeduplicate) {
return nil, nil
}
return p.parseDeduplicateExpr(pos)
}

func (p *Parser) parseDeduplicateExpr(pos Pos) (*DeduplicateExpr, error) {
if err := p.consumeKeyword(KeywordDeduplicate); err != nil {
return nil, err
}
if p.tryConsumeKeyword(KeywordBy) == nil {
return &DeduplicateExpr{
DeduplicatePos: pos,
}, nil
}

by, err := p.parseColumnExprList(p.Pos())
if err != nil {
return nil, err
}
var except *ColumnExprList
if p.tryConsumeKeyword(KeywordExcept) != nil {
except, err = p.parseColumnExprList(p.Pos())
if err != nil {
return nil, err
}
}
return &DeduplicateExpr{
DeduplicatePos: pos,
By: by,
Except: except,
}, nil
}

func (p *Parser) parseOptimizeExpr(pos Pos) (*OptimizeExpr, error) {
if err := p.consumeKeyword(KeywordOptimize); err != nil {
return nil, err
}
if err := p.consumeKeyword(KeywordTable); err != nil {
return nil, err
}
table, err := p.parseTableIdentifier(p.Pos())
if err != nil {
return nil, err
}
statmentEnd := table.End()
onCluster, err := p.tryParseOnCluster(p.Pos())
if err != nil {
return nil, err
}
if onCluster != nil {
statmentEnd = onCluster.End()
}
partitionExpr, err := p.tryParsePartitionExpr(p.Pos())
if err != nil {
return nil, err
}
if partitionExpr != nil {
statmentEnd = partitionExpr.End()
}

hasFinal := false
lastPos := p.Pos()
if p.tryConsumeKeyword(KeywordFinal) != nil {
hasFinal = true
statmentEnd = lastPos
}
deduplicate, err := p.tryParseDeduplicateExpr(p.Pos())
if err != nil {
return nil, err
}

return &OptimizeExpr{
OptimizePos: pos,
StatementEnd: statmentEnd,
Table: table,
OnCluster: onCluster,
Partition: partitionExpr,
HasFinal: hasFinal,
Deduplicate: deduplicate,
}, nil
}

func (p *Parser) parseSystemExpr(pos Pos) (*SystemExpr, error) {
if err := p.consumeKeyword(KeywordSystem); err != nil {
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions parser/parser_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,8 @@ func (p *Parser) parseStatement(pos Pos) (Expr, error) {
expr, err = p.parseSetExpr(pos)
case p.matchKeyword(KeywordSystem):
expr, err = p.parseSystemExpr(pos)
case p.matchKeyword(KeywordOptimize):
expr, err = p.parseOptimizeExpr(pos)
default:
return nil, fmt.Errorf("unexpected token: %q", p.last().String)
}
Expand Down
19 changes: 19 additions & 0 deletions parser/testdata/ddl/format/optimize.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-- Origin SQL:
OPTIMIZE TABLE table DEDUPLICATE; -- all columns
OPTIMIZE TABLE table DEDUPLICATE BY *; -- excludes MATERIALIZED and ALIAS columns
OPTIMIZE TABLE table DEDUPLICATE BY colX,colY,colZ;
OPTIMIZE TABLE table DEDUPLICATE BY * EXCEPT colX;
OPTIMIZE TABLE table DEDUPLICATE BY * EXCEPT (colX, colY);
OPTIMIZE TABLE table DEDUPLICATE BY COLUMNS('column-matched-by-regex');
OPTIMIZE TABLE table DEDUPLICATE BY COLUMNS('column-matched-by-regex') EXCEPT colX;
OPTIMIZE TABLE table DEDUPLICATE BY COLUMNS('column-matched-by-regex') EXCEPT (colX, colY);

-- Format SQL:
OPTIMIZE TABLE table DEDUPLICATE;
OPTIMIZE TABLE table DEDUPLICATE BY *;
OPTIMIZE TABLE table DEDUPLICATE BY colX, colY, colZ;
OPTIMIZE TABLE table DEDUPLICATE BY * EXCEPT colX;
OPTIMIZE TABLE table DEDUPLICATE BY * EXCEPT (colX, colY);
OPTIMIZE TABLE table DEDUPLICATE BY COLUMNS('column-matched-by-regex');
OPTIMIZE TABLE table DEDUPLICATE BY COLUMNS('column-matched-by-regex') EXCEPT colX;
OPTIMIZE TABLE table DEDUPLICATE BY COLUMNS('column-matched-by-regex') EXCEPT (colX, colY);
8 changes: 8 additions & 0 deletions parser/testdata/ddl/optimize.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
OPTIMIZE TABLE table DEDUPLICATE; -- all columns
OPTIMIZE TABLE table DEDUPLICATE BY *; -- excludes MATERIALIZED and ALIAS columns
OPTIMIZE TABLE table DEDUPLICATE BY colX,colY,colZ;
OPTIMIZE TABLE table DEDUPLICATE BY * EXCEPT colX;
OPTIMIZE TABLE table DEDUPLICATE BY * EXCEPT (colX, colY);
OPTIMIZE TABLE table DEDUPLICATE BY COLUMNS('column-matched-by-regex');
OPTIMIZE TABLE table DEDUPLICATE BY COLUMNS('column-matched-by-regex') EXCEPT colX;
OPTIMIZE TABLE table DEDUPLICATE BY COLUMNS('column-matched-by-regex') EXCEPT (colX, colY);
Loading

0 comments on commit 1ad6389

Please sign in to comment.