Repository: AfterShip/clickhouse-sql-parser
Pull request #10 (2023-09-28 07:29:57)

Add the support of RENAME TABLE expression


Patch:
diff --git a/parser/ast.go b/parser/ast.go
index 34f7233..fb4ce10 100644
--- a/parser/ast.go
+++ b/parser/ast.go
@@ -3504,3 +3504,57 @@ func (n *UnaryExpr) End() Pos {
 func (n *UnaryExpr) String(level int) string {
 	return "-" + n.Expr.String(level+1)
 }
+
+type RenameTable struct {
+	RenamePos     Pos
+	StatementEnd  Pos
+	TablePairList []*TablePair
+	OnCluster     *OnClusterExpr
+}
+
+func (r *RenameTable) Pos() Pos {
+	return r.RenamePos
+}
+
+func (r *RenameTable) End() Pos {
+	return r.StatementEnd
+}
+
+func (r *RenameTable) Type() string {
+	return "RENAME TABLE"
+}
+
+func (r *RenameTable) String(level int) string {
+	var builder strings.Builder
+	builder.WriteString("RENAME TABLE ")
+	for i, pair := range r.TablePairList {
+		if i > 0 {
+			builder.WriteString(", ")
+		}
+		builder.WriteString(pair.Old.String(level))
+		builder.WriteString(" TO ")
+		builder.WriteString(pair.New.String(level))
+	}
+	if r.OnCluster != nil {
+		builder.WriteString(NewLine(level))
+		builder.WriteString(r.OnCluster.String(level))
+	}
+	return builder.String()
+}
+
+type TablePair struct {
+	Old *TableIdentifier
+	New *TableIdentifier
+}
+
+func (t *TablePair) Pos() Pos {
+	return t.Old.Pos()
+}
+
+func (t *TablePair) End() Pos {
+	return t.New.End()
+}
+
+func (t *TablePair) String() string {
+	return t.Old.String(0) + " TO " + t.New.String(0)
+}
diff --git a/parser/parser_table.go b/parser/parser_table.go
index 51ccb75..69ae212 100644
--- a/parser/parser_table.go
+++ b/parser/parser_table.go
@@ -46,6 +46,8 @@ func (p *Parser) parseDDL(pos Pos) (DDL, error) {
 		}
 	case p.matchKeyword(KeywordTruncate):
 		return p.parseTruncateTable(pos)
+	case p.matchKeyword(KeywordRename):
+		return p.parseRenameTable(pos)
 	}
 	return nil, nil // nolint
 }
