|
21 | 21 | #define SQL_SS_TIMESTAMPOFFSET (-155) |
22 | 22 | #define SQL_C_SS_TIMESTAMPOFFSET (0x4001) |
23 | 23 | #define MAX_DIGITS_IN_NUMERIC 64 |
| 24 | +#define SQL_MAX_NUMERIC_LEN 16 |
| 25 | +#define SQL_SS_XML (-152) |
24 | 26 |
|
25 | 27 | #define STRINGIFY_FOR_CASE(x) \ |
26 | 28 | case x: \ |
@@ -56,12 +58,18 @@ struct NumericData { |
56 | 58 | SQLCHAR precision; |
57 | 59 | SQLSCHAR scale; |
58 | 60 | SQLCHAR sign; // 1=pos, 0=neg |
59 | | - std::uint64_t val; // 123.45 -> 12345 |
| 61 | + std::string val; // 123.45 -> 12345 |
60 | 62 |
|
61 | | - NumericData() : precision(0), scale(0), sign(0), val(0) {} |
| 63 | + NumericData() : precision(0), scale(0), sign(0), val(SQL_MAX_NUMERIC_LEN, '\0') {} |
62 | 64 |
|
63 | | - NumericData(SQLCHAR precision, SQLSCHAR scale, SQLCHAR sign, std::uint64_t value) |
64 | | - : precision(precision), scale(scale), sign(sign), val(value) {} |
| 65 | + NumericData(SQLCHAR precision, SQLSCHAR scale, SQLCHAR sign, const std::string& valueBytes) |
| 66 | + : precision(precision), scale(scale), sign(sign), val(SQL_MAX_NUMERIC_LEN, '\0') { |
| 67 | + if (valueBytes.size() > SQL_MAX_NUMERIC_LEN) { |
| 68 | + throw std::runtime_error("NumericData valueBytes size exceeds SQL_MAX_NUMERIC_LEN (16)"); |
| 69 | + } |
| 70 | + // Copy binary data to buffer, remaining bytes stay zero-padded |
| 71 | + std::memcpy(&val[0], valueBytes.data(), valueBytes.size()); |
| 72 | + } |
65 | 73 | }; |
66 | 74 |
|
67 | 75 | // Struct to hold the DateTimeOffset structure |
@@ -557,9 +565,10 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params, |
557 | 565 | decimalPtr->sign = decimalParam.sign; |
558 | 566 | // Convert the integer decimalParam.val to char array |
559 | 567 | std::memset(static_cast<void*>(decimalPtr->val), 0, sizeof(decimalPtr->val)); |
560 | | - std::memcpy(static_cast<void*>(decimalPtr->val), |
561 | | - reinterpret_cast<char*>(&decimalParam.val), |
562 | | - sizeof(decimalParam.val)); |
| 568 | + size_t copyLen = std::min(decimalParam.val.size(), sizeof(decimalPtr->val)); |
| 569 | + if (copyLen > 0) { |
| 570 | + std::memcpy(decimalPtr->val, decimalParam.val.data(), copyLen); |
| 571 | + } |
563 | 572 | dataPtr = static_cast<void*>(decimalPtr); |
564 | 573 | break; |
565 | 574 | } |
@@ -2050,15 +2059,17 @@ SQLRETURN BindParameterArray(SQLHANDLE hStmt, |
2050 | 2059 | throw std::runtime_error(MakeParamMismatchErrorStr(info.paramCType, paramIndex)); |
2051 | 2060 | } |
2052 | 2061 | NumericData decimalParam = element.cast<NumericData>(); |
2053 | | - LOG("Received numeric parameter at [%zu]: precision=%d, scale=%d, sign=%d, val=%lld", |
2054 | | - i, decimalParam.precision, decimalParam.scale, decimalParam.sign, decimalParam.val); |
2055 | | - numericArray[i].precision = decimalParam.precision; |
2056 | | - numericArray[i].scale = decimalParam.scale; |
2057 | | - numericArray[i].sign = decimalParam.sign; |
2058 | | - std::memset(numericArray[i].val, 0, sizeof(numericArray[i].val)); |
2059 | | - std::memcpy(numericArray[i].val, |
2060 | | - reinterpret_cast<const char*>(&decimalParam.val), |
2061 | | - std::min(sizeof(decimalParam.val), sizeof(numericArray[i].val))); |
| 2062 | + LOG("Received numeric parameter at [%zu]: precision=%d, scale=%d, sign=%d, val=%s", |
| 2063 | + i, decimalParam.precision, decimalParam.scale, decimalParam.sign, decimalParam.val.c_str()); |
| 2064 | + SQL_NUMERIC_STRUCT& target = numericArray[i]; |
| 2065 | + std::memset(&target, 0, sizeof(SQL_NUMERIC_STRUCT)); |
| 2066 | + target.precision = decimalParam.precision; |
| 2067 | + target.scale = decimalParam.scale; |
| 2068 | + target.sign = decimalParam.sign; |
| 2069 | + size_t copyLen = std::min(decimalParam.val.size(), sizeof(target.val)); |
| 2070 | + if (copyLen > 0) { |
| 2071 | + std::memcpy(target.val, decimalParam.val.data(), copyLen); |
| 2072 | + } |
2062 | 2073 | strLenOrIndArray[i] = sizeof(SQL_NUMERIC_STRUCT); |
2063 | 2074 | } |
2064 | 2075 | dataPtr = numericArray; |
@@ -2525,6 +2536,12 @@ SQLRETURN SQLGetData_wrap(SqlHandlePtr StatementHandle, SQLUSMALLINT colCount, p |
2525 | 2536 | } |
2526 | 2537 | break; |
2527 | 2538 | } |
| 2539 | + case SQL_SS_XML: |
| 2540 | + { |
| 2541 | + LOG("Streaming XML for column {}", i); |
| 2542 | + row.append(FetchLobColumnData(hStmt, i, SQL_C_WCHAR, true, false)); |
| 2543 | + break; |
| 2544 | + } |
2528 | 2545 | case SQL_WCHAR: |
2529 | 2546 | case SQL_WVARCHAR: |
2530 | 2547 | case SQL_WLONGVARCHAR: { |
@@ -3395,6 +3412,7 @@ size_t calculateRowSize(py::list& columnNames, SQLUSMALLINT numCols) { |
3395 | 3412 | case SQL_LONGVARCHAR: |
3396 | 3413 | rowSize += columnSize; |
3397 | 3414 | break; |
| 3415 | + case SQL_SS_XML: |
3398 | 3416 | case SQL_WCHAR: |
3399 | 3417 | case SQL_WVARCHAR: |
3400 | 3418 | case SQL_WLONGVARCHAR: |
@@ -3499,7 +3517,7 @@ SQLRETURN FetchMany_wrap(SqlHandlePtr StatementHandle, py::list& rows, int fetch |
3499 | 3517 |
|
3500 | 3518 | if ((dataType == SQL_WVARCHAR || dataType == SQL_WLONGVARCHAR || |
3501 | 3519 | dataType == SQL_VARCHAR || dataType == SQL_LONGVARCHAR || |
3502 | | - dataType == SQL_VARBINARY || dataType == SQL_LONGVARBINARY) && |
| 3520 | + dataType == SQL_VARBINARY || dataType == SQL_LONGVARBINARY || dataType == SQL_SS_XML) && |
3503 | 3521 | (columnSize == 0 || columnSize == SQL_NO_TOTAL || columnSize > SQL_MAX_LOB_SIZE)) { |
3504 | 3522 | lobColumns.push_back(i + 1); // 1-based |
3505 | 3523 | } |
@@ -3621,7 +3639,7 @@ SQLRETURN FetchAll_wrap(SqlHandlePtr StatementHandle, py::list& rows) { |
3621 | 3639 |
|
3622 | 3640 | if ((dataType == SQL_WVARCHAR || dataType == SQL_WLONGVARCHAR || |
3623 | 3641 | dataType == SQL_VARCHAR || dataType == SQL_LONGVARCHAR || |
3624 | | - dataType == SQL_VARBINARY || dataType == SQL_LONGVARBINARY) && |
| 3642 | + dataType == SQL_VARBINARY || dataType == SQL_LONGVARBINARY || dataType == SQL_SS_XML) && |
3625 | 3643 | (columnSize == 0 || columnSize == SQL_NO_TOTAL || columnSize > SQL_MAX_LOB_SIZE)) { |
3626 | 3644 | lobColumns.push_back(i + 1); // 1-based |
3627 | 3645 | } |
@@ -3792,7 +3810,7 @@ PYBIND11_MODULE(ddbc_bindings, m) { |
3792 | 3810 | // Define numeric data class |
3793 | 3811 | py::class_<NumericData>(m, "NumericData") |
3794 | 3812 | .def(py::init<>()) |
3795 | | - .def(py::init<SQLCHAR, SQLSCHAR, SQLCHAR, std::uint64_t>()) |
| 3813 | + .def(py::init<SQLCHAR, SQLSCHAR, SQLCHAR, const std::string&>()) |
3796 | 3814 | .def_readwrite("precision", &NumericData::precision) |
3797 | 3815 | .def_readwrite("scale", &NumericData::scale) |
3798 | 3816 | .def_readwrite("sign", &NumericData::sign) |
|
0 commit comments