Skip to content

Commit 0811744

Browse files
committed
latest 2
1 parent 1a68058 commit 0811744

File tree

1 file changed

+24
-9
lines changed

1 file changed

+24
-9
lines changed

mssql_python/pybind/ddbc_bindings.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3181,14 +3181,28 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum
31813181
LOG("Error while fetching rows in batches");
31823182
return ret;
31833183
}
3184+
// Pre-cache column metadata to avoid repeated dictionary lookups (major optimization)
3185+
struct ColumnInfo {
3186+
SQLSMALLINT dataType;
3187+
SQLULEN columnSize;
3188+
bool isLob; // Pre-compute LOB status for O(1) lookup
3189+
};
3190+
std::vector<ColumnInfo> columnInfos(numCols);
3191+
for (SQLUSMALLINT col = 0; col < numCols; col++) {
3192+
const auto& columnMeta = columnNames[col].cast<py::dict>();
3193+
columnInfos[col].dataType = columnMeta["DataType"].cast<SQLSMALLINT>();
3194+
columnInfos[col].columnSize = columnMeta["ColumnSize"].cast<SQLULEN>();
3195+
columnInfos[col].isLob = std::find(lobColumns.begin(), lobColumns.end(), col + 1) != lobColumns.end(); // col+1 because lobColumns uses 1-based indexing
3196+
}
3197+
31843198
// numRowsFetched is the SQL_ATTR_ROWS_FETCHED_PTR attribute. It'll be populated by
31853199
// SQLFetchScroll
31863200
for (SQLULEN i = 0; i < numRowsFetched; i++) {
31873201
py::list row(numCols); // Pre-allocate with known column count for better performance
31883202
for (SQLUSMALLINT col = 1; col <= numCols; col++) {
3189-
// Cache column metadata lookup for better performance
3190-
const auto& columnMeta = columnNames[col - 1].cast<py::dict>();
3191-
SQLSMALLINT dataType = columnMeta["DataType"].cast<SQLSMALLINT>();
3203+
// Use pre-cached column metadata for optimal performance
3204+
const ColumnInfo& colInfo = columnInfos[col - 1];
3205+
SQLSMALLINT dataType = colInfo.dataType;
31923206
SQLLEN dataLen = buffers.indicators[col - 1][i]; if (dataLen == SQL_NULL_DATA) {
31933207
row[col - 1] = py::none();
31943208
continue;
@@ -3229,11 +3243,11 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum
32293243
case SQL_CHAR:
32303244
case SQL_VARCHAR:
32313245
case SQL_LONGVARCHAR: {
3232-
SQLULEN columnSize = columnMeta["ColumnSize"].cast<SQLULEN>();
3246+
SQLULEN columnSize = colInfo.columnSize;
32333247
HandleZeroColumnSizeAtFetch(columnSize);
32343248
uint64_t fetchBufferSize = columnSize + 1 /*null-terminator*/;
32353249
uint64_t numCharsInData = dataLen / sizeof(SQLCHAR);
3236-
bool isLob = std::find(lobColumns.begin(), lobColumns.end(), col) != lobColumns.end();
3250+
bool isLob = colInfo.isLob; // Use cached LOB status for O(1) lookup
32373251
// fetchBufferSize includes null-terminator, numCharsInData doesn't. Hence '<'
32383252
if (!isLob && numCharsInData < fetchBufferSize) {
32393253
// SQLFetch will nullterminate the data
@@ -3249,11 +3263,11 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum
32493263
case SQL_WVARCHAR:
32503264
case SQL_WLONGVARCHAR: {
32513265
// TODO: variable length data needs special handling, this logic wont suffice
3252-
SQLULEN columnSize = columnMeta["ColumnSize"].cast<SQLULEN>();
3266+
SQLULEN columnSize = colInfo.columnSize;
32533267
HandleZeroColumnSizeAtFetch(columnSize);
32543268
uint64_t fetchBufferSize = columnSize + 1 /*null-terminator*/;
32553269
uint64_t numCharsInData = dataLen / sizeof(SQLWCHAR);
3256-
bool isLob = std::find(lobColumns.begin(), lobColumns.end(), col) != lobColumns.end();
3270+
bool isLob = colInfo.isLob; // Use cached LOB status for O(1) lookup
32573271
// fetchBufferSize includes null-terminator, numCharsInData doesn't. Hence '<'
32583272
if (!isLob && numCharsInData < fetchBufferSize) {
32593273
// SQLFetch will nullterminate the data
@@ -3411,9 +3425,9 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum
34113425
case SQL_BINARY:
34123426
case SQL_VARBINARY:
34133427
case SQL_LONGVARBINARY: {
3414-
SQLULEN columnSize = columnMeta["ColumnSize"].cast<SQLULEN>();
3428+
SQLULEN columnSize = colInfo.columnSize;
34153429
HandleZeroColumnSizeAtFetch(columnSize);
3416-
bool isLob = std::find(lobColumns.begin(), lobColumns.end(), col) != lobColumns.end();
3430+
bool isLob = colInfo.isLob; // Use cached LOB status for O(1) lookup
34173431
if (!isLob && static_cast<size_t>(dataLen) <= columnSize) {
34183432
row[col - 1] = py::bytes(reinterpret_cast<const char*>(
34193433
&buffers.charBuffers[col - 1][i * columnSize]),
@@ -3424,6 +3438,7 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum
34243438
break;
34253439
}
34263440
default: {
3441+
const auto& columnMeta = columnNames[col - 1].cast<py::dict>(); // Re-fetch for error case only
34273442
std::wstring columnName = columnMeta["ColumnName"].cast<std::wstring>();
34283443
std::ostringstream errorString;
34293444
errorString << "Unsupported data type for column - " << columnName.c_str()

0 commit comments

Comments
 (0)