Skip to content

Commit e4d1a4f

Browse files
authored
refactor(exasol)!: map date/timestamp TRUNC to DATE_TRUNC (#6328)
* chore(exasol): implementing date trunc, trunc relating to date and timestamp trunc to exasol date_trunc * chore(exasol): refactored implmentation using is_string to check if expression is a string and adding more test
1 parent f08d87b commit e4d1a4f

File tree

2 files changed

+51
-22
lines changed

2 files changed

+51
-22
lines changed

sqlglot/dialects/exasol.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
rename_func,
1313
strposition_sql,
1414
timestrtotime_sql,
15-
unit_to_str,
1615
timestamptrunc_sql,
1716
build_date_delta,
1817
)
@@ -107,6 +106,27 @@ def prefix_local(node):
107106
return expression
108107

109108

109+
def _trunc_sql(self: Exasol.Generator, kind: str, expression: exp.DateTrunc) -> str:
110+
unit = expression.text("unit")
111+
node = expression.this.this if isinstance(expression.this, exp.Cast) else expression.this
112+
expr_sql = self.sql(node)
113+
if isinstance(node, exp.Literal) and node.is_string:
114+
expr_sql = (
115+
f"{kind} '{node.this.replace('T', ' ')}'"
116+
if kind == "TIMESTAMP"
117+
else f"DATE '{node.this}'"
118+
)
119+
return f"DATE_TRUNC('{unit}', {expr_sql})"
120+
121+
122+
def _date_trunc_sql(self: Exasol.Generator, expression: exp.DateTrunc) -> str:
123+
return _trunc_sql(self, "DATE", expression)
124+
125+
126+
def _timestamp_trunc_sql(self: Exasol.Generator, expression: exp.DateTrunc) -> str:
127+
return _trunc_sql(self, "TIMESTAMP", expression)
128+
129+
110130
DATE_UNITS = {"DAY", "WEEK", "MONTH", "YEAR", "HOUR", "MINUTE", "SECOND"}
111131

112132

@@ -308,7 +328,7 @@ def datatype_sql(self, expression: exp.DataType) -> str:
308328
# https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/div.htm#DIV
309329
exp.IntDiv: rename_func("DIV"),
310330
exp.TsOrDsDiff: _date_diff_sql,
311-
exp.DateTrunc: lambda self, e: self.func("TRUNC", e.this, unit_to_str(e)),
331+
exp.DateTrunc: _date_trunc_sql,
312332
exp.DayOfWeek: lambda self, e: f"CAST(TO_CHAR({self.sql(e, 'this')}, 'D') AS INTEGER)",
313333
exp.DatetimeTrunc: timestamptrunc_sql(),
314334
exp.GroupConcat: lambda self, e: groupconcat_sql(
@@ -338,7 +358,7 @@ def datatype_sql(self, expression: exp.DataType) -> str:
338358
exp.TsOrDsToDate: lambda self, e: self.func("TO_DATE", e.this, self.format_time(e)),
339359
exp.TimeToStr: lambda self, e: self.func("TO_CHAR", e.this, self.format_time(e)),
340360
exp.TimeStrToTime: timestrtotime_sql,
341-
exp.TimestampTrunc: timestamptrunc_sql(),
361+
exp.TimestampTrunc: _timestamp_trunc_sql,
342362
exp.StrToTime: lambda self, e: self.func("TO_DATE", e.this, self.format_time(e)),
343363
exp.CurrentUser: lambda *_: "CURRENT_USER",
344364
exp.AtTimeZone: lambda self, e: self.func(
@@ -373,6 +393,7 @@ def datatype_sql(self, expression: exp.DataType) -> str:
373393
exp.Date: rename_func("TO_DATE"),
374394
# https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/to_timestamp.htm
375395
exp.Timestamp: rename_func("TO_TIMESTAMP"),
396+
exp.Quarter: lambda self, e: f"CEIL(MONTH(TO_DATE({self.sql(e, 'this')}))/3)",
376397
}
377398

378399
def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str:

tests/dialects/test_exasol.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -407,26 +407,34 @@ def test_datetime_functions(self):
407407
"SELECT CAST(CAST(CURRENT_TIMESTAMP() AS TIMESTAMP) AT TIME ZONE 'CET' AS DATE) - 1",
408408
"SELECT CAST(CONVERT_TZ(CAST(CURRENT_TIMESTAMP() AS TIMESTAMP), 'UTC', 'CET') AS DATE) - 1",
409409
)
410+
units = ["MM", "QUARTER", "WEEK", "MINUTE", "YEAR"]
411+
for unit in units:
412+
with self.subTest(f"Testing TO_CHAR with format '{unit}'"):
413+
self.validate_all(
414+
f"SELECT TRUNC(CAST('2006-12-31' AS DATE), '{unit}') AS TRUNC",
415+
write={
416+
"exasol": f"SELECT DATE_TRUNC('{unit}', DATE '2006-12-31') AS TRUNC",
417+
"presto": f"SELECT DATE_TRUNC('{unit}', CAST('2006-12-31' AS DATE)) AS TRUNC",
418+
"databricks": f"SELECT TRUNC(CAST('2006-12-31' AS DATE), '{unit}') AS TRUNC",
419+
},
420+
)
410421

