|
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 |
24 | 25 | #define SQL_SS_XML (-152) |
25 | 26 |
|
26 | 27 | #define STRINGIFY_FOR_CASE(x) \ |
@@ -57,12 +58,18 @@ struct NumericData { |
57 | 58 | SQLCHAR precision; |
58 | 59 | SQLSCHAR scale; |
59 | 60 | SQLCHAR sign; // 1=pos, 0=neg |
60 | | - std::uint64_t val; // 123.45 -> 12345 |
| 61 | + std::string val; // 123.45 -> 12345 |
61 | 62 |
|
62 | | - NumericData() : precision(0), scale(0), sign(0), val(0) {} |
| 63 | + NumericData() : precision(0), scale(0), sign(0), val(SQL_MAX_NUMERIC_LEN, '\0') {} |
63 | 64 |
|
64 | | - NumericData(SQLCHAR precision, SQLSCHAR scale, SQLCHAR sign, std::uint64_t value) |
65 | | - : 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 | + } |
66 | 73 | }; |
67 | 74 |
|
68 | 75 | // Struct to hold the DateTimeOffset structure |
@@ -558,9 +565,10 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params, |
558 | 565 | decimalPtr->sign = decimalParam.sign; |
559 | 566 | // Convert the integer decimalParam.val to char array |
560 | 567 | std::memset(static_cast<void*>(decimalPtr->val), 0, sizeof(decimalPtr->val)); |
561 | | - std::memcpy(static_cast<void*>(decimalPtr->val), |
562 | | - reinterpret_cast<char*>(&decimalParam.val), |
563 | | - 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 | + } |
564 | 572 | dataPtr = static_cast<void*>(decimalPtr); |
565 | 573 | break; |
566 | 574 | } |
@@ -2051,15 +2059,17 @@ SQLRETURN BindParameterArray(SQLHANDLE hStmt, |
2051 | 2059 | throw std::runtime_error(MakeParamMismatchErrorStr(info.paramCType, paramIndex)); |
2052 | 2060 | } |
2053 | 2061 | NumericData decimalParam = element.cast<NumericData>(); |
2054 | | - LOG("Received numeric parameter at [%zu]: precision=%d, scale=%d, sign=%d, val=%lld", |
2055 | | - i, decimalParam.precision, decimalParam.scale, decimalParam.sign, decimalParam.val); |
2056 | | - numericArray[i].precision = decimalParam.precision; |
2057 | | - numericArray[i].scale = decimalParam.scale; |
2058 | | - numericArray[i].sign = decimalParam.sign; |
2059 | | - std::memset(numericArray[i].val, 0, sizeof(numericArray[i].val)); |
2060 | | - std::memcpy(numericArray[i].val, |
2061 | | - reinterpret_cast<const char*>(&decimalParam.val), |
2062 | | - 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 | + } |
2063 | 2073 | strLenOrIndArray[i] = sizeof(SQL_NUMERIC_STRUCT); |
2064 | 2074 | } |
2065 | 2075 | dataPtr = numericArray; |
@@ -3800,7 +3810,7 @@ PYBIND11_MODULE(ddbc_bindings, m) { |
3800 | 3810 | // Define numeric data class |
3801 | 3811 | py::class_<NumericData>(m, "NumericData") |
3802 | 3812 | .def(py::init<>()) |
3803 | | - .def(py::init<SQLCHAR, SQLSCHAR, SQLCHAR, std::uint64_t>()) |
| 3813 | + .def(py::init<SQLCHAR, SQLSCHAR, SQLCHAR, const std::string&>()) |
3804 | 3814 | .def_readwrite("precision", &NumericData::precision) |
3805 | 3815 | .def_readwrite("scale", &NumericData::scale) |
3806 | 3816 | .def_readwrite("sign", &NumericData::sign) |
|
0 commit comments