Skip to content

feat: support structured C types in SQLBindParameter for string SQL types#749

Merged
sfc-gh-makowalski merged 6 commits intomainfrom
feat/bindparam-c-structured-to-varchar
Apr 3, 2026
Merged

feat: support structured C types in SQLBindParameter for string SQL types#749
sfc-gh-makowalski merged 6 commits intomainfrom
feat/bindparam-c-structured-to-varchar

Conversation

@sfc-gh-makowalski
Copy link
Copy Markdown
Contributor

@sfc-gh-makowalski sfc-gh-makowalski commented Mar 27, 2026

Summary

Add date, time, timestamp, SQL_NUMERIC_STRUCT, and binary C type
conversions in SnowflakeVarchar::ReadODBC for string SQL parameters.

  • SQL_C_TYPE_TIMESTAMP: formats as "YYYY-MM-DD HH:MM:SS[.nnnnnnnnn]"
    (matches old driver format from BindCatchTest)
  • SQL_C_TYPE_DATE: formats as "YYYY-MM-DD"
  • SQL_C_TYPE_TIME: formats as "HH:MM:SS"
  • SQL_C_NUMERIC: reads SQL_NUMERIC_STRUCT, converts 128-bit LE magnitude
    with sign and scale (including negative scale) to decimal string
  • SQL_C_BINARY: hex-encodes raw bytes

Follow-up from PR #748

Handles the remaining structured C types that were left as UnsupportedCDataType in the first PR.

Test plan

  • 7 Rust unit tests for structured type conversions (timestamp, timestamp with fraction, date, time, numeric, negative numeric with scale, numeric with negative scale, negative numeric with negative scale, binary)
  • 8 e2e tests:
    • SQL_C_TYPE_TIMESTAMP → SQL_VARCHAR
    • SQL_C_TYPE_TIMESTAMP with fraction → SQL_VARCHAR
    • SQL_C_TYPE_DATE → SQL_VARCHAR
    • SQL_C_TYPE_TIME → SQL_VARCHAR
    • SQL_C_NUMERIC (integer) → SQL_VARCHAR
    • SQL_C_NUMERIC (negative with scale) → SQL_VARCHAR
    • SQL_C_NUMERIC (negative scale) → SQL_VARCHAR
    • SQL_C_BINARY → SQL_VARCHAR
  • All existing unit tests continue to pass

SNOW-3031761

@github-actions github-actions Bot added the odbc label Mar 27, 2026
Copy link
Copy Markdown
Contributor Author

sfc-gh-makowalski commented Mar 27, 2026

