Skip to content

FIX: executemany RuntimeError when decimals change signs (GH-557)#560

Open
jahnvi480 wants to merge 1 commit intomainfrom
jahnvi/fix-executemany-decimal-sign-change-557
Open

FIX: executemany RuntimeError when decimals change signs (GH-557)#560
jahnvi480 wants to merge 1 commit intomainfrom
jahnvi/fix-executemany-decimal-sign-change-557

Conversation

@jahnvi480
Copy link
Copy Markdown
Contributor

@jahnvi480 jahnvi480 commented May 8, 2026

Work Item / Issue Reference

AB#44997

GitHub Issue: #557


Summary

This pull request fixes an issue with inserting decimal values of varying sign (positive/negative) using executemany, where the allocated column size could be too small if a negative value's string representation is longer than the sample used for sizing. It ensures the correct column size is used for all rows, preventing runtime errors. A new test is added to verify the fix.

Bug fix for decimal handling in executemany:

  • In mssql_python/cursor.py, when inserting decimals as SQL_VARCHAR, the code now scans all rows to determine the maximum formatted string length, ensuring the column size is large enough even when negative values are present.

Testing improvements:

  • Added test_executemany_decimal_sign_change in tests/test_004_cursor.py to cover cases where decimals change sign, verifying that no runtime error occurs and the data is correctly inserted and retrieved.

Root cause: In executemany(), Decimal values in the SMALLMONEY/MONEY range are bound as SQL_VARCHAR with column_size derived from a single sample value's formatted string length. The sample is chosen by _compute_column_type() based on precision/scale, not string length. When the sample is positive (e.g. '1.0' = 3 chars) but the batch contains a negative value (e.g. '-0.1' = 4 chars), the leading '-' makes it exceed the allocated buffer, causing the C++ layer to throw RuntimeError.

Fix: After paraminfo is created for auto-detected types, scan all Decimal values in the column to find the true maximum formatted string length and adjust columnSize accordingly. This mirrors the existing pattern used for binary data sizing.

Added test_executemany_decimal_sign_change covering: negative-then-positive, positive-then-negative, mixed sign batches, and data correctness verification.

Closes #557
Copilot AI review requested due to automatic review settings May 8, 2026 09:21
@github-actions github-actions Bot added the pr-size: small Minimal code update label May 8, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

📊 Code Coverage Report

🔥 Diff Coverage

100%


🎯 Overall Coverage

79%


📈 Total Lines Covered: 6869 out of 8645
📁 Project: mssql-python


Diff Coverage

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

  • mssql_python/cursor.py (100%)

Summary

  • Total: 9 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: 67.9%
mssql_python.row.py: 70.5%
mssql_python.pybind.logger_bridge.hpp: 70.8%
mssql_python.pybind.ddbc_bindings.cpp: 74.6%
mssql_python.pybind.connection.connection.cpp: 76.2%
mssql_python.__init__.py: 77.3%
mssql_python.ddbc_bindings.py: 79.6%
mssql_python.pybind.connection.connection_pool.cpp: 79.6%
mssql_python.connection.py: 85.3%

🔗 Quick Links

⚙️ Build Summary 📋 Coverage Details

View Azure DevOps Build

Browse Full Coverage Report

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

Fixes cursor.executemany() failures when batches contain decimal.Decimal values whose formatted length differs across rows (notably due to sign changes), by ensuring the inferred parameter columnSize can accommodate the longest value in the batch. This aligns with the reported RuntimeError in GH-557 and adds regression coverage.

Changes:

  • Update executemany parameter sizing for Decimal values that are bound as SQL_VARCHAR by scanning the batch to find the maximum formatted length (GH-557).
  • Add a regression test that inserts decimal batches with sign changes and verifies inserts succeed and data is retrievable.

Reviewed changes

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

File Description
mssql_python/cursor.py Adjusts executemany auto-detected SQL_VARCHAR column sizing to avoid under-allocation when Decimal string length varies across rows.
tests/test_004_cursor.py Adds a regression test covering executemany with Decimal values that change sign within/between batches (GH-557).

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

Comment thread mssql_python/cursor.py
Comment on lines +2328 to +2337
# Scan all rows to find the true maximum formatted length.
if paraminfo.paramSQLType == ddbc_sql_const.SQL_VARCHAR.value:
max_decimal_size = paraminfo.columnSize
for row in seq_of_parameters:
value = row[col_index]
if value is not None and isinstance(value, decimal.Decimal):
formatted_len = len(format(value, "f"))
if formatted_len > max_decimal_size:
max_decimal_size = formatted_len
paraminfo.columnSize = max_decimal_size
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-size: small Minimal code update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants