Skip to content

FIX: executemany SQL_C_NUMERIC mismatch#611

Merged
jahnvi480 merged 3 commits into
mainfrom
jahnvi/github_issue_609
Jun 3, 2026
Merged

FIX: executemany SQL_C_NUMERIC mismatch#611
jahnvi480 merged 3 commits into
mainfrom
jahnvi/github_issue_609

Conversation

@jahnvi480
Copy link
Copy Markdown
Contributor

@jahnvi480 jahnvi480 commented Jun 1, 2026

Work Item / Issue Reference

AB#45380

GitHub Issue: #609


Summary

This pull request addresses a critical bug in the handling of executemany with large Decimal values in the mssql_python driver, specifically when values exceed the SQL Server MONEY range. The main fix ensures that parameter type detection and conversion are consistent, preventing runtime errors when binding large decimal values. Extensive unit and integration tests are added to verify the fix and cover edge cases involving Decimal values, including scenarios with NULLs and multi-column inserts.

Bug Fix: Executemany Decimal Handling

  • In cursor.py, the executemany method now explicitly overrides the C type for parameters with SQL type DECIMAL or NUMERIC to use SQL_C_CHAR (string binding) when the data is converted to strings. This prevents mismatches that previously caused runtime errors when inserting large decimal values. The column size is also adjusted to fit the longest string representation.

Testing: Unit and Integration Tests for Decimal Handling

  • Added comprehensive unit tests in test_001_globals.py to verify type detection, mapping, and the override logic for executemany with large Decimal values, both within and outside the MONEY range. These tests confirm that the C type override is necessary and correctly applied.
  • Added integration tests in test_004_cursor.py to exercise the fixed behavior in real database scenarios, including:
    • Inserting batches with decimals inside and outside the MONEY range.
    • Handling NULL values alongside large decimals.
    • Multi-column inserts where one column contains large decimals.

Copilot AI review requested due to automatic review settings June 1, 2026 14:41
@github-actions github-actions Bot added pr-size: medium Moderate update size labels Jun 1, 2026
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 pull request fixes a failure in Cursor.executemany() when binding large Decimal values (outside SQL Server MONEY range) by ensuring the detected parameter C type matches the actual converted parameter data, and improves bulkcopy() compatibility with iterable row objects (e.g., Row from fetchmany). It also adds unit and integration tests covering the reported GH-609 scenario.

Changes:

  • Adjust executemany auto-detected parameter binding for DECIMAL/NUMERIC to use SQL_C_CHAR to match the Decimal-to-string conversion path (GH-609).
  • Add a bulkcopy adapter to convert iterable row objects to tuples before passing to the Rust backend.
  • Add new unit + integration tests covering large Decimal batches (including mixed batches and NULLs).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
mssql_python/cursor.py Updates executemany DECIMAL/NUMERIC binding and adds tuple-normalization for bulkcopy input rows.
tests/test_001_globals.py Adds unit tests for the executemany Decimal type-detection/override pipeline (GH-609).
tests/test_004_cursor.py Adds integration tests reproducing and validating the GH-609 executemany scenario.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread mssql_python/cursor.py Outdated
Comment thread tests/test_001_globals.py Outdated
@jahnvi480 jahnvi480 force-pushed the jahnvi/github_issue_609 branch from 7d46896 to 73ab7a2 Compare June 1, 2026 14:51
…H-609)

Bug 1: executemany auto-detection path set paramCType=SQL_C_NUMERIC for
Decimal values outside the MONEY range, but the conversion loop converts
all Decimals to strings. The C extension then received strings where it
expected NumericData structs, raising RuntimeError. Fixed by overriding
SQL_C_NUMERIC to SQL_C_CHAR in the auto-detection path, matching the
existing GH-503 fix in the setinputsizes path.

Bug 2: bulkcopy passed Row objects directly to mssql_py_core which expects
native tuples. Added _ensure_tuples() wrapper to auto-convert Row/list
objects to tuples.

Fixes #609
@jahnvi480 jahnvi480 force-pushed the jahnvi/github_issue_609 branch 2 times, most recently from 4b6fb85 to d454a6f Compare June 1, 2026 15:06
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 1, 2026

📊 Code Coverage Report

🔥 Diff Coverage

100%


🎯 Overall Coverage

80%


📈 Total Lines Covered: 6654 out of 8256
📁 Project: mssql-python


Diff Coverage

