summaryrefslogtreecommitdiff
path: root/src/ext/Sql/ca/scasqlstr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Sql/ca/scasqlstr.cpp')
-rw-r--r--src/ext/Sql/ca/scasqlstr.cpp728
1 files changed, 728 insertions, 0 deletions
diff --git a/src/ext/Sql/ca/scasqlstr.cpp b/src/ext/Sql/ca/scasqlstr.cpp
new file mode 100644
index 00000000..c3ebd43d
--- /dev/null
+++ b/src/ext/Sql/ca/scasqlstr.cpp
@@ -0,0 +1,728 @@
1// 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.
2
3#include "precomp.h"
4
5// sql queries
6LPCWSTR vcsSqlStringQuery = L"SELECT `String`, `SqlDb_`, `Component_`,`SQL`,`User_`,`Attributes`,`Sequence` "
7L"FROM `Wix4SqlString` ORDER BY `SqlDb_`,`Sequence`";
8enum eSqlStringQuery { ssqSqlString = 1, ssqSqlDb, ssqComponent, ssqSQL, ssqUser, ssqAttributes, ssqSequence };
9
10LPCWSTR vcsSqlScriptQuery = L"SELECT `ScriptBinary_`,`Script`, `SqlDb_`, `Component_`,`User_`,`Attributes`,`Sequence` "
11L"FROM `Wix4SqlScript` ORDER BY `SqlDb_`,`Sequence`";
12enum eSqlScriptQuery { sscrqScriptBinary=1, sscrqSqlScript, sscrqSqlDb, sscrqComponent, sscrqUser, sscrqAttributes, sscrqSequence };
13
14LPCWSTR vcsSqlBinaryScriptQuery = L"SELECT `Data` FROM `Binary` WHERE `Name`=?";
15enum eSqlBinaryScriptQuery { ssbsqData = 1 };
16
17
18// prototypes for private helper functions
19static HRESULT NewSqlStr(
20 __out SCA_SQLSTR** ppsss
21 );
22static SCA_SQLSTR* AddSqlStrToList(
23 __in SCA_SQLSTR* psssList,
24 __in SCA_SQLSTR* psss
25 );
26static HRESULT ExecuteStrings(
27 __in SCA_DB* psdList,
28 __in SCA_SQLSTR* psssList,
29 __in BOOL fInstall
30 );
31
32HRESULT ScaSqlStrsRead(
33 __inout SCA_SQLSTR** ppsssList,
34 __in SCA_ACTION saAction
35 )
36{
37 HRESULT hr = S_OK;
38 UINT er = ERROR_SUCCESS;
39 PMSIHANDLE hView, hRec;
40 PMSIHANDLE hViewUser, hRecUser;
41
42 LPWSTR pwzComponent = NULL;
43 LPWSTR pwzData = NULL;
44
45 SCA_SQLSTR* psss = NULL;
46
47 if (S_OK != WcaTableExists(L"Wix4SqlString") || S_OK != WcaTableExists(L"Wix4SqlDatabase"))
48 {
49 WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsRead() - Wix4SqlString and/or Wix4SqlDatabase table not present");
50 ExitFunction1(hr = S_FALSE);
51 }
52
53 // loop through all the sql strings
54 hr = WcaOpenExecuteView(vcsSqlStringQuery, &hView);
55 ExitOnFailure(hr, "Failed to open view on Wix4SqlString table");
56 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
57 {
58 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
59 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
60
61 hr = WcaGetRecordString(hRec, ssqComponent, &pwzComponent);
62 ExitOnFailure(hr, "Failed to get Component for SQL String.");
63
64 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction);
65 hr = HRESULT_FROM_WIN32(er);
66 ExitOnFailure(hr, "Failed to get state for component: %ls", pwzComponent);
67
68 // If we're doing install but the Component is not being installed or we're doing
69 // uninstall but the Component is not being uninstalled, skip it.
70 if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) ||
71 (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction))
72 {
73 continue;
74 }
75
76 hr = NewSqlStr(&psss);
77 ExitOnFailure(hr, "failed to allocation new sql string element");
78
79 psss->isInstalled = isInstalled;
80 psss->isAction = isAction;
81
82 hr = WcaGetRecordString(hRec, ssqSqlString, &pwzData);
83 ExitOnFailure(hr, "Failed to get Wix4SqlString.String");
84 hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), pwzData);
85 ExitOnFailure(hr, "Failed to copy Wix4SqlString.String: %ls", pwzData);
86
87 // find the database information for this string
88 hr = WcaGetRecordString(hRec, ssqSqlDb, &pwzData);
89 ExitOnFailure(hr, "Failed to get Wix4SqlString.SqlDb_ for SqlString '%ls'", psss->wzKey);
90 hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), pwzData);
91 ExitOnFailure(hr, "Failed to copy Wix4SqlString.SqlDb_: %ls", pwzData);
92
93 hr = WcaGetRecordInteger(hRec, ssqAttributes, &psss->iAttributes);
94 ExitOnFailure(hr, "Failed to get Wix4SqlString.Attributes for SqlString '%ls'", psss->wzKey);
95
96 //get the sequence number for the string (note that this will be sequenced with scripts too)
97 hr = WcaGetRecordInteger(hRec, ssqSequence, &psss->iSequence);
98 ExitOnFailure(hr, "Failed to get Wix4SqlString.Sequence for SqlString '%ls'", psss->wzKey);
99
100 // execute SQL
101 hr = WcaGetRecordFormattedString(hRec, ssqSQL, &pwzData);
102 ExitOnFailure(hr, "Failed to get Wix4SqlString.SQL for SQL string '%ls'", psss->wzKey);
103
104 Assert(!psss->pwzSql);
105 hr = StrAllocString(&psss->pwzSql, pwzData, 0);
106 ExitOnFailure(hr, "Failed to alloc string for SQL string '%ls'", psss->wzKey);
107
108 *ppsssList = AddSqlStrToList(*ppsssList, psss);
109 psss = NULL; // set the sss to NULL so it doesn't get freed below
110 }
111
112 if (E_NOMOREITEMS == hr)
113 {
114 hr = S_OK;
115 }
116 ExitOnFailure(hr, "Failure occured while reading Wix4SqlString table");
117
118LExit:
119 // if anything was left over after an error clean it all up
120 if (psss)
121 {
122 ScaSqlStrsFreeList(psss);
123 }
124
125 ReleaseStr(pwzData);
126 ReleaseStr(pwzComponent);
127
128 return hr;
129}
130
131
132HRESULT ScaSqlStrsReadScripts(
133 __inout SCA_SQLSTR** ppsssList,
134 __in SCA_ACTION saAction
135 )
136{
137 HRESULT hr = S_OK;
138 UINT er = ERROR_SUCCESS;
139
140 PMSIHANDLE hView, hRec;
141 PMSIHANDLE hViewBinary, hRecBinary;
142 PMSIHANDLE hViewUser, hRecUser;
143
144 LPWSTR pwzComponent = NULL;
145 LPWSTR pwzData = NULL;
146
147 BYTE* pbScript = NULL;
148 DWORD cbRead = 0;
149 DWORD cbScript = 0;
150 DWORD cchScript = 0;
151
152 LPWSTR pwzScriptBuffer = NULL;
153 WCHAR* pwzScript = NULL;
154 WCHAR* pwz;
155 DWORD cch = 0;
156
157 SCA_SQLSTR sss;
158 SCA_SQLSTR* psss = NULL;
159
160 if (S_OK != WcaTableExists(L"Wix4SqlScript") || S_OK != WcaTableExists(L"Wix4SqlDatabase") || S_OK != WcaTableExists(L"Binary"))
161 {
162 WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsReadScripts() - Wix4SqlScript and/or Wix4SqlDatabase table not present");
163 ExitFunction1(hr = S_FALSE);
164 }
165
166 // open a view on the binary table
167 hr = WcaOpenView(vcsSqlBinaryScriptQuery, &hViewBinary);
168 ExitOnFailure(hr, "Failed to open view on Binary table for SQL scripts");
169
170 // loop through all the sql scripts
171 hr = WcaOpenExecuteView(vcsSqlScriptQuery, &hView);
172 ExitOnFailure(hr, "Failed to open view on Wix4SqlScript table");
173 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
174 {
175 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
176 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
177
178 hr = WcaGetRecordString(hRec, sscrqComponent, &pwzComponent);
179 ExitOnFailure(hr, "Failed to get Component for SQL Script.");
180
181 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction);
182 hr = HRESULT_FROM_WIN32(er);
183 ExitOnFailure(hr, "Failed to get state for component: %ls", pwzComponent);
184
185 // If we're doing install but the Component is not being installed or we're doing
186 // uninstall but the Component is not being uninstalled, skip it.
187 if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) ||
188 (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction))
189 {
190 continue;
191 }
192
193 ::ZeroMemory(&sss, sizeof(sss));
194
195 sss.isInstalled = isInstalled;
196 sss.isAction = isAction;
197
198 hr = WcaGetRecordString(hRec, sscrqSqlScript, &pwzData);
199 ExitOnFailure(hr, "Failed to get Wix4SqlScript.Script");
200 hr = ::StringCchCopyW(sss.wzKey, countof(sss.wzKey), pwzData);
201 ExitOnFailure(hr, "Failed to copy Wix4SqlScript.Script: %ls", pwzData);
202
203 // find the database information for this string
204 hr = WcaGetRecordString(hRec, sscrqSqlDb, &pwzData);
205 ExitOnFailure(hr, "Failed to get Wix4SqlScript.SqlDb_ for SqlScript '%ls'", sss.wzKey);
206 hr = ::StringCchCopyW(sss.wzSqlDb, countof(sss.wzSqlDb), pwzData);
207 ExitOnFailure(hr, "Failed to copy Wix4SqlScript.SqlDbb: %ls", pwzData);
208
209 hr = WcaGetRecordInteger(hRec, sscrqAttributes, &sss.iAttributes);
210 ExitOnFailure(hr, "Failed to get Wix4SqlScript.Attributes for SqlScript '%ls'", sss.wzKey);
211
212 hr = WcaGetRecordInteger(hRec, sscrqSequence, &sss.iSequence);
213 ExitOnFailure(hr, "Failed to get Wix4SqlScript.Sequence for SqlScript '%ls'", sss.wzKey);
214
215 // get the sql script out of the binary stream
216 hr = WcaExecuteView(hViewBinary, hRec);
217 ExitOnFailure(hr, "Failed to open Wix4SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey);
218 hr = WcaFetchSingleRecord(hViewBinary, &hRecBinary);
219 ExitOnFailure(hr, "Failed to fetch Wix4SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey);
220
221 // Note: We need to allocate an extra character on the stream to NULL terminate the SQL script.
222 // The WcaGetRecordStream() function won't let us add extra space on the end of the stream
223 // so we'll read the stream "the old fashioned way".
224 //hr = WcaGetRecordStream(hRecBinary, ssbsqData, (BYTE**)&pbScript, &cbScript);
225 //ExitOnFailure(hr, "Failed to read Wix4SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey);
226 er = ::MsiRecordReadStream(hRecBinary, ssbsqData, NULL, &cbRead);
227 hr = HRESULT_FROM_WIN32(er);
228 ExitOnFailure(hr, "failed to get size of stream");
229
230 cbScript = cbRead + sizeof(WCHAR); // we may have an ANSI SQL script but leave enough to even NULL terminate a WCHAR string
231 hr = WcaAllocStream(&pbScript, cbScript); // this will allocate a fully zeroed out buffer so our string will be NULL terminated
232 ExitOnFailure(hr, "failed to allocate data for stream");
233
234 er = ::MsiRecordReadStream(hRecBinary, ssbsqData, reinterpret_cast<char*>(pbScript), &cbRead); //read the buffer but leave the space for the NULL terminator
235 hr = HRESULT_FROM_WIN32(er);
236 ExitOnFailure(hr, "failed to read from stream");
237
238 Assert(cbRead + sizeof(WCHAR) == cbScript);
239
240 // Check for the UNICODE BOM file marker.
241 if ((0xFF == *pbScript) && (0xFE == *(pbScript + 1)))
242 {
243 // Copy the UNICODE string after the BOM marker (subtract one because we'll skip the BOM marker).
244 cchScript = (cbScript / sizeof(WCHAR)) - 1;
245
246 hr = StrAllocString(&pwzScriptBuffer, reinterpret_cast<LPWSTR>(pbScript) + 1, 0);
247 ExitOnFailure(hr, "Failed to allocate WCHAR string of size '%d'", cchScript);
248 }
249 else
250 {
251 // We have an ANSI string so convert it to UNICODE.
252 cchScript = cbScript;
253
254 hr = StrAllocStringAnsi(&pwzScriptBuffer, reinterpret_cast<LPCSTR>(pbScript), 0, CP_ACP);
255 ExitOnFailure(hr, "Failed to allocate WCHAR string of size '%d'", cchScript);
256 }
257
258 // Free the byte buffer since it has been converted to a new UNICODE string, one way or another.
259 if (pbScript)
260 {
261 WcaFreeStream(pbScript);
262 pbScript = NULL;
263 }
264
265 // Process the SQL script stripping out unnecessary stuff (like comments) and looking for "GO" statements.
266 pwzScript = pwzScriptBuffer;
267 while (cchScript && pwzScript && *pwzScript)
268 {
269 // strip off leading whitespace
270 while (cchScript && *pwzScript && iswspace(*pwzScript))
271 {
272 ++pwzScript;
273 --cchScript;
274 }
275
276 Assert(0 <= cchScript);
277
278 // if there is a SQL comment remove it
279 while (cchScript && L'/' == *pwzScript && L'*' == *(pwzScript + 1))
280 {
281 // go until end of comment
282 while (cchScript && *pwzScript && *(pwzScript + 1) && !(L'*' == *pwzScript && L'/' == *(pwzScript + 1)))
283 {
284 ++pwzScript;
285 --cchScript;
286 }
287
288 Assert(2 <= cchScript);
289
290 if (2 <= cchScript)
291 {
292 // to account for */ at end
293 pwzScript+=2;
294 cchScript-=2;
295 }
296
297 Assert(0 <= cchScript);
298
299 // strip off any new leading whitespace
300 while (cchScript && *pwzScript && iswspace(*pwzScript))
301 {
302 ++pwzScript;
303 --cchScript;
304 }
305 }
306
307 while (cchScript && L'-' == *pwzScript && L'-' == *(pwzScript + 1))
308 {
309 // go past the new line character
310 while (cchScript && *pwzScript && L'\n' != *pwzScript)
311 {
312 ++pwzScript;
313 --cchScript;
314 }
315
316 Assert(0 <= cchScript);
317
318 if (cchScript && L'\n' == *pwzScript)
319 {
320 ++pwzScript;
321 --cchScript;
322 }
323
324 Assert(0 <= cchScript);
325
326 // strip off any new leading whitespace
327 while (cchScript && *pwzScript && iswspace(*pwzScript))
328 {
329 ++pwzScript;
330 --cchScript;
331 }
332 }
333
334 Assert(0 <= cchScript);
335
336 // try to isolate a "GO" keyword and count the characters in the SQL string
337 pwz = pwzScript;
338 cch = 0;
339 while (cchScript && *pwz)
340 {
341 //skip past comment lines that might have "go" in them
342 //note that these comments are "in the middle" of our function,
343 //or possibly at the end of a line
344 if (cchScript && L'-' == *pwz && L'-' == *(pwz + 1))
345 {
346 // skip past chars until the new line character
347 while (cchScript && *pwz && (L'\n' != *pwz))
348 {
349 ++pwz;
350 ++cch;
351 --cchScript;
352 }
353 }
354
355 //skip past comment lines of form /* to */ that might have "go" in them
356 //note that these comments are "in the middle" of our function,
357 //or possibly at the end of a line
358 if (cchScript && L'/' == *pwz && L'*' == *(pwz + 1))
359 {
360 // skip past chars until the new line character
361 while (cchScript && *pwz && *(pwz + 1) && !((L'*' == *pwz) && (L'/' == *(pwz + 1))))
362 {
363 ++pwz;
364 ++cch;
365 --cchScript;
366 }
367
368 if (2 <= cchScript)
369 {
370 // to account for */ at end
371 pwz+=2;
372 cch+=2;
373 cchScript-=2;
374 }
375 }
376
377 // Skip past strings that may be part of the SQL statement that might have a "go" in them
378 if ( cchScript && L'\'' == *pwz )
379 {
380 ++pwz;
381 ++cch;
382 --cchScript;
383
384 // Skip past chars until the end of the string
385 while ( cchScript && *pwz && !(L'\'' == *pwz) )
386 {
387 ++pwz;
388 ++cch;
389 --cchScript;
390 }
391 }
392
393 // Skip past strings that may be part of the SQL statement that might have a "go" in them
394 if ( cchScript && L'\"' == *pwz )
395 {
396 ++pwz;
397 ++cch;
398 --cchScript;
399
400 // Skip past chars until the end of the string
401 while ( cchScript && *pwz && !(L'\"' == *pwz) )
402 {
403 ++pwz;
404 ++cch;
405 --cchScript;
406 }
407 }
408
409 // if "GO" is isolated
410 if ((pwzScript == pwz || iswspace(*(pwz - 1))) &&
411 (L'G' == *pwz || L'g' == *pwz) &&
412 (L'O' == *(pwz + 1) || L'o' == *(pwz + 1)) &&
413 (0 == *(pwz + 2) || iswspace(*(pwz + 2))))
414 {
415 *pwz = 0; // null terminate the SQL string on the "G"
416 pwz += 2;
417 cchScript -= 2;
418 break; // found "GO" now add SQL string to list
419 }
420
421 ++pwz;
422 ++cch;
423 --cchScript;
424 }
425
426 Assert(0 <= cchScript);
427
428 if (0 < cch) //don't process if there's nothing to process
429 {
430 // replace tabs with spaces
431 for (LPWSTR pwzTab = wcsstr(pwzScript, L"\t"); pwzTab; pwzTab = wcsstr(pwzTab, L"\t"))
432 *pwzTab = ' ';
433
434 // strip off whitespace at the end of the script string
435 for (LPWSTR pwzErase = pwzScript + cch - 1; pwzScript < pwzErase && iswspace(*pwzErase); pwzErase--)
436 {
437 *(pwzErase) = 0;
438 cch--;
439 }
440 }
441
442 if (0 < cch)
443 {
444 hr = NewSqlStr(&psss);
445 ExitOnFailure(hr, "failed to allocate new sql string element");
446
447 // copy everything over
448 hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), sss.wzKey);
449 ExitOnFailure(hr, "Failed to copy key string to sqlstr object");
450 hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), sss.wzSqlDb);
451 ExitOnFailure(hr, "Failed to copy DB string to sqlstr object");
452 hr = ::StringCchCopyW(psss->wzComponent, countof(psss->wzComponent), sss.wzComponent);
453 ExitOnFailure(hr, "Failed to copy component string to sqlstr object");
454 psss->isInstalled = sss.isInstalled;
455 psss->isAction = sss.isAction;
456 psss->iAttributes = sss.iAttributes;
457 psss->iSequence = sss.iSequence;
458
459 // cchRequired includes the NULL terminating char
460 hr = StrAllocString(&psss->pwzSql, pwzScript, 0);
461 ExitOnFailure(hr, "Failed to allocate string for SQL script: '%ls'", psss->wzKey);
462
463 *ppsssList = AddSqlStrToList(*ppsssList, psss);
464 psss = NULL; // set the db NULL so it doesn't accidentally get freed below
465 }
466
467 pwzScript = pwz;
468 }
469 }
470
471 if (E_NOMOREITEMS == hr)
472 {
473 hr = S_OK;
474 }
475 ExitOnFailure(hr, "Failure occured while reading Wix4SqlScript table");
476
477LExit:
478 // if anything was left over after an error clean it all up
479 if (psss)
480 {
481 ScaSqlStrsFreeList(psss);
482 }
483
484 if (pbScript)
485 {
486 WcaFreeStream(pbScript);
487 }
488
489 ReleaseStr(pwzScriptBuffer);
490 ReleaseStr(pwzData);
491 ReleaseStr(pwzComponent);
492
493 return hr;
494}
495
496
497HRESULT ScaSqlStrsInstall(
498 __in SCA_DB* psdList,
499 __in SCA_SQLSTR* psssList
500 )
501{
502 HRESULT hr = ExecuteStrings(psdList, psssList, TRUE);
503
504 return hr;
505}
506
507
508HRESULT ScaSqlStrsUninstall(
509 __in SCA_DB* psdList,
510 __in SCA_SQLSTR* psssList
511 )
512{
513 HRESULT hr = ExecuteStrings(psdList, psssList, FALSE);
514
515 return hr;
516}
517
518
519void ScaSqlStrsFreeList(
520 __in SCA_SQLSTR* psssList
521 )
522{
523 SCA_SQLSTR* psssDelete = psssList;
524 while (psssList)
525 {
526 psssDelete = psssList;
527 psssList = psssList->psssNext;
528
529 if (psssDelete->pwzSql)
530 {
531 ReleaseStr(psssDelete->pwzSql);
532 }
533
534 MemFree(psssDelete);
535 }
536}
537
538
539// private helper functions
540
541static HRESULT NewSqlStr(
542 __out SCA_SQLSTR** ppsss
543 )
544{
545 HRESULT hr = S_OK;
546 SCA_SQLSTR* psss = static_cast<SCA_SQLSTR*>(MemAlloc(sizeof(SCA_SQLSTR), TRUE));
547 ExitOnNull(psss, hr, E_OUTOFMEMORY, "failed to allocate memory for new sql string element");
548
549 *ppsss = psss;
550
551LExit:
552 return hr;
553}
554
555
556static SCA_SQLSTR* AddSqlStrToList(
557 __in SCA_SQLSTR* psssList,
558 __in SCA_SQLSTR* psss
559 )
560{
561 Assert(psss); //just checking
562
563 //make certain we have a valid sequence number; note that negatives are technically valid
564 if (MSI_NULL_INTEGER == psss->iSequence)
565 {
566 psss->iSequence = 0;
567 }
568
569 if (psssList)
570 {
571 //list already exists, so insert psss into the list in Sequence order
572
573 //see if we need to change the head, otherwise figure out where in the order it fits
574 if (psss->iSequence < psssList->iSequence)
575 {
576 psss->psssNext = psssList;
577 psssList = psss;
578 }
579 else
580 {
581 SCA_SQLSTR* psssT = psssList;
582 //note that if Sequence numbers are duplicated, as in the case of a sqlscript,
583 //we need to insert them "at the end" of the group so the sqlfile stays in order
584 while (psssT->psssNext && (psssT->psssNext->iSequence <= psss->iSequence))
585 {
586 psssT = psssT->psssNext;
587 }
588
589 //insert our new psss AFTER psssT
590 psss->psssNext = psssT->psssNext;
591 psssT->psssNext = psss;
592 }
593 }
594 else
595 {
596 psssList = psss;
597 }
598
599 return psssList;
600}
601
602
603static HRESULT ExecuteStrings(
604 __in SCA_DB* psdList,
605 __in SCA_SQLSTR* psssList,
606 __in BOOL fInstall
607 )
608{
609 HRESULT hr = S_FALSE; // assume nothing will be done
610
611 int iRollback = -1;
612 int iOldRollback = iRollback;
613
614 LPCWSTR wzOldDb = NULL;
615 UINT uiCost = 0;
616 WCHAR* pwzCustomActionData = NULL;
617 WCHAR wzNumber[64];
618
619 // loop through all sql strings
620 for (SCA_SQLSTR* psss = psssList; psss; psss = psss->psssNext)
621 {
622 // if installing this component
623 if ((fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_INSTALL) && WcaIsInstalling(psss->isInstalled, psss->isAction) && !WcaIsReInstalling(psss->isInstalled, psss->isAction)) ||
624 (fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_REINSTALL) && WcaIsReInstalling(psss->isInstalled, psss->isAction)) ||
625 (!fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_UNINSTALL) && WcaIsUninstalling(psss->isInstalled, psss->isAction)))
626 {
627 // determine if this is a rollback scheduling or normal deferred scheduling
628 if (psss->iAttributes & SCASQL_ROLLBACK)
629 {
630 iRollback = 1;
631 }
632 else
633 {
634 iRollback = 0;
635 }
636
637 // if we need to create a connection to a new server\database
638 if (!wzOldDb || 0 != lstrcmpW(wzOldDb, psss->wzSqlDb) || iOldRollback != iRollback)
639 {
640 const SCA_DB* psd = ScaDbsFindDatabase(psss->wzSqlDb, psdList);
641 if (!psd)
642 {
643 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "failed to find data for Database: %ls", psss->wzSqlDb);
644 }
645
646 if (-1 == iOldRollback)
647 {
648 iOldRollback = iRollback;
649 }
650 Assert(0 == iOldRollback || 1 == iOldRollback);
651
652 // if there was custom action data before, schedule the action to write it
653 if (pwzCustomActionData && *pwzCustomActionData)
654 {
655 Assert(pwzCustomActionData && *pwzCustomActionData && uiCost);
656
657 hr = WcaDoDeferredAction(1 == iOldRollback ? CUSTOM_ACTION_DECORATION(L"RollbackExecuteSqlStrings") : CUSTOM_ACTION_DECORATION(L"ExecuteSqlStrings"), pwzCustomActionData, uiCost);
658 ExitOnFailure(hr, "failed to schedule ExecuteSqlStrings action, rollback: %d", iOldRollback);
659 iOldRollback = iRollback;
660
661 *pwzCustomActionData = L'\0';
662 uiCost = 0;
663 }
664
665 Assert(!pwzCustomActionData || (pwzCustomActionData && 0 == *pwzCustomActionData) && 0 == uiCost);
666
667 hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData);
668 ExitOnFailure(hr, "Failed to add SQL Server Database String to CustomActionData for Database String: %ls", psd->wzKey);
669
670 hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData);
671 ExitOnFailure(hr, "Failed to add SQL Server to CustomActionData for Database String: %ls", psd->wzKey);
672
673 hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData);
674 ExitOnFailure(hr, "Failed to add SQL Instance to CustomActionData for Database String: %ls", psd->wzKey);
675
676 hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData);
677 ExitOnFailure(hr, "Failed to add SQL Database to CustomActionData for Database String: %ls", psd->wzKey);
678
679 hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->iAttributes);
680 ExitOnFailure(hr, "Failed to format attributes integer value to string");
681 hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData);
682 ExitOnFailure(hr, "Failed to add SQL Attributes to CustomActionData for Database String: %ls", psd->wzKey);
683
684 hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->fUseIntegratedAuth);
685 ExitOnFailure(hr, "Failed to format UseIntegratedAuth integer value to string");
686 hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData);
687 ExitOnFailure(hr, "Failed to add SQL IntegratedAuth flag to CustomActionData for Database String: %ls", psd->wzKey);
688
689 hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData);
690 ExitOnFailure(hr, "Failed to add SQL UserName to CustomActionData for Database String: %ls", psd->wzKey);
691
692 hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData);
693 ExitOnFailure(hr, "Failed to add SQL Password to CustomActionData for Database String: %ls", psd->wzKey);
694
695 uiCost += COST_SQL_CONNECTDB;
696
697 wzOldDb = psss->wzSqlDb;
698 }
699
700 WcaLog(LOGMSG_VERBOSE, "Scheduling SQL string: %ls", psss->pwzSql);
701
702 hr = WcaWriteStringToCaData(psss->wzKey, &pwzCustomActionData);
703 ExitOnFailure(hr, "Failed to add SQL Key to CustomActionData for SQL string: %ls", psss->wzKey);
704
705 hr = WcaWriteIntegerToCaData(psss->iAttributes, &pwzCustomActionData);
706 ExitOnFailure(hr, "failed to add attributes to CustomActionData for SQL string: %ls", psss->wzKey);
707
708 hr = WcaWriteStringToCaData(psss->pwzSql, &pwzCustomActionData);
709 ExitOnFailure(hr, "Failed to to add SQL Query to CustomActionData for SQL string: %ls", psss->wzKey);
710 uiCost += COST_SQL_STRING;
711 }
712 }
713
714 if (pwzCustomActionData && *pwzCustomActionData)
715 {
716 Assert(pwzCustomActionData && *pwzCustomActionData && uiCost);
717 hr = WcaDoDeferredAction(1 == iRollback ? CUSTOM_ACTION_DECORATION(L"RollbackExecuteSqlStrings") : CUSTOM_ACTION_DECORATION(L"ExecuteSqlStrings"), pwzCustomActionData, uiCost);
718 ExitOnFailure(hr, "Failed to schedule ExecuteSqlStrings action");
719
720 *pwzCustomActionData = L'\0';
721 uiCost = 0;
722 }
723
724LExit:
725 ReleaseStr(pwzCustomActionData);
726
727 return hr;
728}