Skip to content

Reprint Trino/Presto TIMESTAMP(x) as CAST(x AS TIMESTAMP) - #16

Merged
ravenac95 merged 4 commits into
mainfrom
trino-timestamp-function
Nov 10, 2026
Merged

ravenac95 merged 4 commits into
mainfrom
trino-timestamp-function

Conversation

@ravenac95

@ravenac95 ravenac95 commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Neither Trino nor Presto has a timestamp() function, so TIMESTAMP('2025-09-16 13:51:30.000') fails there (FUNCTION_NOT_FOUND). sqlglot's Presto/Trino generators reprint it (no_timestamp_sql), so a query using it runs after a sqlglot round trip but not after a polyglot one. polyglot treated it as an anonymous function and passed it through.

This matches sqlglot:

input output
TIMESTAMP(x) CAST(x AS TIMESTAMP)
TIMESTAMP(x, 'zone'), zone a known time-zone name AT_TIMEZONE(CAST(x AS TIMESTAMP), 'zone')
TIMESTAMP(x, '12:00:00'), TIMESTAMP(x, z) and other arities unchanged

"Known time-zone name" is sqlglot's own test: polyglot's port of its list, time::is_valid_timezone. That keeps upstream's sqlglot_transpilation fixture TIMESTAMP(x, '12:00:00') (Presto → Presto/DuckDB) as written.

  • The rewrite lives in a new dialects/presto_family.rs, compiled when either dialect-presto or dialect-trino is enabled.
  • Both dialect features now enable time, which has no dependencies, so a Trino-only build with default-features = false (as kuma uses) gets the zone list.

Tests

🤖 Generated with Claude Code

https://claude.ai/code/session_017CxHoCFbTWJA9bcZWC9ydu

Neither engine has a timestamp() function; sqlglot's Presto/Trino generators
write TIMESTAMP(x) as CAST(x AS TIMESTAMP) and TIMESTAMP(x, 'zone') as
AT_TIMEZONE(CAST(x AS TIMESTAMP), 'zone'). Match them, so a query that runs
after a sqlglot reprint also runs after a polyglot one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017CxHoCFbTWJA9bcZWC9ydu
…t does

sqlglot's no_timestamp_sql emits AT_TIMEZONE only when the zone literal is in
its time-zone list; TIMESTAMP(x, '12:00:00') stays as written. Use the same
list (crate::time::is_valid_timezone). Fixes sqlglot_transpilation's
Presto TIMESTAMP(x, '12:00:00') fixtures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017CxHoCFbTWJA9bcZWC9ydu
TIMESTAMP(x, zone) checks the zone with time::is_valid_timezone, so a
Trino-only build (default-features = false) needs the time module.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017CxHoCFbTWJA9bcZWC9ydu
@ravenac95

Copy link
Copy Markdown
Member Author

Just double checking but vanilla sqlglot does this casting?

Copy link
Copy Markdown
Member Author

Yes, this is vanilla sqlglot behaviour, not something OSO-specific:

  • Generator: sqlglot's Presto generator maps exp.Timestamp to no_timestamp_sql, and Trino inherits it (sqlglot/generators/presto.py:399 at v30.14.0, the SQLGLOT_REF this repo's fixtures come from; sqlglot/dialects/presto.py:514 in 27.28.1, the version kuma's scheduler runs). In no_timestamp_sql (sqlglot/dialects/dialect.py):
    • With no zone, it emits CAST(x AS <annotated type, default TIMESTAMP>).
    • When the zone is in sqlglot's TIMEZONES list, it emits AT_TIMEZONE(CAST(x AS TIMESTAMP), zone).
    • Otherwise it leaves TIMESTAMP(x, zone) as written.
  • Parser: sqlglot's parser reads TIMESTAMP(…) as exp.Timestamp in any dialect, Trino included.
  • Observed with sqlglot 27.28.1: sqlglot.transpile("SELECT TIMESTAMP('2025-09-16 13:51:30.000')", read="trino", write="trino") gives SELECT CAST('2025-09-16 13:51:30.000' AS TIMESTAMP). That's how the production model with TIMESTAMP('…') runs today.
  • sqlglot's own tests: tests/dialects/test_presto.py asserts CAST(x AS TIMESTAMP) from TIMESTAMP(x) (read from MySQL), and keeps TIMESTAMP(x, '12:00:00') unchanged. That second case is the sqlglot_transpilation fixture this PR's first commit broke and the second commit fixed, by using the same zone list (time::is_valid_timezone).

Generated by Claude Code

@ravenac95 ravenac95 closed this in #19 Nov 9, 2026
@ravenac95 ravenac95 reopened this Nov 10, 2026
@ravenac95
ravenac95 merged commit 1867d07 into main Nov 10, 2026
35 checks passed
ravenac95 added a commit that referenced this pull request Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants