Skip to content

Commit 32e7d04

Browse files
committed
also fixes the github issue #241
1 parent b7fceaa commit 32e7d04

File tree

3 files changed

+150
-113
lines changed

3 files changed

+150
-113
lines changed

mssql_python/cursor.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,16 @@ def _map_sql_type(self, param, parameters_list, i):
319319
parameters_list[i].scale,
320320
False,
321321
)
322+
323+
if isinstance(param, uuid.UUID):
324+
parameters_list[i] = param.bytes_le
325+
return (
326+
ddbc_sql_const.SQL_GUID.value,
327+
ddbc_sql_const.SQL_C_GUID.value,
328+
16,
329+
0,
330+
False,
331+
)
322332

323333
if isinstance(param, str):
324334
if (
@@ -333,6 +343,20 @@ def _map_sql_type(self, param, parameters_list, i):
333343
0,
334344
False,
335345
)
346+
347+
try:
348+
val = uuid.UUID(param)
349+
parameters_list[i] = val.bytes_le
350+
return (
351+
ddbc_sql_const.SQL_GUID.value,
352+
ddbc_sql_const.SQL_C_GUID.value,
353+
16,
354+
0,
355+
False
356+
)
357+
except ValueError:
358+
pass
359+
336360

337361
# Attempt to parse as date, datetime, datetime2, timestamp, smalldatetime or time
338362
if self._parse_date(param):
@@ -426,15 +450,6 @@ def _map_sql_type(self, param, parameters_list, i):
426450
False,
427451
)
428452

429-
if isinstance(param, uuid.UUID):
430-
return (
431-
ddbc_sql_const.SQL_GUID.value,
432-
ddbc_sql_const.SQL_C_GUID.value,
433-
16,
434-
0,
435-
False,
436-
)
437-
438453
if isinstance(param, datetime.datetime):
439454
return (
440455
ddbc_sql_const.SQL_TIMESTAMP.value,

mssql_python/pybind/ddbc_bindings.cpp

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -484,27 +484,28 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params,
484484
break;
485485
}
486486
case SQL_C_GUID: {
487-
py::object uuid_obj = param;
488-
py::object uuid_cls = py::module_::import("uuid").attr("UUID");
489-
if (!py::isinstance(uuid_obj, uuid_cls)) {
487+
if (!py::isinstance<py::bytes>(param)) {
490488
ThrowStdException(MakeParamMismatchErrorStr(paramInfo.paramCType, paramIndex));
491489
}
492-
py::bytes uuid_bytes = uuid_obj.attr("bytes").cast<py::bytes>();
490+
py::bytes uuid_bytes = param.cast<py::bytes>();
491+
const unsigned char* uuid_data = reinterpret_cast<const unsigned char*>(PyBytes_AS_STRING(uuid_bytes.ptr()));
493492
if (PyBytes_GET_SIZE(uuid_bytes.ptr()) != 16) {
493+
LOG("Invalid UUID parameter at index {}: expected 16 bytes, got {} bytes, type {}", paramIndex, PyBytes_GET_SIZE(uuid_bytes.ptr()), paramInfo.paramCType);
494494
ThrowStdException("UUID binary data must be exactly 16 bytes long.");
495495
}
496-
const unsigned char* b = reinterpret_cast<const unsigned char*>(PyBytes_AS_STRING(uuid_bytes.ptr()));
497496
SQLGUID* guid_data_ptr = AllocateParamBuffer<SQLGUID>(paramBuffers);
498-
guid_data_ptr->Data1 = (static_cast<uint32_t>(b[3]) << 24) |
499-
(static_cast<uint32_t>(b[2]) << 16) |
500-
(static_cast<uint32_t>(b[1]) << 8) |
501-
static_cast<uint32_t>(b[0]);
502-
guid_data_ptr->Data2 = (static_cast<uint16_t>(b[5]) << 8) |
503-
static_cast<uint16_t>(b[4]);
504-
guid_data_ptr->Data3 = (static_cast<uint16_t>(b[7]) << 8) |
505-
static_cast<uint16_t>(b[6]);
506-
std::memcpy(guid_data_ptr->Data4, &b[8], 8);
507-
497+
guid_data_ptr->Data1 =
498+
(static_cast<uint32_t>(uuid_data[3]) << 24) |
499+
(static_cast<uint32_t>(uuid_data[2]) << 16) |
500+
(static_cast<uint32_t>(uuid_data[1]) << 8) |
501+
(static_cast<uint32_t>(uuid_data[0]));
502+
guid_data_ptr->Data2 =
503+
(static_cast<uint16_t>(uuid_data[5]) << 8) |
504+
(static_cast<uint16_t>(uuid_data[4]));
505+
guid_data_ptr->Data3 =
506+
(static_cast<uint16_t>(uuid_data[7]) << 8) |
507+
(static_cast<uint16_t>(uuid_data[6]));
508+
std::memcpy(guid_data_ptr->Data4, &uuid_data[8], 8);
508509
dataPtr = static_cast<void*>(guid_data_ptr);
509510
bufferLength = sizeof(SQLGUID);
510511
strLenOrIndPtr = AllocateParamBuffer<SQLLEN>(paramBuffers);
@@ -2240,7 +2241,8 @@ SQLRETURN SQLGetData_wrap(SqlHandlePtr StatementHandle, SQLUSMALLINT colCount, p
22402241
std::memcpy(&guid_bytes[8], guidValue.Data4, sizeof(guidValue.Data4));
22412242

22422243
py::bytes py_guid_bytes(guid_bytes.data(), guid_bytes.size());
2243-
py::object uuid_obj = py::module_::import("uuid").attr("UUID")(py::arg("bytes") = py_guid_bytes);
2244+
py::object uuid_module = py::module_::import("uuid");
2245+
py::object uuid_obj = uuid_module.attr("UUID")(py::arg("bytes")=py_guid_bytes);
22442246
row.append(uuid_obj);
22452247
} else if (indicator == SQL_NULL_DATA) {
22462248
row.append(py::none());
@@ -2622,10 +2624,18 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum
26222624
}
26232625
case SQL_GUID: {
26242626
SQLGUID* guidValue = &buffers.guidBuffers[col - 1][i];
2625-
std::vector<char> guid_bytes(16);
2626-
std::memcpy(guid_bytes.data(), guidValue, sizeof(SQLGUID));
2627-
2628-
py::bytes py_guid_bytes(guid_bytes.data(), guid_bytes.size());
2627+
uint8_t reordered[16];
2628+
reordered[0] = ((char*)&guidValue->Data1)[3];
2629+
reordered[1] = ((char*)&guidValue->Data1)[2];
2630+
reordered[2] = ((char*)&guidValue->Data1)[1];
2631+
reordered[3] = ((char*)&guidValue->Data1)[0];
2632+
reordered[4] = ((char*)&guidValue->Data2)[1];
2633+
reordered[5] = ((char*)&guidValue->Data2)[0];
2634+
reordered[6] = ((char*)&guidValue->Data3)[1];
2635+
reordered[7] = ((char*)&guidValue->Data3)[0];
2636+
std::memcpy(reordered + 8, guidValue->Data4, 8);
2637+
2638+
py::bytes py_guid_bytes(reinterpret_cast<char*>(reordered), 16);
26292639
py::dict kwargs;
26302640
kwargs["bytes"] = py_guid_bytes;
26312641
py::object uuid_obj = py::module_::import("uuid").attr("UUID")(**kwargs);

0 commit comments

Comments
 (0)