diff --git a/mssql_python/pybind/connection/connection.cpp b/mssql_python/pybind/connection/connection.cpp index 58f35ae4..b5184f4e 100644 --- a/mssql_python/pybind/connection/connection.cpp +++ b/mssql_python/pybind/connection/connection.cpp @@ -27,7 +27,7 @@ static SqlHandlePtr getEnvHandle() { if (!SQL_SUCCEEDED(ret)) { ThrowStdException("Failed to set environment attributes"); } - return std::make_shared(SQL_HANDLE_ENV, env); + return std::make_shared(static_cast(SQL_HANDLE_ENV), env); }(); return envHandle; @@ -54,7 +54,7 @@ void Connection::allocateDbcHandle() { LOG("Allocate SQL Connection Handle"); SQLRETURN ret = SQLAllocHandle_ptr(SQL_HANDLE_DBC, _envHandle->get(), &dbc); checkError(ret); - _dbcHandle = std::make_shared(SQL_HANDLE_DBC, dbc); + _dbcHandle = std::make_shared(static_cast(SQL_HANDLE_DBC), dbc); } void Connection::connect(const py::dict& attrs_before) { @@ -91,7 +91,7 @@ void Connection::disconnect() { void Connection::checkError(SQLRETURN ret) const{ if (!SQL_SUCCEEDED(ret)) { ErrorInfo err = SQLCheckError_Wrap(SQL_HANDLE_DBC, _dbcHandle, ret); - std::string errorMsg = std::string(err.ddbcErrorMsg.begin(), err.ddbcErrorMsg.end()); + std::string errorMsg = WideToUTF8(err.ddbcErrorMsg); ThrowStdException(errorMsg); } } @@ -122,7 +122,7 @@ void Connection::setAutocommit(bool enable) { } SQLINTEGER value = enable ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF; LOG("Set SQL Connection Attribute"); - SQLRETURN ret = SQLSetConnectAttr_ptr(_dbcHandle->get(), SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)value, 0); + SQLRETURN ret = SQLSetConnectAttr_ptr(_dbcHandle->get(), SQL_ATTR_AUTOCOMMIT, reinterpret_cast(static_cast(value)), 0); checkError(ret); _autocommit = enable; } @@ -148,7 +148,7 @@ SqlHandlePtr Connection::allocStatementHandle() { SQLHANDLE stmt = nullptr; SQLRETURN ret = SQLAllocHandle_ptr(SQL_HANDLE_STMT, _dbcHandle->get(), &stmt); checkError(ret); - return std::make_shared(SQL_HANDLE_STMT, stmt); + return std::make_shared(static_cast(SQL_HANDLE_STMT), stmt); } @@ -214,7 +214,6 @@ bool Connection::reset() { ThrowStdException("Connection handle not allocated"); } LOG("Resetting connection via SQL_ATTR_RESET_CONNECTION"); - SQLULEN reset = SQL_TRUE; SQLRETURN ret = SQLSetConnectAttr_ptr( _dbcHandle->get(), SQL_ATTR_RESET_CONNECTION, diff --git a/mssql_python/pybind/ddbc_bindings.cpp b/mssql_python/pybind/ddbc_bindings.cpp index f480fe2a..68c772e8 100644 --- a/mssql_python/pybind/ddbc_bindings.cpp +++ b/mssql_python/pybind/ddbc_bindings.cpp @@ -320,9 +320,9 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params, } // TODO: can be moved to python by registering SQL_DATE_STRUCT in pybind SQL_DATE_STRUCT* sqlDatePtr = AllocateParamBuffer(paramBuffers); - sqlDatePtr->year = param.attr("year").cast(); - sqlDatePtr->month = param.attr("month").cast(); - sqlDatePtr->day = param.attr("day").cast(); + sqlDatePtr->year = static_cast(param.attr("year").cast()); + sqlDatePtr->month = static_cast(param.attr("month").cast()); + sqlDatePtr->day = static_cast(param.attr("day").cast()); dataPtr = static_cast(sqlDatePtr); break; } @@ -333,9 +333,9 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params, } // TODO: can be moved to python by registering SQL_TIME_STRUCT in pybind SQL_TIME_STRUCT* sqlTimePtr = AllocateParamBuffer(paramBuffers); - sqlTimePtr->hour = param.attr("hour").cast(); - sqlTimePtr->minute = param.attr("minute").cast(); - sqlTimePtr->second = param.attr("second").cast(); + sqlTimePtr->hour = static_cast(param.attr("hour").cast()); + sqlTimePtr->minute = static_cast(param.attr("minute").cast()); + sqlTimePtr->second = static_cast(param.attr("second").cast()); dataPtr = static_cast(sqlTimePtr); break; } @@ -346,12 +346,12 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params, } SQL_TIMESTAMP_STRUCT* sqlTimestampPtr = AllocateParamBuffer(paramBuffers); - sqlTimestampPtr->year = param.attr("year").cast(); - sqlTimestampPtr->month = param.attr("month").cast(); - sqlTimestampPtr->day = param.attr("day").cast(); - sqlTimestampPtr->hour = param.attr("hour").cast(); - sqlTimestampPtr->minute = param.attr("minute").cast(); - sqlTimestampPtr->second = param.attr("second").cast(); + sqlTimestampPtr->year = static_cast(param.attr("year").cast()); + sqlTimestampPtr->month = static_cast(param.attr("month").cast()); + sqlTimestampPtr->day = static_cast(param.attr("day").cast()); + sqlTimestampPtr->hour = static_cast(param.attr("hour").cast()); + sqlTimestampPtr->minute = static_cast(param.attr("minute").cast()); + sqlTimestampPtr->second = static_cast(param.attr("second").cast()); // SQL server supports in ns, but python datetime supports in µs sqlTimestampPtr->fraction = static_cast( param.attr("microsecond").cast() * 1000); // Convert µs to ns @@ -372,7 +372,7 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params, decimalPtr->scale = decimalParam.scale; decimalPtr->sign = decimalParam.sign; // Convert the integer decimalParam.val to char array - std:memset(static_cast(decimalPtr->val), 0, sizeof(decimalPtr->val)); + std::memset(static_cast(decimalPtr->val), 0, sizeof(decimalPtr->val)); std::memcpy(static_cast(decimalPtr->val), reinterpret_cast(&decimalParam.val), sizeof(decimalParam.val)); @@ -395,8 +395,11 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params, assert(SQLBindParameter_ptr && SQLGetStmtAttr_ptr && SQLSetDescField_ptr); RETCODE rc = SQLBindParameter_ptr( - hStmt, paramIndex + 1 /* 1-based indexing */, paramInfo.inputOutputType, - paramInfo.paramCType, paramInfo.paramSQLType, paramInfo.columnSize, + hStmt, + static_cast(paramIndex + 1), /* 1-based indexing */ + static_cast(paramInfo.inputOutputType), + static_cast(paramInfo.paramCType), + static_cast(paramInfo.paramSQLType), paramInfo.columnSize, paramInfo.decimalDigits, dataPtr, bufferLength, strLenOrIndPtr); if (!SQL_SUCCEEDED(rc)) { LOG("Error when binding parameter - {}", paramIndex); @@ -406,7 +409,7 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params, // https://learn.microsoft.com/en-us/sql/odbc/reference/appendixes/retrieve-numeric-data-sql-numeric-struct-kb222831?view=sql-server-ver16#sql_c_numeric-overview if (paramInfo.paramCType == SQL_C_NUMERIC) { SQLHDESC hDesc = nullptr; - RETCODE rc = SQLGetStmtAttr_ptr(hStmt, SQL_ATTR_APP_PARAM_DESC, &hDesc, 0, NULL); + rc = SQLGetStmtAttr_ptr(hStmt, SQL_ATTR_APP_PARAM_DESC, &hDesc, 0, NULL); if(!SQL_SUCCEEDED(rc)) { LOG("Error when getting statement attribute - {}", paramIndex); return rc; @@ -469,6 +472,14 @@ void LOG(const std::string& formatString, Args&&... args) { logging.attr("debug")(message); } +std::string WideToUTF8(const std::wstring& wstr) { + if (wstr.empty()) return {}; + int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), nullptr, 0, nullptr, nullptr); + std::string result(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), result.data(), size_needed, nullptr, nullptr); + return result; +} + // TODO: Add more nuanced exception classes void ThrowStdException(const std::string& message) { throw std::runtime_error(message); } @@ -523,8 +534,7 @@ std::wstring LoadDriverOrThrowException() { } // Convert wstring to string for logging - std::string dllDirStr(dllDir.begin(), dllDir.end()); - LOG("Attempting to load driver from - {}", dllDirStr); + LOG("Attempting to load driver from - {}", WideToUTF8(dllDir)); HMODULE hModule = LoadLibraryW(dllDir.c_str()); if (!hModule) { @@ -597,7 +607,6 @@ std::wstring LoadDriverOrThrowException() { SQLDisconnect_ptr && SQLFreeStmt_ptr && SQLGetDiagRec_ptr; if (!success) { - LOG("Failed to load required function pointers from driver - {}", dllDirStr); ThrowStdException("Failed to load required function pointers from driver"); } LOG("Successfully loaded function pointers from driver"); @@ -860,7 +869,7 @@ SQLRETURN SQLGetData_wrap(SqlHandlePtr StatementHandle, SQLUSMALLINT colCount, p DriverLoader::getInstance().loadDriver(); // Load the driver } - SQLRETURN ret; + SQLRETURN ret = SQL_SUCCESS; SQLHSTMT hStmt = StatementHandle->get(); for (SQLSMALLINT i = 1; i <= colCount; ++i) { SQLWCHAR columnName[256]; @@ -1137,7 +1146,7 @@ SQLRETURN SQLGetData_wrap(SqlHandlePtr StatementHandle, SQLUSMALLINT colCount, p if (SQL_SUCCEEDED(ret)) { // TODO: Refactor these if's across other switches to avoid code duplication if (dataLen > 0) { - if (dataLen <= columnSize) { + if (static_cast(dataLen) <= columnSize) { row.append(py::bytes(reinterpret_cast( dataBuffer.get()), dataLen)); } else { @@ -1551,7 +1560,7 @@ SQLRETURN FetchBatchData(SQLHSTMT hStmt, ColumnBuffers& buffers, py::list& colum // TODO: variable length data needs special handling, this logic wont suffice SQLULEN columnSize = columnMeta["ColumnSize"].cast(); HandleZeroColumnSizeAtFetch(columnSize); - if (dataLen <= columnSize) { + if (static_cast(dataLen) <= columnSize) { row.append(py::bytes(reinterpret_cast( &buffers.charBuffers[col - 1][i * columnSize]), dataLen)); @@ -1702,7 +1711,7 @@ SQLRETURN FetchMany_wrap(SqlHandlePtr StatementHandle, py::list& rows, int fetch } SQLULEN numRowsFetched; - SQLSetStmtAttr_ptr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)fetchSize, 0); + SQLSetStmtAttr_ptr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)(intptr_t)fetchSize, 0); SQLSetStmtAttr_ptr(hStmt, SQL_ATTR_ROWS_FETCHED_PTR, &numRowsFetched, 0); ret = FetchBatchData(hStmt, buffers, columnNames, rows, numCols, numRowsFetched); @@ -1790,7 +1799,7 @@ SQLRETURN FetchAll_wrap(SqlHandlePtr StatementHandle, py::list& rows) { } SQLULEN numRowsFetched; - SQLSetStmtAttr_ptr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)fetchSize, 0); + SQLSetStmtAttr_ptr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)(intptr_t)fetchSize, 0); SQLSetStmtAttr_ptr(hStmt, SQL_ATTR_ROWS_FETCHED_PTR, &numRowsFetched, 0); while (ret != SQL_NO_DATA) { diff --git a/mssql_python/pybind/ddbc_bindings.h b/mssql_python/pybind/ddbc_bindings.h index 3d3925aa..bb050eab 100644 --- a/mssql_python/pybind/ddbc_bindings.h +++ b/mssql_python/pybind/ddbc_bindings.h @@ -177,3 +177,5 @@ struct ErrorInfo { std::wstring ddbcErrorMsg; }; ErrorInfo SQLCheckError_Wrap(SQLSMALLINT handleType, SqlHandlePtr handle, SQLRETURN retcode); + +std::string WideToUTF8(const std::wstring& wstr); \ No newline at end of file