Diff: main...HEAD, staged and unstaged changes

  • mssql_python/cursor.py (100%)

Summary

  • Total: 4 lines
  • Missing: 0 lines
  • Coverage: 100%

📋 Files Needing Attention

📉 Files with overall lowest coverage (click to expand)
mssql_python.pybind.logger_bridge.cpp: 59.2%
mssql_python.pybind.ddbc_bindings.h: 59.7%
mssql_python.pybind.logger_bridge.hpp: 70.8%
mssql_python.pybind.ddbc_bindings.cpp: 76.1%
mssql_python.row.py: 76.9%
mssql_python.__init__.py: 77.3%
mssql_python.pybind.connection.connection.cpp: 77.3%
mssql_python.ddbc_bindings.py: 79.6%
mssql_python.logging.py: 85.5%
mssql_python.connection.py: 85.6%

🔗 Quick Links

⚙️ Build Summary 📋 Coverage Details

View Azure DevOps Build

Browse Full Coverage Report

…EY range (GH-609)

The executemany auto-detection path set paramCType=SQL_C_NUMERIC for
Decimal values outside the MONEY range, but the conversion loop converts
all Decimals to strings. The C extension then received strings where it
expected NumericData structs, raising RuntimeError. Fixed by overriding
SQL_C_NUMERIC to SQL_C_CHAR in the auto-detection path, matching the
existing GH-503 fix in the setinputsizes path.

Fixes #609
@jahnvi480 jahnvi480 force-pushed the jahnvi/github_issue_609 branch from d454a6f to ba19ba7 Compare June 2, 2026 04:30
@jahnvi480 jahnvi480 changed the title FIX: executemany SQL_C_NUMERIC mismatch and bulkcopy Row acceptance FIX: executemany SQL_C_NUMERIC mismatch Jun 2, 2026
bewithgaurav
bewithgaurav previously approved these changes Jun 2, 2026
Copy link
Copy Markdown
Collaborator

@bewithgaurav bewithgaurav left a comment

Choose a reason for hiding this comment

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

reproduced #609 against sql2022, fix is clear and well-scoped. lgtm.

Comment thread tests/test_001_globals.py Outdated
@bewithgaurav
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@jahnvi480 jahnvi480 merged commit f748115 into main Jun 3, 2026
29 checks passed
jahnvi480 added a commit that referenced this pull request Jun 5, 2026
### Work Item / Issue Reference  
<!-- 
IMPORTANT: Please follow the PR template guidelines below.
For mssql-python maintainers: Insert your ADO Work Item ID below 
For external contributors: Insert Github Issue number below
Only one reference is required - either GitHub issue OR ADO Work Item.
-->

<!-- mssql-python maintainers: ADO Work Item -->
>
[AB#45380](https://sqlclientdrivers.visualstudio.com/c6d89619-62de-46a0-8b46-70b92a84d85e/_workitems/edit/45380)

<!-- External contributors: GitHub Issue -->
> GitHub Issue: #609 

-------------------------------------------------------------------
### Summary   
This pull request addresses a critical bug in the handling of
`executemany` with large `Decimal` values in the `mssql_python` driver,
specifically when values exceed the SQL Server `MONEY` range. The main
fix ensures that parameter type detection and conversion are consistent,
preventing runtime errors when binding large decimal values. Extensive
unit and integration tests are added to verify the fix and cover edge
cases involving `Decimal` values, including scenarios with `NULL`s and
multi-column inserts.

**Bug Fix: Executemany Decimal Handling**

* In `cursor.py`, the `executemany` method now explicitly overrides the
C type for parameters with SQL type `DECIMAL` or `NUMERIC` to use
`SQL_C_CHAR` (string binding) when the data is converted to strings.
This prevents mismatches that previously caused runtime errors when
inserting large decimal values. The column size is also adjusted to fit
the longest string representation.

**Testing: Unit and Integration Tests for Decimal Handling**

* Added comprehensive unit tests in `test_001_globals.py` to verify type
detection, mapping, and the override logic for `executemany` with large
`Decimal` values, both within and outside the `MONEY` range. These tests
confirm that the C type override is necessary and correctly applied.
* Added integration tests in `test_004_cursor.py` to exercise the fixed
behavior in real database scenarios, including:
- Inserting batches with decimals inside and outside the `MONEY` range.
  - Handling `NULL` values alongside large decimals.
  - Multi-column inserts where one column contains large decimals.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-size: medium Moderate update size

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants