Skip to content

Commit daab245

Browse files
committed
fix review comments
1 parent e21b47e commit daab245

File tree

1 file changed

+28
-136
lines changed

1 file changed

+28
-136
lines changed

mssql_python/pybind/ddbc_bindings.cpp

Lines changed: 28 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,112 +1711,6 @@ SQLRETURN SQLFetch_wrap(SqlHandlePtr StatementHandle) {
17111711
return SQLFetch_ptr(StatementHandle->get());
17121712
}
17131713

1714-
// static py::object FetchLobColumnData(SQLHSTMT hStmt,
1715-
// SQLUSMALLINT colIndex,
1716-
// SQLSMALLINT cType,
1717-
// bool isWideChar,
1718-
// bool isBinary)
1719-
// {
1720-
// std::vector<char> buffer;
1721-
// SQLLEN indicator = 0;
1722-
// SQLRETURN ret;
1723-
// int loopCount = 0;
1724-
1725-
// while (true) {
1726-
// ++loopCount;
1727-
// std::vector<char> chunk(DAE_CHUNK_SIZE);
1728-
// ret = SQLGetData_ptr(
1729-
// hStmt,
1730-
// colIndex,
1731-
// cType,
1732-
// chunk.data(),
1733-
// DAE_CHUNK_SIZE,
1734-
// &indicator
1735-
// );
1736-
// if (indicator == SQL_NULL_DATA) {
1737-
// LOG("Loop {}: Column {} is NULL", loopCount, colIndex);
1738-
// return py::none();
1739-
// }
1740-
// if (!SQL_SUCCEEDED(ret) && ret != SQL_SUCCESS_WITH_INFO) {
1741-
// LOG("Loop {}: Error fetching col={} with cType={} ret={}", loopCount, colIndex, cType, ret);
1742-
// ThrowStdException("Error fetching column data");
1743-
// }
1744-
// // SQLLEN copyCount = 0;
1745-
// SQLLEN copyCount = DAE_CHUNK_SIZE;
1746-
// if (indicator >= 0 && indicator != SQL_NO_TOTAL) {
1747-
// copyCount = std::min<SQLLEN>(indicator - buffer.size(), DAE_CHUNK_SIZE);
1748-
// }
1749-
// // else {
1750-
// // copyCount = DAE_CHUNK_SIZE;
1751-
// // }
1752-
// if (isWideChar && (copyCount % sizeof(SQLWCHAR) != 0)) {
1753-
// LOG("Loop {}: Warning – copyCount {} not multiple of {}", loopCount, copyCount, sizeof(SQLWCHAR));
1754-
// copyCount -= copyCount % sizeof(SQLWCHAR);
1755-
// }
1756-
1757-
1758-
// // Check if last byte(s) is a null terminator
1759-
// if (copyCount > 0) {
1760-
// if (!isWideChar && chunk[copyCount - 1] == '\0') {
1761-
// --copyCount;
1762-
// LOG("Loop {}: Trimmed null terminator (narrow)", loopCount);
1763-
// } else if (copyCount >= sizeof(SQLWCHAR)) {
1764-
// auto wcharBuf = reinterpret_cast<const SQLWCHAR*>(chunk.data());
1765-
// if (wcharBuf[(copyCount / sizeof(SQLWCHAR)) - 1] == L'\0') {
1766-
// copyCount -= sizeof(SQLWCHAR);
1767-
// LOG("Loop {}: Trimmed null terminator (wide)", loopCount);
1768-
// }
1769-
// }
1770-
// }
1771-
// if (copyCount > 0) {
1772-
// buffer.insert(buffer.end(), chunk.begin(), chunk.begin() + copyCount);
1773-
// LOG("Loop {}: Appended {} bytes", loopCount, copyCount);
1774-
// }
1775-
// if (ret == SQL_SUCCESS) {
1776-
// LOG("Loop {}: SQL_SUCCESS → no more data", loopCount);
1777-
// break;
1778-
// }
1779-
// }
1780-
// LOG("FetchLobColumnData: Total bytes collected = {}", buffer.size());
1781-
1782-
// if (indicator == 0 || buffer.empty()) {
1783-
// LOG("FetchLobColumnData: Returning empty string for col {}", colIndex);
1784-
// return py::str("");
1785-
// }
1786-
1787-
// if (isWideChar) {
1788-
// // std::wstring wstr(reinterpret_cast<const wchar_t*>(buffer.data()),
1789-
// // buffer.size() / sizeof(wchar_t));
1790-
// // LOG("FetchLobColumnData: Returning wide string of length {}", wstr.length());
1791-
// // return py::cast(wstr);
1792-
// std::wstring wstr = SQLWCHARToWString(reinterpret_cast<const SQLWCHAR*>(buffer.data()), buffer.size() / sizeof(SQLWCHAR));
1793-
// LOG("FetchLobColumnData: Returning wide string of length {}", wstr.length());
1794-
// return py::cast(wstr);
1795-
// // }
1796-
// if (isWideChar) {
1797-
// if (buffer.size() % sizeof(SQLWCHAR) != 0) {
1798-
// LOG("FetchLobColumnData: Buffer size {} not aligned with {}", buffer.size(), sizeof(SQLWCHAR));
1799-
// throw std::runtime_error("Invalid wide char buffer size");
1800-
// }
1801-
// #ifdef _WIN32
1802-
// std::wstring wstr(reinterpret_cast<const wchar_t*>(buffer.data()), buffer.size() / sizeof(wchar_t));
1803-
// #else
1804-
// size_t length = buffer.size() / sizeof(SQLWCHAR);
1805-
// std::wstring wstr = SQLWCHARToWString(reinterpret_cast<const SQLWCHAR*>(buffer.data()), length);
1806-
// #endif
1807-
// LOG("FetchLobColumnData: Returning wide string of length {}", wstr.length());
1808-
// return py::cast(wstr);
1809-
// }
1810-
// if (isBinary) {
1811-
1812-
// LOG("FetchLobColumnData: Returning binary of {} bytes", buffer.size());
1813-
// return py::bytes(buffer.data(), buffer.size());
1814-
// }
1815-
// std::string str(buffer.data(), buffer.size());
1816-
// LOG("FetchLobColumnData: Returning narrow string of length {}", str.length());
1817-
// return py::str(str);
1818-
// }
1819-
18201714
static py::object FetchLobColumnData(SQLHSTMT hStmt,
18211715
SQLUSMALLINT colIndex,
18221716
SQLSMALLINT cType,
@@ -1829,39 +1723,39 @@ static py::object FetchLobColumnData(SQLHSTMT hStmt,
18291723

18301724
while (true) {
18311725
++loopCount;
1832-
1833-
std::vector<char> chunk(DAE_CHUNK_SIZE, 0); // Fill with zeros to handle padding safely
1834-
SQLLEN indicator = 0;
1835-
1726+
std::vector<char> chunk(DAE_CHUNK_SIZE, 0);
1727+
SQLLEN actualRead = 0;
18361728
ret = SQLGetData_ptr(hStmt,
18371729
colIndex,
18381730
cType,
18391731
chunk.data(),
18401732
DAE_CHUNK_SIZE,
1841-
&indicator);
1733+
&actualRead);
18421734

1843-
if (indicator == SQL_NULL_DATA) {
1735+
if (ret == SQL_ERROR || !SQL_SUCCEEDED(ret) && ret != SQL_SUCCESS_WITH_INFO) {
1736+
LOG("Loop {}: Error fetching column {} with cType={}", loopCount, colIndex, cType);
1737+
ThrowStdException("Error fetching column data");
1738+
}
1739+
if (actualRead == SQL_NULL_DATA) {
18441740
LOG("Loop {}: Column {} is NULL", loopCount, colIndex);
18451741
return py::none();
18461742
}
1847-
if (!SQL_SUCCEEDED(ret) && ret != SQL_SUCCESS_WITH_INFO) {
1848-
LOG("Loop {}: Error fetching column {} with cType={} ret={}", loopCount, colIndex, cType, ret);
1849-
ThrowStdException("Error fetching column data");
1850-
}
18511743

18521744
size_t bytesRead = 0;
1853-
1854-
// Determine how many bytes to process
1855-
if (indicator > 0 && indicator != SQL_NO_TOTAL) {
1856-
bytesRead = std::min<size_t>(static_cast<size_t>(indicator), DAE_CHUNK_SIZE);
1745+
if (actualRead >= 0) {
1746+
bytesRead = static_cast<size_t>(actualRead);
1747+
if (bytesRead > DAE_CHUNK_SIZE) {
1748+
bytesRead = DAE_CHUNK_SIZE;
1749+
}
18571750
} else {
1858-
// If unknown, assume full buffer minus possible null terminator padding
1751+
// fallback: use full buffer size if actualRead is unknown
18591752
bytesRead = DAE_CHUNK_SIZE;
18601753
}
18611754

18621755
// For character data, trim trailing null terminators
18631756
if (!isBinary && bytesRead > 0) {
18641757
if (!isWideChar) {
1758+
// Narrow characters
18651759
while (bytesRead > 0 && chunk[bytesRead - 1] == '\0') {
18661760
--bytesRead;
18671761
}
@@ -1872,9 +1766,9 @@ static py::object FetchLobColumnData(SQLHSTMT hStmt,
18721766
// Wide characters
18731767
size_t wcharSize = sizeof(SQLWCHAR);
18741768
if (bytesRead >= wcharSize) {
1875-
auto wcharBuf = reinterpret_cast<const SQLWCHAR*>(chunk.data());
1769+
auto sqlwBuf = reinterpret_cast<const SQLWCHAR*>(chunk.data());
18761770
size_t wcharCount = bytesRead / wcharSize;
1877-
while (wcharCount > 0 && wcharBuf[wcharCount - 1] == 0) {
1771+
while (wcharCount > 0 && sqlwBuf[wcharCount - 1] == 0) {
18781772
--wcharCount;
18791773
bytesRead -= wcharSize;
18801774
}
@@ -1884,47 +1778,45 @@ static py::object FetchLobColumnData(SQLHSTMT hStmt,
18841778
}
18851779
}
18861780
}
1887-
18881781
if (bytesRead > 0) {
18891782
buffer.insert(buffer.end(), chunk.begin(), chunk.begin() + bytesRead);
18901783
LOG("Loop {}: Appended {} bytes", loopCount, bytesRead);
18911784
}
1892-
18931785
if (ret == SQL_SUCCESS) {
18941786
LOG("Loop {}: SQL_SUCCESS → no more data", loopCount);
18951787
break;
18961788
}
18971789
}
1898-
18991790
LOG("FetchLobColumnData: Total bytes collected = {}", buffer.size());
19001791

1901-
// If buffer is empty, return empty string or bytes
19021792
if (buffer.empty()) {
19031793
if (isBinary) {
19041794
return py::bytes("");
19051795
}
19061796
return py::str("");
19071797
}
1908-
1909-
// Convert the collected buffer to appropriate Python type
19101798
if (isWideChar) {
1911-
std::wstring wstr = SQLWCHARToWString(reinterpret_cast<const SQLWCHAR*>(buffer.data()), buffer.size() / sizeof(SQLWCHAR));
1912-
LOG("FetchLobColumnData: Returning wide string of length {}", wstr.length());
1913-
return py::cast(wstr);
1799+
#if defined(_WIN32)
1800+
std::wstring wstr(reinterpret_cast<const wchar_t*>(buffer.data()), buffer.size() / sizeof(wchar_t));
1801+
std::string utf8str = WideToUTF8(wstr);
1802+
return py::str(utf8str);
1803+
#else
1804+
// Linux/macOS handling
1805+
size_t wcharCount = buffer.size() / sizeof(SQLWCHAR);
1806+
const SQLWCHAR* sqlwBuf = reinterpret_cast<const SQLWCHAR*>(buffer.data());
1807+
std::string utf8str = SQLWCHARToUTF8String(sqlwBuf, wcharCount);
1808+
return py::str(utf8str);
1809+
#endif
19141810
}
1915-
19161811
if (isBinary) {
19171812
LOG("FetchLobColumnData: Returning binary of {} bytes", buffer.size());
19181813
return py::bytes(buffer.data(), buffer.size());
19191814
}
1920-
1921-
// Default: narrow string
19221815
std::string str(buffer.data(), buffer.size());
19231816
LOG("FetchLobColumnData: Returning narrow string of length {}", str.length());
19241817
return py::str(str);
19251818
}
19261819

1927-
19281820
// Helper function to retrieve column data
19291821
SQLRETURN SQLGetData_wrap(SqlHandlePtr StatementHandle, SQLUSMALLINT colCount, py::list& row) {
19301822
LOG("Get data from columns");

0 commit comments

Comments
 (0)