Repository: tobymao/sqlglot

Issue:
Cannot parse "ALTER SESSION SET" queries in snowflake
`ALTER SESSION SET STATEMENT_TIMEOUT_IN_SECONDS=3` works in snowflake but this raises ParseError:

```python
import sqlglot

print(sqlglot.transpile("ALTER SESSION SET STATEMENT_TIMEOUT_IN_SECONDS=3", read="snowflake"))
```

<details>

<summary>Stack trace</summary>

```python-traceback
ParseError                                Traceback (most recent call last)
Cell In[3], line 3
      1 import sqlglot
----> 3 print(sqlglot.transpile("ALTER SESSION SET STATEMENT_TIMEOUT_IN_SECONDS=3", read="snowflake"))

File ~/opt/anaconda3/envs/ponder-product-testing/lib/python3.10/site-packages/sqlglot/__init__.py:177, in transpile(sql, read, write, identity, error_level, **opts)
    158 """
    159 Parses the given SQL string in accordance with the source dialect and returns a list of SQL strings transformed
    160 to conform to the target dialect. Each string in the returned list represents a single transformed SQL statement.
   (...)
    172     The list of transpiled SQL statements.
    173 """
    174 write = write or read if identity else write
    175 return [
    176     Dialect.get_or_raise(write)().generate(expression, **opts)
--> 177     for expression in parse(sql, read, error_level=error_level)
    178 ]

File ~/opt/anaconda3/envs/ponder-product-testing/lib/python3.10/site-packages/sqlglot/__init__.py:65, in parse(sql, read, **opts)
     53 """
     54 Parses the given SQL string into a collection of syntax trees, one per parsed SQL statement.
     55
   (...)
     62     The resulting syntax tree collection.
     63 """
     64 dialect = Dialect.get_or_raise(read)()
---> 65 return dialect.parse(sql, **opts)

File ~/opt/anaconda3/envs/ponder-product-testing/lib/python3.10/site-packages/sqlglot/dialects/dialect.py:163, in Dialect.parse(self, sql, **opts)
    162 def parse(self, sql: str, **opts) -> t.List[t.Optional[exp.Expression]]:
--> 163     return self.parser(**opts).parse(self.tokenizer.tokenize(sql), sql)

File ~/opt/anaconda3/envs/ponder-product-testing/lib/python3.10/site-packages/sqlglot/parser.py:707, in Parser.parse(self, raw_tokens, sql)
    693 def parse(
    694     self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    695 ) -> t.List[t.Optional[exp.Expression]]:
    696     """
    697     Parses a list of tokens and returns a list of syntax trees, one tree
    698     per parsed SQL statement.
   (...)
    705         The list of syntax trees.
    706     """
--> 707     return self._parse(
    708         parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    709     )

File ~/opt/anaconda3/envs/ponder-product-testing/lib/python3.10/site-packages/sqlglot/parser.py:773, in Parser._parse(self, parse_method, raw_tokens, sql)
    770     expressions.append(parse_method(self))
    772     if self._index < len(self._tokens):
--> 773         self.raise_error("Invalid expression / Unexpected token")
    775     self.check_errors()
    777 return expressions

File ~/opt/anaconda3/envs/ponder-product-testing/lib/python3.10/site-packages/sqlglot/parser.py:816, in Parser.raise_error(self, message, token)
    804 error = ParseError.new(
    805     f"{message}. Line {token.line}, Col: {token.col}.\n"
    806     f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
   (...)
    812     end_context=end_context,
    813 )
    815 if self.error_level == ErrorLevel.IMMEDIATE:
--> 816     raise error
    818 self.errors.append(error)

ParseError: Invalid expression / Unexpected token. Line 1, Col: 7.
  ALTER SESSION SET STATEMENT_TIMEOUT_IN_SECONDS=3
```

</details>


Discussion:

Resolving patch:
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -3449,7 +3449,7 @@ def _parse_add_constraint(self) -> t.Optional[exp.Expression]:
 
     def _parse_alter(self) -> t.Optional[exp.Expression]:
         if not self._match(TokenType.TABLE):
-            return None
+            return self._parse_as_command(self._prev)
 
         exists = self._parse_exists()
         this = self._parse_table(schema=True)


Test patch:
diff --git a/tests/fixtures/identity.sql b/tests/fixtures/identity.sql
--- a/tests/fixtures/identity.sql
+++ b/tests/fixtures/identity.sql
@@ -589,6 +589,7 @@ INSERT OVERWRITE TABLE a.b PARTITION(ds) SELECT x FROM y
 INSERT OVERWRITE TABLE a.b PARTITION(ds = 'YYYY-MM-DD') SELECT x FROM y
 INSERT OVERWRITE TABLE a.b PARTITION(ds, hour) SELECT x FROM y
 INSERT OVERWRITE TABLE a.b PARTITION(ds = 'YYYY-MM-DD', hour = 'hh') SELECT x FROM y
+ALTER SESSION SET STATEMENT_TIMEOUT_IN_SECONDS=3
 ALTER AGGREGATE bla(foo) OWNER TO CURRENT_USER
 ALTER RULE foo ON bla RENAME TO baz
 ALTER ROLE CURRENT_USER WITH REPLICATION