Skip to content

snowflake-odbc v4.0.0-rc1

Pre-release
Pre-release

Choose a tag to compare

Changelog

Breaking changes

  • Changed SQL_C_CHAR conversion of DECIMAL/NUMERIC to return SQL_ERROR (22003) when whole digits do not fit in the buffer; previously returned SQL_SUCCESS_WITH_INFO with truncated digits.
  • Changed SQL_C_BINARY conversion of DECIMAL/NUMERIC/DECFLOAT to return SQL_ERROR (22003) when the buffer is smaller than sizeof(SQL_NUMERIC_STRUCT); previously BufferLength was ignored, risking buffer overflows.
  • Changed conversion of NaN FLOAT/DOUBLE to integer and SQL_C_BIT targets to return SQL_ERROR (22003); previously returned SQL_SUCCESS_WITH_INFO with a silent 0.
  • Enforced interval leading-field precision for SQL_C_INTERVAL_* types: values that exceed the default precision of 2 now return SQL_ERROR (22015), and SQL_DESC_DATETIME_INTERVAL_PRECISION is respected; previously neither was enforced.
  • Changed SQLRowCount with a NULL RowCountPtr to return SQL_ERROR (HY009); previously returned SQL_SUCCESS.
  • Changed SQLBindParameter to return SQL_ERROR (HY104) for a negative DecimalDigits value; previously accepted negative scale silently.
  • Changed conversion of DECFLOAT values with extreme exponents to SQL_C_BINARY to return SQL_ERROR (22003) instead of silently clamping.
  • Changed SQL_C_NUMERIC to VARCHAR conversion to apply the scale from SQL_NUMERIC_STRUCT (e.g. magnitude 12345 with scale 2 produces "123.45"); previously scale was ignored.
  • Changed binding of subnormal double values near DBL_MIN to preserve the value; previously stored as 0.0.
  • Changed TIME to SQL_C_CHAR/SQL_C_WCHAR buffer-too-small handling: a buffer that cannot hold the base time (HH:MM:SS) now returns SQL_ERROR (22003); a buffer that truncates only fractional seconds returns SQL_SUCCESS_WITH_INFO (01004).
  • Changed DATE to SQL_C_BINARY conversion with an undersized buffer to return SQL_ERROR (22003); previously returned SQL_SUCCESS with truncated data.
  • Changed SQLGetFunctions to report SQL_API_SQLCANCELHANDLE as supported; previously returned SQL_FALSE despite the function being exported.
  • Tightened conversion from VARCHAR to SQL_C_INTERVAL_* types. Truncation returns SQL_SUCCESS_WITH_INFO (01S07) and interval-field overflow returns SQL_ERROR (22015).
  • Changed SQL_C_INTERVAL_SECOND with fractional seconds bound to exact-numeric SQL types to truncate the fraction and succeed; previously returned SQL_ERROR (22015).
  • Changed SQLCancel during data-at-execution to discard all accumulated SQLPutData data so a re-entered sequence starts fresh; previously accumulated data from an interrupted sequence could be concatenated into the next sequence.
  • Changed SQLForeignKeys to resolve a NULL FK catalog and schema from the connection context; previously returned an empty result set unless CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX was enabled.
  • Changed SQLSetConnectAttr(SQL_ATTR_LOGIN_TIMEOUT) called after connect to return SQL_ERROR (HY011); previously returned SQL_SUCCESS as a silent no-op.
  • Changed SQLSetStmtAttr(SQL_ATTR_CURSOR_TYPE) for unsupported cursor types to substitute SQL_CURSOR_FORWARD_ONLY and return SQL_SUCCESS_WITH_INFO (01S02); previously accepted any value silently.
  • Changed the ODBC diagnostic vendor prefix from [Snowflake][Support] to [Snowflake][Snowflake ODBC Driver], matching the ODBC spec format [vendor][ODBC-component-identifier].
  • Changed SQLGetInfo(SQL_DRIVER_NAME) to return the loaded driver library's file name (e.g. libsfodbc.so, libsfodbc.dylib, sfodbc.dll) as the ODBC specification prescribes; previously returned the fixed string Snowflake.
  • Changed SQLCancelHandle(SQL_HANDLE_DBC) to return SQL_ERROR (HY010) when an associated statement is asynchronously executing or mid data-at-execution; previously returned SQL_SUCCESS as a no-op.
  • Changed DECFLOAT fetched as SQL_C_CHAR/SQL_C_WCHAR to return normalized scientific notation (e.g. 1.2e200 instead of 12e199).
  • Changed stage array-binding threshold comparison from > to >= and added support for the arrayBindSupported and CLIENT_STAGE_ARRAY_BINDING_THRESHOLD session parameters; previously the server-provided arrayBindSupported flag was ignored.
  • Removed support for the SQL_SF_CONN_ATTR_PRIV_KEY (raw EVP_PKEY*) connection attribute; use PRIV_KEY_CONTENT, PRIV_KEY_BASE64, or PRIV_KEY_FILE instead.
  • Changed OAuth token and authorization endpoint URL validation to require HTTPS; http:// is allowed only for loopback addresses.
  • Changed the SQLSTATE for OAuth IdP token-exchange rejection from HY000 to 28000 (invalid authorization specification).
  • Changed connection setup to reject WIF-only parameters (e.g. WORKLOAD_IDENTITY_PROVIDER) unless AUTHENTICATOR=WORKLOAD_IDENTITY; previously silently ignored them with any other authenticator.
  • Changed WORKLOAD_IDENTITY_IMPERSONATION_PATH with IDENTITY_PROVIDER=OIDC to return a connection error; previously silently ignored the combination.
  • Changed catalog REMARKS and SQLColumns COLUMN_DEF to return SQL_NULL_DATA when absent instead of an empty string, and SQLTables REMARKS now surfaces a SHOW OBJECTS comment when present.
  • Changed SQL_SF_STMT_ATTR_LAST_QUERY_ID to be read-only and fully populated after every statement execution; changed SQL_SF_STMT_ATTR_MULTI_STATEMENT_COUNT to support get/set with a default of -1 (auto-detect); neither attribute was fully implemented in ODBC 3.x.
  • Changed SQLGetDiagRec / SQLGetDiagField message text to append an internal error trace by default; set ErrorTraceEnabled=false in sf.odbc.ini to restore 3.x-shaped message text.
  • Fixed return codes and diagnostics under iODBC to match the ODBC specification: zero-row DML returns SQL_NO_DATA, length-only queries return SQL_SUCCESS, and required SUCCESS_WITH_INFO / HY012 diagnostics are posted correctly.
  • Fixed orphaned child statement handles under iODBC: SQLDisconnect and SQLFreeStmt(SQL_DROP) now invalidate all associated handles through iODBC's alloc table so a subsequent SQLFreeHandle on an orphaned handle returns SQL_INVALID_HANDLE instead of SQL_SUCCESS.
  • Fixed SQLGetDescField and SQLSetDescField called during SQL_NEED_DATA state under iODBC to return SQL_ERROR (HY010); previously returned SQL_SUCCESS.
  • Fixed ODBC 3.x-standard SQLSTATEs under iODBC (e.g. HY090, HY010, HY017, HY092, 07009, HY008); previously returned vendor HY000 or ODBC 2.x aliases.
  • Fixed SQL_C_WCHAR fetch encoding under iODBC to use a uniform UTF-32 width driven by DriverManagerEncoding in sf.odbc.ini; previously the code-unit width varied by Snowflake source column type.
  • Changed proxy resolution so HTTP_PROXY / HTTPS_PROXY / NO_PROXY environment variables are ignored unless USE_PROXY_ENV=true (alias PROXYWITHENV); explicit PROXY= / NO_PROXY= connection parameters still apply. ODBC 3.x fell back to those environment variables when no DSN/simba.snowflake.ini proxy was set. PROXYWITHENV no longer writes the connection's PROXY value into the process environment.
  • Changed SF_GLOBAL_SSL_VERSION (and TLS settings) below TLS 1.2 to fail the connection; previously logged a deprecation warning and still negotiated.
  • Removed support of OCSP certificate validation in favor of CRL validation.

