Skip to content

Refuse typed timestamp literals Snowflake rejects - #142

Merged
kvlonge merged 9 commits into
mainfrom
fix/typed-timestamp-literals
Nov 8, 2026
Merged

kvlonge merged 9 commits into
mainfrom
fix/typed-timestamp-literals

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Snowflake rejects a typed literal on a timestamp name other than TIMESTAMP, but the parser read it as a cast and conversion went ahead. This PR makes each spelling fail in the same phase that Snowflake rejects it.

  • Syntax error (1003/42000): TIMESTAMP_NTZ, TIMESTAMP_LTZ, TIMESTAMP_TZ, TIMESTAMPNTZ, TIMESTAMPLTZ, TIMESTAMPTZ and DATETIME before a string. The parser refuses these with SQ0001, with the caret at the string.
  • Compilation error after parsing (2121/42601): TIMESTAMP_NTZ(3) '…' and TIMESTAMP_TZ(3) '…'. These parse as casts through the named-type rule, and the refusal pass rejects them as the new code SQ0211 unsupported_type_literal.

Both messages point to '…'::TIMESTAMP_NTZ or TO_TIMESTAMP_NTZ. TIMESTAMP '…' and DATE '…' are unchanged.

Coverage:

  • Nine negative-neighbour limits give sf.expressions.data-types-datetime.date-time-constant obligations o009–o017 and nine cases.
  • Import 171 (run tslit-ex-00, 0.0 credits) records their receipts: seven syntax errors and two 2121s.
  • The two precision cases settle as accept, stage semantic.
  • syntax-coverage diff gains all nine obligations. It still lists the form as lost until its review is renewed, because the new obligations changed its definition.

Separate commit: the case builder now finds a run-database receipt's setup by its digest alone. Before, a rebuild rewrote 13 IPADDRESS/UUID cases to the held setup, because their run lists no inputs for their SQL. The same bug made a rebuild move about 60 create-warehouse DDL cases off their recorded "d103 sweep" setup, which also made some settlements miss. With the fix, a plain rebuild of expressions and ddl reproduces the committed files, and #143 then only adds the pending settlements.

With the digest-only lookup, the builder's setup_review list goes from empty to 16 cases: 14 ddl (alter-external-volume, alter-materialized-view, alter-restricted-session-scope, alter-semantic-view, alter-stream, alter-type, desc-transaction, show-mcp-servers) and 2 functions (system-resolve-python-packages). Their receipts disagree on whether the setup made a syntax error, so they keep the default setup. No committed file changes because of them, but they are new review work. On main the lookup found a recorded setup for only 2,746 receipts; it now finds 41,196.

Review: auditor-expressions-016 (two commits from the auditor, bf97f06 and 615a5c2) renews the date-time-constant review at parser tree 90d18284. With it, stale is empty and syntax-coverage diff coverage/syntax/baseline.json gains o009–o017 and loses no form.

Follow-up, not in this PR: TIMESTAMP_LTZ(3), TIMESTAMPNTZ/LTZ/TZ(3), DATETIME(3), TIMESTAMP(3) and TIME(3) before a string have no receipts yet. They will be added as negative neighbours in the next import.

Snowflake takes only DATE, TIME and TIMESTAMP as typed literals. It
rejects TIMESTAMP_NTZ, TIMESTAMP_LTZ, TIMESTAMP_TZ, their spellings
without underscores and DATETIME before a string with a syntax error
(errno 1003), and with a precision as an unsupported literal (errno
2121), but the named-type literal rule read each as a cast that then
converted. The parser now refuses them at the string, pointing to
'...'::<type> or the TO_ function. The date-time constant form gains a
negative neighbour for each, still to capture.
tslit-ex-00, the nine date-time-constant neighbours built at 2541bfd: seven
syntax errors (1003/42000) and the two precision forms as compilation errors
after parsing (2121/42601). Inventory equal, no changes, 0.0 credits.
… after parsing

Snowflake parses TIMESTAMP_NTZ(3) '...' and TIMESTAMP_TZ(3) '...' and rejects them at
compile time (2121, "Unsupported data type literal"), while the seven bare spellings are
syntax errors (1003). The parser now refuses only the bare spellings; a listed type with
parameters before a string parses as a cast, and the refusal pass rejects it as SQ0211
unsupported_type_literal with the same advice to write '...'::TIMESTAMP_NTZ or call
TO_TIMESTAMP_NTZ.

The two precision cases settle as accept with a semantic stage from import 171's receipts.
The case builder looked a receipt's setup text up by the pair of its SQL hash and setup
digest in the reports' inputs. The run that recorded the 13 IPADDRESS and UUID temporary
table cases lists no inputs for their SQL, so the builder fell back to the held setup and
rewrote their recorded setup. The same setup text is listed under the same digest by other
reports, and the digest names the text, so the lookup now uses the digest alone. A plain
rebuild of the expressions family now reproduces the committed case file.
SQ0211 matched any CAST to a listed timestamp type with a precision, so
CAST('...' AS DATETIME(3)), CAST('...' AS TIMESTAMPNTZ(3)) and the
TIMESTAMP_LTZ casts were refused although they are ordinary casts. A cast
now records whether it was written as a typed literal, TYPE '...', and
only those are refused. The flag is left out of the serialized tree, so
parse trees and coverage fingerprints are unchanged.
The DATETIME '...' syntax refusal checked only for the Snowflake dialect, so
the polyglot-matching modes refused it too, where polyglot reads it as a
datetime literal; polyglot's exact corpus check failed on
test_bigquery_date_timezone_to_duckdb_476. It now uses the same gate as the
other Snowflake syntax refusals.
@kvlonge
kvlonge merged commit 89fcbea into main Nov 8, 2026
@kvlonge
kvlonge deleted the fix/typed-timestamp-literals branch November 9, 2026 21:32
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.

1 participant