Repository: AfterShip/clickhouse-sql-parser (go)

Issue:
Why does this fail (is it because of conflict with `interval` as result alias?)
```sql
SELECT
    toStartOfInterval(timestamp, toIntervalMinute(1)) AS interval,
    column_name
FROM table
WHERE true
GROUP BY (interval, column_name)
ORDER BY (interval, column_name) ASC
```

It throws **_line 5:18 unexpected token kind: ,_**

Pull request:
Fix should allow using the keyword as column name
This closes #145.

Patch:
diff --git a/parser/parser_column.go b/parser/parser_column.go
index 1ab9f9b..43897e4 100644
--- a/parser/parser_column.go
+++ b/parser/parser_column.go
@@ -333,7 +333,23 @@ func (p *Parser) peekTokenKind(kind TokenKind) bool {
 	return token.Kind == kind
 }
 
+func (p *Parser) peekKeyword(keyword string) bool {
+	if p.lexer.isEOF() {
+		return false
+	}
+	token, err := p.lexer.peekToken()
+	if err != nil || token == nil {
+		return false
+	}
+	return token.Kind == TokenKindKeyword && strings.EqualFold(token.String, keyword)
+}
+
 func (p *Parser) parseColumnExpr(pos Pos) (Expr, error) { //nolint:funlen
+	// Should parse the keyword as an identifier if the keyword is followed by one of comma, `AS`.
+	// For example: `SELECT 1 as interval GROUP BY interval` is a valid syntax in ClickHouse.
+	if p.matchTokenKind(TokenKindKeyword) && (p.peekTokenKind(TokenKindComma) || p.peekKeyword(KeywordAs)) {
+		return p.parseIdent()
+	}
 	switch {
 	case p.matchKeyword(KeywordInterval):
 		return p.parseColumnExprInterval(pos)


Test patch:
diff --git a/parser/testdata/query/format/select_with_keyword_in_group_by.sql b/parser/testdata/query/format/select_with_keyword_in_group_by.sql
new file mode 100644
index 0000000..e86836c
--- /dev/null
+++ b/parser/testdata/query/format/select_with_keyword_in_group_by.sql
@@ -0,0 +1,11 @@
+-- Origin SQL:
+SELECT
+    toStartOfInterval(timestamp, toIntervalMinute(1)) AS interval,
+    column_name
+FROM table
+WHERE true
+GROUP BY (interval, column_name)
+ORDER BY (interval AS i, column_name) ASC
+
+-- Format SQL:
+SELECT toStartOfInterval(timestamp, toIntervalMinute(1)) AS interval, column_name FROM table WHERE true GROUP BY (interval, column_name) ORDER BY (interval AS i, column_name) ASC;
diff --git a/parser/testdata/query/output/select_with_keyword_in_group_by.sql.golden.json b/parser/testdata/query/output/select_with_keyword_in_group_by.sql.golden.json
new file mode 100644
index 0000000..e7ea4f9
--- /dev/null
+++ b/parser/testdata/query/output/select_with_keyword_in_group_by.sql.golden.json
@@ -0,0 +1,227 @@
+[
+  {
+    "SelectPos": 0,
+    "StatementEnd": 181,
+    "With": null,
+    "Top": null,
+    "SelectItems": [
+      {
+        "Expr": {
+          "Name": {
+            "Name": "toStartOfInterval",
+            "QuoteType": 1,
+            "NamePos": 11,
+            "NameEnd": 28
+          },
+          "Params": {
+            "LeftParenPos": 28,
+            "RightParenPos": 59,
+            "Items": {
+              "ListPos": 29,
+              "ListEnd": 58,
+              "HasDistinct": false,
+              "Items": [
+                {
+                  "Expr": {
+                    "Name": "timestamp",
+                    "QuoteType": 1,
+                    "NamePos": 29,
+                    "NameEnd": 38
+                  },
+                  "Alias": null
+                },
+                {
+                  "Expr": {
+                    "Name": {
+                      "Name": "toIntervalMinute",
+                      "QuoteType": 1,
+                      "NamePos": 40,
+                      "NameEnd": 56
+                    },
+                    "Params": {
+                      "LeftParenPos": 56,
+                      "RightParenPos": 58,
+                      "Items": {
+                        "ListPos": 57,
+                        "ListEnd": 58,
+                        "HasDistinct": false,
+                        "Items": [
+                          {
+                            "Expr": {
+                              "NumPos": 57,
+                              "NumEnd": 58,
+                              "Literal": "1",
+                              "Base": 10
+                            },
+                            "Alias": null
+                          }
+                        ]
+                      },
+                      "ColumnArgList": null
+                    }
+                  },
+                  "Alias": null
+                }
+              ]
+            },
+            "ColumnArgList": null
+          }
+        },
+        "Modifiers": [],
+        "Alias": {
+          "Name": "interval",
+          "QuoteType": 1,
+          "NamePos": 64,
+          "NameEnd": 72
+        }
+      },
+      {
+        "Expr": {
+          "Name": "column_name",
+          "QuoteType": 1,
+          "NamePos": 78,
+          "NameEnd": 89
+        },
+        "Modifiers": [],
+        "Alias": null
+      }
+    ],
+    "From": {
+      "FromPos": 90,
+      "Expr": {
+        "Table": {
+          "TablePos": 95,
+          "TableEnd": 100,
+          "Alias": null,
+          "Expr": {
+            "Database": null,
+            "Table": {
+              "Name": "table",
+              "QuoteType": 1,
+              "NamePos": 95,
+              "NameEnd": 100
+            }
+          },
+          "HasFinal": false
+        },
+        "StatementEnd": 100,
+        "SampleRatio": null,
+        "HasFinal": false
+      }
+    },
+    "ArrayJoin": null,
+    "Window": null,
+    "Prewhere": null,
+    "Where": {
+      "WherePos": 101,
+      "Expr": {
+        "Name": "true",
+        "QuoteType": 1,
+        "NamePos": 107,
+        "NameEnd": 111
+      }
+    },
+    "GroupBy": {
+      "GroupByPos": 112,
+      "AggregateType": "",
+      "Expr": {
+        "ListPos": 121,
+        "ListEnd": 143,
+        "HasDistinct": false,
+        "Items": [
+          {
+            "Expr": {
+              "LeftParenPos": 121,
+              "RightParenPos": 143,
+              "Items": {
+                "ListPos": 122,
+                "ListEnd": 143,
+                "HasDistinct": false,
+                "Items": [
+                  {
+                    "Expr": {
+                      "Name": "interval",
+                      "QuoteType": 1,
+                      "NamePos": 122,
+                      "NameEnd": 130
+                    },
+                    "Alias": null
+                  },
+                  {
+                    "Expr": {
+                      "Name": "column_name",
+                      "QuoteType": 1,
+                      "NamePos": 132,
+                      "NameEnd": 143
+                    },
+                    "Alias": null
+                  }
+                ]
+              },
+              "ColumnArgList": null
+            },
+            "Alias": null
+          }
+        ]
+      },
+      "WithCube": false,
+      "WithRollup": false,
+      "WithTotals": false
+    },
+    "WithTotal": false,
+    "Having": null,
+    "OrderBy": {
+      "OrderPos": 145,
+      "ListEnd": 181,
+      "Items": [
+        {
+          "OrderPos": 145,
+          "Expr": {
+            "LeftParenPos": 154,
+            "RightParenPos": 181,
+            "Items": {
+              "ListPos": 155,
+              "ListEnd": 181,
+              "HasDistinct": false,
+              "Items": [
+                {
+                  "Expr": {
+                    "Name": "interval",
+                    "QuoteType": 1,
+                    "NamePos": 155,
+                    "NameEnd": 163
+                  },
+                  "Alias": {
+                    "Name": "i",
+                    "QuoteType": 1,
+                    "NamePos": 167,
+                    "NameEnd": 168
+                  }
+                },
+                {
+                  "Expr": {
+                    "Name": "column_name",
+                    "QuoteType": 1,
+                    "NamePos": 170,
+                    "NameEnd": 181
+                  },
+                  "Alias": null
+                }
+              ]
+            },
+            "ColumnArgList": null
+          },
+          "Alias": null,
+          "Direction": "ASC"
+        }
+      ]
+    },
+    "LimitBy": null,
+    "Limit": null,
+    "Settings": null,
+    "Format": null,
+    "UnionAll": null,
+    "UnionDistinct": null,
+    "Except": null
+  }
+]
\ No newline at end of file
diff --git a/parser/testdata/query/select_with_keyword_in_group_by.sql b/parser/testdata/query/select_with_keyword_in_group_by.sql
new file mode 100644
index 0000000..9ecc73f
--- /dev/null
+++ b/parser/testdata/query/select_with_keyword_in_group_by.sql
@@ -0,0 +1,7 @@
+SELECT
+    toStartOfInterval(timestamp, toIntervalMinute(1)) AS interval,
+    column_name
+FROM table
+WHERE true
+GROUP BY (interval, column_name)
+ORDER BY (interval AS i, column_name) ASC
\ No newline at end of file