Repository: tobymao/sqlglot

Issue:
duckdb: non-literal date is no longer cast as date when converted from snowflake 
The following conversion fails when executed by duckdb, because `DATE` is not a valid duckdb expression:
```
❯ python -c 'import sqlglot; print(repr(sqlglot.parse_one("SELECT date(a.start_date) from SOURCE_TABLE AS a", read="snowflake").sql(dialect="duckdb")));'
'SELECT DATE(a.start_date) FROM SOURCE_TABLE AS a'
```

sqlglot 21.2 didn't have this problem, and would cast a non-literal as date, eg: 
```
❯ python -c 'import sqlglot; print(repr(sqlglot.parse_one("SELECT date(a.start_date) from SOURCE_TABLE AS a", read="snowflake").sql(dialect="duckdb")));'
'SELECT CAST(a.start_date AS DATE) FROM SOURCE_TABLE AS a'
```

Discussion:

Patch:
diff --git a/sqlglot/dialects/snowflake.py b/sqlglot/dialects/snowflake.py
index 2fdf090c..dba56c47 100644
--- a/sqlglot/dialects/snowflake.py
+++ b/sqlglot/dialects/snowflake.py
@@ -33,10 +33,9 @@ def _build_datetime(
 ) -> t.Callable[[t.List], exp.Func]:
     def _builder(args: t.List) -> exp.Func:
         value = seq_get(args, 0)
+        int_value = value is not None and is_int(value.name)
 
         if isinstance(value, exp.Literal):
-            int_value = is_int(value.this)
-
             # Converts calls like `TO_TIME('01:02:03')` into casts
             if len(args) == 1 and value.is_string and not int_value:
                 return exp.cast(value, kind)
@@ -49,7 +48,7 @@ def _build_datetime(
                 if not is_float(value.this):
                     return build_formatted_time(exp.StrToTime, "snowflake")(args)
 
-        if len(args) == 2 and kind == exp.DataType.Type.DATE:
+        if kind == exp.DataType.Type.DATE and not int_value:
             formatted_exp = build_formatted_time(exp.TsOrDsToDate, "snowflake")(args)
             formatted_exp.set("safe", safe)
             return formatted_exp
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index 4297c563..9546bfc1 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -4301,7 +4301,7 @@ class Parser(metaclass=_Parser):
                 this = self._parse_subquery(
                     this=self._parse_set_operations(this), parse_alias=False
                 )
-            elif len(expressions) > 1:
+            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
                 this = self.expression(exp.Tuple, expressions=expressions)
             else:
                 this = self.expression(exp.Paren, this=this)


Test patch:
diff --git a/tests/dialects/test_snowflake.py b/tests/dialects/test_snowflake.py
index c1e9155a..4ddbed2a 100644
--- a/tests/dialects/test_snowflake.py
+++ b/tests/dialects/test_snowflake.py
@@ -1038,10 +1038,16 @@ WHERE
             "SELECT CAST('2019-02-28' AS DATE) + INTERVAL '1 day, 1 year'",
         )
 
-        self.validate_identity("DATE(x)").assert_is(exp.Anonymous)
-        self.validate_identity("TO_DATE(x)").assert_is(exp.Anonymous)
-        self.validate_identity("TRY_TO_DATE(x)").assert_is(exp.Anonymous)
+        self.validate_identity("TO_DATE(x)").assert_is(exp.TsOrDsToDate)
+        self.validate_identity("TRY_TO_DATE(x)").assert_is(exp.TsOrDsToDate)
 
+        self.validate_all(
+            "DATE(x)",
+            write={
+                "duckdb": "CAST(x AS DATE)",
+                "snowflake": "TO_DATE(x)",
+            },
+        )
         self.validate_all(
             "TO_DATE(x, 'MM-DD-YYYY')",
             write={
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 791d3529..94e8b804 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -87,6 +87,9 @@ class TestParser(unittest.TestCase):
 
         self.assertIsNotNone(parse_one("date").find(exp.Column))
 
+    def test_tuple(self):
+        parse_one("(a,)").assert_is(exp.Tuple)
+
     def test_structs(self):
         cast = parse_one("cast(x as struct<int>)")
         self.assertIsInstance(cast.to.expressions[0], exp.DataType)