Beispiel #1
0
static HRESULT ConfigureSqlData(
    __in SCA_ACTION saAction
    )
{
    //AssertSz(FALSE, "debug ConfigureSqlData()");
    HRESULT hr = S_OK;

    SCA_DB* psdList = NULL;
    SCA_SQLSTR* psssList = NULL;

    // check for the prerequsite tables
    if (S_OK != WcaTableExists(L"SqlDatabase"))
    {
        WcaLog(LOGMSG_VERBOSE, "skipping SQL CustomAction, no SqlDatabase table");
        ExitFunction1(hr = S_FALSE);
    }

    // read tables
    hr = ScaDbsRead(&psdList, saAction);
    ExitOnFailure(hr, "failed to read SqlDatabase table");

    hr = ScaSqlStrsRead(&psssList, saAction);
    ExitOnFailure(hr, "failed to read SqlStrings table");

    hr = ScaSqlStrsReadScripts(&psssList, saAction);
    ExitOnFailure(hr, "failed to read SqlScripts table");

    if (SCA_ACTION_UNINSTALL == saAction)
    {
        // do uninstall actions (order is important!)
        hr = ScaSqlStrsUninstall(psdList, psssList);
        ExitOnFailure(hr, "failed to execute uninstall SQL strings");

        hr = ScaDbsUninstall(psdList);
        ExitOnFailure(hr, "failed to uninstall databases");
    }
    else
    {
        // do install actions (order is important!)
        hr = ScaDbsInstall(psdList);
        ExitOnFailure(hr, "failed to install databases");

        hr = ScaSqlStrsInstall(psdList, psssList);
        ExitOnFailure(hr, "failed to execute install SQL strings, length may be too long, try add GO to break up");
    }

LExit:
    if (psssList)
        ScaSqlStrsFreeList(psssList);

    if (psdList)
        ScaDbsFreeList(psdList);

    return hr;
}
Beispiel #2
0
HRESULT ScaSqlStrsReadScripts(
    __inout SCA_SQLSTR** ppsssList,
    __in SCA_ACTION saAction
    )
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    PMSIHANDLE hView, hRec;
    PMSIHANDLE hViewBinary, hRecBinary;
    PMSIHANDLE hViewUser, hRecUser;

    LPWSTR pwzComponent = NULL;
    LPWSTR pwzData = NULL;

    BYTE* pbScript = NULL;
    DWORD cbRead = 0;
    DWORD cbScript = 0;
    DWORD cchScript = 0;

    LPWSTR pwzScriptBuffer = NULL;
    WCHAR* pwzScript = NULL;
    WCHAR* pwz;
    DWORD cch = 0;

    SCA_SQLSTR sss;
    SCA_SQLSTR* psss = NULL;

    if (S_OK != WcaTableExists(L"SqlScript") || S_OK != WcaTableExists(L"SqlDatabase") || S_OK != WcaTableExists(L"Binary"))
    {
        WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsReadScripts() - SqlScripts and/or SqlDatabase table not present");
        ExitFunction1(hr = S_FALSE);
    }

    // open a view on the binary table
    hr = WcaOpenView(vcsSqlBinaryScriptQuery, &hViewBinary);
    ExitOnFailure(hr, "Failed to open view on Binary table for SqlScripts");

    // loop through all the sql scripts
    hr = WcaOpenExecuteView(vcsSqlScriptQuery, &hView);
    ExitOnFailure(hr, "Failed to open view on SqlScript table");
    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
    {
        INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
        INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;

        hr = WcaGetRecordString(hRec, sscrqComponent, &pwzComponent);
        ExitOnFailure(hr, "Failed to get Component for SQL Script.");

        er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction);
        hr = HRESULT_FROM_WIN32(er);
        ExitOnFailure1(hr, "Failed to get state for component: %ls", pwzComponent);

        // If we're doing install but the Component is not being installed or we're doing
        // uninstall but the Component is not being uninstalled, skip it.
        if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) ||
            (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction))
        {
            continue;
        }

        ::ZeroMemory(&sss, sizeof(sss));

        sss.isInstalled = isInstalled;
        sss.isAction = isAction;

        hr = WcaGetRecordString(hRec, sscrqSqlScript, &pwzData);
        ExitOnFailure(hr, "Failed to get SqlScript.Script");
        hr = ::StringCchCopyW(sss.wzKey, countof(sss.wzKey), pwzData);
        ExitOnFailure1(hr, "Failed to copy SqlScript.Script: %ls", pwzData);

        // find the database information for this string
        hr = WcaGetRecordString(hRec, sscrqSqlDb, &pwzData);
        ExitOnFailure1(hr, "Failed to get SqlScript.SqlDb_ for SqlScript '%ls'", sss.wzKey);
        hr = ::StringCchCopyW(sss.wzSqlDb, countof(sss.wzSqlDb), pwzData);
        ExitOnFailure1(hr, "Failed to copy SqlScritp.SqlDbb: %ls", pwzData);

        hr = WcaGetRecordInteger(hRec, sscrqAttributes, &sss.iAttributes);
        ExitOnFailure1(hr, "Failed to get SqlScript.Attributes for SqlScript '%ls'", sss.wzKey);

        hr = WcaGetRecordInteger(hRec, sscrqSequence, &sss.iSequence);
        ExitOnFailure1(hr, "Failed to get SqlScript.Sequence for SqlScript '%ls'", sss.wzKey);

        // get the sql script out of the binary stream
        hr = WcaExecuteView(hViewBinary, hRec);
        ExitOnFailure1(hr, "Failed to open SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey);
        hr = WcaFetchSingleRecord(hViewBinary, &hRecBinary);
        ExitOnFailure1(hr, "Failed to fetch SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey);

        // Note: We need to allocate an extra character on the stream to NULL terminate the SQL script.
        //       The WcaGetRecordStream() function won't let us add extra space on the end of the stream
        //       so we'll read the stream "the old fashioned way".
        //hr = WcaGetRecordStream(hRecBinary, ssbsqData, (BYTE**)&pbScript, &cbScript);
        //ExitOnFailure1(hr, "Failed to read SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey);
        er = ::MsiRecordReadStream(hRecBinary, ssbsqData, NULL, &cbRead);
        hr = HRESULT_FROM_WIN32(er);
        ExitOnFailure(hr, "failed to get size of stream");

        cbScript = cbRead + sizeof(WCHAR); // we may have an ANSI SQL script but leave enough to even NULL terminate a WCHAR string
        hr = WcaAllocStream(&pbScript, cbScript); // this will allocate a fully zeroed out buffer so our string will be NULL terminated
        ExitOnFailure(hr, "failed to allocate data for stream");

        er = ::MsiRecordReadStream(hRecBinary, ssbsqData, reinterpret_cast<char*>(pbScript), &cbRead); //read the buffer but leave the space for the NULL terminator
        hr = HRESULT_FROM_WIN32(er);
        ExitOnFailure(hr, "failed to read from stream");

        Assert(cbRead + sizeof(WCHAR) == cbScript);

        // Check for the UNICODE BOM file marker.
        if ((0xFF == *pbScript) && (0xFE == *(pbScript + 1)))
        {
            // Copy the UNICODE string after the BOM marker (subtract one because we'll skip the BOM marker).
            cchScript = (cbScript / sizeof(WCHAR)) - 1;

            hr = StrAllocString(&pwzScriptBuffer, reinterpret_cast<LPWSTR>(pbScript) + 1, 0);
            ExitOnFailure1(hr, "Failed to allocate WCHAR string of size '%d'", cchScript);
        }
        else
        {
            // We have an ANSI string so convert it to UNICODE.
            cchScript = cbScript;

            hr = StrAllocStringAnsi(&pwzScriptBuffer, reinterpret_cast<LPCSTR>(pbScript), 0, CP_ACP);
            ExitOnFailure1(hr, "Failed to allocate WCHAR string of size '%d'", cchScript);
        }

        // Free the byte buffer since it has been converted to a new UNICODE string, one way or another.
        if (pbScript)
        {
            WcaFreeStream(pbScript);
            pbScript = NULL;
        }

        // Process the SQL script stripping out unnecessary stuff (like comments) and looking for "GO" statements.
        pwzScript = pwzScriptBuffer;
        while (cchScript && pwzScript && *pwzScript)
        {
            // strip off leading whitespace
            while (cchScript && *pwzScript && iswspace(*pwzScript))
            {
                ++pwzScript;
                --cchScript;
            }

            Assert(0 <= cchScript);

            // if there is a SQL comment remove it
            while (cchScript && L'/' == *pwzScript && L'*' == *(pwzScript + 1))
            {
                // go until end of comment
                while (cchScript && *pwzScript && *(pwzScript + 1) && !(L'*' == *pwzScript && L'/' == *(pwzScript + 1)))
                {
                    ++pwzScript;
                    --cchScript;
                }

                Assert(2 <= cchScript);

                if (2 <= cchScript)
                {
                    // to account for */ at end
                    pwzScript+=2;
                    cchScript-=2;
                }

                Assert(0 <= cchScript);

                // strip off any new leading whitespace
                while (cchScript && *pwzScript && iswspace(*pwzScript))
                {
                    ++pwzScript;
                    --cchScript;
                }
            }

            while (cchScript && L'-' == *pwzScript && L'-' == *(pwzScript + 1))
            {
                // go past the new line character
                while (cchScript && *pwzScript && L'\n' != *pwzScript)
                {
                    ++pwzScript;
                    --cchScript;
                }

                Assert(0 <= cchScript);

                if (cchScript && L'\n' == *pwzScript)
                {
                    ++pwzScript;
                    --cchScript;
                }

                Assert(0 <= cchScript);

                // strip off any new leading whitespace
                while (cchScript && *pwzScript && iswspace(*pwzScript))
                {
                    ++pwzScript;
                    --cchScript;
                }
            }

            Assert(0 <= cchScript);

            // try to isolate a "GO" keyword and count the characters in the SQL string
            pwz = pwzScript;
            cch = 0;
            while (cchScript && *pwz)
            {
                //skip past comment lines that might have "go" in them
                //note that these comments are "in the middle" of our function,
                //or possibly at the end of a line
                if (cchScript && L'-' == *pwz && L'-' == *(pwz + 1))
                {
                    // skip past chars until the new line character
                    while (cchScript && *pwz && (L'\n' != *pwz))
                    {
                        ++pwz;
                        ++cch;
                        --cchScript;
                    }
                }

                //skip past comment lines of form /* to */ that might have "go" in them
                //note that these comments are "in the middle" of our function,
                //or possibly at the end of a line
                if (cchScript && L'/' == *pwz && L'*' == *(pwz + 1))
                {
                    // skip past chars until the new line character
                    while (cchScript && *pwz && *(pwz + 1) && !((L'*' == *pwz) && (L'/' == *(pwz + 1))))
                    {
                        ++pwz;
                        ++cch;
                        --cchScript;
                    }

                    if (2 <= cchScript)
                    {
                        // to account for */ at end
                        pwz+=2;
                        cch+=2;
                        cchScript-=2;
                    }
                }

                // Skip past strings that may be part of the SQL statement that might have a "go" in them
                if ( cchScript && L'\'' == *pwz )
                {
                    ++pwz;
                    ++cch;
                    --cchScript;

                    // Skip past chars until the end of the string
                    while ( cchScript && *pwz && !(L'\'' == *pwz) )
                    {
                        ++pwz;
                        ++cch;
                        --cchScript;
                    }
                }

                // Skip past strings that may be part of the SQL statement that might have a "go" in them
                if ( cchScript && L'\"' == *pwz )
                {
                    ++pwz;
                    ++cch;
                    --cchScript;

                    // Skip past chars until the end of the string
                    while ( cchScript && *pwz && !(L'\"' == *pwz) )
                    {
                        ++pwz;
                        ++cch;
                        --cchScript;
                    }
                }

                // if "GO" is isolated
                if ((pwzScript == pwz || iswspace(*(pwz - 1))) && 
                    (L'G' == *pwz || L'g' == *pwz) && 
                    (L'O' == *(pwz + 1) || L'o' == *(pwz + 1)) &&
                    (0 == *(pwz + 2) || iswspace(*(pwz + 2))))
                {
                    *pwz = 0; // null terminate the SQL string on the "G"
                    pwz += 2;
                    cchScript -= 2;
                    break;   // found "GO" now add SQL string to list
                }

                ++pwz;
                ++cch;
                --cchScript;
            }

            Assert(0 <= cchScript);

            if (0 < cch) //don't process if there's nothing to process
            {
                // replace tabs with spaces
                for (LPWSTR pwzTab = wcsstr(pwzScript, L"\t"); pwzTab; pwzTab = wcsstr(pwzTab, L"\t"))
                    *pwzTab = ' ';

                // strip off whitespace at the end of the script string
                for (LPWSTR pwzErase = pwzScript + cch - 1; pwzScript < pwzErase && iswspace(*pwzErase); pwzErase--)
                {
                    *(pwzErase) = 0;
                    cch--;
                }
            }

            if (0 < cch)
            {
                hr = NewSqlStr(&psss);
                ExitOnFailure(hr, "failed to allocate new sql string element");

                // copy everything over
                hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), sss.wzKey);
                ExitOnFailure(hr, "Failed to copy key string to sqlstr object");
                hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), sss.wzSqlDb);
                ExitOnFailure(hr, "Failed to copy DB string to sqlstr object");
                hr = ::StringCchCopyW(psss->wzComponent, countof(psss->wzComponent), sss.wzComponent);
                ExitOnFailure(hr, "Failed to copy component string to sqlstr object");
                psss->isInstalled = sss.isInstalled;
                psss->isAction = sss.isAction;
                psss->iAttributes = sss.iAttributes;
                psss->iSequence = sss.iSequence;

                // cchRequired includes the NULL terminating char
                hr = StrAllocString(&psss->pwzSql, pwzScript, 0);
                ExitOnFailure1(hr, "Failed to allocate string for SQL script: '%ls'", psss->wzKey);

                *ppsssList = AddSqlStrToList(*ppsssList, psss);
                psss = NULL; // set the db NULL so it doesn't accidentally get freed below
            }

            pwzScript = pwz;
        }
    }

    if (E_NOMOREITEMS == hr)
    {
        hr = S_OK;
    }
    ExitOnFailure(hr, "Failure occured while reading SqlString table");

