diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-09-25 08:20:06 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-09-25 08:20:06 +0000 |
commit | bd2d949d1f2fb728cf4c429dd3ae9a1510e10182 (patch) | |
tree | c051102e5aff0ca2d75e5b96b09968c52114060a /sqlglot/parser.py | |
parent | Adding upstream version 18.5.1. (diff) | |
download | sqlglot-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.py | 110 |
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 |