fix(plugin-snowflake): decode the wire encodings the query-request endpoint sends - #2466
Merged
datlechin merged 6 commits intoAug 26, 2026
Merged
Conversation
datlechin
force-pushed
the
fix/snowflake-date-epoch-days
branch
from
August 26, 2026 15:51
cddfc74 to
3fae388
Compare
… represent as text (TableProApp#2468) Claude-Session: https://claude.ai/code/session_01Qk1xfY3vnneRifC22eV2r7
… type, not a column name (TableProApp#2469) Claude-Session: https://claude.ai/code/session_01Qk1xfY3vnneRifC22eV2r7
… and scope Stop to its own driver (TableProApp#2470) Claude-Session: https://claude.ai/code/session_01Qk1xfY3vnneRifC22eV2r7
datlechin
marked this pull request as ready for review
August 26, 2026 17:47
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Snowflake driver fixes, five commits, each reviewed and merged on its own before landing here: #2467, #2468, #2469, #2470, plus the original decoding change.
The reported bug
SnowflakeConnection.boxis type blind. The legacy/queries/v1/query-requestendpoint sends every cell as a JSON string in Snowflake's own internal encoding, and the driver never consulted therowtypemetadata it had already parsed, so aDATEreached the app as20682rather than2026-08-17.That one boxing produced all three reported symptoms, because display, the picker seed and the
UPDATE/DELETEWHEREanchor all read the samePluginCellValue.Two corrections to the original approach
DATE_OUTPUT_FORMATcannot work, so it is dropped. Its default is alreadyYYYY-MM-DDand the wire still carries20682. Snowflake's ownconverter_snowsql.pyreads the parameter and still callstime.gmtime(int(value) * 86400)first;gosnowflakeandsnowflake-jdbcdecode epoch days unconditionally. It is a display parameter for text casts, not a wire format switch.Foundation is the wrong calendar. Snowflake documents that it does not adjust dates before 1582 to match the Julian calendar. Measured on this toolchain,
Calendar(identifier: .gregorian),Calendar(identifier: .iso8601),ISO8601DateFormatter,Date.FormatStyle.iso8601and a POSIXDateFormatterall render epoch day-719162as0001-01-03where Snowflake means0001-01-01, andgregorianStartDatedoes not exist in the macOS SDK. The conversion is integer arithmetic, andtestProlepticGregorianfails the moment anyone reimplements it on Foundation.What is in here
DATE206822026-08-17TIME3600.00000000001:00:00TIMESTAMP_NTZ1755388800.0000000002025-08-17 00:00:00TIMESTAMP_LTZ1755388800.0000000002025-08-17 00:00:00ZTIMESTAMP_TZ1616173619.000000000 15002021-03-19 18:06:59+01:00BINARY0x34383635364336433646Plus, from the stacked reviews:
SnowflakeObjectQueries.escapeLiteraldoubled the quote and left the backslash, so a schema namedx\' OR 1=1 --closed the literal and ran its own SQL. Three copies of the escaper and five of the identifier quoter existed and nothing made them agree; there is now one owner and no hand-rolled escaping anywhere else in the plugin.TimeZone(secondsFromGMT:)is nil past eighteen hours and the shared parser reads that nil as GMT, so a+18:30payload moved the instant by eighteen and a half hours. Such a value keeps its raw text.number of rows, which missedUPDATEandMERGEentirely and reported aSELECT COUNT(*) AS "number of rows"as rows changed. It now comes from the response'sstatementTypeId.USE DATABASEin one window moved the other. Stop also aborted every query on the session, including a sidebar refresh beside it.A value that cannot be decoded is never invented
Every arm returns the raw text unchanged when the encoding does not explain the value: a non-integer, an out of range epoch day, a malformed offset, an odd-length hex string. Decoding is keyed on the column, never on the value, so an integer sitting in a
VARCHARis left alone.The picker
A date control cannot say "I could not read this":
NSDatePicker.dateValueand every SwiftUIDatePickerbinding are a non-optionalDate. A date cell whose text is non-empty and does not parse now opens the existing text editor instead of a picker seeded with today.Tests
63 cases across
SnowflakeValueDecoderTests,SnowflakeSQLTests,SnowflakeStatementTypeTests,SnowflakeSessionKeyTestsandSnowflakeTypeMapperTests. Decoder expectations were computed independently in Python's proleptic Gregorian calendar rather than from the implementation.Verified on the merged branch: build PASS, SwiftLint 0 violations,
AllPluginscompilesSnowflakeDriverPluginclean, docs checks PASS.Not fixed here
Version 0
TIMESTAMP_TZpayloads pack the zone into the low bits of a single number instead of the"<epoch> <offset>"pair. Decoding it needs Snowflake's timezone index table, which cannot be verified without an account, so those values fall through to raw text, which is the behaviour before this change.Fixes #2454