diff options
Diffstat (limited to 'sqlglot/dialects')
-rw-r--r-- | sqlglot/dialects/bigquery.py | 12 | ||||
-rw-r--r-- | sqlglot/dialects/dialect.py | 13 | ||||
-rw-r--r-- | sqlglot/dialects/hive.py | 4 | ||||
-rw-r--r-- | sqlglot/dialects/mysql.py | 5 | ||||
-rw-r--r-- | sqlglot/dialects/oracle.py | 11 | ||||
-rw-r--r-- | sqlglot/dialects/postgres.py | 6 | ||||
-rw-r--r-- | sqlglot/dialects/presto.py | 1 | ||||
-rw-r--r-- | sqlglot/dialects/snowflake.py | 33 | ||||
-rw-r--r-- | sqlglot/dialects/spark.py | 13 | ||||
-rw-r--r-- | sqlglot/dialects/tsql.py | 5 |
10 files changed, 81 insertions, 22 deletions
diff --git a/sqlglot/dialects/bigquery.py b/sqlglot/dialects/bigquery.py index 86e46cf..62d042e 100644 --- a/sqlglot/dialects/bigquery.py +++ b/sqlglot/dialects/bigquery.py @@ -78,6 +78,16 @@ def _create_sql(self, expression): class BigQuery(Dialect): unnest_column_only = True + time_mapping = { + "%M": "%-M", + "%d": "%-d", + "%m": "%-m", + "%y": "%-y", + "%H": "%-H", + "%I": "%-I", + "%S": "%-S", + "%j": "%-j", + } class Tokenizer(Tokenizer): QUOTES = [ @@ -113,6 +123,7 @@ class BigQuery(Dialect): "DATETIME_SUB": _date_add(exp.DatetimeSub), "TIME_SUB": _date_add(exp.TimeSub), "TIMESTAMP_SUB": _date_add(exp.TimestampSub), + "PARSE_TIMESTAMP": lambda args: exp.StrToTime(this=list_get(args, 1), format=list_get(args, 0)), } NO_PAREN_FUNCTIONS = { @@ -137,6 +148,7 @@ class BigQuery(Dialect): exp.DatetimeSub: _date_add_sql("DATETIME", "SUB"), exp.DateDiff: lambda self, e: f"DATE_DIFF({self.sql(e, 'this')}, {self.sql(e, 'expression')}, {self.sql(e.args.get('unit', 'DAY'))})", exp.ILike: no_ilike_sql, + exp.StrToTime: lambda self, e: f"PARSE_TIMESTAMP({self.format_time(e)}, {self.sql(e, 'this')})", exp.TimeAdd: _date_add_sql("TIME", "ADD"), exp.TimeSub: _date_add_sql("TIME", "SUB"), exp.TimestampAdd: _date_add_sql("TIMESTAMP", "ADD"), diff --git a/sqlglot/dialects/dialect.py b/sqlglot/dialects/dialect.py index 531c72a..46661cf 100644 --- a/sqlglot/dialects/dialect.py +++ b/sqlglot/dialects/dialect.py @@ -2,7 +2,7 @@ from enum import Enum from sqlglot import exp from sqlglot.generator import Generator -from sqlglot.helper import list_get +from sqlglot.helper import flatten, list_get from sqlglot.parser import Parser from sqlglot.time import format_time from sqlglot.tokens import Tokenizer @@ -67,6 +67,11 @@ class _Dialect(type): klass.generator_class.TRANSFORMS[ exp.HexString ] = lambda self, e: f"{hs_start}{int(self.sql(e, 'this')):X}{hs_end}" + if klass.tokenizer_class._BYTE_STRINGS and exp.ByteString not in klass.generator_class.TRANSFORMS: + be_start, be_end = list(klass.tokenizer_class._BYTE_STRINGS.items())[0] + klass.generator_class.TRANSFORMS[ + exp.ByteString + ] = lambda self, e: f"{be_start}{self.sql(e, 'this')}{be_end}" return klass @@ -176,11 +181,7 @@ class Dialect(metaclass=_Dialect): def rename_func(name): def _rename(self, expression): - args = ( - expression.expressions - if isinstance(expression, exp.Func) and expression.is_var_len_args - else expression.args.values() - ) + args = flatten(expression.args.values()) return f"{name}({self.format_args(*args)})" return _rename diff --git a/sqlglot/dialects/hive.py b/sqlglot/dialects/hive.py index 8888df8..0810e0c 100644 --- a/sqlglot/dialects/hive.py +++ b/sqlglot/dialects/hive.py @@ -121,6 +121,9 @@ class Hive(Dialect): "ss": "%S", "s": "%-S", "S": "%f", + "a": "%p", + "DD": "%j", + "D": "%-j", } date_format = "'yyyy-MM-dd'" @@ -200,6 +203,7 @@ class Hive(Dialect): exp.AnonymousProperty: _property_sql, exp.ApproxDistinct: approx_count_distinct_sql, exp.ArrayAgg: rename_func("COLLECT_LIST"), + exp.ArrayConcat: rename_func("CONCAT"), exp.ArraySize: rename_func("SIZE"), exp.ArraySort: _array_sort, exp.With: no_recursive_cte_sql, diff --git a/sqlglot/dialects/mysql.py b/sqlglot/dialects/mysql.py index 8449379..524390f 100644 --- a/sqlglot/dialects/mysql.py +++ b/sqlglot/dialects/mysql.py @@ -97,6 +97,8 @@ class MySQL(Dialect): "%s": "%S", "%S": "%S", "%u": "%W", + "%k": "%-H", + "%l": "%-I", } class Tokenizer(Tokenizer): @@ -145,6 +147,9 @@ class MySQL(Dialect): "_TIS620": TokenType.INTRODUCER, "_UCS2": TokenType.INTRODUCER, "_UJIS": TokenType.INTRODUCER, + # https://dev.mysql.com/doc/refman/8.0/en/string-literals.html + "N": TokenType.INTRODUCER, + "n": TokenType.INTRODUCER, "_UTF8": TokenType.INTRODUCER, "_UTF16": TokenType.INTRODUCER, "_UTF16LE": TokenType.INTRODUCER, diff --git a/sqlglot/dialects/oracle.py b/sqlglot/dialects/oracle.py index 8041ff0..144dba5 100644 --- a/sqlglot/dialects/oracle.py +++ b/sqlglot/dialects/oracle.py @@ -80,17 +80,12 @@ class Oracle(Dialect): sep="", ) - def alias_sql(self, expression): - if isinstance(expression.this, exp.Table): - to_sql = self.sql(expression, "alias") - # oracle does not allow "AS" between table and alias - to_sql = f" {to_sql}" if to_sql else "" - return f"{self.sql(expression, 'this')}{to_sql}" - return super().alias_sql(expression) - def offset_sql(self, expression): return f"{super().offset_sql(expression)} ROWS" + def table_sql(self, expression): + return super().table_sql(expression, sep=" ") + class Tokenizer(Tokenizer): KEYWORDS = { **Tokenizer.KEYWORDS, diff --git a/sqlglot/dialects/postgres.py b/sqlglot/dialects/postgres.py index c91ff4b..459e926 100644 --- a/sqlglot/dialects/postgres.py +++ b/sqlglot/dialects/postgres.py @@ -163,6 +163,7 @@ class Postgres(Dialect): class Tokenizer(Tokenizer): BIT_STRINGS = [("b'", "'"), ("B'", "'")] HEX_STRINGS = [("x'", "'"), ("X'", "'")] + BYTE_STRINGS = [("e'", "'"), ("E'", "'")] KEYWORDS = { **Tokenizer.KEYWORDS, "ALWAYS": TokenType.ALWAYS, @@ -176,6 +177,11 @@ class Postgres(Dialect): "SMALLSERIAL": TokenType.SMALLSERIAL, "UUID": TokenType.UUID, } + QUOTES = ["'", "$$"] + SINGLE_TOKENS = { + **Tokenizer.SINGLE_TOKENS, + "$": TokenType.PARAMETER, + } class Parser(Parser): STRICT_CAST = False diff --git a/sqlglot/dialects/presto.py b/sqlglot/dialects/presto.py index 8dfb2fd..41c0db1 100644 --- a/sqlglot/dialects/presto.py +++ b/sqlglot/dialects/presto.py @@ -172,6 +172,7 @@ class Presto(Dialect): **transforms.UNALIAS_GROUP, exp.ApproxDistinct: _approx_distinct_sql, exp.Array: lambda self, e: f"ARRAY[{self.expressions(e, flat=True)}]", + exp.ArrayConcat: rename_func("CONCAT"), exp.ArrayContains: rename_func("CONTAINS"), exp.ArraySize: rename_func("CARDINALITY"), exp.BitwiseAnd: lambda self, e: f"BITWISE_AND({self.sql(e, 'this')}, {self.sql(e, 'expression')})", diff --git a/sqlglot/dialects/snowflake.py b/sqlglot/dialects/snowflake.py index 19a427c..627258f 100644 --- a/sqlglot/dialects/snowflake.py +++ b/sqlglot/dialects/snowflake.py @@ -69,6 +69,35 @@ def _unix_to_time(self, expression): raise ValueError("Improper scale for timestamp") +# https://docs.snowflake.com/en/sql-reference/functions/date_part.html +# https://docs.snowflake.com/en/sql-reference/functions-date-time.html#label-supported-date-time-parts +def _parse_date_part(self): + this = self._parse_var() or self._parse_type() + self._match(TokenType.COMMA) + expression = self._parse_bitwise() + + name = this.name.upper() + if name.startswith("EPOCH"): + if name.startswith("EPOCH_MILLISECOND"): + scale = 10**3 + elif name.startswith("EPOCH_MICROSECOND"): + scale = 10**6 + elif name.startswith("EPOCH_NANOSECOND"): + scale = 10**9 + else: + scale = None + + ts = self.expression(exp.Cast, this=expression, to=exp.DataType.build("TIMESTAMP")) + to_unix = self.expression(exp.TimeToUnix, this=ts) + + if scale: + to_unix = exp.Mul(this=to_unix, expression=exp.Literal.number(scale)) + + return to_unix + + return self.expression(exp.Extract, this=this, expression=expression) + + class Snowflake(Dialect): null_ordering = "nulls_are_large" time_format = "'yyyy-mm-dd hh24:mi:ss'" @@ -115,7 +144,7 @@ class Snowflake(Dialect): FUNCTION_PARSERS = { **Parser.FUNCTION_PARSERS, - "DATE_PART": lambda self: self._parse_extract(), + "DATE_PART": _parse_date_part, } FUNC_TOKENS = { @@ -161,9 +190,11 @@ class Snowflake(Dialect): class Generator(Generator): TRANSFORMS = { **Generator.TRANSFORMS, + exp.ArrayConcat: rename_func("ARRAY_CAT"), exp.If: rename_func("IFF"), exp.StrToTime: lambda self, e: f"TO_TIMESTAMP({self.sql(e, 'this')}, {self.format_time(e)})", exp.UnixToTime: _unix_to_time, + exp.TimeToUnix: lambda self, e: f"EXTRACT(epoch_second FROM {self.sql(e, 'this')})", exp.Array: inline_array_sql, exp.StrPosition: rename_func("POSITION"), exp.Parameter: lambda self, e: f"${self.sql(e, 'this')}", diff --git a/sqlglot/dialects/spark.py b/sqlglot/dialects/spark.py index 95a7ab4..6bf4ff0 100644 --- a/sqlglot/dialects/spark.py +++ b/sqlglot/dialects/spark.py @@ -1,9 +1,5 @@ from sqlglot import exp -from sqlglot.dialects.dialect import ( - create_with_partitions_sql, - no_ilike_sql, - rename_func, -) +from sqlglot.dialects.dialect import create_with_partitions_sql, rename_func from sqlglot.dialects.hive import Hive from sqlglot.helper import list_get from sqlglot.parser import Parser @@ -98,13 +94,14 @@ class Spark(Hive): } TRANSFORMS = { - **{k: v for k, v in Hive.Generator.TRANSFORMS.items() if k not in {exp.ArraySort}}, + **{k: v for k, v in Hive.Generator.TRANSFORMS.items() if k not in {exp.ArraySort, exp.ILike}}, + exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"), exp.FileFormatProperty: lambda self, e: f"USING {e.text('value').upper()}", exp.ArraySum: lambda self, e: f"AGGREGATE({self.sql(e, 'this')}, 0, (acc, x) -> acc + x, acc -> acc)", exp.BitwiseLeftShift: rename_func("SHIFTLEFT"), exp.BitwiseRightShift: rename_func("SHIFTRIGHT"), + exp.DateTrunc: rename_func("TRUNC"), exp.Hint: lambda self, e: f" /*+ {self.expressions(e).strip()} */", - exp.ILike: no_ilike_sql, exp.StrToDate: _str_to_date, exp.StrToTime: lambda self, e: f"TO_TIMESTAMP({self.sql(e, 'this')}, {self.format_time(e)})", exp.UnixToTime: _unix_to_time, @@ -112,6 +109,8 @@ class Spark(Hive): exp.Map: _map_sql, exp.Reduce: rename_func("AGGREGATE"), exp.StructKwarg: lambda self, e: f"{self.sql(e, 'this')}: {self.sql(e, 'expression')}", + exp.TimestampTrunc: lambda self, e: f"DATE_TRUNC({self.sql(e, 'unit')}, {self.sql(e, 'this')})", + exp.VariancePop: rename_func("VAR_POP"), } WRAP_DERIVED_VALUES = False diff --git a/sqlglot/dialects/tsql.py b/sqlglot/dialects/tsql.py index 73b232e..1f2e50d 100644 --- a/sqlglot/dialects/tsql.py +++ b/sqlglot/dialects/tsql.py @@ -32,6 +32,11 @@ class TSQL(Dialect): } class Parser(Parser): + FUNCTIONS = { + **Parser.FUNCTIONS, + "CHARINDEX": exp.StrPosition.from_arg_list, + } + def _parse_convert(self): to = self._parse_types() self._match(TokenType.COMMA) |