Skip to content

Commit ceb1f02

Browse files
authored
fix(snowflake)!: support TO_CHAR to duckdb STRFTIME (tobymao#4866)
* fix(snowflake): support TO_CHAR to duckdb STRFTIME * PR feedback 1
1 parent 6914684 commit ceb1f02

File tree

4 files changed

+28
-14
lines changed

4 files changed

+28
-14
lines changed

sqlglot/dialects/dialect.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,3 +1856,17 @@ def groupconcat_sql(
18561856
listagg.set("expressions", [f"{args}{self.sql(expression=expression.this)}"])
18571857

18581858
return self.sql(listagg)
1859+
1860+
1861+
def build_timetostr_or_tochar(args: t.List, dialect: Dialect) -> exp.TimeToStr | exp.ToChar:
1862+
this = seq_get(args, 0)
1863+
1864+
if this and not this.type:
1865+
from sqlglot.optimizer.annotate_types import annotate_types
1866+
1867+
annotate_types(this)
1868+
if this.is_type(*exp.DataType.TEMPORAL_TYPES):
1869+
dialect_name = dialect.__class__.__name__.lower()
1870+
return build_formatted_time(exp.TimeToStr, dialect_name, default=True)(args)
1871+
1872+
return exp.ToChar.from_arg_list(args)

sqlglot/dialects/oracle.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from sqlglot.dialects.dialect import (
77
Dialect,
88
NormalizationStrategy,
9+
build_timetostr_or_tochar,
910
build_formatted_time,
1011
no_ilike_sql,
1112
rename_func,
@@ -21,19 +22,6 @@
2122
from sqlglot._typing import E
2223

2324

24-
def _build_timetostr_or_tochar(args: t.List) -> exp.TimeToStr | exp.ToChar:
25-
this = seq_get(args, 0)
26-
27-
if this and not this.type:
28-
from sqlglot.optimizer.annotate_types import annotate_types
29-
30-
annotate_types(this)
31-
if this.is_type(*exp.DataType.TEMPORAL_TYPES):
32-
return build_formatted_time(exp.TimeToStr, "oracle", default=True)(args)
33-
34-
return exp.ToChar.from_arg_list(args)
35-
36-
3725
def _trim_sql(self: Oracle.Generator, expression: exp.Trim) -> str:
3826
position = expression.args.get("position")
3927

@@ -117,7 +105,7 @@ class Parser(parser.Parser):
117105
**parser.Parser.FUNCTIONS,
118106
"NVL": lambda args: build_coalesce(args, is_nvl=True),
119107
"SQUARE": lambda args: exp.Pow(this=seq_get(args, 0), expression=exp.Literal.number(2)),
120-
"TO_CHAR": _build_timetostr_or_tochar,
108+
"TO_CHAR": build_timetostr_or_tochar,
121109
"TO_TIMESTAMP": build_formatted_time(exp.StrToTime, "oracle"),
122110
"TO_DATE": build_formatted_time(exp.StrToDate, "oracle"),
123111
"TRUNC": lambda args: exp.DateTrunc(

sqlglot/dialects/snowflake.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from sqlglot.dialects.dialect import (
77
Dialect,
88
NormalizationStrategy,
9+
build_timetostr_or_tochar,
910
binary_from_function,
1011
build_default_decimal_type,
1112
build_timestamp_from_parts,
@@ -463,6 +464,7 @@ class Parser(parser.Parser):
463464
"TRY_TO_TIMESTAMP": _build_datetime(
464465
"TRY_TO_TIMESTAMP", exp.DataType.Type.TIMESTAMP, safe=True
465466
),
467+
"TO_CHAR": build_timetostr_or_tochar,
466468
"TO_DATE": _build_datetime("TO_DATE", exp.DataType.Type.DATE),
467469
"TO_NUMBER": lambda args: exp.ToNumber(
468470
this=seq_get(args, 0),

tests/dialects/test_snowflake.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,16 @@ def test_snowflake(self):
588588
"teradata": "TO_CHAR(x, y)",
589589
},
590590
)
591+
self.validate_identity(
592+
"TO_CHAR(foo::DATE, 'yyyy')", "TO_CHAR(CAST(CAST(foo AS DATE) AS TIMESTAMP), 'yyyy')"
593+
)
594+
self.validate_all(
595+
"TO_CHAR(foo::TIMESTAMP, 'YYYY-MM')",
596+
write={
597+
"snowflake": "TO_CHAR(CAST(foo AS TIMESTAMP), 'yyyy-mm')",
598+
"duckdb": "STRFTIME(CAST(foo AS TIMESTAMP), '%Y-%m')",
599+
},
600+
)
591601
self.validate_all(
592602
"SQUARE(x)",
593603
write={

0 commit comments

Comments
 (0)