Skip to content

Commit f70f124

Browse files
authored
Feat!: transpile MySQL FORMAT to DuckDB (#4488)
1 parent 3db54b1 commit f70f124

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

sqlglot/dialects/duckdb.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,3 +1021,12 @@ def regexpextract_sql(self, expression: exp.RegexpExtract) -> str:
10211021
return self.func(
10221022
"REGEXP_EXTRACT", expression.this, expression.expression, group, params
10231023
)
1024+
1025+
@unsupported_args("culture")
1026+
def numbertostr_sql(self, expression: exp.NumberToStr) -> str:
1027+
fmt = expression.args.get("format")
1028+
if fmt and fmt.is_int:
1029+
return self.func("FORMAT", f"'{{:,.{fmt.name}f}}'", expression.this)
1030+
1031+
self.unsupported("Only integer formats are supported by NumberToStr")
1032+
return self.function_fallback_sql(expression)

sqlglot/dialects/mysql.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ class Parser(parser.Parser):
307307
"DAYOFMONTH": lambda args: exp.DayOfMonth(this=exp.TsOrDsToDate(this=seq_get(args, 0))),
308308
"DAYOFWEEK": lambda args: exp.DayOfWeek(this=exp.TsOrDsToDate(this=seq_get(args, 0))),
309309
"DAYOFYEAR": lambda args: exp.DayOfYear(this=exp.TsOrDsToDate(this=seq_get(args, 0))),
310+
"FORMAT": exp.NumberToStr.from_arg_list,
310311
"FROM_UNIXTIME": build_formatted_time(exp.UnixToTime, "mysql"),
311312
"ISNULL": isnull_to_is_null,
312313
"LOCATE": locate_to_strposition,
@@ -735,6 +736,7 @@ class Generator(generator.Generator):
735736
exp.Month: _remove_ts_or_ds_to_date(),
736737
exp.NullSafeEQ: lambda self, e: self.binary(e, "<=>"),
737738
exp.NullSafeNEQ: lambda self, e: f"NOT {self.binary(e, '<=>')}",
739+
exp.NumberToStr: rename_func("FORMAT"),
738740
exp.Pivot: no_pivot_sql,
739741
exp.Select: transforms.preprocess(
740742
[

tests/dialects/test_mysql.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import unittest
22
import sys
33

4-
from sqlglot import expressions as exp
4+
from sqlglot import UnsupportedError, expressions as exp
55
from sqlglot.dialects.mysql import MySQL
66
from tests.dialects.test_dialect import Validator
77

@@ -1344,3 +1344,33 @@ def test_explain(self):
13441344

13451345
for format in ("JSON", "TRADITIONAL", "TREE"):
13461346
self.validate_identity(f"DESCRIBE FORMAT={format} UPDATE test SET test_col = 'abc'")
1347+
1348+
def test_number_format(self):
1349+
self.validate_all(
1350+
"SELECT FORMAT(12332.123456, 4)",
1351+
write={
1352+
"duckdb": "SELECT FORMAT('{:,.4f}', 12332.123456)",
1353+
"mysql": "SELECT FORMAT(12332.123456, 4)",
1354+
},
1355+
)
1356+
self.validate_all(
1357+
"SELECT FORMAT(12332.1, 4)",
1358+
write={
1359+
"duckdb": "SELECT FORMAT('{:,.4f}', 12332.1)",
1360+
"mysql": "SELECT FORMAT(12332.1, 4)",
1361+
},
1362+
)
1363+
self.validate_all(
1364+
"SELECT FORMAT(12332.2, 0)",
1365+
write={
1366+
"duckdb": "SELECT FORMAT('{:,.0f}', 12332.2)",
1367+
"mysql": "SELECT FORMAT(12332.2, 0)",
1368+
},
1369+
)
1370+
self.validate_all(
1371+
"SELECT FORMAT(12332.2, 2, 'de_DE')",
1372+
write={
1373+
"duckdb": UnsupportedError,
1374+
"mysql": "SELECT FORMAT(12332.2, 2, 'de_DE')",
1375+
},
1376+
)

0 commit comments

Comments
 (0)