@sfc-gh-makowalski sfc-gh-makowalski force-pushed the feat/bindparam-c-structured-to-varchar branch 9 times, most recently from f5f01b3 to f0f2ba6 Compare March 30, 2026 10:44
@sfc-gh-makowalski sfc-gh-makowalski force-pushed the feat/bindparam-c-numeric-to-varchar branch from 33122b1 to fc535e4 Compare April 1, 2026 06:10
@sfc-gh-makowalski sfc-gh-makowalski force-pushed the feat/bindparam-c-structured-to-varchar branch from f0f2ba6 to 16e574d Compare April 1, 2026 07:16
@sfc-gh-makowalski sfc-gh-makowalski force-pushed the feat/bindparam-c-numeric-to-varchar branch from 9f45025 to 02415d1 Compare April 1, 2026 07:16
@sfc-gh-makowalski sfc-gh-makowalski marked this pull request as ready for review April 1, 2026 07:24
@sfc-gh-makowalski sfc-gh-makowalski requested a review from a team as a code owner April 1, 2026 07:25
@sfc-gh-makowalski sfc-gh-makowalski force-pushed the feat/bindparam-c-structured-to-varchar branch from 16e574d to d6f0bf6 Compare April 1, 2026 07:54
@sfc-gh-makowalski sfc-gh-makowalski force-pushed the feat/bindparam-c-numeric-to-varchar branch from 4632498 to 055aa4a Compare April 1, 2026 08:35
@sfc-gh-makowalski sfc-gh-makowalski force-pushed the feat/bindparam-c-structured-to-varchar branch 2 times, most recently from 3360a20 to 0914a53 Compare April 1, 2026 08:57
github-merge-queue Bot pushed a commit that referenced this pull request Apr 1, 2026
…SQL types (#748)

## Summary

- Expand `SnowflakeVarchar::ReadODBC` to properly handle integer, float,
and BIT C types when bound to string SQL types (`SQL_VARCHAR`,
`SQL_CHAR`, `SQL_LONGVARCHAR`, `SQL_WCHAR`, `SQL_WVARCHAR`,
`SQL_WLONGVARCHAR`)
- Previously all non-WCHAR C types fell through to `read_char_str`,
which interpreted raw struct bytes as a char string — producing garbage
for numeric C types like `SQL_C_LONG` or `SQL_C_DOUBLE`
- Map `SQL_C_DEFAULT` to `read_char_str` to match the `WriteODBCType`
side and avoid a regression from the prior catch-all
- Normalize `-0.0` to `"0"` for float-to-varchar binding to match old
driver behavior
- The catch-all now returns `UnsupportedCDataType` error instead of
silently misinterpreting unknown C types

### C types now supported for string SQL parameters

| C Type | Conversion |
|--------|-----------|
| `SQL_C_LONG` / `SQL_C_SLONG` | `i32 -> .to_string()` |
| `SQL_C_SHORT` / `SQL_C_SSHORT` | `i16 -> .to_string()` |
| `SQL_C_SBIGINT` | `i64 -> .to_string()` |
| `SQL_C_ULONG` | `u32 -> .to_string()` |
| `SQL_C_USHORT` | `u16 -> .to_string()` |
| `SQL_C_UBIGINT` | `u64 -> .to_string()` |
| `SQL_C_TINYINT` / `SQL_C_STINYINT` | `i8 -> .to_string()` |
| `SQL_C_UTINYINT` | `u8 -> .to_string()` |
| `SQL_C_DOUBLE` | `f64 -> .to_string()` (negative zero normalized to
"0") |
| `SQL_C_FLOAT` | `f32 -> .to_string()` (negative zero normalized to
"0") |
| `SQL_C_BIT` | `u8 -> "0" or "1"` |

### Follow-up (PR 2)

Structured C types (`SQL_C_TYPE_TIMESTAMP`, `SQL_C_TYPE_DATE`,
`SQL_C_TYPE_TIME`, `SQL_C_NUMERIC`, `SQL_C_BINARY`) are handled in the
stacked PR #749.

## Test plan

- [x] 36 e2e tests:
- Each numeric C type bound to SQL_VARCHAR (SLONG, ULONG, SSHORT,
USHORT, SBIGINT, UBIGINT, STINYINT, UTINYINT, DOUBLE, FLOAT)
  - Negative value test (negative SLONG)
  - BIT true, BIT false, BIT value > 1
  - Deprecated C type aliases (SQL_C_LONG, SQL_C_SHORT, SQL_C_TINYINT)
- SQL_C_SLONG bound to all 5 other string SQL types (SQL_CHAR,
SQL_LONGVARCHAR, SQL_WCHAR, SQL_WVARCHAR, SQL_WLONGVARCHAR)
- Boundary values: INT_MIN, INT_MAX, zero, LLONG_MIN, LLONG_MAX,
ULLONG_MAX
- Float edge cases: -0.0, NaN (double + float), +infinity (double +
float), -infinity (double + float)
  - SQL_C_DEFAULT bound to SQL_VARCHAR
- [x] All existing unit tests continue to pass

SNOW-3031761
Base automatically changed from feat/bindparam-c-numeric-to-varchar to main April 1, 2026 10:18
@sfc-gh-makowalski sfc-gh-makowalski force-pushed the feat/bindparam-c-structured-to-varchar branch from 0914a53 to 5229587 Compare April 1, 2026 11:06
Copy link
Copy Markdown
Contributor

sfc-gh-pbulawa commented Apr 1, 2026

Please add E2E tests

Comment thread odbc/src/conversion/varchar.rs
Copilot AI review requested due to automatic review settings April 1, 2026 13:25
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the ODBC parameter-to-JSON conversion path for string SQL parameter types (e.g., VARCHAR) by adding support for additional structured/typed C buffers in SnowflakeVarchar::read_odbc, enabling date/time/timestamp, SQL_NUMERIC_STRUCT, and binary parameters to be represented as strings.

Changes:

  • Added string formatting for SQL_C_TYPE_TIMESTAMP / SQL_C_TIMESTAMP, SQL_C_TYPE_DATE / SQL_C_DATE, and SQL_C_TYPE_TIME / SQL_C_TIME when binding to VARCHAR.
  • Added SQL_C_NUMERIC (SQL_NUMERIC_STRUCT) conversion to a decimal string (magnitude/sign/scale).
  • Added SQL_C_BINARY conversion to lowercase hex string, plus end-to-end tests covering these conversions.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
odbc/src/conversion/varchar.rs Adds structured C-type decoding/formatting in SnowflakeVarchar::read_odbc for string SQL types.
odbc/src/conversion/param_binding.rs Adds unit tests validating the new structured C-type → VARCHAR conversion behavior.

Comment thread odbc/src/conversion/varchar.rs Outdated
@github-actions github-actions Bot added the tests label Apr 1, 2026
Copilot AI review requested due to automatic review settings April 1, 2026 14:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings April 2, 2026 07:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment thread odbc/src/conversion/varchar.rs
…ypes

Add date, time, timestamp, SQL_NUMERIC_STRUCT, and binary C type
conversions in SnowflakeVarchar::ReadODBC for string SQL parameters.

- SQL_C_TYPE_TIMESTAMP: formats as "YYYY-MM-DD HH:MM:SS[.nnnnnnnnn]"
  (matches old driver format from BindCatchTest)
- SQL_C_TYPE_DATE: formats as "YYYY-MM-DD"
- SQL_C_TYPE_TIME: formats as "HH:MM:SS"
- SQL_C_NUMERIC: reads SQL_NUMERIC_STRUCT, converts 128-bit LE magnitude
  with sign and scale to decimal string
- SQL_C_BINARY: hex-encodes raw bytes

SNOW-3031761

Made-with: Cursor
Per ODBC spec, SQL_NUMERIC_STRUCT.scale is SQLSCHAR (signed). Negative
scale means the value is multiplied by 10^|scale| (e.g. val=123,
scale=-2 represents 12300). Previously this fell through to the
scale==0 branch, returning the raw magnitude without trailing zeros.

Made-with: Cursor
8 new tests covering SQL_C_TYPE_TIMESTAMP (with and without fraction),
SQL_C_TYPE_DATE, SQL_C_TYPE_TIME, SQL_C_NUMERIC (integer, negative
with scale, negative scale), and SQL_C_BINARY bound to SQL_VARCHAR.

Made-with: Cursor
BD#32: Old driver (Simba SDK) ignores the scale field in
SQL_NUMERIC_STRUCT when converting to VARCHAR. New driver applies scale
per ODBC spec (value = val × 10^(−scale)).

BD#33: Old driver fails with HTTP 400 when binding SQL_C_BINARY to
SQL_VARCHAR. New driver hex-encodes the binary data, which Snowflake
accepts.

Also fix clang-format issues in the new e2e tests.

Made-with: Cursor
@sfc-gh-makowalski sfc-gh-makowalski force-pushed the feat/bindparam-c-structured-to-varchar branch from f979995 to 36d0388 Compare April 3, 2026 06:47
@sfc-gh-makowalski sfc-gh-makowalski added this pull request to the merge queue Apr 3, 2026
Merged via the queue into main with commit 3eabd8c Apr 3, 2026
71 of 72 checks passed
@sfc-gh-makowalski sfc-gh-makowalski deleted the feat/bindparam-c-structured-to-varchar branch April 3, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants