From e290d11f23ac1c003f651236e63a470fc35fd32b Mon Sep 17 00:00:00 2001 From: vaggelisd Date: Tue, 5 Nov 2024 18:17:04 +0200 Subject: [PATCH] feat(spark, bigquery): Add support for UNIX_SECONDS(...) --- sqlglot/dialects/bigquery.py | 1 + sqlglot/dialects/spark.py | 1 + sqlglot/expressions.py | 4 ++++ sqlglot/generator.py | 15 +++++++++++++++ tests/dialects/test_bigquery.py | 19 +++++++++++++++++++ 5 files changed, 40 insertions(+) diff --git a/sqlglot/dialects/bigquery.py b/sqlglot/dialects/bigquery.py index 6198aa97a..bfc1d2412 100644 --- a/sqlglot/dialects/bigquery.py +++ b/sqlglot/dialects/bigquery.py @@ -704,6 +704,7 @@ class Generator(generator.Generator): WITH_PROPERTIES_PREFIX = "OPTIONS" SUPPORTS_EXPLODING_PROJECTIONS = False EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False + SUPPORTS_UNIX_SECONDS = True TRANSFORMS = { **generator.Generator.TRANSFORMS, diff --git a/sqlglot/dialects/spark.py b/sqlglot/dialects/spark.py index 6c4f19489..a58b708d2 100644 --- a/sqlglot/dialects/spark.py +++ b/sqlglot/dialects/spark.py @@ -137,6 +137,7 @@ class Generator(Spark2.Generator): PAD_FILL_PATTERN_IS_REQUIRED = False SUPPORTS_CONVERT_TIMEZONE = True SUPPORTS_MEDIAN = True + SUPPORTS_UNIX_SECONDS = True TYPE_MAPPING = { **Spark2.Generator.TYPE_MAPPING, diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py index a4c056c5a..281f373db 100644 --- a/sqlglot/expressions.py +++ b/sqlglot/expressions.py @@ -6516,6 +6516,10 @@ class UnixToTimeStr(Func): pass +class UnixSeconds(Func): + pass + + class Uuid(Func): _sql_names = ["UUID", "GEN_RANDOM_UUID", "GENERATE_UUID", "UUID_STRING"] diff --git a/sqlglot/generator.py b/sqlglot/generator.py index 61d4f9db9..e07e4916d 100644 --- a/sqlglot/generator.py +++ b/sqlglot/generator.py @@ -436,6 +436,9 @@ class Generator(metaclass=_Generator): # Whether MEDIAN(expr) is supported; if not, it will be generated as PERCENTILE_CONT(expr, 0.5) SUPPORTS_MEDIAN = True + # Whether UNIX_SECONDS(timestamp) is supported + SUPPORTS_UNIX_SECONDS = False + # The name to generate for the JSONPath expression. If `None`, only `this` will be generated PARSE_JSON_NAME: t.Optional[str] = "PARSE_JSON" @@ -4472,3 +4475,15 @@ def overflowtruncatebehavior_sql(self, expression: exp.OverflowTruncateBehavior) filler = f" {filler}" if filler else "" with_count = "WITH COUNT" if expression.args.get("with_count") else "WITHOUT COUNT" return f"TRUNCATE{filler} {with_count}" + + def unixseconds_sql(self, expression: exp.UnixSeconds) -> str: + if self.SUPPORTS_UNIX_SECONDS: + return self.function_fallback_sql(expression) + + start_ts = exp.cast( + exp.Literal.string("1970-01-01 00:00:00+00"), to=exp.DataType.Type.TIMESTAMPTZ + ) + + return self.sql( + exp.TimestampDiff(this=expression.this, expression=start_ts, unit=exp.var("SECONDS")) + ) diff --git a/tests/dialects/test_bigquery.py b/tests/dialects/test_bigquery.py index 776303401..f3b9949f6 100644 --- a/tests/dialects/test_bigquery.py +++ b/tests/dialects/test_bigquery.py @@ -2095,3 +2095,22 @@ def test_json_extract_scalar(self): "snowflake": """SELECT JSON_EXTRACT_PATH_TEXT('{"name": "Jakob", "age": "6"}', 'age')""", }, ) + + def test_unix_seconds(self): + self.validate_all( + "SELECT UNIX_SECONDS('2008-12-25 15:30:00+00')", + read={ + "bigquery": "SELECT UNIX_SECONDS('2008-12-25 15:30:00+00')", + "spark": "SELECT UNIX_SECONDS('2008-12-25 15:30:00+00')", + "databricks": "SELECT UNIX_SECONDS('2008-12-25 15:30:00+00')", + }, + write={ + "spark": "SELECT UNIX_SECONDS('2008-12-25 15:30:00+00')", + "databricks": "SELECT UNIX_SECONDS('2008-12-25 15:30:00+00')", + "duckdb": "SELECT DATE_DIFF('SECONDS', CAST('1970-01-01 00:00:00+00' AS TIMESTAMPTZ), '2008-12-25 15:30:00+00')", + "snowflake": "SELECT TIMESTAMPDIFF(SECONDS, CAST('1970-01-01 00:00:00+00' AS TIMESTAMPTZ), '2008-12-25 15:30:00+00')", + }, + ) + + for dialect in ("bigquery", "spark", "databricks"): + parse_one("UNIX_SECONDS(col)", dialect=dialect).assert_is(exp.UnixSeconds)