Skip to content

Commit 95a1f18

Browse files
authored
FIX: Executemany String corruption on Unix systems + tests (#217)
### Work Item / Issue Reference <!-- IMPORTANT: Please follow the PR template guidelines below. For mssql-python maintainers: Insert your ADO Work Item ID below (e.g. AB#37452) For external contributors: Insert Github Issue number below (e.g. #149) Only one reference is required - either GitHub issue OR ADO Work Item. --> <!-- mssql-python maintainers: ADO Work Item --> > [AB#38479](https://sqlclientdrivers.visualstudio.com/c6d89619-62de-46a0-8b46-70b92a84d85e/_workitems/edit/38479) <!-- External contributors: GitHub Issue --> > GitHub Issue: #<ISSUE_NUMBER> ------------------------------------------------------------------- ### Summary <!-- Insert your summary of changes below. Minimum 10 characters required. --> ## Fix string handling in executemany batch operations on Unix systems **Issue:** `executemany` was corrupting string data on Unix/macOS due to encoding mismatch in batch parameter binding. Strings were either truncated or returned garbage data. **Root Cause:** In `BindParameterArray` function, `std::wstring` (UTF-32 on Unix) was directly copied to `SQLWCHAR` buffers (UTF-16) without proper encoding conversion, while single parameter binding in `execute` correctly used `WStringToSQLWCHAR()`. **Fix:** - Added platform-specific string conversion in `BindParameterArray` for `SQL_C_WCHAR` case - Unix: Use `WStringToSQLWCHAR()` for proper UTF-32 → UTF-16 conversion - Windows: Keep existing direct copy (both are UTF-16) **Impact:** - All string data (including empty strings) now correctly preserved in executemany - Eliminates data corruption and truncation on Unix platforms - Maintains existing Windows behavior - Consistent string handling between `execute` and `executemany` <!-- ### PR Title Guide > For feature requests FEAT: (short-description) > For non-feature requests like test case updates, config updates , dependency updates etc CHORE: (short-description) > For Fix requests FIX: (short-description) > For doc update requests DOC: (short-description) > For Formatting, indentation, or styling update STYLE: (short-description) > For Refactor, without any feature changes REFACTOR: (short-description) > For release related changes, without any feature changes RELEASE: #<RELEASE_VERSION> (short-description) ### Contribution Guidelines External contributors: - Create a GitHub issue first - Link the GitHub issue in the "GitHub Issue" section above - Follow the PR title format and provide a meaningful summary mssql-python maintainers: - Create an ADO Work Item following internal processes - Link the ADO Work Item in the "ADO Work Item" section above - Follow the PR title format and provide a meaningful summary -->
1 parent 1da4fa9 commit 95a1f18

File tree

2 files changed

+529
-0
lines changed

2 files changed

+529
-0
lines changed

mssql_python/pybind/ddbc_bindings.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,11 +1352,25 @@ SQLRETURN BindParameterArray(SQLHANDLE hStmt,
13521352
std::memset(wcharArray + i * (info.columnSize + 1), 0, (info.columnSize + 1) * sizeof(SQLWCHAR));
13531353
} else {
13541354
std::wstring wstr = columnValues[i].cast<std::wstring>();
1355+
#if defined(__APPLE__) || defined(__linux__)
1356+
// Convert to UTF-16 first, then check the actual UTF-16 length
1357+
auto utf16Buf = WStringToSQLWCHAR(wstr);
1358+
// Check UTF-16 length (excluding null terminator) against column size
1359+
if (utf16Buf.size() > 0 && (utf16Buf.size() - 1) > info.columnSize) {
1360+
std::string offending = WideToUTF8(wstr);
1361+
ThrowStdException("Input string UTF-16 length exceeds allowed column size at parameter index " + std::to_string(paramIndex) +
1362+
". UTF-16 length: " + std::to_string(utf16Buf.size() - 1) + ", Column size: " + std::to_string(info.columnSize));
1363+
}
1364+
// If we reach here, the UTF-16 string fits - copy it completely
1365+
std::memcpy(wcharArray + i * (info.columnSize + 1), utf16Buf.data(), utf16Buf.size() * sizeof(SQLWCHAR));
1366+
#else
1367+
// On Windows, wchar_t is already UTF-16, so the original check is sufficient
13551368
if (wstr.length() > info.columnSize) {
13561369
std::string offending = WideToUTF8(wstr);
13571370
ThrowStdException("Input string exceeds allowed column size at parameter index " + std::to_string(paramIndex));
13581371
}
13591372
std::memcpy(wcharArray + i * (info.columnSize + 1), wstr.c_str(), (wstr.length() + 1) * sizeof(SQLWCHAR));
1373+
#endif
13601374
strLenOrIndArray[i] = SQL_NTS;
13611375
}
13621376
}

0 commit comments

Comments
 (0)