summaryrefslogtreecommitdiffstats
path: root/sqlglot/parser.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-09-25 08:20:06 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-09-25 08:20:06 +0000
commitbd2d949d1f2fb728cf4c429dd3ae9a1510e10182 (patch)
treec051102e5aff0ca2d75e5b96b09968c52114060a /sqlglot/parser.py
parentAdding upstream version 18.5.1. (diff)
downloadsqlglot-bd2d949d1f2fb728cf4c429dd3ae9a1510e10182.tar.xz
sqlglot-bd2d949d1f2fb728cf4c429dd3ae9a1510e10182.zip
Adding upstream version 18.7.0.upstream/18.7.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sqlglot/parser.py')
-rw-r--r--sqlglot/parser.py110
1 files changed, 72 insertions, 38 deletions
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index 06bc1eb..84b2639 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -278,6 +278,7 @@ class Parser(metaclass=_Parser):
TokenType.ISNULL,
TokenType.INTERVAL,
TokenType.KEEP,
+ TokenType.KILL,
TokenType.LEFT,
TokenType.LOAD,
TokenType.MERGE,
@@ -285,6 +286,7 @@ class Parser(metaclass=_Parser):
TokenType.NEXT,
TokenType.OFFSET,
TokenType.ORDINALITY,
+ TokenType.OVERLAPS,
TokenType.OVERWRITE,
TokenType.PARTITION,
TokenType.PERCENT,
@@ -316,6 +318,7 @@ class Parser(metaclass=_Parser):
INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
+ TokenType.ANTI,
TokenType.APPLY,
TokenType.ASOF,
TokenType.FULL,
@@ -324,6 +327,7 @@ class Parser(metaclass=_Parser):
TokenType.NATURAL,
TokenType.OFFSET,
TokenType.RIGHT,
+ TokenType.SEMI,
TokenType.WINDOW,
}
@@ -541,6 +545,7 @@ class Parser(metaclass=_Parser):
TokenType.DESCRIBE: lambda self: self._parse_describe(),
TokenType.DROP: lambda self: self._parse_drop(),
TokenType.INSERT: lambda self: self._parse_insert(),
+ TokenType.KILL: lambda self: self._parse_kill(),
TokenType.LOAD: lambda self: self._parse_load(),
TokenType.MERGE: lambda self: self._parse_merge(),
TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
@@ -856,6 +861,8 @@ class Parser(metaclass=_Parser):
DISTINCT_TOKENS = {TokenType.DISTINCT}
+ NULL_TOKENS = {TokenType.NULL}
+
STRICT_CAST = True
# A NULL arg in CONCAT yields NULL by default
@@ -873,6 +880,9 @@ class Parser(metaclass=_Parser):
# Whether or not the table sample clause expects CSV syntax
TABLESAMPLE_CSV = False
+ # Whether or not the SET command needs a delimiter (e.g. "=") for assignments.
+ SET_REQUIRES_ASSIGNMENT_DELIMITER = True
+
__slots__ = (
"error_level",
"error_message_context",
@@ -1280,7 +1290,14 @@ class Parser(metaclass=_Parser):
else:
begin = self._match(TokenType.BEGIN)
return_ = self._match_text_seq("RETURN")
- expression = self._parse_statement()
+
+ if self._match(TokenType.STRING, advance=False):
+ # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
+ # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
+ expression = self._parse_string()
+ extend_props(self._parse_properties())
+ else:
+ expression = self._parse_statement()
if return_:
expression = self.expression(exp.Return, this=expression)
@@ -1400,20 +1417,18 @@ class Parser(metaclass=_Parser):
if self._match_text_seq("SQL", "SECURITY"):
return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
- assignment = self._match_pair(
- TokenType.VAR, TokenType.EQ, advance=False
- ) or self._match_pair(TokenType.STRING, TokenType.EQ, advance=False)
+ index = self._index
+ key = self._parse_column()
- if assignment:
- key = self._parse_var_or_string()
- self._match(TokenType.EQ)
- return self.expression(
- exp.Property,
- this=key,
- value=self._parse_column() or self._parse_var(any_token=True),
- )
+ if not self._match(TokenType.EQ):
+ self._retreat(index)
+ return None
- return None
+ return self.expression(
+ exp.Property,
+ this=key.to_dot() if isinstance(key, exp.Column) else key,
+ value=self._parse_column() or self._parse_var(any_token=True),
+ )
def _parse_stored(self) -> exp.FileFormatProperty:
self._match(TokenType.ALIAS)
@@ -1818,6 +1833,15 @@ class Parser(metaclass=_Parser):
ignore=ignore,
)
+ def _parse_kill(self) -> exp.Kill:
+ kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
+
+ return self.expression(
+ exp.Kill,
+ this=self._parse_primary(),
+ kind=kind,
+ )
+
def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
conflict = self._match_text_seq("ON", "CONFLICT")
duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
@@ -2459,7 +2483,7 @@ class Parser(metaclass=_Parser):
index = self._parse_id_var()
table = None
- using = self._parse_field() if self._match(TokenType.USING) else None
+ using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
if self._match(TokenType.L_PAREN, advance=False):
columns = self._parse_wrapped_csv(self._parse_ordered)
@@ -2476,6 +2500,7 @@ class Parser(metaclass=_Parser):
primary=primary,
amp=amp,
partition_by=self._parse_partition_by(),
+ where=self._parse_where(),
)
def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
@@ -2634,25 +2659,27 @@ class Parser(metaclass=_Parser):
return None
expressions = self._parse_wrapped_csv(self._parse_type)
- ordinality = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
+ offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
alias = self._parse_table_alias() if with_alias else None
- if alias and self.UNNEST_COLUMN_ONLY:
- if alias.args.get("columns"):
- self.raise_error("Unexpected extra column alias in unnest.")
+ if alias:
+ if self.UNNEST_COLUMN_ONLY:
+ if alias.args.get("columns"):
+ self.raise_error("Unexpected extra column alias in unnest.")
+
+ alias.set("columns", [alias.this])
+ alias.set("this", None)
- alias.set("columns", [alias.this])
- alias.set("this", None)
+ columns = alias.args.get("columns") or []
+ if offset and len(expressions) < len(columns):
+ offset = columns.pop()
- offset = None
- if self._match_pair(TokenType.WITH, TokenType.OFFSET):
+ if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
self._match(TokenType.ALIAS)
offset = self._parse_id_var() or exp.to_identifier("offset")
- return self.expression(
- exp.Unnest, expressions=expressions, ordinality=ordinality, alias=alias, offset=offset
- )
+ return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
@@ -2940,20 +2967,20 @@ class Parser(metaclass=_Parser):
def _parse_ordered(self) -> exp.Ordered:
this = self._parse_conjunction()
- self._match(TokenType.ASC)
- is_desc = self._match(TokenType.DESC)
+ asc = self._match(TokenType.ASC)
+ desc = self._match(TokenType.DESC) or (asc and False)
+
is_nulls_first = self._match_text_seq("NULLS", "FIRST")
is_nulls_last = self._match_text_seq("NULLS", "LAST")
- desc = is_desc or False
- asc = not desc
+
nulls_first = is_nulls_first or False
explicitly_null_ordered = is_nulls_first or is_nulls_last
if (
not explicitly_null_ordered
and (
- (asc and self.NULL_ORDERING == "nulls_are_small")
+ (not desc and self.NULL_ORDERING == "nulls_are_small")
or (desc and self.NULL_ORDERING != "nulls_are_small")
)
and self.NULL_ORDERING != "nulls_are_last"
@@ -3227,8 +3254,8 @@ class Parser(metaclass=_Parser):
return self.UNARY_PARSERS[self._prev.token_type](self)
return self._parse_at_time_zone(self._parse_type())
- def _parse_type(self) -> t.Optional[exp.Expression]:
- interval = self._parse_interval()
+ def _parse_type(self, parse_interval: bool = True) -> t.Optional[exp.Expression]:
+ interval = parse_interval and self._parse_interval()
if interval:
return interval
@@ -3247,7 +3274,7 @@ class Parser(metaclass=_Parser):
return self._parse_column()
return self._parse_column_ops(data_type)
- return this
+ return this and self._parse_column_ops(this)
def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
this = self._parse_type()
@@ -3404,7 +3431,7 @@ class Parser(metaclass=_Parser):
return this
def _parse_struct_types(self) -> t.Optional[exp.Expression]:
- this = self._parse_type() or self._parse_id_var()
+ this = self._parse_type(parse_interval=False) or self._parse_id_var()
self._match(TokenType.COLON)
return self._parse_column_def(this)
@@ -3847,6 +3874,8 @@ class Parser(metaclass=_Parser):
action = "NO ACTION"
elif self._match_text_seq("CASCADE"):
action = "CASCADE"
+ elif self._match_text_seq("RESTRICT"):
+ action = "RESTRICT"
elif self._match_pair(TokenType.SET, TokenType.NULL):
action = "SET NULL"
elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
@@ -4573,7 +4602,7 @@ class Parser(metaclass=_Parser):
return self._parse_var() or self._parse_string()
def _parse_null(self) -> t.Optional[exp.Expression]:
- if self._match(TokenType.NULL):
+ if self._match_set(self.NULL_TOKENS):
return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
return self._parse_placeholder()
@@ -4608,14 +4637,18 @@ class Parser(metaclass=_Parser):
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
@@ -4931,8 +4964,9 @@ class Parser(metaclass=_Parser):
return self._parse_set_transaction(global_=kind == "GLOBAL")
left = self._parse_primary() or self._parse_id_var()
+ assignment_delimiter = self._match_texts(("=", "TO"))
- if not self._match_texts(("=", "TO")):
+ if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
self._retreat(index)
return None