Skip to content

v0.16.0

Choose a tag to compare

@kenshaw kenshaw released this 10 Oct 02:20
· 24 commits to main since this release

This release adds the driver snowflake, for Snowflake. No other driver changes for a caller.

New

  • Snowflake. The package snowflake runs SQL on Snowflake through its SQL REST API, /api/v2/statements, which is HTTPS and JSON. It does not use the private protocol of gosnowflake and needs no Arrow. The DSN is snowflake://user:key@<org>-<account>.snowflakecomputing.com/database/schema, with the keys role, warehouse, timeout (a duration, such as 60s) and timezone. The password is the private key of the user, as base64url text of the PKCS8 DER bytes (D183).
  • Login. The login is a key-pair JWT only. The driver signs it with RS256 and signs a new one before the old one expires. Other kinds of token are not part of this release.
  • Statements. The driver starts each statement with ?async=true and polls until it ends, so that it always holds the handle. When the context ends, and when the caller closes the rows early, it sends POST /cancel for the statement.
  • Results. The first partition is in the answer, and each later one is fetched with GET in order, one at a time. The server runs the whole statement first, so an error always comes before any row. RowsAffected is read from the row of the answer, and from stats when the row has none.
  • Types. A fixed of scale 0 and precision 18 or less is an int64, and any other is an *apd.Decimal. A real is a float64. A date is a dbimp.Date, a time is a dbimp.LocalTime, a timestamp_ntz is a dbimp.LocalDateTime, and the other two timestamps are a time.Time. A variant is the decoded JSON value, an object is a map[string]any, an array is a []any, a geography and a geometry are the map[string]any of their GeoJSON, and a vector is a dbimp.Vector[float64].
  • Parameters. Each argument is a typed binding of the server, chosen from its Go type. Infinity and -Infinity bind as the server takes them. A map or a list is refused, because VARIANT is not a type of a binding.

What a caller must know

  • BeginTx fails with dbimp.ErrNotSupported, because the server refuses BEGIN alone and each request is its own session. A request of several statements is refused for now.
  • A timestamp_ltz value has the location of the key timezone, or time.Local when none is named. Use timezone=UTC on a server.
  • A statement that fails while it runs has no SQLSTATE. The error names the code, the message and the handle.
  • A TIMESTAMP_TZ binding does not convert by itself into a TIMESTAMP_LTZ column in a list of values, so a statement casts it.
  • WithParameter refuses the nine output-format parameters, because they change the text of a value.
  • A TRUNCATE of an empty table gives no count, so RowsAffected returns an error that wraps dbimp.ErrNotSupported.

Other changes

  • The recorder dbimptest/cmd/record sends the same credentials on a followed page as on the first request: basic, Bearer or Signature Version 4.
  • The workflow leaves a hosted service out of its job list, because dbrun does not start it.
  • Hard rule 4 names the rows of a Snowflake query. The sibling repository xo/cql is now xo/cassandra in the documents.

Tests

CI passed all 42 jobs on the tagged commit. The jobs of Snowflake replay the 158 recorded exchanges and use fake servers, because the account is a hosted trial. The integration tests ran by hand against the live trial account on 2026-10-10 and passed: all nine tests, 47 subtests, with the round trip of every type. They read SNOWFLAKE_DSN and skip when it is empty. VoltDB gets no driver here (D180).