From 7d813eaad8eaca04a687d1bb942316232d1c54fd Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Sun, 16 Dec 2018 13:53:48 -0600 Subject: Import implementation of SqlCA from old repo's scasched/scaexec. --- src/ca/scaexec.cpp | 393 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 src/ca/scaexec.cpp (limited to 'src/ca/scaexec.cpp') diff --git a/src/ca/scaexec.cpp b/src/ca/scaexec.cpp new file mode 100644 index 00000000..7a30f52a --- /dev/null +++ b/src/ca/scaexec.cpp @@ -0,0 +1,393 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +/******************************************************************** + * CreateDatabase - CUSTOM ACTION ENTRY POINT for creating databases + * + * Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword + * ****************************************************************/ +extern "C" UINT __stdcall CreateDatabase(MSIHANDLE hInstall) +{ +//AssertSz(FALSE, "debug CreateDatabase here"); + UINT er = ERROR_SUCCESS; + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + IDBCreateSession* pidbSession = NULL; + BSTR bstrErrorDescription = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzDatabaseKey = NULL; + LPWSTR pwzServer = NULL; + LPWSTR pwzInstance = NULL; + LPWSTR pwzDatabase = NULL; + LPWSTR pwzTemp = NULL; + int iAttributes; + BOOL fIntegratedAuth; + LPWSTR pwzUser = NULL; + LPWSTR pwzPassword = NULL; + BOOL fHaveDbFileSpec = FALSE; + SQL_FILESPEC sfDb; + BOOL fHaveLogFileSpec = FALSE; + SQL_FILESPEC sfLog; + BOOL fInitializedCom = FALSE; + + memset(&sfDb, 0, sizeof(sfDb)); + memset(&sfLog, 0, sizeof(sfLog)); + + hr = WcaInitialize(hInstall, "CreateDatabase"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to intialize COM"); + fInitializedCom = TRUE; + + hr = WcaGetProperty( L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + pwz = pwzData; + hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); // SQL Server + ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz); + hr = WcaReadStringFromCaData(&pwz, &pwzServer); // SQL Server + ExitOnFailure(hr, "failed to read server from custom action data: %ls", pwz); + hr = WcaReadStringFromCaData(&pwz, &pwzInstance); // SQL Server Instance + ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz); + hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); // SQL Database + ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz); + hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); + ExitOnFailure(hr, "failed to read attributes from custom action data: %ls", pwz); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fIntegratedAuth)); // Integrated Windows Authentication? + ExitOnFailure(hr, "failed to read integrated auth flag from custom action data: %ls", pwz); + hr = WcaReadStringFromCaData(&pwz, &pwzUser); // SQL User + ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz); + hr = WcaReadStringFromCaData(&pwz, &pwzPassword); // SQL User Password + ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz); + + // db file spec + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fHaveDbFileSpec)); + ExitOnFailure(hr, "failed to read db file spec from custom action data: %ls", pwz); + + if (fHaveDbFileSpec) + { + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read db file spec name from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfDb.wzName, countof(sfDb.wzName), pwzTemp); + ExitOnFailure(hr, "failed to copy db file spec name: %ls", pwzTemp); + + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read db file spec filename from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfDb.wzFilename, countof(sfDb.wzFilename), pwzTemp); + ExitOnFailure(hr, "failed to copy db file spec filename: %ls", pwzTemp); + + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read db file spec size from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfDb.wzSize, countof(sfDb.wzSize), pwzTemp); + ExitOnFailure(hr, "failed to copy db file spec size value: %ls", pwzTemp); + + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read db file spec max size from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfDb.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp); + ExitOnFailure(hr, "failed to copy db file spec max size: %ls", pwzTemp); + + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read db file spec grow from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfDb.wzGrow, countof(sfDb.wzGrow), pwzTemp); + ExitOnFailure(hr, "failed to copy db file spec grow value: %ls", pwzTemp); + } + + // log file spec + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fHaveLogFileSpec)); + ExitOnFailure(hr, "failed to read log file spec from custom action data: %ls", pwz); + if (fHaveLogFileSpec) + { + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read log file spec name from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfLog.wzName, countof(sfDb.wzName), pwzTemp); + ExitOnFailure(hr, "failed to copy log file spec name: %ls", pwzTemp); + + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read log file spec filename from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfLog.wzFilename, countof(sfDb.wzFilename), pwzTemp); + ExitOnFailure(hr, "failed to copy log file spec filename: %ls", pwzTemp); + + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read log file spec size from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfLog.wzSize, countof(sfDb.wzSize), pwzTemp); + ExitOnFailure(hr, "failed to copy log file spec size value: %ls", pwzTemp); + + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read log file spec max size from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfLog.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp); + ExitOnFailure(hr, "failed to copy log file spec max size: %ls", pwzTemp); + + hr = WcaReadStringFromCaData(&pwz, &pwzTemp); + ExitOnFailure(hr, "failed to read log file spec grow from custom action data: %ls", pwz); + hr = ::StringCchCopyW(sfLog.wzGrow, countof(sfDb.wzGrow), pwzTemp); + ExitOnFailure(hr, "failed to copy log file spec grow value: %ls", pwzTemp); + } + + if (iAttributes & SCADB_CONFIRM_OVERWRITE) + { + // Check if the database already exists + hr = SqlDatabaseExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription); + MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to check if database exists: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription); + + if (S_OK == hr) // found an existing database, confirm that they don't want to stop before it gets trampled, in no UI case just continue anyways + { + hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); + if (IDNO == WcaErrorMessage(msierrSQLDatabaseAlreadyExists, hr, MB_YESNO, 1, pwzDatabase)) + ExitOnFailure(hr, "failed to initialize"); + } + } + + hr = SqlDatabaseEnsureExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, fHaveDbFileSpec ? &sfDb : NULL, fHaveLogFileSpec ? &sfLog : NULL, &bstrErrorDescription); + if ((iAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr)) + { + WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to create SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase); + hr = S_OK; + } + MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to create to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription); + + hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE); +LExit: + ReleaseStr(pwzDatabaseKey); + ReleaseStr(pwzServer); + ReleaseStr(pwzInstance); + ReleaseStr(pwzDatabase); + ReleaseStr(pwzUser); + ReleaseStr(pwzPassword); + ReleaseObject(pidbSession); + ReleaseBSTR(bstrErrorDescription); + + if (fInitializedCom) + { + ::CoUninitialize(); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + + +/******************************************************************** + DropDatabase - CUSTOM ACTION ENTRY POINT for removing databases + + Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword + * ****************************************************************/ +extern "C" UINT __stdcall DropDatabase(MSIHANDLE hInstall) +{ +//Assert(FALSE); + UINT er = ERROR_SUCCESS; + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + IDBCreateSession* pidbSession = NULL; + BSTR bstrErrorDescription = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzDatabaseKey = NULL; + LPWSTR pwzServer = NULL; + LPWSTR pwzInstance = NULL; + LPWSTR pwzDatabase = NULL; + long lAttributes; + BOOL fIntegratedAuth; + LPWSTR pwzUser = NULL; + LPWSTR pwzPassword = NULL; + BOOL fInitializedCom = TRUE; + + hr = WcaInitialize(hInstall, "DropDatabase"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to intialize COM"); + fInitializedCom = TRUE; + + hr = WcaGetProperty( L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + pwz = pwzData; + hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); + ExitOnFailure(hr, "failed to read database key"); + hr = WcaReadStringFromCaData(&pwz, &pwzServer); + ExitOnFailure(hr, "failed to read server"); + hr = WcaReadStringFromCaData(&pwz, &pwzInstance); + ExitOnFailure(hr, "failed to read instance"); + hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); + ExitOnFailure(hr, "failed to read database"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&lAttributes)); + ExitOnFailure(hr, "failed to read attributes"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fIntegratedAuth)); // Integrated Windows Authentication? + ExitOnFailure(hr, "failed to read integrated auth flag"); + hr = WcaReadStringFromCaData(&pwz, &pwzUser); + ExitOnFailure(hr, "failed to read user"); + hr = WcaReadStringFromCaData(&pwz, &pwzPassword); + ExitOnFailure(hr, "failed to read password"); + + hr = SqlDropDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription); + if ((lAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr)) + { + WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to drop SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase); + hr = S_OK; + } + MessageExitOnFailure(hr, msierrSQLFailedDropDatabase, "failed to drop to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription); + + hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE); + +LExit: + ReleaseStr(pwzDatabaseKey); + ReleaseStr(pwzServer); + ReleaseStr(pwzInstance); + ReleaseStr(pwzDatabase); + ReleaseStr(pwzUser); + ReleaseStr(pwzPassword); + ReleaseStr(pwzData); + ReleaseObject(pidbSession); + ReleaseBSTR(bstrErrorDescription); + + if (fInitializedCom) + { + ::CoUninitialize(); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + + +/******************************************************************** + ExecuteSqlStrings - CUSTOM ACTION ENTRY POINT for running SQL strings + + Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword\tSQLKey1\tSQLString1\tSQLKey2\tSQLString2\tSQLKey3\tSQLString3\t... + rollback CustomActionData - same as above + * ****************************************************************/ +extern "C" UINT __stdcall ExecuteSqlStrings(MSIHANDLE hInstall) +{ +//Assert(FALSE); + UINT er = ERROR_SUCCESS; + HRESULT hr = S_OK; + HRESULT hrDB = S_OK; + + LPWSTR pwzData = NULL; + IDBCreateSession* pidbSession = NULL; + BSTR bstrErrorDescription = NULL; + + LPWSTR pwz = NULL; + LPWSTR pwzDatabaseKey = NULL; + LPWSTR pwzServer = NULL; + LPWSTR pwzInstance = NULL; + LPWSTR pwzDatabase = NULL; + int iAttributesDB; + int iAttributesSQL; + BOOL fIntegratedAuth; + LPWSTR pwzUser = NULL; + LPWSTR pwzPassword = NULL; + LPWSTR pwzSqlKey = NULL; + LPWSTR pwzSql = NULL; + BOOL fInitializedCom = FALSE; + + hr = WcaInitialize(hInstall, "ExecuteSqlStrings"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to intialize COM"); + fInitializedCom = TRUE; + + hr = WcaGetProperty( L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + pwz = pwzData; + hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); + ExitOnFailure(hr, "failed to read database key"); + hr = WcaReadStringFromCaData(&pwz, &pwzServer); + ExitOnFailure(hr, "failed to read server"); + hr = WcaReadStringFromCaData(&pwz, &pwzInstance); + ExitOnFailure(hr, "failed to read instance"); + hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); + ExitOnFailure(hr, "failed to read database"); + hr = WcaReadIntegerFromCaData(&pwz, &iAttributesDB); + ExitOnFailure(hr, "failed to read attributes"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fIntegratedAuth)); // Integrated Windows Authentication? + ExitOnFailure(hr, "failed to read integrated auth flag"); + hr = WcaReadStringFromCaData(&pwz, &pwzUser); + ExitOnFailure(hr, "failed to read user"); + hr = WcaReadStringFromCaData(&pwz, &pwzPassword); + ExitOnFailure(hr, "failed to read password"); + + // Store off the result of the connect, only exit if we don't care if the database connection succeeds + // Wait to fail until later to see if we actually have work to do that is not set to continue on error + hrDB = SqlConnectDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &pidbSession); + if ((iAttributesDB & SCADB_CONTINUE_ON_ERROR) && FAILED(hrDB)) + { + WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase); + ExitFunction1(hr = S_OK); + } + + while (S_OK == hr && S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzSqlKey))) + { + hr = WcaReadIntegerFromCaData(&pwz, &iAttributesSQL); + ExitOnFailure(hr, "failed to read attributes for SQL string: %ls", pwzSqlKey); + + hr = WcaReadStringFromCaData(&pwz, &pwzSql); + ExitOnFailure(hr, "failed to read SQL string for key: %ls", pwzSqlKey); + + // If the SqlString row is set to continue on error and the DB connection failed, skip attempting to execute + if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hrDB)) + { + WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase); + continue; + } + + // Now check if the DB connection succeeded + MessageExitOnFailure(hr = hrDB, msierrSQLFailedConnectDatabase, "failed to connect to database: '%ls'", pwzDatabase); + + WcaLog(LOGMSG_VERBOSE, "Executing SQL string: %ls", pwzSql); + hr = SqlSessionExecuteQuery(pidbSession, pwzSql, NULL, NULL, &bstrErrorDescription); + if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hr)) + { + WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to execute SQL string but continuing, error: %ls, SQL key: %ls SQL string: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql); + hr = S_OK; + } + MessageExitOnFailure(hr, msierrSQLFailedExecString, "failed to execute SQL string, error: %ls, SQL key: %ls SQL string: %ls", NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql); + + WcaProgressMessage(COST_SQL_STRING, FALSE); + } + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + +LExit: + ReleaseStr(pwzDatabaseKey); + ReleaseStr(pwzServer); + ReleaseStr(pwzInstance); + ReleaseStr(pwzDatabase); + ReleaseStr(pwzUser); + ReleaseStr(pwzPassword); + ReleaseStr(pwzData); + + ReleaseBSTR(bstrErrorDescription); + ReleaseObject(pidbSession); + + if (fInitializedCom) + { + ::CoUninitialize(); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} -- cgit v1.2.3-55-g6feb