Repository: AfterShip/clickhouse-sql-parser
Pull request #81 (2024-07-16 08:57:53)

Fix missing DROP keyword in alter table drop clause


Patch:
diff --git a/parser/ast.go b/parser/ast.go
index f654d8c..b403ec4 100644
--- a/parser/ast.go
+++ b/parser/ast.go
@@ -324,8 +324,10 @@ func (a *AlterTableDetachPartition) Accept(visitor ASTVisitor) error {
 }
 
 type AlterTableDropPartition struct {
-	DropPos   Pos
-	Partition *PartitionClause
+	DropPos     Pos
+	HasDetached bool
+	Partition   *PartitionClause
+	Settings    *SettingsClause
 }
 
 func (a *AlterTableDropPartition) Pos() Pos {
@@ -333,6 +335,9 @@ func (a *AlterTableDropPartition) Pos() Pos {
 }
 
 func (a *AlterTableDropPartition) End() Pos {
+	if a.Settings != nil {
+		a.Settings.End()
+	}
 	return a.Partition.End()
 }
 
@@ -343,7 +348,14 @@ func (a *AlterTableDropPartition) AlterType() string {
 func (a *AlterTableDropPartition) String(level int) string {
 	var builder strings.Builder
 	builder.WriteString("DROP ")
+	if a.HasDetached {
+		builder.WriteString("DETACHED ")
+	}
 	builder.WriteString(a.Partition.String(level))
+	if a.Settings != nil {
+		builder.WriteByte(' ')
+		builder.WriteString(a.Settings.String(level))
+	}
 	return builder.String()
 }
 
@@ -3276,6 +3288,7 @@ type CompressionCodec struct {
 	CodecPos      Pos
 	RightParenPos Pos
 	Type          *Ident
+	TypeLevel     *NumberLiteral
 	Name          *Ident
 	Level         *NumberLiteral // compression level
 }
@@ -3293,6 +3306,11 @@ func (c *CompressionCodec) String(level int) string {
 	builder.WriteString("CODEC(")
 	if c.Type != nil {
 		builder.WriteString(c.Type.String(level))
+		if c.TypeLevel != nil {
+			builder.WriteByte('(')
+			builder.WriteString(c.TypeLevel.String(level))
+			builder.WriteByte(')')
+		}
 		builder.WriteByte(',')
 		builder.WriteByte(' ')
 	}
@@ -3309,6 +3327,14 @@ func (c *CompressionCodec) String(level int) string {
 func (c *CompressionCodec) Accept(visitor ASTVisitor) error {
 	visitor.enter(c)
 	defer visitor.leave(c)
+	if err := c.Type.Accept(visitor); err != nil {
+		return err
+	}
+	if c.TypeLevel != nil {
+		if err := c.TypeLevel.Accept(visitor); err != nil {
+			return err
+		}
+	}
 	if err := c.Name.Accept(visitor); err != nil {
 		return err
 	}
@@ -4942,6 +4968,7 @@ type SelectQuery struct {
 	LimitBy       *LimitByClause
 	Limit         *LimitClause
 	Settings      *SettingsClause
+	Format        *FormatClause
 	UnionAll      *SelectQuery
 	UnionDistinct *SelectQuery
 	Except        *SelectQuery
@@ -5026,6 +5053,10 @@ func (s *SelectQuery) String(level int) string { // nolint: funlen
 		builder.WriteString(NewLine(level))
 		builder.WriteString(s.Settings.String(level))
 	}
+	if s.Format != nil {
+		builder.WriteString(NewLine(level))
+		builder.WriteString(s.Format.String(level))
+	}
 	if s.UnionAll != nil {
 		builder.WriteString(NewLine(level))
 		builder.WriteString(" UNION ALL ")
@@ -5115,6 +5146,11 @@ func (s *SelectQuery) Accept(visitor ASTVisitor) error {
 			return err
 		}
 	}
+	if s.Format != nil {
+		if err := s.Format.Accept(visitor); err != nil {
+			return err
+		}
+	}
 	if s.UnionAll != nil {
 		if err := s.UnionAll.Accept(visitor); err != nil {
 			return err
diff --git a/parser/parser_alter.go b/parser/parser_alter.go
index 5cfaaac..5a3db06 100644
--- a/parser/parser_alter.go
+++ b/parser/parser_alter.go
@@ -295,10 +295,7 @@ func (p *Parser) parseAlterTableDrop(pos Pos) (AlterTableClause, error) {
 	switch {
 	case p.matchKeyword(KeywordColumn), p.matchKeyword(KeywordIndex), p.matchKeyword(KeywordProjection):
 		return p.parseAlterTableDropClause(pos)
-	case p.matchKeyword(KeywordDetached):
-		_ = p.lexer.consumeToken()
-		return p.parseAlterTableDetachPartition(pos)
-	case p.matchKeyword(KeywordPartition):
+	case p.matchKeyword(KeywordDetached), p.matchKeyword(KeywordPartition):
 		return p.parseAlterTableDropPartition(pos)
 	default:
 		return nil, errors.New("expected keyword: COLUMN|INDEX|PROJECTION|DETACHED|PARTITION")
@@ -443,6 +440,11 @@ func (p *Parser) tryParseAfterClause() (*NestedIdentifier, error) {
 
 // Syntax: ALTER TABLE DROP partitionClause
 func (p *Parser) parseAlterTableDropPartition(pos Pos) (AlterTableClause, error) {
+	var hasDetached bool
+	if p.matchKeyword(KeywordDetached) {
+		_ = p.lexer.consumeToken()
+		hasDetached = true
+	}
 	partitionPos := p.Pos()
 	if err := p.consumeKeyword(KeywordPartition); err != nil {
 		return nil, err
@@ -456,9 +458,16 @@ func (p *Parser) parseAlterTableDropPartition(pos Pos) (AlterTableClause, error)
 	}
 	partition.Expr = expr
 
+	settings, err := p.tryParseSettingsClause(p.Pos())
+	if err != nil {
+		return nil, err
+	}
+
 	return &AlterTableDropPartition{
-		DropPos:   pos,
-		Partition: partition,
+		DropPos:     pos,
+		Partition:   partition,
+		HasDetached: hasDetached,
+		Settings:    settings,
 	}, nil
 }
 
diff --git a/parser/parser_column.go b/parser/parser_column.go
index 9b56dcc..4cbda1b 100644
--- a/parser/parser_column.go
+++ b/parser/parser_column.go
@@ -803,10 +803,12 @@ func (p *Parser) tryParseCompressionCodecs(pos Pos) (*CompressionCodec, error) {
 	}
 	// parse DELTA if  CODEC(Delta, ZSTD(1)) or CODEC(Delta(9), ZSTD(1))
 	var codecType *Ident
+	var typeLevel *NumberLiteral
 	if strings.ToUpper(name.Name) == "DELTA" {
 		codecType = name
 		// try parse delta level
-		if _, err := p.tryParseCompressionLevel(p.Pos()); err != nil {
+		typeLevel, err = p.tryParseCompressionLevel(p.Pos())
+		if err != nil {
 			return nil, err
 		}
 		// consume comma
@@ -838,6 +840,7 @@ func (p *Parser) tryParseCompressionCodecs(pos Pos) (*CompressionCodec, error) {
 		CodecPos:      pos,
 		RightParenPos: rightParenPos,
 		Type:          codecType,
+		TypeLevel:     typeLevel,
 		Name:          name,
 		Level:         level,
 	}, nil
diff --git a/parser/parser_query.go b/parser/parser_query.go
index 6ff3a5d..6efe8a6 100644
--- a/parser/parser_query.go
+++ b/parser/parser_query.go
@@ -907,6 +907,14 @@ func (p *Parser) parseSelectStmt(pos Pos) (*SelectQuery, error) { // nolint: fun
 		statementEnd = settings.End()
 	}
 
+	format, err := p.tryParseFormat(p.Pos())
+	if err != nil {
+		return nil, err
+	}
+	if format != nil {
+		statementEnd = format.End()
+	}
+
 	return &SelectQuery{
 		With:          withClause,
 		SelectPos:     pos,
@@ -924,6 +932,7 @@ func (p *Parser) parseSelectStmt(pos Pos) (*SelectQuery, error) { // nolint: fun
 		LimitBy:       limitBy,
 		Limit:         limit,
 		Settings:      settings,
+		Format:        format,
 		WithTotal:     withTotal,
 	}, nil
 }


Test patch:
diff --git a/parser/testdata/ddl/format/alter_table_drop_detach_partition.sql b/parser/testdata/ddl/format/alter_table_drop_detach_partition.sql
index 867990e..acf7322 100644
--- a/parser/testdata/ddl/format/alter_table_drop_detach_partition.sql
+++ b/parser/testdata/ddl/format/alter_table_drop_detach_partition.sql
@@ -3,4 +3,4 @@ ALTER TABLE app_utc_00.app_message_as_notification_organization_sent_stats_i_d_l
 
 -- Format SQL:
 ALTER TABLE app_utc_00.app_message_as_notification_organization_sent_stats_i_d_local
-DETACH PARTITION '2022-05-24' SETTINGS allow_drop_detached=1;
+DROP DETACHED PARTITION '2022-05-24' SETTINGS allow_drop_detached=1;
diff --git a/parser/testdata/ddl/format/create_table_with_codec_delta.sql b/parser/testdata/ddl/format/create_table_with_codec_delta.sql
index 082189b..e0b4731 100644
--- a/parser/testdata/ddl/format/create_table_with_codec_delta.sql
+++ b/parser/testdata/ddl/format/create_table_with_codec_delta.sql
@@ -19,7 +19,7 @@ CREATE TABLE IF NOT EXISTS test_local
 (
   `id` UInt64 CODEC(Delta, ZSTD(1)),
   `api_id` UInt64 CODEC(ZSTD(1)),
-  `app_id` UInt64 CODEC(Delta, ZSTD(1)),
+  `app_id` UInt64 CODEC(Delta(9), ZSTD(1)),
   `timestamp` DateTime64(9) CODEC(ZSTD(1)),
   INDEX timestamp_index(timestamp) TYPE minmax GRANULARITY 4
 )
diff --git a/parser/testdata/ddl/output/alter_table_drop_detach_partition.sql.golden.json b/parser/testdata/ddl/output/alter_table_drop_detach_partition.sql.golden.json
index 0028775..037df24 100644
--- a/parser/testdata/ddl/output/alter_table_drop_detach_partition.sql.golden.json
+++ b/parser/testdata/ddl/output/alter_table_drop_detach_partition.sql.golden.json
@@ -19,7 +19,8 @@
     "OnCluster": null,
     "AlterExprs": [
       {
-        "DetachPos": 85,
+        "DropPos": 85,
+        "HasDetached": true,
         "Partition": {
           "PartitionPos": 99,
           "Expr": {
diff --git a/parser/testdata/ddl/output/alter_table_drop_partition.sql.golden.json b/parser/testdata/ddl/output/alter_table_drop_partition.sql.golden.json
index f08d3c3..440d917 100644
--- a/parser/testdata/ddl/output/alter_table_drop_partition.sql.golden.json
+++ b/parser/testdata/ddl/output/alter_table_drop_partition.sql.golden.json
@@ -27,6 +27,7 @@
     "AlterExprs": [
       {
         "DropPos": 53,
+        "HasDetached": false,
         "Partition": {
           "PartitionPos": 58,
           "Expr": {
@@ -36,7 +37,8 @@
           },
           "ID": null,
           "All": false
-        }
+        },
+        "Settings": null
       }
     ]
   }
diff --git a/parser/testdata/ddl/output/bug_001.sql.golden.json b/parser/testdata/ddl/output/bug_001.sql.golden.json
index 3a07232..1bf1334 100644
--- a/parser/testdata/ddl/output/bug_001.sql.golden.json
+++ b/parser/testdata/ddl/output/bug_001.sql.golden.json
@@ -501,6 +501,7 @@
         "LimitBy": null,
         "Limit": null,
         "Settings": null,
+        "Format": null,
         "UnionAll": null,
         "UnionDistinct": null,
         "Except": null
diff --git a/parser/testdata/ddl/output/create_live_view_basic.sql.golden.json b/parser/testdata/ddl/output/create_live_view_basic.sql.golden.json
index 43f159f..7146443 100644
--- a/parser/testdata/ddl/output/create_live_view_basic.sql.golden.json
+++ b/parser/testdata/ddl/output/create_live_view_basic.sql.golden.json
@@ -127,6 +127,7 @@
         "LimitBy": null,
         "Limit": null,
         "Settings": null,
+        "Format": null,
         "UnionAll": null,
         "UnionDistinct": null,
         "Except": null
diff --git a/parser/testdata/ddl/output/create_materialized_view_basic.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_basic.sql.golden.json
index 3e50d25..f4aba51 100644
--- a/parser/testdata/ddl/output/create_materialized_view_basic.sql.golden.json
+++ b/parser/testdata/ddl/output/create_materialized_view_basic.sql.golden.json
@@ -486,6 +486,7 @@
         "LimitBy": null,
         "Limit": null,
         "Settings": null,
+        "Format": null,
         "UnionAll": null,
         "UnionDistinct": null,
         "Except": null
diff --git a/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json
index a379f2a..ead806a 100644
--- a/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json
+++ b/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json
@@ -427,6 +427,7 @@
                   "LimitBy": null,
                   "Limit": null,
                   "Settings": null,
+                  "Format": null,
                   "UnionAll": null,
                   "UnionDistinct": null,
                   "Except": null
@@ -476,6 +477,7 @@
         "LimitBy": null,
         "Limit": null,
         "Settings": null,
+        "Format": null,
         "UnionAll": null,
         "UnionDistinct": null,
         "Except": null
diff --git a/parser/testdata/ddl/output/create_table_basic.sql.golden.json b/parser/testdata/ddl/output/create_table_basic.sql.golden.json
index d928845..6bc90b8 100644
--- a/parser/testdata/ddl/output/create_table_basic.sql.golden.json
+++ b/parser/testdata/ddl/output/create_table_basic.sql.golden.json
@@ -78,6 +78,7 @@
             "CodecPos": 198,
             "RightParenPos": 212,
             "Type": null,
+            "TypeLevel": null,
             "Name": {
               "Name": "ZSTD",
               "QuoteType": 1,
diff --git a/parser/testdata/ddl/output/create_table_with_codec_delta.sql.golden.json b/parser/testdata/ddl/output/create_table_with_codec_delta.sql.golden.json
index be21b0e..e65f4aa 100644
--- a/parser/testdata/ddl/output/create_table_with_codec_delta.sql.golden.json
+++ b/parser/testdata/ddl/output/create_table_with_codec_delta.sql.golden.json
@@ -50,6 +50,7 @@
               "NamePos": 59,
               "NameEnd": 64
             },
+            "TypeLevel": null,
             "Name": {
               "Name": "ZSTD",
               "QuoteType": 1,
@@ -94,6 +95,7 @@
             "CodecPos": 93,
             "RightParenPos": 107,
             "Type": null,
+            "TypeLevel": null,
             "Name": {
               "Name": "ZSTD",
               "QuoteType": 1,
@@ -143,6 +145,12 @@
               "NamePos": 132,
               "NameEnd": 137
             },
+            "TypeLevel": {
+              "NumPos": 137,
+              "NumEnd": 139,
+              "Literal": "9",
+              "Base": 10
+            },
             "Name": {
               "Name": "ZSTD",
               "QuoteType": 1,
@@ -197,6 +205,7 @@
             "CodecPos": 179,
             "RightParenPos": 193,
             "Type": null,
+            "TypeLevel": null,
             "Name": {
               "Name": "ZSTD",
               "QuoteType": 1,
diff --git a/parser/testdata/ddl/output/create_table_with_index.sql.golden.json b/parser/testdata/ddl/output/create_table_with_index.sql.golden.json
index 67e0632..da08722 100644
--- a/parser/testdata/ddl/output/create_table_with_index.sql.golden.json
+++ b/parser/testdata/ddl/output/create_table_with_index.sql.golden.json
@@ -50,6 +50,7 @@
               "NamePos": 59,
               "NameEnd": 64
             },
+            "TypeLevel": null,
             "Name": {
               "Name": "ZSTD",
               "QuoteType": 1,
@@ -94,6 +95,7 @@
             "CodecPos": 93,
             "RightParenPos": 107,
             "Type": null,
+            "TypeLevel": null,
             "Name": {
               "Name": "ZSTD",
               "QuoteType": 1,
@@ -178,6 +180,7 @@
             "CodecPos": 148,
             "RightParenPos": 162,
             "Type": null,
+            "TypeLevel": null,
             "Name": {
               "Name": "ZSTD",
               "QuoteType": 1,
diff --git a/parser/testdata/ddl/output/create_view_basic.sql.golden.json b/parser/testdata/ddl/output/create_view_basic.sql.golden.json
index 69a6817..403222e 100644
--- a/parser/testdata/ddl/output/create_view_basic.sql.golden.json
+++ b/parser/testdata/ddl/output/create_view_basic.sql.golden.json
@@ -138,6 +138,7 @@
         "LimitBy": null,
         "Limit": null,
         "Settings": null,
+        "Format": null,
         "UnionAll": null,
         "UnionDistinct": null,
         "Except": null
diff --git a/parser/testdata/ddl/output/create_view_on_cluster_with_uuid.sql.golden.json b/parser/testdata/ddl/output/create_view_on_cluster_with_uuid.sql.golden.json
index 9be946b..f5cf10a 100644
--- a/parser/testdata/ddl/output/create_view_on_cluster_with_uuid.sql.golden.json
+++ b/parser/testdata/ddl/output/create_view_on_cluster_with_uuid.sql.golden.json
@@ -93,6 +93,7 @@
         "LimitBy": null,
         "Limit": null,
         "Settings": null,
+        "Format": null,
         "UnionAll": null,
         "UnionDistinct": null,
         "Except": null
diff --git a/parser/testdata/dml/output/insert_with_select.sql.golden.json b/parser/testdata/dml/output/insert_with_select.sql.golden.json
index a2d3afa..28502bb 100644
--- a/parser/testdata/dml/output/insert_with_select.sql.golden.json
+++ b/parser/testdata/dml/output/insert_with_select.sql.golden.json
@@ -93,6 +93,7 @@
       "LimitBy": null,
       "Limit": null,
       "Settings": null,
+      "Format": null,
       "UnionAll": null,
       "UnionDistinct": null,
       "Except": null
diff --git a/parser/testdata/query/format/select_with_union_distinct.sql b/parser/testdata/query/format/select_with_union_distinct.sql
index 77c9a59..a9becdd 100644
--- a/parser/testdata/query/format/select_with_union_distinct.sql
+++ b/parser/testdata/query/format/select_with_union_distinct.sql
@@ -11,4 +11,5 @@ FROM
 SELECT 
   replica_name
 FROM
-  system.ha_unique_replicas;
+  system.ha_unique_replicas
+FORMAT JSON;
diff --git a/parser/testdata/query/output/select_cast.sql.golden.json b/parser/testdata/query/output/select_cast.sql.golden.json
index 33bc315..bab844b 100644
--- a/parser/testdata/query/output/select_cast.sql.golden.json
+++ b/parser/testdata/query/output/select_cast.sql.golden.json
@@ -51,6 +51,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
@@ -104,6 +105,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
@@ -168,6 +170,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
@@ -222,6 +225,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_column_alias_string.sql.golden.json b/parser/testdata/query/output/select_column_alias_string.sql.golden.json
index 6bb5559..25e1997 100644
--- a/parser/testdata/query/output/select_column_alias_string.sql.golden.json
+++ b/parser/testdata/query/output/select_column_alias_string.sql.golden.json
@@ -37,6 +37,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_simple.sql.golden.json b/parser/testdata/query/output/select_simple.sql.golden.json
index 25f492a..f6c6d37 100644
--- a/parser/testdata/query/output/select_simple.sql.golden.json
+++ b/parser/testdata/query/output/select_simple.sql.golden.json
@@ -380,6 +380,7 @@
     },
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_simple_with_bracket.sql.golden.json b/parser/testdata/query/output/select_simple_with_bracket.sql.golden.json
index 6eb1271..8c12b68 100644
--- a/parser/testdata/query/output/select_simple_with_bracket.sql.golden.json
+++ b/parser/testdata/query/output/select_simple_with_bracket.sql.golden.json
@@ -155,6 +155,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_simple_with_cte_with_column_aliases.sql.golden.json b/parser/testdata/query/output/select_simple_with_cte_with_column_aliases.sql.golden.json
index c818d37..d46ee71 100644
--- a/parser/testdata/query/output/select_simple_with_cte_with_column_aliases.sql.golden.json
+++ b/parser/testdata/query/output/select_simple_with_cte_with_column_aliases.sql.golden.json
@@ -110,6 +110,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -204,6 +205,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_simple_with_group_by_with_cube_totals.sql.golden.json b/parser/testdata/query/output/select_simple_with_group_by_with_cube_totals.sql.golden.json
index 863deac..5028eed 100644
--- a/parser/testdata/query/output/select_simple_with_group_by_with_cube_totals.sql.golden.json
+++ b/parser/testdata/query/output/select_simple_with_group_by_with_cube_totals.sql.golden.json
@@ -116,6 +116,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_simple_with_is_not_null.sql.golden.json b/parser/testdata/query/output/select_simple_with_is_not_null.sql.golden.json
index 58968b2..4867063 100644
--- a/parser/testdata/query/output/select_simple_with_is_not_null.sql.golden.json
+++ b/parser/testdata/query/output/select_simple_with_is_not_null.sql.golden.json
@@ -196,6 +196,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_simple_with_is_null.sql.golden.json b/parser/testdata/query/output/select_simple_with_is_null.sql.golden.json
index b41a093..f6c0114 100644
--- a/parser/testdata/query/output/select_simple_with_is_null.sql.golden.json
+++ b/parser/testdata/query/output/select_simple_with_is_null.sql.golden.json
@@ -182,6 +182,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_simple_with_top_clause.sql.golden.json b/parser/testdata/query/output/select_simple_with_top_clause.sql.golden.json
index 6e75392..c584082 100644
--- a/parser/testdata/query/output/select_simple_with_top_clause.sql.golden.json
+++ b/parser/testdata/query/output/select_simple_with_top_clause.sql.golden.json
@@ -61,6 +61,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_simple_with_with_clause.sql.golden.json b/parser/testdata/query/output/select_simple_with_with_clause.sql.golden.json
index 5d55b8b..a0dddd9 100644
--- a/parser/testdata/query/output/select_simple_with_with_clause.sql.golden.json
+++ b/parser/testdata/query/output/select_simple_with_with_clause.sql.golden.json
@@ -66,6 +66,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -131,6 +132,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -275,6 +277,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_table_alias_without_keyword.sql.golden.json b/parser/testdata/query/output/select_table_alias_without_keyword.sql.golden.json
index 6207280..1487980 100644
--- a/parser/testdata/query/output/select_table_alias_without_keyword.sql.golden.json
+++ b/parser/testdata/query/output/select_table_alias_without_keyword.sql.golden.json
@@ -156,6 +156,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_with_join_only.sql.golden.json b/parser/testdata/query/output/select_with_join_only.sql.golden.json
index 6bcefd1..2e61223 100644
--- a/parser/testdata/query/output/select_with_join_only.sql.golden.json
+++ b/parser/testdata/query/output/select_with_join_only.sql.golden.json
@@ -99,6 +99,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_with_left_join.sql.golden.json b/parser/testdata/query/output/select_with_left_join.sql.golden.json
index e4eb41a..2ea4c66 100644
--- a/parser/testdata/query/output/select_with_left_join.sql.golden.json
+++ b/parser/testdata/query/output/select_with_left_join.sql.golden.json
@@ -53,6 +53,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -105,6 +106,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -209,6 +211,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_with_literal_table_name.sql.golden.json b/parser/testdata/query/output/select_with_literal_table_name.sql.golden.json
index 6a0ad35..4f8a106 100644
--- a/parser/testdata/query/output/select_with_literal_table_name.sql.golden.json
+++ b/parser/testdata/query/output/select_with_literal_table_name.sql.golden.json
@@ -65,6 +65,7 @@
       "Offset": null
     },
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_with_multi_join.sql.golden.json b/parser/testdata/query/output/select_with_multi_join.sql.golden.json
index b4eed35..5113869 100644
--- a/parser/testdata/query/output/select_with_multi_join.sql.golden.json
+++ b/parser/testdata/query/output/select_with_multi_join.sql.golden.json
@@ -52,6 +52,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -103,6 +104,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -154,6 +156,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -419,6 +422,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_with_multi_line_comment.sql.golden.json b/parser/testdata/query/output/select_with_multi_line_comment.sql.golden.json
index 393d38e..2a6b80e 100644
--- a/parser/testdata/query/output/select_with_multi_line_comment.sql.golden.json
+++ b/parser/testdata/query/output/select_with_multi_line_comment.sql.golden.json
@@ -51,6 +51,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_with_string_expr.sql.golden.json b/parser/testdata/query/output/select_with_string_expr.sql.golden.json
index 90e27d4..1872786 100644
--- a/parser/testdata/query/output/select_with_string_expr.sql.golden.json
+++ b/parser/testdata/query/output/select_with_string_expr.sql.golden.json
@@ -53,6 +53,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -108,6 +109,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null
diff --git a/parser/testdata/query/output/select_with_union_distinct.sql.golden.json b/parser/testdata/query/output/select_with_union_distinct.sql.golden.json
index e26ec64..a98c0b0 100644
--- a/parser/testdata/query/output/select_with_union_distinct.sql.golden.json
+++ b/parser/testdata/query/output/select_with_union_distinct.sql.golden.json
@@ -56,10 +56,11 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": {
       "SelectPos": 59,
-      "StatementEnd": 109,
+      "StatementEnd": 121,
       "With": null,
       "Top": null,
       "SelectColumns": {
@@ -114,6 +115,15 @@
       "LimitBy": null,
       "Limit": null,
       "Settings": null,
+      "Format": {
+        "FormatPos": 110,
+        "Format": {
+          "Name": "JSON",
+          "QuoteType": 1,
+          "NamePos": 117,
+          "NameEnd": 121
+        }
+      },
       "UnionAll": null,
       "UnionDistinct": null,
       "Except": null
diff --git a/parser/testdata/query/output/select_with_variable.sql.golden.json b/parser/testdata/query/output/select_with_variable.sql.golden.json
index ad5b84c..e27d903 100644
--- a/parser/testdata/query/output/select_with_variable.sql.golden.json
+++ b/parser/testdata/query/output/select_with_variable.sql.golden.json
@@ -53,6 +53,7 @@
             "LimitBy": null,
             "Limit": null,
             "Settings": null,
+            "Format": null,
             "UnionAll": null,
             "UnionDistinct": null,
             "Except": null
@@ -108,6 +109,7 @@
     "LimitBy": null,
     "Limit": null,
     "Settings": null,
+    "Format": null,
     "UnionAll": null,
     "UnionDistinct": null,
     "Except": null