New features

  • Added VECTOR column fetch: VECTOR columns are returned as compact JSON array strings (e.g. [1,2,3]) via SQL_C_CHAR, SQL_C_WCHAR, and SQL_C_BINARY; SQLDescribeCol reports SQL_VARCHAR and SQL_DESC_TYPE_NAME returns VECTOR.
  • Added ALTER USER ADD PROGRAMMATIC ACCESS TOKEN result-set support: the generated token is returned as a result row; ODBC 3.x returned an invalid cursor state for this DDL.
  • Implemented SQLTransact (ODBC 2.x) as a mapping to SQLEndTran, restoring compatibility with ODBC 2.x applications that bypass the Driver Manager.
  • Added TIME to SQL_C_BINARY conversion support.
  • Added SQL_C_BINARY as SQLBindParameter source type for SQL_DECIMAL, SQL_NUMERIC, SQL_TIME, and SQL_TIMESTAMP when the buffer length matches the SQL data length.
  • Added PUT local-path tilde expansion: a leading ~/ or ~ in the source path is expanded to the user's home directory.
  • Added automatic creation of a missing destination directory for GET operations.
  • Added SQLGetDiagField(SQL_DIAG_SERVER_NAME) population: returns the connected server name instead of an empty string.
  • Added SQLGetDiagField(SQL_DIAG_DYNAMIC_FUNCTION) / SQL_DIAG_DYNAMIC_FUNCTION_CODE population after statement execution (e.g. SELECT → 85 / SQL_DIAG_SELECT_CURSOR); previously returned empty / 0.
  • Added SQL_C_BINARY to VARCHAR binding: binary bytes are hex-encoded before send (e.g. 0xDEADBEEF"deadbeef"); ODBC 3.x forwarded raw bytes and the server rejected the request with HTTP 400.
  • Added SQL_SF_TIMESTAMP_TZ parameter binding for SQL_C_TYPE_TIMESTAMP (stored at UTC) and SQL_C_CHAR/SQL_C_WCHAR strings with a +/-HH:MM offset.
  • Added SQLBindParameter support for binding to SQL_INTERVAL_* parameters from same-family SQL_C_INTERVAL_*, SQL_C_CHAR/SQL_C_WCHAR, and exact-numeric C sources (approximate-numeric sources are rejected with SQL_ERROR 07006).
  • Added SQL_SF_CONN_ATTR_APPLICATION as a pre-connect get/set attribute that forwards the application name to the server.
  • Added SQLGetFunctions reporting of SQL_API_SQLSETSCROLLOPTIONS and SQL_API_SQLPARAMOPTIONS as supported under iODBC.

