From b2c4600453f926fbfdc63219126930ad39601f25 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 8 Apr 2021 14:06:21 -0700 Subject: Port missing WiX v3 changes --- src/dutil/sqlutil.cpp | 171 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 145 insertions(+), 26 deletions(-) (limited to 'src/dutil/sqlutil.cpp') diff --git a/src/dutil/sqlutil.cpp b/src/dutil/sqlutil.cpp index 63ee80ac..782c7088 100644 --- a/src/dutil/sqlutil.cpp +++ b/src/dutil/sqlutil.cpp @@ -10,7 +10,22 @@ #include "sqlutil.h" +//Please note that only SQL native client 11 has TLS1.2 support +#define _SQLNCLI_OLEDB_DEPRECATE_WARNING + +#if !defined(SQLNCLI_VER) +#define SQLNCLI_VER 1100 +#endif + +#if SQLNCLI_VER >= 1100 +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) +#define SQLNCLI_CLSID CLSID_SQLNCLI11 +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) +extern const GUID OLEDBDECLSPEC _SQLNCLI_OLEDB_DEPRECATE_WARNING CLSID_SQLNCLI11 = { 0x397C2819L,0x8272,0x4532,{ 0xAD,0x3A,0xFB,0x5E,0x43,0xBE,0xAA,0x39 } }; +#endif // SQLNCLI_VER >= 1100 + // Exit macros +#define SqlExitTrace(x, s, ...) ExitTraceSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) #define SqlExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) #define SqlExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) #define SqlExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) @@ -25,11 +40,18 @@ #define SqlExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_SQLUTIL, g, x, s, __VA_ARGS__) // private prototypes +static HRESULT InitializeDatabaseConnection( + __in REFCLSID rclsid, + __in_z LPCSTR szFriendlyClsidName, + __in DBPROPSET rgdbpsetInit[], + __in_ecount(rgdbpsetInit) DWORD cdbpsetInit, + __out IDBCreateSession** ppidbSession + ); +HRESULT DumpErrorRecords(); static HRESULT FileSpecToString( __in const SQL_FILESPEC* psf, __out LPWSTR* ppwz ); - static HRESULT EscapeSqlIdentifier( __in_z LPCWSTR wzDatabase, __deref_out_z LPWSTR* ppwz @@ -55,22 +77,11 @@ extern "C" HRESULT DAPI SqlConnectDatabase( Assert(wzServer && wzDatabase && *wzDatabase && ppidbSession); HRESULT hr = S_OK; - IDBInitialize* pidbInitialize = NULL; - IDBProperties* pidbProperties = NULL; - LPWSTR pwzServerInstance = NULL; - DBPROP rgdbpInit[4]; - DBPROPSET rgdbpsetInit[1]; + DBPROP rgdbpInit[4] = { }; + DBPROPSET rgdbpsetInit[1] = { }; ULONG cProperties = 0; - memset(rgdbpInit, 0, sizeof(rgdbpInit)); - memset(rgdbpsetInit, 0, sizeof(rgdbpsetInit)); - - //obtain access to the SQLOLEDB provider - hr = ::CoCreateInstance(CLSID_SQLOLEDB, NULL, CLSCTX_INPROC_SERVER, - IID_IDBInitialize, (LPVOID*)&pidbInitialize); - SqlExitOnFailure(hr, "failed to create IID_IDBInitialize object"); - // if there is an instance if (wzInstance && *wzInstance) { @@ -137,17 +148,23 @@ extern "C" HRESULT DAPI SqlConnectDatabase( rgdbpsetInit[0].rgProperties = rgdbpInit; rgdbpsetInit[0].cProperties = cProperties; - // create and set the property set - hr = pidbInitialize->QueryInterface(IID_IDBProperties, (LPVOID*)&pidbProperties); - SqlExitOnFailure(hr, "failed to get IID_IDBProperties object"); - hr = pidbProperties->SetProperties(1, rgdbpsetInit); - SqlExitOnFailure(hr, "failed to set properties"); - - //initialize connection to datasource - hr = pidbInitialize->Initialize(); - SqlExitOnFailure(hr, "failed to initialize connection to database: %ls", wzDatabase); + // obtain access to the SQL Native Client provider + hr = InitializeDatabaseConnection(SQLNCLI_CLSID, "SQL Native Client", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession); + if (FAILED(hr)) + { + SqlExitTrace(hr, "Could not initialize SQL Native Client, falling back to SQL OLE DB..."); - hr = pidbInitialize->QueryInterface(IID_IDBCreateSession, (LPVOID*)ppidbSession); + // try OLE DB but if that fails return original error failure + HRESULT hr2 = InitializeDatabaseConnection(CLSID_SQLOLEDB, "SQL OLE DB", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession); + if (FAILED(hr2)) + { + SqlExitTrace(hr2, "Could not initialize SQL OLE DB either, giving up."); + } + else + { + hr = S_OK; + } + } LExit: for (; 0 < cProperties; cProperties--) @@ -155,8 +172,6 @@ LExit: ::VariantClear(&rgdbpInit[cProperties - 1].vValue); } - ReleaseObject(pidbProperties); - ReleaseObject(pidbInitialize); ReleaseStr(pwzServerInstance); return hr; @@ -787,6 +802,110 @@ LExit: // private // +static HRESULT InitializeDatabaseConnection( + __in REFCLSID rclsid, + __in_z LPCSTR szFriendlyClsidName, + __in DBPROPSET rgdbpsetInit[], + __in_ecount(rgdbpsetInit) DWORD cdbpsetInit, + __out IDBCreateSession** ppidbSession +) +{ + Unused(szFriendlyClsidName); // only used in DEBUG builds + + HRESULT hr = S_OK; + IDBInitialize* pidbInitialize = NULL; + IDBProperties* pidbProperties = NULL; + + hr = ::CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (LPVOID*)&pidbInitialize); + SqlExitOnFailure(hr, "failed to initialize %s", szFriendlyClsidName); + + // create and set the property set + hr = pidbInitialize->QueryInterface(IID_IDBProperties, (LPVOID*)&pidbProperties); + SqlExitOnFailure(hr, "failed to get IID_IDBProperties for %s", szFriendlyClsidName); + + hr = pidbProperties->SetProperties(cdbpsetInit, rgdbpsetInit); + SqlExitOnFailure(hr, "failed to set properties for %s", szFriendlyClsidName); + + // initialize connection to datasource + hr = pidbInitialize->Initialize(); + if (FAILED(hr)) + { + DumpErrorRecords(); + } + SqlExitOnFailure(hr, "failed to initialize connection for %s", szFriendlyClsidName); + + hr = pidbInitialize->QueryInterface(IID_IDBCreateSession, (LPVOID*)ppidbSession); + SqlExitOnFailure(hr, "failed to query for connection session for %s", szFriendlyClsidName); + +LExit: + ReleaseObject(pidbProperties); + ReleaseObject(pidbInitialize); + + return hr; +} + +HRESULT DumpErrorRecords() +{ + HRESULT hr = S_OK; + IErrorInfo* pIErrorInfo = NULL; + IErrorRecords* pIErrorRecords = NULL; + IErrorInfo* pIErrorInfoRecord = NULL; + BSTR bstrDescription = NULL; + ULONG i = 0; + ULONG cRecords = 0; + ERRORINFO ErrorInfo = { }; + + // Get IErrorInfo pointer from OLE. + hr = ::GetErrorInfo(0, &pIErrorInfo); + if (FAILED(hr)) + { + ExitFunction(); + } + + // QI for IID_IErrorRecords. + hr = pIErrorInfo->QueryInterface(IID_IErrorRecords, (void**)&pIErrorRecords); + if (FAILED(hr)) + { + ExitFunction(); + } + + // Get error record count. + hr = pIErrorRecords->GetRecordCount(&cRecords); + if (FAILED(hr)) + { + ExitFunction(); + } + + // Loop through the error records. + for (i = 0; i < cRecords; i++) + { + // Get pIErrorInfo from pIErrorRecords. + hr = pIErrorRecords->GetErrorInfo(i, 1033, &pIErrorInfoRecord); + + if (SUCCEEDED(hr)) + { + // Get error description and source. + hr = pIErrorInfoRecord->GetDescription(&bstrDescription); + + // Retrieve the ErrorInfo structures. + hr = pIErrorRecords->GetBasicErrorInfo(i, &ErrorInfo); + + SqlExitTrace(ErrorInfo.hrError, "SQL error %lu/%lu: %ls", i + 1, cRecords, bstrDescription); + + ReleaseNullObject(pIErrorInfoRecord); + ReleaseNullBSTR(bstrDescription); + } + } + +LExit: + ReleaseNullBSTR(bstrDescription); + ReleaseObject(pIErrorInfoRecord); + ReleaseObject(pIErrorRecords); + ReleaseObject(pIErrorInfo); + + return hr; +} + /******************************************************************** FileSpecToString -- cgit v1.2.3-55-g6feb