Repository: tobymao/sqlglot

Issue:
Snowflake `exclude` incorrect parsing
Hi! `sqlglot` seems to be incorrectly parsing `exclude` for single columns when no parenthesis are used. Having no parenthesis is [valid Snowflake syntax](https://docs.snowflake.com/en/sql-reference/sql/select).

Thoughts?

```python
import sqlglot

sql = """
select
    * exclude b  -- incorrectly parsed
    ,b
    ,c
from
    test
;
"""

print(sqlglot.parse_one(sql, read="snowflake"))

sql = """
select
    * exclude(b) -- correctly parsed
    ,b
    ,c
from
    test
;
"""

print(sqlglot.parse_one(sql, read="snowflake"))

# output:
# SELECT * EXCEPT (b /* incorrectly parsed */, b, c) FROM test
# SELECT * EXCEPT (b) /* correctly parsed */, b, c FROM test
```


Discussion:

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,7 @@
         "fallback_version": "0.0.0",
         "local_scheme": "no-local-version",
     },
-    setup_requires=["setuptools_scm"],
+    setup_requires=["setuptools_scm<8.0.1"],
     python_requires=">=3.7",
     extras_require={
         "dev": [
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -4616,14 +4616,18 @@ def _parse_except(self) -> t.Optional[t.List[exp.Expression]]:
             return None
         if self._match(TokenType.L_PAREN, advance=False):
             return self._parse_wrapped_csv(self._parse_column)
-        return self._parse_csv(self._parse_column)
+
+        except_column = self._parse_column()
+        return [except_column] if except_column else None
 
     def _parse_replace(self) -> t.Optional[t.List[exp.Expression]]:
         if not self._match(TokenType.REPLACE):
             return None
         if self._match(TokenType.L_PAREN, advance=False):
             return self._parse_wrapped_csv(self._parse_expression)
-        return self._parse_expressions()
+
+        replace_expression = self._parse_expression()
+        return [replace_expression] if replace_expression else None
 
     def _parse_csv(
         self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA


Test patch:
diff --git a/tests/dialects/test_snowflake.py b/tests/dialects/test_snowflake.py
--- a/tests/dialects/test_snowflake.py
+++ b/tests/dialects/test_snowflake.py
@@ -279,13 +279,13 @@ def test_snowflake(self):
         self.validate_all(
             "SELECT * EXCLUDE a, b FROM xxx",
             write={
-                "snowflake": "SELECT * EXCLUDE (a, b) FROM xxx",
+                "snowflake": "SELECT * EXCLUDE (a), b FROM xxx",
             },
         )
         self.validate_all(
             "SELECT * RENAME a AS b, c AS d FROM xxx",
             write={
-                "snowflake": "SELECT * RENAME (a AS b, c AS d) FROM xxx",
+                "snowflake": "SELECT * RENAME (a AS b), c AS d FROM xxx",
             },
         )
         self.validate_all(
diff --git a/tests/fixtures/pretty.sql b/tests/fixtures/pretty.sql
--- a/tests/fixtures/pretty.sql
+++ b/tests/fixtures/pretty.sql
@@ -361,7 +361,8 @@ CROSS JOIN UNNEST(fruit_basket) WITH ORDINALITY AS fruit(basket_index);
 SELECT A.* EXCEPT A.COL_1, A.COL_2 FROM TABLE_1 A;
 SELECT
   A.*
-  EXCEPT (A.COL_1, A.COL_2)
+  EXCEPT (A.COL_1),
+  A.COL_2
 FROM TABLE_1 AS A;
 
 SELECT *