Skip to content

Commit d72de69

Browse files
committed
OPTIMIZATION #2: Direct Python C API for integer and floating-point types
- Replaced pybind11 wrappers with direct Python C API calls - SQL_INTEGER, SQL_SMALLINT, SQL_BIGINT: PyLong_FromLong/PyLong_FromLongLong - SQL_TINYINT, SQL_BIT: PyLong_FromLong/PyBool_FromLong - SQL_REAL, SQL_DOUBLE, SQL_FLOAT: PyFloat_FromDouble - Uses PyList_SET_ITEM macro for direct list assignment (no bounds checking) - Eliminates pybind11 wrapper overhead for simple numeric types - Added PERF_TIMER instrumentation for each numeric type conversion
1 parent b0c45d0 commit d72de69

File tree

1 file changed

+56
-7
lines changed

1 file changed

+56
-7
lines changed

mssql_python/pybind/ddbc_bindings.cpp

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3354,23 +3354,58 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum
33543354
break;
33553355
}
33563356
case SQL_INTEGER: {
3357-
row[col - 1] = buffers.intBuffers[col - 1][i];
3357+
PERF_TIMER("construct_rows::int_c_api_assign");
3358+
if (buffers.indicators[col - 1][i] == SQL_NULL_DATA) {
3359+
Py_INCREF(Py_None);
3360+
PyList_SET_ITEM(row.ptr(), col - 1, Py_None);
3361+
} else {
3362+
PyObject* pyInt = PyLong_FromLong(buffers.intBuffers[col - 1][i]);
3363+
PyList_SET_ITEM(row.ptr(), col - 1, pyInt);
3364+
}
33583365
break;
33593366
}
33603367
case SQL_SMALLINT: {
3361-
row[col - 1] = buffers.smallIntBuffers[col - 1][i];
3368+
PERF_TIMER("construct_rows::smallint_c_api_assign");
3369+
if (buffers.indicators[col - 1][i] == SQL_NULL_DATA) {
3370+
Py_INCREF(Py_None);
3371+
PyList_SET_ITEM(row.ptr(), col - 1, Py_None);
3372+
} else {
3373+
PyObject* pyInt = PyLong_FromLong(buffers.smallIntBuffers[col - 1][i]);
3374+
PyList_SET_ITEM(row.ptr(), col - 1, pyInt);
3375+
}
33623376
break;
33633377
}
33643378
case SQL_TINYINT: {
3365-
row[col - 1] = buffers.charBuffers[col - 1][i];
3379+
PERF_TIMER("construct_rows::tinyint_c_api_assign");
3380+
if (buffers.indicators[col - 1][i] == SQL_NULL_DATA) {
3381+
Py_INCREF(Py_None);
3382+
PyList_SET_ITEM(row.ptr(), col - 1, Py_None);
3383+
} else {
3384+
PyObject* pyInt = PyLong_FromLong(buffers.charBuffers[col - 1][i]);
3385+
PyList_SET_ITEM(row.ptr(), col - 1, pyInt);
3386+
}
33663387
break;
33673388
}
33683389
case SQL_BIT: {
3369-
row[col - 1] = static_cast<bool>(buffers.charBuffers[col - 1][i]);
3390+
PERF_TIMER("construct_rows::bit_c_api_assign");
3391+
if (buffers.indicators[col - 1][i] == SQL_NULL_DATA) {
3392+
Py_INCREF(Py_None);
3393+
PyList_SET_ITEM(row.ptr(), col - 1, Py_None);
3394+
} else {
3395+
PyObject* pyBool = PyBool_FromLong(buffers.charBuffers[col - 1][i]);
3396+
PyList_SET_ITEM(row.ptr(), col - 1, pyBool);
3397+
}
33703398
break;
33713399
}
33723400
case SQL_REAL: {
3373-
row[col - 1] = buffers.realBuffers[col - 1][i];
3401+
PERF_TIMER("construct_rows::real_c_api_assign");
3402+
if (buffers.indicators[col - 1][i] == SQL_NULL_DATA) {
3403+
Py_INCREF(Py_None);
3404+
PyList_SET_ITEM(row.ptr(), col - 1, Py_None);
3405+
} else {
3406+
PyObject* pyFloat = PyFloat_FromDouble(buffers.realBuffers[col - 1][i]);
3407+
PyList_SET_ITEM(row.ptr(), col - 1, pyFloat);
3408+
}
33743409
break;
33753410
}
33763411
case SQL_DECIMAL:
@@ -3392,7 +3427,14 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum
33923427
}
33933428
case SQL_DOUBLE:
33943429
case SQL_FLOAT: {
3395-
row[col - 1] = buffers.doubleBuffers[col - 1][i];
3430+
PERF_TIMER("construct_rows::double_c_api_assign");
3431+
if (buffers.indicators[col - 1][i] == SQL_NULL_DATA) {
3432+
Py_INCREF(Py_None);
3433+
PyList_SET_ITEM(row.ptr(), col - 1, Py_None);
3434+
} else {
3435+
PyObject* pyFloat = PyFloat_FromDouble(buffers.doubleBuffers[col - 1][i]);
3436+
PyList_SET_ITEM(row.ptr(), col - 1, pyFloat);
3437+
}
33963438
break;
33973439
}
33983440
case SQL_TIMESTAMP:
@@ -3405,7 +3447,14 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum
34053447
break;
34063448
}
34073449
case SQL_BIGINT: {
3408-
row[col - 1] = buffers.bigIntBuffers[col - 1][i];
3450+
PERF_TIMER("construct_rows::bigint_c_api_assign");
3451+
if (buffers.indicators[col - 1][i] == SQL_NULL_DATA) {
3452+
Py_INCREF(Py_None);
3453+
PyList_SET_ITEM(row.ptr(), col - 1, Py_None);
3454+
} else {
3455+
PyObject* pyInt = PyLong_FromLongLong(buffers.bigIntBuffers[col - 1][i]);
3456+
PyList_SET_ITEM(row.ptr(), col - 1, pyInt);
3457+
}
34093458
break;
34103459
}
34113460
case SQL_TYPE_DATE: {

0 commit comments

Comments
 (0)