Changes

  • Renamed the default driver registration name to Snowflake ODBC; update DSN Driver= entries that reference SnowflakeDSIIDriver (custom names still configurable via DRIVER_NAME= / SF_DRIVER_NAME).
  • Changed distributable ODBC package filenames to snowflake-odbc-<version>.<arch>.<extension> with unified architectures aarch64 / x86_64 / x86_32 / universal.
  • Changed SQLGetInfo(SQL_DRIVER_VER) to return the zero-padded MM.mm.bbbb format (e.g. 04.00.0000) per the ODBC specification instead of the unpadded semver string (e.g. 3.16.0).
  • Changed process-wide driver configuration to use sf.odbc.ini (searched in $SF_ODBC_INI, ~/.config/snowflake/sf.odbc.ini, ~/.snowflake/sf.odbc.ini, and /opt/snowflake/snowflakeodbc/sf.odbc.ini); update deployment scripts that write simba.snowflake.ini.
  • Changed PASSCODEINPASSWORD connection parameter to accept true and 1 in addition to on.
  • Changed QUERY_TAG connection parameter to be applied as a server session parameter at connection time.
  • Changed the on-disk credential cache file from credential_cache_v1.json to credential_cache_v2.json (same lookup order: $SF_TEMPORARY_CREDENTIAL_CACHE_DIR, $XDG_CACHE_HOME/snowflake, $HOME/.cache/snowflake). Tokens cached by ODBC 3.x are not read by 4.x, so expect one extra authentication after upgrading.
  • Changed GET downloads on Unix to create files with owner-only (0600) permissions by default; set UNSAFE_FILE_WRITE=true to use the process umask.
  • Changed PRIV_KEY_FILE / private_key_file reads on Unix to require owner-only permissions (mode 0600); overly permissive key files now fail unless UNSAFE_SKIP_CONFIG_FILE_PERMISSIONS_CHECK=true.
  • Changed AUTHENTICATOR=WORKLOAD_IDENTITY to reject hosts outside the recognized Snowflake suffixes (snowflakecomputing.com / .cn / .mil) before fetching cloud credentials; extend the list only via the SNOWFLAKE_WIF_ALLOWED_HOST_SUFFIXES environment variable.
  • Changed client-side-encryption KeyWrappingMetadata.EncryptionLibrary metadata to "Rust(OpenSSL)".
  • Changed client-side rejection of invalid ACCOUNT / SERVER / PORT characters to SQLSTATE 01S00 (native error 0); ODBC 3.x returned 28000 (native error 20032).
  • Changed CLIENT_SESSION_KEEP_ALIVE_HEARTBEAT_FREQUENCY to be sent as a server session parameter during login (queryable via SHOW PARAMETERS) in addition to configuring the client heartbeat interval; ODBC 3.x used it client-side only.
  • Changed control-plane response body reads with a cap of 20MB (OAuth, browser, GCP metadata, CRL)
  • Changed strict owner-only permissions and single-open I/O in CRL cache handling

