30
30
#ifndef ARCHITECTURE
31
31
#define ARCHITECTURE " win64" // Default to win64 if not defined during compilation
32
32
#endif
33
-
33
+ # define DAE_CHUNK_SIZE 8192
34
34
// -------------------------------------------------------------------------------------------------
35
35
// Class definitions
36
36
// -------------------------------------------------------------------------------------------------
@@ -43,11 +43,8 @@ struct ParamInfo {
43
43
SQLSMALLINT paramSQLType;
44
44
SQLULEN columnSize;
45
45
SQLSMALLINT decimalDigits;
46
- // TODO: Reuse python buffer for large data using Python buffer protocol
47
- // Stores pointer to the python object that holds parameter value
48
-
49
46
SQLLEN strLenOrInd = 0 ; // Required for DAE
50
- bool isDAE = false ; // Indicates if we need to stream via SQLPutData
47
+ bool isDAE = false ; // Indicates if we need to stream
51
48
py::object dataPtr;
52
49
};
53
50
@@ -251,14 +248,13 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params,
251
248
!py::isinstance<py::bytes>(param)) {
252
249
ThrowStdException (MakeParamMismatchErrorStr (paramInfo.paramCType , paramIndex));
253
250
}
254
-
255
251
if (paramInfo.isDAE ) {
256
252
// deferred execution
257
253
LOG (" Parameter[{}] is marked for DAE streaming" , paramIndex);
258
254
dataPtr = const_cast <void *>(reinterpret_cast <const void *>(¶mInfos[paramIndex]));
259
255
strLenOrIndPtr = AllocateParamBuffer<SQLLEN>(paramBuffers);
260
256
*strLenOrIndPtr = SQL_LEN_DATA_AT_EXEC (0 );
261
- bufferLength = 0 ; // Not used
257
+ bufferLength = 0 ;
262
258
} else {
263
259
// Normal small-string case
264
260
std::wstring* strParam =
@@ -784,7 +780,6 @@ DriverHandle LoadDriverOrThrowException() {
784
780
785
781
SQLParamData_ptr = GetFunctionPointer<SQLParamDataFunc>(handle, " SQLParamData" );
786
782
SQLPutData_ptr = GetFunctionPointer<SQLPutDataFunc>(handle, " SQLPutData" );
787
-
788
783
bool success =
789
784
SQLAllocHandle_ptr && SQLSetEnvAttr_ptr && SQLSetConnectAttr_ptr &&
790
785
SQLSetStmtAttr_ptr && SQLGetConnectAttr_ptr && SQLDriverConnect_ptr &&
@@ -998,7 +993,7 @@ SQLRETURN SQLExecute_wrap(const SqlHandlePtr statementHandle,
998
993
LOG (" Beginning SQLParamData/SQLPutData loop for DAE." );
999
994
SQLPOINTER paramToken = nullptr ;
1000
995
while ((rc = SQLParamData_ptr (hStmt, ¶mToken)) == SQL_NEED_DATA) {
1001
- // Find the paramInfo that matches the returned token
996
+ // Finding the paramInfo that matches the returned token
1002
997
const ParamInfo* matchedInfo = nullptr ;
1003
998
for (auto & info : paramInfos) {
1004
999
if (reinterpret_cast <SQLPOINTER>(const_cast <ParamInfo*>(&info)) == paramToken) {
@@ -1009,18 +1004,21 @@ SQLRETURN SQLExecute_wrap(const SqlHandlePtr statementHandle,
1009
1004
if (!matchedInfo) {
1010
1005
ThrowStdException (" Unrecognized paramToken returned by SQLParamData" );
1011
1006
}
1012
-
1013
1007
const py::object& pyObj = matchedInfo->dataPtr ;
1014
1008
if (pyObj.is_none ()) {
1015
1009
SQLPutData_ptr (hStmt, nullptr , 0 );
1016
1010
continue ;
1017
1011
}
1018
1012
if (py::isinstance<py::str>(pyObj)) {
1019
- std::string utf16_str = pyObj.attr (" encode" )(" utf-16-le" ).cast <py::bytes>();
1013
+ std::string utf16_str;
1014
+ try {
1015
+ utf16_str = pyObj.attr (" encode" )(" utf-16-le" ).cast <py::bytes>();
1016
+ } catch (const std::exception& e) {
1017
+ ThrowStdException (" Error encoding string to UTF-16: " + std::string (e.what ()));
1018
+ }
1020
1019
const char * dataPtr = utf16_str.data ();
1021
1020
SQLLEN totalBytes = static_cast <SQLLEN>(utf16_str.size ());
1022
-
1023
- const size_t chunkSize = 8192 ;
1021
+ const size_t chunkSize = DAE_CHUNK_SIZE;
1024
1022
for (size_t offset = 0 ; offset < totalBytes; offset += chunkSize) {
1025
1023
size_t len = std::min (chunkSize, totalBytes - offset);
1026
1024
rc = SQLPutData_ptr (hStmt, (SQLPOINTER)(dataPtr + offset), static_cast <SQLLEN>(len));
@@ -1033,14 +1031,12 @@ SQLRETURN SQLExecute_wrap(const SqlHandlePtr statementHandle,
1033
1031
ThrowStdException (" DAE only supported for str or bytes" );
1034
1032
}
1035
1033
}
1036
-
1037
1034
if (!SQL_SUCCEEDED (rc)) {
1038
1035
LOG (" SQLParamData final rc: {}" , rc);
1039
1036
return rc;
1040
1037
}
1041
1038
LOG (" DAE complete, SQLExecute resumed internally." );
1042
1039
}
1043
-
1044
1040
if (!SQL_SUCCEEDED (rc) && rc != SQL_NO_DATA) {
1045
1041
LOG (" DDBCSQLExecute: Error during execution of the statement" );
1046
1042
return rc;
0 commit comments