@@ -890,7 +892,8 @@ func (p *Parser) parseStatement(pos Pos) (Expr, error) {
 		p.matchKeyword(KeywordAlter),
 		p.matchKeyword(KeywordDrop),
 		p.matchKeyword(KeywordDetach),
-		p.matchKeyword(KeywordTruncate):
+		p.matchKeyword(KeywordTruncate),
+		p.matchKeyword(KeywordRename):
 		expr, err = p.parseDDL(pos)
 	case p.matchKeyword(KeywordSelect), p.matchKeyword(KeywordWith):
 		expr, err = p.parseSelectQuery(pos)
@@ -1166,3 +1169,61 @@ func (p *Parser) parseInsertExpr(pos Pos) (*InsertExpr, error) {
 
 	return insertExpr, nil
 }
+
+func (p *Parser) parseRenameTable(pos Pos) (*RenameTable, error) {
+	if err := p.consumeKeyword(KeywordRename); err != nil {
+		return nil, err
+	}
+	if err := p.consumeKeyword(KeywordTable); err != nil {
+		return nil, err
+	}
+
+	tablePair, err := p.parseTablePair(p.Pos())
+	if err != nil {
+		return nil, err
+	}
+	tablePairList := []*TablePair{tablePair}
+	for p.tryConsumeTokenKind(",") != nil {
+		tablePair, err := p.parseTablePair(p.Pos())
+		if err != nil {
+			return nil, err
+		}
+		tablePairList = append(tablePairList, tablePair)
+	}
+
+	renameTable := &RenameTable{
+		RenamePos:     pos,
+		StatementEnd:  tablePairList[len(tablePairList)-1].End(),
+		TablePairList: tablePairList,
+	}
+
+	onClusterExpr, err := p.tryParseOnCluster(p.Pos())
+	if err != nil {
+		return nil, err
+	}
+	if onClusterExpr != nil {
+		renameTable.OnCluster = onClusterExpr
+		renameTable.StatementEnd = onClusterExpr.End()
+	}
+
+	return renameTable, nil
+}
+
+func (p *Parser) parseTablePair(_ Pos) (*TablePair, error) {
+	oldTable, err := p.parseTableIdentifier(p.Pos())
+	if err != nil {
+		return nil, err
+	}
+	if err = p.consumeKeyword(KeywordTo); err != nil {
+		return nil, err
+	}
+	newTable, err := p.parseTableIdentifier(p.Pos())
+	if err != nil {
+		return nil, err
+	}
+
+	return &TablePair{
+		Old: oldTable,
+		New: newTable,
+	}, nil
+}


Test patch:
diff --git a/parser/testdata/ddl/format/rename_table.sql b/parser/testdata/ddl/format/rename_table.sql
new file mode 100644
index 0000000..f7055d2
--- /dev/null
+++ b/parser/testdata/ddl/format/rename_table.sql
@@ -0,0 +1,14 @@
+-- Origin SQL:
+RENAME TABLE t1 TO t11;
+RENAME TABLE t1 TO t11 ON CLUSTER 'default_cluster';
+RENAME TABLE t1 TO t11, t2 TO t22;
+RENAME TABLE t1 TO t11, t2 TO t22 ON CLUSTER 'default_cluster';
+
+
+-- Format SQL:
+RENAME TABLE t1 TO t11;
+RENAME TABLE t1 TO t11
+ON CLUSTER 'default_cluster';
+RENAME TABLE t1 TO t11, t2 TO t22;
+RENAME TABLE t1 TO t11, t2 TO t22
+ON CLUSTER 'default_cluster';
diff --git a/parser/testdata/ddl/output/rename_table.sql.golden.json b/parser/testdata/ddl/output/rename_table.sql.golden.json
new file mode 100644
index 0000000..27170bd
--- /dev/null
+++ b/parser/testdata/ddl/output/rename_table.sql.golden.json
@@ -0,0 +1,164 @@
+[
+  {
+    "RenamePos": 0,
+    "StatementEnd": 22,
+    "TablePairList": [
+      {
+        "Old": {
+          "Database": null,
+          "Table": {
+            "Name": "t1",
+            "Unquoted": false,
+            "NamePos": 13,
+            "NameEnd": 15
+          }
+        },
+        "New": {
+          "Database": null,
+          "Table": {
+            "Name": "t11",
+            "Unquoted": false,
+            "NamePos": 19,
+            "NameEnd": 22
+          }
+        }
+      }
+    ],
+    "OnCluster": null
+  },
+  {
+    "RenamePos": 24,
+    "StatementEnd": 74,
+    "TablePairList": [
+      {
+        "Old": {
+          "Database": null,
+          "Table": {
+            "Name": "t1",
+            "Unquoted": false,
+            "NamePos": 37,
+            "NameEnd": 39
+          }
+        },
+        "New": {
+          "Database": null,
+          "Table": {
+            "Name": "t11",
+            "Unquoted": false,
+            "NamePos": 43,
+            "NameEnd": 46
+          }
+        }
+      }
+    ],
+    "OnCluster": {
+      "OnPos": 47,
+      "Expr": {
+        "LiteralPos": 59,
+        "LiteralEnd": 74,
+        "Literal": "default_cluster"
+      }
+    }
+  },
+  {
+    "RenamePos": 77,
+    "StatementEnd": 110,
+    "TablePairList": [
+      {
+        "Old": {
+          "Database": null,
+          "Table": {
+            "Name": "t1",
+            "Unquoted": false,
+            "NamePos": 90,
+            "NameEnd": 92
+          }
+        },
+        "New": {
+          "Database": null,
+          "Table": {
+            "Name": "t11",
+            "Unquoted": false,
+            "NamePos": 96,
+            "NameEnd": 99
+          }
+        }
+      },
+      {
+        "Old": {
+          "Database": null,
+          "Table": {
+            "Name": "t2",
+            "Unquoted": false,
+            "NamePos": 101,
+            "NameEnd": 103
+          }
+        },
+        "New": {
+          "Database": null,
+          "Table": {
+            "Name": "t22",
+            "Unquoted": false,
+            "NamePos": 107,
+            "NameEnd": 110
+          }
+        }
+      }
+    ],
+    "OnCluster": null
+  },
+  {
+    "RenamePos": 112,
+    "StatementEnd": 173,
+    "TablePairList": [
+      {
+        "Old": {
+          "Database": null,
+          "Table": {
+            "Name": "t1",
+            "Unquoted": false,
+            "NamePos": 125,
+            "NameEnd": 127
+          }
+        },
+        "New": {
+          "Database": null,
+          "Table": {
+            "Name": "t11",
+            "Unquoted": false,
+            "NamePos": 131,
+            "NameEnd": 134
+          }
+        }
+      },
+      {
+        "Old": {
+          "Database": null,
+          "Table": {
+            "Name": "t2",
+            "Unquoted": false,
+            "NamePos": 136,
+            "NameEnd": 138
+          }
+        },
+        "New": {
+          "Database": null,
+          "Table": {
+            "Name": "t22",
+            "Unquoted": false,
+            "NamePos": 142,
+            "NameEnd": 145
+          }
+        }
+      }
+    ],
+    "OnCluster": {
+      "OnPos": 146,
+      "Expr": {
+        "LiteralPos": 158,
+        "LiteralEnd": 173,
+        "Literal": "default_cluster"
+      }
+    }
+  }
+]
\ No newline at end of file
diff --git a/parser/testdata/ddl/rename_table.sql b/parser/testdata/ddl/rename_table.sql
new file mode 100644
index 0000000..6229d65
--- /dev/null
+++ b/parser/testdata/ddl/rename_table.sql
@@ -0,0 +1,4 @@
+RENAME TABLE t1 TO t11;
+RENAME TABLE t1 TO t11 ON CLUSTER 'default_cluster';
+RENAME TABLE t1 TO t11, t2 TO t22;
+RENAME TABLE t1 TO t11, t2 TO t22 ON CLUSTER 'default_cluster';