Skip to content

Report 22003 for out-of-range integer conversions instead of silently wrapping (#207) - #210

Merged
davecramer merged 1 commit into
mainfrom
fix-207-int-overflow-22003
Sep 4, 2026
Merged

Report 22003 for out-of-range integer conversions instead of silently wrapping (#207)#210
davecramer merged 1 commit into
mainfrom
fix-207-int-overflow-22003

Conversation

@davecramer

Copy link
Copy Markdown
Contributor

Fixes #207.

Problem

SQLGetData/SQLBindCol of an integer that does not fit the requested C type returned SQL_SUCCESS with the wrapped low bits, no diagnostic:

  • 9223372036854775807::bigint as SQL_C_SLONG -> -1, as SQL_C_SSHORT -> -1
  • 4294967297::bigint as SQL_C_SLONG -> 1
  • 70000::int4 as SQL_C_SSHORT -> 4464

ODBC specifies SQL_ERROR with SQLSTATE 22003 (numeric value out of range). copy_and_convert_field() parsed with pg_atoi/pg_atol into a wide integer and the narrowing assignment truncated; nothing range-checked.

Fix

  • Add int_value_out_of_range() (parse once into 64-bit, flag ERANGE or out-of-[min,max]).
  • Range-check in the SQL_C_[S|U]TINYINT / [S|U]SHORT / [S|U]LONG / [S|U]BIGINT branches; on overflow leave the buffer untouched and return a new COPY_RESULT_OVERFLOW, mapped to STMT_VALUE_OUT_OF_RANGE (22003) in both the SQLGetData (results.c) and SQLFetch/SQLBindCol (statement.c) paths.
  • Correct the STMT_VALUE_OUT_OF_RANGE ODBC3 SQLSTATE, which was HY019 instead of 22003 (no other code used it).

Values that fit are unchanged; SQL_C_SBIGINT and SQL_C_NUMERIC were already correct.

Verification (PostgreSQL 18)

Issue repro now returns 22003 for the four out-of-range reads and the exact values for the in-range ones.

New int-overflow-test covers these cases. result-conversions expected output updated where it previously captured the wrapped values (all changes are out-of-range narrowings now reporting 22003); numeric, getresult unchanged.

…#207)

SQLGetData/SQLBindCol of an integer value that does not fit the requested
C type stored the low bits and returned SQL_SUCCESS -- e.g.
9223372036854775807::bigint read as SQL_C_SLONG gave -1, 70000::int4 as
SQL_C_SSHORT gave 4464.  pg_atoi/pg_atol parse into a wide integer and the
narrowing assignment silently truncates; nothing range-checked the value.
ODBC specifies SQL_ERROR with SQLSTATE 22003 (numeric value out of range).

Add int_value_out_of_range() and range-check the parsed value against the
target C type's limits in the SQL_C_[S|U]TINYINT / [S|U]SHORT / [S|U]LONG /
[S|U]BIGINT branches of copy_and_convert_field(); on overflow leave the
buffer untouched and return the new COPY_RESULT_OVERFLOW, mapped to
STMT_VALUE_OUT_OF_RANGE (22003) in the SQLGetData and SQLFetch/SQLBindCol
paths.  Also correct the STMT_VALUE_OUT_OF_RANGE ODBC3 SQLSTATE, which was
HY019 rather than 22003 (the code had no other users).

Values that fit are unchanged; SQL_C_SBIGINT and SQL_C_NUMERIC were
already correct.  New int-overflow-test covers the issue's cases;
result-conversions expected output updated where it previously captured
the wrapped values.
@davecramer
davecramer merged commit 4a5a0e7 into main Sep 4, 2026
11 checks passed
davecramer added a commit that referenced this pull request Sep 8, 2026
…eview)

On the SQL_ERROR path for a numeric-out-of-range conversion the data
buffer is left untouched; skip writing the length/indicator too, for
symmetry.  Within spec either way (buffer/indicator undefined after
SQL_ERROR), per review feedback on #210.
davecramer added a commit that referenced this pull request Sep 8, 2026
…eview) (#211)

On the SQL_ERROR path for a numeric-out-of-range conversion the data
buffer is left untouched; skip writing the length/indicator too, for
symmetry.  Within spec either way (buffer/indicator undefined after
SQL_ERROR), per review feedback on #210.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant