@@ -9,9 +9,12 @@ class so that callers only need to call :meth:`DialectParser.parse`.
99from typing import Any , Optional
1010
1111import sqlglot
12- from sqlglot import Dialect , exp
12+ from sqlglot import exp
13+ from sqlglot .dialects .dialect import Dialect , DialectType
14+ from sqlglot .dialects .redshift import Redshift
1315from sqlglot .dialects .tsql import TSQL
1416from sqlglot .errors import ParseError , TokenError
17+ from sqlglot .parsers .redshift import RedshiftParser
1518from sqlglot .tokens import Tokenizer as BaseTokenizer
1619
1720from sql_metadata .comments import _has_hash_variables
@@ -47,6 +50,31 @@ class Tokenizer(BaseTokenizer):
4750 VAR_SINGLE_TOKENS = {* BaseTokenizer .VAR_SINGLE_TOKENS , "#" }
4851
4952
53+ class _RedshiftAppendParser (RedshiftParser ):
54+ """Redshift parser extended with ``ALTER TABLE ... APPEND FROM``."""
55+
56+ def _parse_alter_table_append (self ) -> "exp.Expr | None" :
57+ self ._match_text_seq ("FROM" )
58+ return self ._parse_table ()
59+
60+ ALTER_PARSERS = {
61+ ** RedshiftParser .ALTER_PARSERS ,
62+ "APPEND" : lambda self : self ._parse_alter_table_append (),
63+ }
64+
65+
66+ class RedshiftAppendDialect (Redshift ):
67+ """Redshift dialect extended with ``ALTER TABLE ... APPEND FROM`` support.
68+
69+ Redshift's ``APPEND FROM`` syntax is not natively supported by sqlglot,
70+ which causes the statement to degrade to ``exp.Command``. This dialect
71+ adds an ``APPEND`` entry to ``ALTER_PARSERS`` so the statement is parsed
72+ as a proper ``exp.Alter`` with ``exp.Table`` nodes.
73+ """
74+
75+ Parser = _RedshiftAppendParser
76+
77+
5078class BracketedTableDialect (TSQL ):
5179 """TSQL dialect for queries containing ``[bracketed]`` identifiers.
5280
@@ -65,7 +93,7 @@ class BracketedTableDialect(TSQL):
6593class DialectParser :
6694 """Detect the appropriate sqlglot dialect and parse SQL into an AST."""
6795
68- def parse (self , clean_sql : str ) -> tuple [exp .Expression , object ]:
96+ def parse (self , clean_sql : str ) -> tuple [exp .Expression , DialectType ]:
6997 """Parse *clean_sql*, returning ``(ast, dialect)``.
7098
7199 Detects candidate dialects via heuristics, tries each in order,
@@ -110,13 +138,15 @@ def _detect_dialects(sql: str) -> list:
110138 return [BracketedTableDialect , None , "mysql" ]
111139 if " UNIQUE " in upper :
112140 return [None , "mysql" , "oracle" ]
141+ if "APPEND FROM" in upper :
142+ return [RedshiftAppendDialect , None , "mysql" ]
113143 return [None , "mysql" ]
114144
115145 # -- parsing ------------------------------------------------------------
116146
117147 def _try_dialects (
118148 self , clean_sql : str , dialects : list
119- ) -> tuple [exp .Expression , object ]:
149+ ) -> tuple [exp .Expression , DialectType ]:
120150 """Try parsing *clean_sql* with each dialect, returning the best.
121151
122152 :returns: 2-tuple of ``(ast_node, winning_dialect)``.
0 commit comments