LExit:
    // if anything was left over after an error clean it all up
    if (psss)
    {
        ScaSqlStrsFreeList(psss);
    }

    if (pbScript)
    {
        WcaFreeStream(pbScript);
    }

    ReleaseStr(pwzScriptBuffer);
    ReleaseStr(pwzData);
    ReleaseStr(pwzComponent);

    return hr;
}
Beispiel #3
0
HRESULT ScaSqlStrsRead(
    __inout SCA_SQLSTR** ppsssList,
    __in SCA_ACTION saAction
    )
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;
    PMSIHANDLE hView, hRec;
    PMSIHANDLE hViewUser, hRecUser;

    LPWSTR pwzComponent = NULL;
    LPWSTR pwzData = NULL;

    SCA_SQLSTR* psss = NULL;

    if (S_OK != WcaTableExists(L"SqlString") || S_OK != WcaTableExists(L"SqlDatabase"))
    {
        WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsRead() - SqlString and/or SqlDatabase table not present");
        ExitFunction1(hr = S_FALSE);
    }

    // loop through all the sql strings
    hr = WcaOpenExecuteView(vcsSqlStringQuery, &hView);
    ExitOnFailure(hr, "Failed to open view on SqlString table");
    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
    {
        INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
        INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;

        hr = WcaGetRecordString(hRec, ssqComponent, &pwzComponent);
        ExitOnFailure(hr, "Failed to get Component for SQL String.");

        er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction);
        hr = HRESULT_FROM_WIN32(er);
        ExitOnFailure1(hr, "Failed to get state for component: %ls", pwzComponent);

        // If we're doing install but the Component is not being installed or we're doing
        // uninstall but the Component is not being uninstalled, skip it.
        if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) ||
            (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction))
        {
            continue;
        }

        hr = NewSqlStr(&psss);
        ExitOnFailure(hr, "failed to allocation new sql string element");

        psss->isInstalled = isInstalled;
        psss->isAction = isAction;

        hr = WcaGetRecordString(hRec, ssqSqlString, &pwzData);
        ExitOnFailure(hr, "Failed to get SqlString.String");
        hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), pwzData);
        ExitOnFailure1(hr, "Failed to copy SqlString.String: %ls", pwzData);

        // find the database information for this string
        hr = WcaGetRecordString(hRec, ssqSqlDb, &pwzData);
        ExitOnFailure1(hr, "Failed to get SqlString.SqlDb_ for SqlString '%ls'", psss->wzKey);
        hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), pwzData);
        ExitOnFailure1(hr, "Failed to copy SqlString.SqlDb_: %ls", pwzData);

        hr = WcaGetRecordInteger(hRec, ssqAttributes, &psss->iAttributes);
        ExitOnFailure1(hr, "Failed to get SqlString.Attributes for SqlString '%ls'", psss->wzKey);

        //get the sequence number for the string (note that this will be sequenced with scripts too)
        hr = WcaGetRecordInteger(hRec, ssqSequence, &psss->iSequence);
        ExitOnFailure1(hr, "Failed to get SqlString.Sequence for SqlString '%ls'", psss->wzKey);

        // execute SQL
        hr = WcaGetRecordFormattedString(hRec, ssqSQL, &pwzData);
        ExitOnFailure1(hr, "Failed to get SqlString.SQL for SqlString '%ls'", psss->wzKey);

        Assert(!psss->pwzSql);
        hr = StrAllocString(&psss->pwzSql, pwzData, 0);
        ExitOnFailure1(hr, "Failed to alloc string for SqlString '%ls'", psss->wzKey);

        *ppsssList = AddSqlStrToList(*ppsssList, psss);
        psss = NULL; // set the sss to NULL so it doesn't get freed below
    }

    if (E_NOMOREITEMS == hr)
    {
        hr = S_OK;
    }
    ExitOnFailure(hr, "Failure occured while reading SqlString table");

