Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions parser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1442,6 +1442,121 @@ func (a *AlterTableReplacePartition) Accept(visitor ASTVisitor) error {
return visitor.VisitAlterTableReplacePartition(a)
}

type AlterTableDelete struct {
DeletePos Pos
StatementEnd Pos
WhereClause Expr
}

func (a *AlterTableDelete) Pos() Pos {
return a.DeletePos
}

func (a *AlterTableDelete) End() Pos {
return a.StatementEnd
}

func (a *AlterTableDelete) AlterType() string {
return "DELETE"
}

func (a *AlterTableDelete) String() string {
var builder strings.Builder
builder.WriteString("DELETE WHERE ")
builder.WriteString(a.WhereClause.String())
return builder.String()
}

func (a *AlterTableDelete) Accept(visitor ASTVisitor) error {
visitor.Enter(a)
defer visitor.Leave(a)
if err := a.WhereClause.Accept(visitor); err != nil {
return err
}
return visitor.VisitAlterTableDelete(a)
}

type AlterTableUpdate struct {
UpdatePos Pos
StatementEnd Pos
Assignments []*UpdateAssignment
WhereClause Expr
}

func (a *AlterTableUpdate) Pos() Pos {
return a.UpdatePos
}

func (a *AlterTableUpdate) End() Pos {
return a.StatementEnd
}

func (a *AlterTableUpdate) AlterType() string {
return "UPDATE"
}

func (a *AlterTableUpdate) String() string {
var builder strings.Builder
builder.WriteString("UPDATE ")
for i, assignment := range a.Assignments {
if i > 0 {
builder.WriteString(", ")
}
builder.WriteString(assignment.String())
}
builder.WriteString(" WHERE ")
builder.WriteString(a.WhereClause.String())
return builder.String()
}

func (a *AlterTableUpdate) Accept(visitor ASTVisitor) error {
visitor.Enter(a)
defer visitor.Leave(a)
for _, assignment := range a.Assignments {
if err := assignment.Accept(visitor); err != nil {
return err
}
}
if err := a.WhereClause.Accept(visitor); err != nil {
return err
}
return visitor.VisitAlterTableUpdate(a)
}

type UpdateAssignment struct {
AssignmentPos Pos
Column *NestedIdentifier
Expr Expr
}

func (u *UpdateAssignment) Pos() Pos {
return u.AssignmentPos
}

func (u *UpdateAssignment) End() Pos {
return u.Expr.End()
}

func (u *UpdateAssignment) String() string {
var builder strings.Builder
builder.WriteString(u.Column.String())
builder.WriteString(" = ")
builder.WriteString(u.Expr.String())
return builder.String()
}

func (u *UpdateAssignment) Accept(visitor ASTVisitor) error {
visitor.Enter(u)
defer visitor.Leave(u)
if err := u.Column.Accept(visitor); err != nil {
return err
}
if err := u.Expr.Accept(visitor); err != nil {
return err
}
return visitor.VisitUpdateAssignment(u)
}

