Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sqlglot/generators/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ class MySQLGenerator(generator.Generator):
),
exp.TimestampSub: date_add_interval_sql("DATE", "SUB"),
exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"),
exp.TimeToUnix: rename_func("UNIX_TIMESTAMP"),
exp.TimeStrToTime: lambda self, e: timestrtotime_sql(
self,
e,
Expand Down
11 changes: 11 additions & 0 deletions sqlglot/parsers/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ def _has_time_specifier(date_format: str) -> bool:
return False


def _build_unix_timestamp(args: list) -> exp.TimeToUnix:
# UNIX_TIMESTAMP(): with no arg, convert the current timestamp to epoch seconds
if not args:
return exp.TimeToUnix(this=exp.CurrentTimestamp())

# UNIX_TIMESTAMP(ts): the arg may be a string, so cast it to a timestamp first
# and then convert to epoch seconds
return exp.TimeToUnix(this=exp.TsOrDsToTimestamp(this=args[0]))


def _str_to_date(args: list) -> exp.StrToDate | exp.StrToTime:
mysql_date_format = seq_get(args, 1)
date_format = Dialect["mysql"].format_time(mysql_date_format)
Expand Down Expand Up @@ -143,6 +153,7 @@ class MySQLParser(parser.Parser):
)
+ 1
),
"UNIX_TIMESTAMP": _build_unix_timestamp,
"VERSION": exp.CurrentVersion.from_arg_list,
"WEEK": lambda args: exp.Week(
this=exp.TsOrDsToDate(this=seq_get(args, 0)), mode=seq_get(args, 1)
Expand Down
21 changes: 21 additions & 0 deletions tests/dialects/test_mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,27 @@ def test_canonical_functions(self):
"tsql": "CHAR(10)",
},
)
self.validate_all(
"SELECT UNIX_TIMESTAMP(ts)",
write={
"mysql": "SELECT UNIX_TIMESTAMP(CAST(ts AS DATETIME))",
"duckdb": "SELECT EPOCH(CAST(ts AS TIMESTAMP))",
},
)
self.validate_all(
"SELECT UNIX_TIMESTAMP('2021-01-01 00:00:00')",
write={
"mysql": "SELECT UNIX_TIMESTAMP(CAST('2021-01-01 00:00:00' AS DATETIME))",
"duckdb": "SELECT EPOCH(CAST('2021-01-01 00:00:00' AS TIMESTAMP))",
},
)
self.validate_all(
"SELECT UNIX_TIMESTAMP()",
write={
"mysql": "SELECT UNIX_TIMESTAMP(CURRENT_TIMESTAMP())",
"duckdb": "SELECT EPOCH(CURRENT_TIMESTAMP)",
},
)
Comment on lines +491 to +511

@geooo109 geooo109 Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you try these against the engines ?

The transpilation should preserve the output type of MySQL.

mysql> SELECT UNIX_TIMESTAMP('2021-01-01 00:00:00.2');
Field   1:  `UNIX_TIMESTAMP('2021-01-01 00:00:00.2')`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       NEWDECIMAL
Collation:  binary (63)
Length:     14
Max_length: 12
Decimals:   1
Flags:      NOT_NULL BINARY NUM 

+-----------------------------------------+
| UNIX_TIMESTAMP('2021-01-01 00:00:00.2') |
+-----------------------------------------+
|                            1609452000.2 |
+-----------------------------------------+
1 row in set (0.000 sec)
===================================
mysql> SELECT UNIX_TIMESTAMP('2021-01-01 00:00:00');
Field   1:  `UNIX_TIMESTAMP('2021-01-01 00:00:00')`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       LONGLONG
Collation:  binary (63)
Length:     21
Max_length: 10
Decimals:   0
Flags:      NOT_NULL BINARY NUM 

+---------------------------------------+
| UNIX_TIMESTAMP('2021-01-01 00:00:00') |
+---------------------------------------+
|                            1609452000 |
+---------------------------------------+
1 row in set (0.000 sec)

My tests ^ show that based on the input the output type changes for MySQL.

My suggestion is to focus on the transpilation from mysql to duckdb for now.

  1. We should take care of the input argument. MySQL can take as input a raw string.
    We should wrap the argument of MySQL with a exp.TsOrDsToTimestamp in order to cast it at the output (duckdb doesn't support string args).

  2. Let's apply 1. and then validate that my mysql queries above, transpile correctly to duckdb.

cc: @georgesittas (for visibility)

self.validate_identity("CREATE TABLE t (foo VARBINARY(5))")
self.validate_all(
"CREATE TABLE t (foo BLOB)",
Expand Down
Loading