LExit:
    // if anything was left over after an error clean it all up
    if (psss)
    {
        ScaSqlStrsFreeList(psss);
    }

    ReleaseStr(pwzData);
    ReleaseStr(pwzComponent);

    return hr;
}
Beispiel #4
0
HRESULT ScaSqlStrsRead(
	__inout SCA_SQLSTR** ppsssList
	)
{
	HRESULT hr = S_OK;
	UINT er = ERROR_SUCCESS;
	PMSIHANDLE hView, hRec;
	PMSIHANDLE hViewUser, hRecUser;

	LPWSTR pwzData = NULL;

	SCA_SQLSTR* psss = NULL;

	if (S_OK != WcaTableExists(L"SqlString") || S_OK != WcaTableExists(L"SqlDatabase"))
	{
		WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsRead() - SqlString and/or SqlDatabase table not present");
		hr = S_FALSE;
		goto LExit;
	}

	// loop through all the sql strings
	hr = WcaOpenExecuteView(vcsSqlStringQuery, &hView);
	ExitOnFailure(hr, "Failed to open view on SqlString table");
	while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
	{
		hr = NewSqlStr(&psss);
		ExitOnFailure(hr, "failed to allocation new sql string element");

		hr = WcaGetRecordString(hRec, ssqSqlString, &pwzData);
		ExitOnFailure(hr, "Failed to get SqlString.String");
		StringCchCopyW(psss->wzKey, countof(psss->wzKey), pwzData);

		// find the database information for this string
		hr = WcaGetRecordString(hRec, ssqSqlDb, &pwzData);
		ExitOnFailure1(hr, "Failed to get SqlString.SqlDb_ for SqlString '%S'", psss->wzKey);
		StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), pwzData);

		// get component install state
		hr = WcaGetRecordString(hRec, ssqComponent, &pwzData);
		ExitOnFailure1(hr, "Failed to get SqlString.Component_ for SqlString '%S'", psss->wzKey);
		StringCchCopyW(psss->wzComponent, countof(psss->wzComponent), pwzData);

		er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &psss->isInstalled, &psss->isAction);
		hr = HRESULT_FROM_WIN32(er);
		ExitOnFailure1(hr, "Failed to get Component state for SqlString '%S'", psss->wzKey);

		hr = WcaGetRecordInteger(hRec, ssqAttributes, &psss->iAttributes);
		ExitOnFailure1(hr, "Failed to get SqlString.Attributes for SqlString '%S'", psss->wzKey);

		//get the sequence number for the string (note that this will be sequenced with scripts too)
		hr = WcaGetRecordInteger(hRec, ssqSequence, &psss->iSequence);
		ExitOnFailure1(hr, "Failed to get SqlString.Sequence for SqlString '%S'", psss->wzKey);

		// execute SQL
		hr = WcaGetRecordFormattedString(hRec, ssqSQL, &pwzData);
		ExitOnFailure1(hr, "Failed to get SqlString.SQL for SqlString '%S'", psss->wzKey);

		Assert(!psss->pwzSql);
		hr = StrAllocString(&psss->pwzSql, pwzData, 0);
		ExitOnFailure1(hr, "Failed to alloc string for SqlString '%S'", psss->wzKey);

		*ppsssList = AddSqlStrToList(*ppsssList, psss);
		psss = NULL;	// set the db NULL so it doesn't accidentally get freed below
	}

	if (E_NOMOREITEMS == hr)
		hr = S_OK;
	ExitOnFailure(hr, "Failure occured while reading SqlString table");

LExit:
	// if anything was left over after an error clean it all up
	if (psss)
	{
		ScaSqlStrsFreeList(psss);
	}

	ReleaseStr(pwzData);

	return hr;
}