type RemovePropertyType struct {
RemovePos Pos

Expand Down
24 changes: 24 additions & 0 deletions parser/ast_visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ type ASTVisitor interface {
VisitAlterTableModifySetting(expr *AlterTableModifySetting) error
VisitAlterTableResetSetting(expr *AlterTableResetSetting) error
VisitAlterTableReplacePartition(expr *AlterTableReplacePartition) error
VisitAlterTableDelete(expr *AlterTableDelete) error
VisitAlterTableUpdate(expr *AlterTableUpdate) error
VisitUpdateAssignment(expr *UpdateAssignment) error
VisitRemovePropertyType(expr *RemovePropertyType) error
VisitTableIndex(expr *TableIndex) error
VisitIdent(expr *Ident) error
Expand Down Expand Up @@ -420,6 +423,27 @@ func (v *DefaultASTVisitor) VisitAlterTableReplacePartition(expr *AlterTableRepl
return nil
}

func (v *DefaultASTVisitor) VisitAlterTableDelete(expr *AlterTableDelete) error {
if v.Visit != nil {
return v.Visit(expr)
}
return nil
}

func (v *DefaultASTVisitor) VisitAlterTableUpdate(expr *AlterTableUpdate) error {
if v.Visit != nil {
return v.Visit(expr)
}
return nil
}

func (v *DefaultASTVisitor) VisitUpdateAssignment(expr *UpdateAssignment) error {
if v.Visit != nil {
return v.Visit(expr)
}
return nil
}

func (v *DefaultASTVisitor) VisitRemovePropertyType(expr *RemovePropertyType) error {
if v.Visit != nil {
return v.Visit(expr)
Expand Down
91 changes: 90 additions & 1 deletion parser/parser_alter.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ func (p *Parser) parseAlterTable(pos Pos) (*AlterTable, error) {
alter, err = p.parseAlterTableMaterialize(p.Pos())
case p.matchKeyword(KeywordReset):
alter, err = p.parseAlterTableReset(p.Pos())
case p.matchKeyword(KeywordDelete):
alter, err = p.parseAlterTableDelete(p.Pos())
case p.matchKeyword(KeywordUpdate):
alter, err = p.parseAlterTableUpdate(p.Pos())
default:
return nil, errors.New("expected token: ADD|DROP|ATTACH|DETACH|FREEZE|REMOVE|CLEAR|MODIFY|REPLACE|MATERIALIZE|RESET")
return nil, errors.New("expected token: ADD|DROP|ATTACH|DETACH|FREEZE|REMOVE|CLEAR|MODIFY|REPLACE|MATERIALIZE|RESET|DELETE|UPDATE")
}
if err != nil {
return nil, err
Expand Down Expand Up @@ -833,3 +837,88 @@ func (p *Parser) parseAlterTableReset(pos Pos) (AlterTableClause, error) {
Settings: settings,
}, nil
}

// Syntax: ALTER TABLE DELETE WHERE condition
func (p *Parser) parseAlterTableDelete(pos Pos) (AlterTableClause, error) {
if err := p.expectKeyword(KeywordDelete); err != nil {
return nil, err
}

if err := p.expectKeyword(KeywordWhere); err != nil {
return nil, err
}

whereExpr, err := p.parseExpr(p.Pos())
if err != nil {
return nil, err
}

return &AlterTableDelete{
DeletePos: pos,
StatementEnd: whereExpr.End(),
WhereClause: whereExpr,
}, nil
}

// Syntax: ALTER TABLE UPDATE column1 = expr1 [, column2 = expr2, ...] WHERE condition
func (p *Parser) parseAlterTableUpdate(pos Pos) (AlterTableClause, error) {
if err := p.expectKeyword(KeywordUpdate); err != nil {
return nil, err
}

// Parse at least one assignment
assignments := make([]*UpdateAssignment, 0)
assignment, err := p.parseUpdateAssignment(p.Pos())
if err != nil {
return nil, err
}
assignments = append(assignments, assignment)

// Parse additional comma-separated assignments
for p.tryConsumeTokenKind(TokenKindComma) != nil {
assignment, err = p.parseUpdateAssignment(p.Pos())
if err != nil {
return nil, err
}
assignments = append(assignments, assignment)
}

if err := p.expectKeyword(KeywordWhere); err != nil {
return nil, err
}

whereExpr, err := p.parseExpr(p.Pos())
if err != nil {
return nil, err
}

return &AlterTableUpdate{
UpdatePos: pos,
StatementEnd: whereExpr.End(),
Assignments: assignments,
WhereClause: whereExpr,
}, nil
}

// Parse column = expression assignment
func (p *Parser) parseUpdateAssignment(pos Pos) (*UpdateAssignment, error) {
column, err := p.ParseNestedIdentifier(p.Pos())
if err != nil {
return nil, err
}

if err := p.expectTokenKind(TokenKindSingleEQ); err != nil {
return nil, err
}

expr, err := p.parseExpr(p.Pos())
if err != nil {
return nil, err
}

return &UpdateAssignment{
AssignmentPos: pos,
Column: column,
Expr: expr,
}, nil
}
1 change: 1 addition & 0 deletions parser/testdata/ddl/alter_table_delete.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE test.events DELETE WHERE created_at < '2023-01-01';
1 change: 1 addition & 0 deletions parser/testdata/ddl/alter_table_delete_with_cluster.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE test.events ON CLUSTER 'default_cluster' DELETE WHERE id = 123 AND status = 'deleted';
1 change: 1 addition & 0 deletions parser/testdata/ddl/alter_table_update.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE test.users UPDATE status = 'active', updated_at = now() WHERE status = 'pending';
1 change: 1 addition & 0 deletions parser/testdata/ddl/alter_table_update_with_cluster.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE db.table ON CLUSTER cluster1 UPDATE column1 = column1 + 1 WHERE id > 100;
6 changes: 6 additions & 0 deletions parser/testdata/ddl/format/alter_table_delete.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Origin SQL:
ALTER TABLE test.events DELETE WHERE created_at < '2023-01-01';


-- Format SQL:
ALTER TABLE test.events DELETE WHERE created_at < '2023-01-01';
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Origin SQL:
ALTER TABLE test.events ON CLUSTER 'default_cluster' DELETE WHERE id = 123 AND status = 'deleted';


-- Format SQL:
ALTER TABLE test.events ON CLUSTER 'default_cluster' DELETE WHERE id = 123 AND status = 'deleted';
6 changes: 6 additions & 0 deletions parser/testdata/ddl/format/alter_table_update.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Origin SQL:
ALTER TABLE test.users UPDATE status = 'active', updated_at = now() WHERE status = 'pending';


-- Format SQL:
ALTER TABLE test.users UPDATE status = 'active', updated_at = now() WHERE status = 'pending';
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Origin SQL:
ALTER TABLE db.table ON CLUSTER cluster1 UPDATE column1 = column1 + 1 WHERE id > 100;


-- Format SQL:
ALTER TABLE db.table ON CLUSTER cluster1 UPDATE column1 = column1 + 1 WHERE id > 100;
43 changes: 43 additions & 0 deletions parser/testdata/ddl/output/alter_table_delete.sql.golden.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[
{
"AlterPos": 0,
"StatementEnd": 61,
"TableIdentifier": {
"Database": {
"Name": "test",
"QuoteType": 1,
"NamePos": 12,
"NameEnd": 16
},
"Table": {
"Name": "events",
"QuoteType": 1,
"NamePos": 17,
"NameEnd": 23
}
},
"OnCluster": null,
"AlterExprs": [
{
"DeletePos": 24,
"StatementEnd": 61,
"WhereClause": {
"LeftExpr": {
"Name": "created_at",
"QuoteType": 1,
"NamePos": 37,
"NameEnd": 47
},
"Operation": "\u003c",
"RightExpr": {
"LiteralPos": 51,
"LiteralEnd": 61,
"Literal": "2023-01-01"
},
"HasGlobal": false,
"HasNot": false
}
}
]
}
]
Loading