Bug fixes

  • Fixed failed GET downloads to leave no partial or corrupt file at the destination; the driver now writes to a .part temporary file and renames it on successful completion.
  • Fixed concurrent SQLDisconnect to be thread-safe.
  • Fixed SQLDisconnect to free child statement handles and explicitly allocated descriptors after a successful disconnect so a later SQLFreeHandle on those handles returns SQL_INVALID_HANDLE.
  • Fixed SQLDisconnect to return SQL_ERROR (HY010) without disconnecting when a child statement is asynchronously executing or mid data-at-execution.
  • Fixed SQLCancel on a statement with SQL_ATTR_ASYNC_ENABLE to actually interrupt the in-progress operation: subsequent polling returns SQL_ERROR (HY008) once the cancellation is acknowledged. Previously polling kept returning SQL_STILL_EXECUTING until the query completed naturally.
  • Fixed cross-thread SQLCancel and SQLCancelHandle to always return SQL_SUCCESS and post no diagnostics of their own, per the ODBC specification; previously they intermittently returned SQL_ERROR (HY008, native error 604) when the server-side abort raced the query's completion. Only the canceled function returns HY008.
  • Fixed FLOAT/DOUBLE boundary values (FLT_MAX, DBL_MAX) being incorrectly rejected with a numeric out-of-range error; they are now returned successfully.
  • Fixed a crash during TIMESTAMP to SQL_C_CHAR/SQL_C_WCHAR conversion when the destination buffer was too small.
  • Fixed SQLNumResultCols and SQLDescribeCol to return the correct column count and metadata after a prepared statement's cursor is closed - including the async SQLPrepare + SQLExecute + SQLCloseCursor path - instead of returning incorrect results or errors.
  • Fixed SQLDescribeCol column size for SQL_DOUBLE / SQL_FLOAT to report 15 (decimal digit precision) instead of 53 (binary mantissa bits).
  • Fixed SQLColumns NUM_PREC_RADIX for FLOAT/DOUBLE/REAL to return 10, matching decimal COLUMN_SIZE (query-result SQLColAttribute radix for DOUBLE remains 2).
  • Fixed SQLFreeHandle(SQL_HANDLE_DESC) on an implicitly allocated descriptor to return SQL_ERROR (HY017) and leave the handle valid.
  • Fixed external-browser SSO/OAuth on WSL/Linux to validate the browser URL before launching the browser.
  • Fixed SQL_C_CHAR fetch of FLOAT/DOUBLE/REAL with a truncated buffer to post SQLSTATE 01004.
  • Fixed SQL_C_WCHAR chunked SQLGetData buffer capacity to use sizeof(SQLWCHAR) so an 8-byte buffer fits three data characters plus NUL.
  • Fixed SQL_C_WCHAR decimal-string binding to SQL_DECIMAL to convert correctly on all platforms.
  • Fixed crashes under iODBC during some SQLFreeHandle / SQLDisconnect / SQLCopyDesc handle-hierarchy sequences that aborted or segfaulted.
  • Fixed connection-attribute state after SQLDisconnect under iODBC: SQL_ATTR_CONNECTION_DEAD reports SQL_CD_TRUE and reads of other connection attributes return SQL_ERROR instead of stale cached values.
  • Fixed SQLGetData conversion from DECFLOAT to SQL_C_WCHAR under iODBC to convert the value instead of returning SQL_SUCCESS with SQL_NULL_DATA and an untouched buffer.
  • Fixed SQLColAttribute to map ODBC 2.x field identifiers (SQL_COLUMN_NAME, SQL_COLUMN_TYPE, etc.) to their SQL_DESC_* equivalents as previous behavior was inconsistent (empty strings, wrong values, or HY091).
  • Fixed SQLPrimaryKeys / SQLForeignKeys with SQL_ATTR_METADATA_ID=TRUE to case-fold unquoted identifiers to uppercase before matching instead of comparing case-sensitively and returning empty results for lowercase names.
  • Fixed SQLProcedures / SQLProcedureColumns with SQL_ATTR_METADATA_ID=TRUE to case-fold unquoted identifiers to uppercase before matching instead of returning empty results for lowercase names.
  • Fixed SQLTables with SQL_ATTR_METADATA_ID=TRUE to case-fold unquoted identifiers to uppercase before matching instead of returning empty results for lowercase names.
  • Fixed SQLGetData with SQL_C_NUMERIC to honor SQL_DESC_PRECISION and SQL_DESC_SCALE set on the ARD via SQLSetDescFieldinstead of hardcoded precision 38 / scale 0.
  • Fixed DATE to SQL_C_CHAR/SQL_C_WCHAR conversion with an undersized buffer to return SQL_ERROR (22003) instead of truncating.
  • Fixed SQLGetDescField on an empty IPD (no parameters bound) to return SQL_NO_DATA instead of SQL_ERROR.
  • Fixed SQLGetStmtAttr / SQLGetConnectAttr with a negative string BufferLength to return SQL_ERROR (HY090).
  • Fixed SQLGetConnectAttr with an out-of-range attribute identifier to return SQL_ERROR (HY092).
  • Fixed SQLSetConnectAttr with ODBC 2.x statement-level attribute IDs (SQL_ATTR_MAX_ROWS, SQL_ATTR_QUERY_TIMEOUT) to return SQL_ERROR (HY092) instead of SQL_SUCCESS as a silent no-op.
  • Fixed fractional truncation on a numeric-to-character fetch to return SQL_SUCCESS_WITH_INFO with SQLSTATE 01S07.
  • Fixed FLOAT/REAL to single-field interval fetch with a nonzero fractional part to return SQL_SUCCESS_WITH_INFO (01S07).
  • Fixed numeric-to-interval conversion so a value that truncates to zero always yields +0 (no negative-zero interval sign).

