summaryrefslogtreecommitdiffstats
path: root/sqlglot/parser.py
diff options
context:
space:
mode:
Diffstat (limited to 'sqlglot/parser.py')
-rw-r--r--sqlglot/parser.py83
1 files changed, 58 insertions, 25 deletions
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index b94313a..79a1d90 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -131,6 +131,7 @@ class Parser:
TokenType.ALTER,
TokenType.ALWAYS,
TokenType.ANTI,
+ TokenType.APPLY,
TokenType.BEGIN,
TokenType.BOTH,
TokenType.BUCKET,
@@ -190,6 +191,7 @@ class Parser:
TokenType.TABLE,
TokenType.TABLE_FORMAT,
TokenType.TEMPORARY,
+ TokenType.TRANSIENT,
TokenType.TOP,
TokenType.TRAILING,
TokenType.TRUNCATE,
@@ -204,7 +206,7 @@ class Parser:
*TYPE_TOKENS,
}
- TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.NATURAL}
+ TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.NATURAL, TokenType.APPLY}
TRIM_TYPES = {TokenType.LEADING, TokenType.TRAILING, TokenType.BOTH}
@@ -685,6 +687,7 @@ class Parser:
def _parse_create(self):
replace = self._match(TokenType.OR) and self._match(TokenType.REPLACE)
temporary = self._match(TokenType.TEMPORARY)
+ transient = self._match(TokenType.TRANSIENT)
unique = self._match(TokenType.UNIQUE)
materialized = self._match(TokenType.MATERIALIZED)
@@ -723,6 +726,7 @@ class Parser:
exists=exists,
properties=properties,
temporary=temporary,
+ transient=transient,
replace=replace,
unique=unique,
materialized=materialized,
@@ -1057,8 +1061,8 @@ class Parser:
return self._parse_set_operations(this) if this else None
- def _parse_with(self):
- if not self._match(TokenType.WITH):
+ def _parse_with(self, skip_with_token=False):
+ if not skip_with_token and not self._match(TokenType.WITH):
return None
recursive = self._match(TokenType.RECURSIVE)
@@ -1167,28 +1171,53 @@ class Parser:
return self.expression(exp.From, expressions=self._parse_csv(self._parse_table))
def _parse_lateral(self):
- if not self._match(TokenType.LATERAL):
+ outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY)
+ cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
+
+ if outer_apply or cross_apply:
+ this = self._parse_select(table=True)
+ view = None
+ outer = not cross_apply
+ elif self._match(TokenType.LATERAL):
+ this = self._parse_select(table=True)
+ view = self._match(TokenType.VIEW)
+ outer = self._match(TokenType.OUTER)
+ else:
return None
- subquery = self._parse_select(table=True)
+ if not this:
+ this = self._parse_function()
- if subquery:
- return self.expression(exp.Lateral, this=subquery)
+ table_alias = self._parse_id_var(any_token=False)
- self._match(TokenType.VIEW)
- outer = self._match(TokenType.OUTER)
+ columns = None
+ if self._match(TokenType.ALIAS):
+ columns = self._parse_csv(self._parse_id_var)
+ elif self._match(TokenType.L_PAREN):
+ columns = self._parse_csv(self._parse_id_var)
+ self._match(TokenType.R_PAREN)
- return self.expression(
+ expression = self.expression(
exp.Lateral,
- this=self._parse_function(),
+ this=this,
+ view=view,
outer=outer,
alias=self.expression(
exp.TableAlias,
- this=self._parse_id_var(any_token=False),
- columns=(self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else None),
+ this=table_alias,
+ columns=columns,
),
)
+ if outer_apply or cross_apply:
+ return self.expression(
+ exp.Join,
+ this=expression,
+ side=None if cross_apply else "LEFT",
+ )
+
+ return expression
+
def _parse_join_side_and_kind(self):
return (
self._match(TokenType.NATURAL) and self._prev,
@@ -1196,10 +1225,10 @@ class Parser:
self._match_set(self.JOIN_KINDS) and self._prev,
)
- def _parse_join(self):
+ def _parse_join(self, skip_join_token=False):
natural, side, kind = self._parse_join_side_and_kind()
- if not self._match(TokenType.JOIN):
+ if not skip_join_token and not self._match(TokenType.JOIN):
return None
kwargs = {"this": self._parse_table()}
@@ -1425,13 +1454,13 @@ class Parser:
unpivot=unpivot,
)
- def _parse_where(self):
- if not self._match(TokenType.WHERE):
+ def _parse_where(self, skip_where_token=False):
+ if not skip_where_token and not self._match(TokenType.WHERE):
return None
return self.expression(exp.Where, this=self._parse_conjunction())
- def _parse_group(self):
- if not self._match(TokenType.GROUP_BY):
+ def _parse_group(self, skip_group_by_token=False):
+ if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
return None
return self.expression(
exp.Group,
@@ -1457,8 +1486,8 @@ class Parser:
return self.expression(exp.Tuple, expressions=grouping_set)
return self._parse_id_var()
- def _parse_having(self):
- if not self._match(TokenType.HAVING):
+ def _parse_having(self, skip_having_token=False):
+ if not skip_having_token and not self._match(TokenType.HAVING):
return None
return self.expression(exp.Having, this=self._parse_conjunction())
@@ -1467,8 +1496,8 @@ class Parser:
return None
return self.expression(exp.Qualify, this=self._parse_conjunction())
- def _parse_order(self, this=None):
- if not self._match(TokenType.ORDER_BY):
+ def _parse_order(self, this=None, skip_order_token=False):
+ if not skip_order_token and not self._match(TokenType.ORDER_BY):
return this
return self.expression(exp.Order, this=this, expressions=self._parse_csv(self._parse_ordered))
@@ -1502,7 +1531,11 @@ class Parser:
def _parse_limit(self, this=None, top=False):
if self._match(TokenType.TOP if top else TokenType.LIMIT):
- return self.expression(exp.Limit, this=this, expression=self._parse_number())
+ limit_paren = self._match(TokenType.L_PAREN)
+ limit_exp = self.expression(exp.Limit, this=this, expression=self._parse_number())
+ if limit_paren:
+ self._match(TokenType.R_PAREN)
+ return limit_exp
if self._match(TokenType.FETCH):
direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
direction = self._prev.text if direction else "FIRST"
@@ -2136,7 +2169,7 @@ class Parser:
return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to)
def _parse_convert(self, strict):
- this = self._parse_field()
+ this = self._parse_column()
if self._match(TokenType.USING):
to = self.expression(exp.CharacterSet, this=self._parse_var())
elif self._match(TokenType.COMMA):