Skip to content

Commit e31c88c

Browse files
authored
Add support of ALTER TABLE DELETE/UPDATE mutations (#203)
1 parent 78ff34b commit e31c88c

16 files changed

+568
-1
lines changed

parser/ast.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,6 +1442,121 @@ func (a *AlterTableReplacePartition) Accept(visitor ASTVisitor) error {
14421442
return visitor.VisitAlterTableReplacePartition(a)
14431443
}
14441444

1445+
type AlterTableDelete struct {
1446+
DeletePos Pos
1447+
StatementEnd Pos
1448+
WhereClause Expr
1449+
}
1450+
1451+
func (a *AlterTableDelete) Pos() Pos {
1452+
return a.DeletePos
1453+
}
1454+
1455+
func (a *AlterTableDelete) End() Pos {
1456+
return a.StatementEnd
1457+
}
1458+
1459+
func (a *AlterTableDelete) AlterType() string {
1460+
return "DELETE"
1461+
}
1462+
1463+
func (a *AlterTableDelete) String() string {
1464+
var builder strings.Builder
1465+
builder.WriteString("DELETE WHERE ")
1466+
builder.WriteString(a.WhereClause.String())
1467+
return builder.String()
1468+
}
1469+
1470+
func (a *AlterTableDelete) Accept(visitor ASTVisitor) error {
1471+
visitor.Enter(a)
1472+
defer visitor.Leave(a)
1473+
if err := a.WhereClause.Accept(visitor); err != nil {
1474+
return err
1475+
}
1476+
return visitor.VisitAlterTableDelete(a)
1477+
}
1478+
1479+
type AlterTableUpdate struct {
1480+
UpdatePos Pos
1481+
StatementEnd Pos
1482+
Assignments []*UpdateAssignment
1483+
WhereClause Expr
1484+
}
1485+
1486+
func (a *AlterTableUpdate) Pos() Pos {
1487+
return a.UpdatePos
1488+
}
1489+
1490+
func (a *AlterTableUpdate) End() Pos {
1491+
return a.StatementEnd
1492+
}
1493+
1494+
func (a *AlterTableUpdate) AlterType() string {
1495+
return "UPDATE"
1496+
}
1497+
1498+
func (a *AlterTableUpdate) String() string {
1499+
var builder strings.Builder
1500+
builder.WriteString("UPDATE ")
1501+
for i, assignment := range a.Assignments {
1502+
if i > 0 {
1503+
builder.WriteString(", ")
1504+
}
1505+
builder.WriteString(assignment.String())
1506+
}
1507+
builder.WriteString(" WHERE ")
1508+
builder.WriteString(a.WhereClause.String())
1509+
return builder.String()
1510+
}
1511+
1512+
func (a *AlterTableUpdate) Accept(visitor ASTVisitor) error {
1513+
visitor.Enter(a)
1514+
defer visitor.Leave(a)
1515+
for _, assignment := range a.Assignments {
1516+
if err := assignment.Accept(visitor); err != nil {
1517+
return err
1518+
}
1519+
}
1520+
if err := a.WhereClause.Accept(visitor); err != nil {
1521+
return err
1522+
}
1523+
return visitor.VisitAlterTableUpdate(a)
1524+
}
1525+
1526+
type UpdateAssignment struct {
1527+
AssignmentPos Pos
1528+
Column *NestedIdentifier
1529+
Expr Expr
1530+
}
1531+
1532+
func (u *UpdateAssignment) Pos() Pos {
1533+
return u.AssignmentPos
1534+
}
1535+
1536+
func (u *UpdateAssignment) End() Pos {
1537+
return u.Expr.End()
1538+
}
1539+
1540+
func (u *UpdateAssignment) String() string {
1541+
var builder strings.Builder
1542+
builder.WriteString(u.Column.String())
1543+
builder.WriteString(" = ")
1544+
builder.WriteString(u.Expr.String())
1545+
return builder.String()
1546+
}
1547+
1548+
func (u *UpdateAssignment) Accept(visitor ASTVisitor) error {
1549+
visitor.Enter(u)
1550+
defer visitor.Leave(u)
1551+
if err := u.Column.Accept(visitor); err != nil {
1552+
return err
1553+
}
1554+
if err := u.Expr.Accept(visitor); err != nil {
1555+
return err
1556+
}
1557+
return visitor.VisitUpdateAssignment(u)
1558+
}
1559+
14451560
type RemovePropertyType struct {
14461561
RemovePos Pos
14471562

parser/ast_visitor.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ type ASTVisitor interface {
3232
VisitAlterTableModifySetting(expr *AlterTableModifySetting) error
3333
VisitAlterTableResetSetting(expr *AlterTableResetSetting) error
3434
VisitAlterTableReplacePartition(expr *AlterTableReplacePartition) error
35+
VisitAlterTableDelete(expr *AlterTableDelete) error
36+
VisitAlterTableUpdate(expr *AlterTableUpdate) error
37+
VisitUpdateAssignment(expr *UpdateAssignment) error
3538
VisitRemovePropertyType(expr *RemovePropertyType) error
3639
VisitTableIndex(expr *TableIndex) error
3740
VisitIdent(expr *Ident) error
@@ -420,6 +423,27 @@ func (v *DefaultASTVisitor) VisitAlterTableReplacePartition(expr *AlterTableRepl
420423
return nil
421424
}
422425

426+
func (v *DefaultASTVisitor) VisitAlterTableDelete(expr *AlterTableDelete) error {
427+
if v.Visit != nil {
428+
return v.Visit(expr)
429+
}
430+
return nil
431+
}
432+
433+
func (v *DefaultASTVisitor) VisitAlterTableUpdate(expr *AlterTableUpdate) error {
434+
if v.Visit != nil {
435+
return v.Visit(expr)
436+
}
437+
return nil
438+
}
439+
440+
func (v *DefaultASTVisitor) VisitUpdateAssignment(expr *UpdateAssignment) error {
441+
if v.Visit != nil {
442+
return v.Visit(expr)
443+
}
444+
return nil
445+
}
446+
423447
func (v *DefaultASTVisitor) VisitRemovePropertyType(expr *RemovePropertyType) error {
424448
if v.Visit != nil {
425449
return v.Visit(expr)

parser/parser_alter.go

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,12 @@ func (p *Parser) parseAlterTable(pos Pos) (*AlterTable, error) {
5353
alter, err = p.parseAlterTableMaterialize(p.Pos())
5454
case p.matchKeyword(KeywordReset):
5555
alter, err = p.parseAlterTableReset(p.Pos())
56+
case p.matchKeyword(KeywordDelete):
57+
alter, err = p.parseAlterTableDelete(p.Pos())
58+
case p.matchKeyword(KeywordUpdate):
59+
alter, err = p.parseAlterTableUpdate(p.Pos())
5660
default:
57-
return nil, errors.New("expected token: ADD|DROP|ATTACH|DETACH|FREEZE|REMOVE|CLEAR|MODIFY|REPLACE|MATERIALIZE|RESET")
61+
return nil, errors.New("expected token: ADD|DROP|ATTACH|DETACH|FREEZE|REMOVE|CLEAR|MODIFY|REPLACE|MATERIALIZE|RESET|DELETE|UPDATE")
5862
}
5963
if err != nil {
6064
return nil, err
@@ -833,3 +837,88 @@ func (p *Parser) parseAlterTableReset(pos Pos) (AlterTableClause, error) {
833837
Settings: settings,
834838
}, nil
835839
}
840+
841+
// Syntax: ALTER TABLE DELETE WHERE condition
842+
func (p *Parser) parseAlterTableDelete(pos Pos) (AlterTableClause, error) {
843+
if err := p.expectKeyword(KeywordDelete); err != nil {
844+
return nil, err
845+
}
846+
847+
if err := p.expectKeyword(KeywordWhere); err != nil {
848+
return nil, err
849+
}
850+
851+
whereExpr, err := p.parseExpr(p.Pos())
852+
if err != nil {
853+
return nil, err
854+
}
855+
856+
return &AlterTableDelete{
857+
DeletePos: pos,
858+
StatementEnd: whereExpr.End(),
859+
WhereClause: whereExpr,
860+
}, nil
861+
}
862+
863+
// Syntax: ALTER TABLE UPDATE column1 = expr1 [, column2 = expr2, ...] WHERE condition
864+
func (p *Parser) parseAlterTableUpdate(pos Pos) (AlterTableClause, error) {
865+
if err := p.expectKeyword(KeywordUpdate); err != nil {
866+
return nil, err
867+
}
868+
869+
// Parse at least one assignment
870+
assignments := make([]*UpdateAssignment, 0)
871+
assignment, err := p.parseUpdateAssignment(p.Pos())
872+
if err != nil {
873+
return nil, err
874+
}
875+
assignments = append(assignments, assignment)
876+
877+
// Parse additional comma-separated assignments
878+
for p.tryConsumeTokenKind(TokenKindComma) != nil {
879+
assignment, err = p.parseUpdateAssignment(p.Pos())
880+
if err != nil {
881+
return nil, err
882+
}
883+
assignments = append(assignments, assignment)
884+
}
885+
886+
if err := p.expectKeyword(KeywordWhere); err != nil {
887+
return nil, err
888+
}
889+
890+
whereExpr, err := p.parseExpr(p.Pos())
891+
if err != nil {
892+
return nil, err
893+
}
894+
895+
return &AlterTableUpdate{
896+
UpdatePos: pos,
897+
StatementEnd: whereExpr.End(),
898+
Assignments: assignments,
899+
WhereClause: whereExpr,
900+
}, nil
901+
}
902+
903+
// Parse column = expression assignment
904+
func (p *Parser) parseUpdateAssignment(pos Pos) (*UpdateAssignment, error) {
905+
column, err := p.ParseNestedIdentifier(p.Pos())
906+
if err != nil {
907+
return nil, err
908+
}
909+
910+
if err := p.expectTokenKind(TokenKindSingleEQ); err != nil {
911+
return nil, err
912+
}
913+
914+
expr, err := p.parseExpr(p.Pos())
915+
if err != nil {
916+
return nil, err
917+
}
918+
919+
return &UpdateAssignment{
920+
AssignmentPos: pos,
921+
Column: column,
922+
Expr: expr,
923+
}, nil
924+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE test.events DELETE WHERE created_at < '2023-01-01';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE test.events ON CLUSTER 'default_cluster' DELETE WHERE id = 123 AND status = 'deleted';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE test.users UPDATE status = 'active', updated_at = now() WHERE status = 'pending';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE db.table ON CLUSTER cluster1 UPDATE column1 = column1 + 1 WHERE id > 100;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- Origin SQL:
2+
ALTER TABLE test.events DELETE WHERE created_at < '2023-01-01';
3+
4+
5+
-- Format SQL:
6+
ALTER TABLE test.events DELETE WHERE created_at < '2023-01-01';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- Origin SQL:
2+
ALTER TABLE test.events ON CLUSTER 'default_cluster' DELETE WHERE id = 123 AND status = 'deleted';
3+
4+
5+
-- Format SQL:
6+
ALTER TABLE test.events ON CLUSTER 'default_cluster' DELETE WHERE id = 123 AND status = 'deleted';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- Origin SQL:
2+
ALTER TABLE test.users UPDATE status = 'active', updated_at = now() WHERE status = 'pending';
3+
4+
5+
-- Format SQL:
6+
ALTER TABLE test.users UPDATE status = 'active', updated_at = now() WHERE status = 'pending';

0 commit comments

Comments
 (0)