Known issues

  • Binding "Infinity", "-Infinity", or "NaN" as SQL_C_CHAR / SQL_C_WCHAR to a float SQL type returns SQL_ERROR (22018); ODBC 3.x forwarded the literal and stored a non-finite FLOAT.
  • SQLForeignKeys with SQL_ATTR_METADATA_ID=TRUE allows unused FK-side NULL pointers instead of returning HY009; ODBC 3.x rejected the call with SQL_ERROR.
  • Conversion from FLOAT / DOUBLE / REAL to SQL_C_BINARY returns a 19-byte SQL_NUMERIC_STRUCT; ODBC 3.x returned the raw 8-byte IEEE 754 double.
  • Any nonzero SQL_C_NUMERIC value bound to SQL_BIT converts to true; ODBC 3.x rejected values outside {0, 1} with SQL_ERROR (22003).
  • SQL_C_CHAR / SQL_C_WCHAR hex literals bound to SQL_BINARY are hex-decoded (e.g. "DEADBEEF" → 4 bytes); ODBC 3.x forwarded the raw ASCII bytes.
  • PUT compression type is returned in uppercase (e.g. GZIP); ODBC 3.x returned lowercase (e.g. gzip).
  • Gzip-compressed PUT uploads omit the original filename from the gzip FNAME header and zero the mtime; ODBC 3.x included the filename in the header.
  • OAuth Authorization Code token caching is disabled by default; set CLIENT_STORE_TEMPORARY_CREDENTIAL=true to re-enable. ODBC 3.x cached by default on all platforms.
  • SQLDescribeParam normalizes Snowflake vendor TIMESTAMP type codes (2000 / 2001 / 2002) to SQL_TYPE_TIMESTAMP (93); ODBC 3.x preserved the vendor codes.
  • Under iODBC, the driver manager may return different return codes or SQLSTATEs for identical calls because ODBC 4.x and ODBC 3.x advertise different driver capabilities (e.g. DSN-name lookup, catalog calls, SQLGetFunctions probes).
  • SQLBrowseConnect under iODBC returns SQL_ERROR for partial connection input instead of SQL_NEED_DATA for the iterative protocol.