Repository: tobymao/sqlglot

Issue:
Clickhouse current_timestamp table field is not support
**Before you file an issue**
`parse_one(sql, read="clickhouse")`

**Fully reproducible code snippet**
Please include a fully reproducible code snippet or the input sql, dialect, and expected output.

In clickhouse, current_timestamp can be used as a field name, and this is not a SQL expression, but is converted to exp.CurrentTimestamp during parse.

Clickhouse sql:
```
select current_timestamp, a from t
```
Parsed AST as following:
```
Select(
  expressions=[
    CurrentTimestamp(),
    Column(
      this=Identifier(this=a, quoted=False))],
  from=From(
    this=Table(
      this=Identifier(this=t, quoted=False))))
```
I excepted output is `current_timestamp` Column.

Execute in clickhouse:
```
INTO my_db.my_table2 (event_date, event_time, current_timestamp, user_id, clicks)
VALUES ('2023-12-31', '2023-12-31 23:59:59', 1725616170, 1, 10);

INSERT INTO my_db.my_table2 (event_date, event_time, current_timestamp, user_id, clicks) FORMAT Values

Query id: 0e2beb83-6acd-447e-a176-31816c982142

Ok.

1 row in set. Elapsed: 0.026 sec. 
```

select current_timestamp from my_db.my_table2;
```
0c40e341ddf3 :) select current_timestamp from my_db.my_table2;

SELECT current_timestamp
FROM my_db.my_table2

Query id: 871b946d-e790-4858-b0da-d4b63c359d88

   ┌─current_timestamp─┐
1. │        1725616170 │ -- 1.73 billion
   └───────────────────┘
```

SELECT current_timestamp
```
SELECT current_timestamp

Query id: abfc55fd-6313-4c1c-a80f-c636bbdeb027


Elapsed: 0.013 sec. 

Received exception from server (version 24.8.3):
Code: 47. DB::Exception: Received from localhost:9000. DB::Exception: Unknown expression identifier 'current_timestamp' in scope SELECT current_timestamp. (UNKNOWN_IDENTIFIER)

```

Discussion:

Solution patch:
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
index 74e6bd9aac..7796e84d70 100644
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -403,6 +403,9 @@ class Parser(parser.Parser):
         NO_PAREN_FUNCTION_PARSERS = parser.Parser.NO_PAREN_FUNCTION_PARSERS.copy()
         NO_PAREN_FUNCTION_PARSERS.pop("ANY")
 
+        NO_PAREN_FUNCTIONS = parser.Parser.NO_PAREN_FUNCTIONS.copy()
+        NO_PAREN_FUNCTIONS.pop(TokenType.CURRENT_TIMESTAMP)
+
         RANGE_PARSERS = {
             **parser.Parser.RANGE_PARSERS,
             TokenType.GLOBAL: lambda self, this: self._match(TokenType.IN)
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index 218dc79614..a15dd8155e 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -5359,18 +5359,19 @@ def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.
             ("ALIAS", "MATERIALIZED")
         ):
             persisted = self._prev.text.upper() == "MATERIALIZED"
-            constraints.append(
-                self.expression(
-                    exp.ComputedColumnConstraint,
-                    this=self._parse_assignment(),
-                    persisted=persisted or self._match_text_seq("PERSISTED"),
-                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
-                )
+            constraint_kind = exp.ComputedColumnConstraint(
+                this=self._parse_assignment(),
+                persisted=persisted or self._match_text_seq("PERSISTED"),
+                not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
             )
+            constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
         elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
             self._match(TokenType.ALIAS)
             constraints.append(
-                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
+                self.expression(
+                    exp.ColumnConstraint,
+                    kind=exp.TransformColumnConstraint(this=self._parse_field()),
+                )
             )
 
         while True:


Test patch:
diff --git a/tests/dialects/test_clickhouse.py b/tests/dialects/test_clickhouse.py
index 2cd272dfe3..ea6064a6be 100644
--- a/tests/dialects/test_clickhouse.py
+++ b/tests/dialects/test_clickhouse.py
@@ -515,6 +515,7 @@ def test_clickhouse(self):
         )
         self.validate_identity("SELECT TRIM(TRAILING ')' FROM '(   Hello, world!   )')")
         self.validate_identity("SELECT TRIM(LEADING '(' FROM '(   Hello, world!   )')")
+        self.validate_identity("current_timestamp").assert_is(exp.Column)
 
     def test_clickhouse_values(self):
         values = exp.select("*").from_(
@@ -1016,6 +1017,12 @@ def test_ddl(self):
             pretty=True,
         )
 
+        self.assertIsNotNone(
+            self.validate_identity("CREATE TABLE t1 (a String MATERIALIZED func())").find(
+                exp.ColumnConstraint
+            )
+        )
+
     def test_agg_functions(self):
         def extract_agg_func(query):
             return parse_one(query, read="clickhouse").selects[0].this
diff --git a/tests/dialects/test_snowflake.py b/tests/dialects/test_snowflake.py
index 49f1a4ff73..3e0d600a8d 100644
--- a/tests/dialects/test_snowflake.py
+++ b/tests/dialects/test_snowflake.py
@@ -1423,6 +1423,12 @@ def test_ddl(self):
                     },
                 )
 
+        self.assertIsNotNone(
+            self.validate_identity("CREATE TABLE foo (bar INT AS (foo))").find(
+                exp.TransformColumnConstraint
+            )
+        )
+
     def test_user_defined_functions(self):
         self.validate_all(
             "CREATE FUNCTION a(x DATE, y BIGINT) RETURNS ARRAY LANGUAGE JAVASCRIPT AS $$ SELECT 1 $$",