411-
self.validate_all(
412-
"SELECT TRUNC(CAST('2006-12-31' AS DATE), 'MM') AS TRUNC",
413-
write={
414-
"exasol": "SELECT TRUNC(CAST('2006-12-31' AS DATE), 'MM') AS TRUNC",
415-
"presto": "SELECT DATE_TRUNC('MM', CAST('2006-12-31' AS DATE)) AS TRUNC",
416-
"databricks": "SELECT TRUNC(CAST('2006-12-31' AS DATE), 'MM') AS TRUNC",
417-
},
418-
)
419-
self.validate_all(
420-
"SELECT DATE_TRUNC('minute', TIMESTAMP '2006-12-31 23:59:59') DATE_TRUNC",
421-
write={
422-
"exasol": "SELECT DATE_TRUNC('MINUTE', CAST('2006-12-31 23:59:59' AS TIMESTAMP)) AS DATE_TRUNC",
423-
"presto": "SELECT DATE_TRUNC('MINUTE', CAST('2006-12-31 23:59:59' AS TIMESTAMP)) AS DATE_TRUNC",
424-
"databricks": "SELECT DATE_TRUNC('MINUTE', CAST('2006-12-31 23:59:59' AS TIMESTAMP)) AS DATE_TRUNC",
425-
},
426-
)
427-
self.validate_identity(
428-
"SELECT DAY_OF_WEEK('2023-01-01')", "SELECT CAST(TO_CHAR('2023-01-01', 'D') AS INTEGER)"
429-
)
422+
self.validate_all(
423+
f"SELECT DATE_TRUNC('{unit}', TIMESTAMP '2006-12-31T23:59:59') DATE_TRUNC",
424+
write={
425+
"exasol": f"SELECT DATE_TRUNC('{unit}', TIMESTAMP '2006-12-31 23:59:59') AS DATE_TRUNC",
426+
"presto": f"SELECT DATE_TRUNC('{unit}', CAST('2006-12-31T23:59:59' AS TIMESTAMP)) AS DATE_TRUNC",
427+
"databricks": f"SELECT DATE_TRUNC('{unit}', CAST('2006-12-31T23:59:59' AS TIMESTAMP)) AS DATE_TRUNC",
428+
},
429+
)
430+
self.validate_all(
431+
f"SELECT DATE_TRUNC('{unit}', CURRENT_TIMESTAMP) DATE_TRUNC",
432+
write={
433+
"exasol": f"SELECT DATE_TRUNC('{unit}', CURRENT_TIMESTAMP()) AS DATE_TRUNC",
434+
"presto": f"SELECT DATE_TRUNC('{unit}', CURRENT_TIMESTAMP) AS DATE_TRUNC",
435+
"databricks": f"SELECT DATE_TRUNC('{unit}', CURRENT_TIMESTAMP()) AS DATE_TRUNC",
436+
},
437+
)
430438

431439
from sqlglot.dialects.exasol import DATE_UNITS
432440

0 commit comments

Comments
 (0)