aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Sql/wixext/SqlCompiler.cs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-05-04 22:50:16 -0700
committerRob Mensching <rob@firegiant.com>2021-05-04 22:50:16 -0700
commite713e6695bd531d1021482d454401b86c84f3f2d (patch)
treebf76f3a6a411edd1c4b47f3a54625f7f1023e95b /src/ext/Sql/wixext/SqlCompiler.cs
parent2977d0ffabcd6d68790e711736d2edd1fe0cc0af (diff)
downloadwix-e713e6695bd531d1021482d454401b86c84f3f2d.tar.gz
wix-e713e6695bd531d1021482d454401b86c84f3f2d.tar.bz2
wix-e713e6695bd531d1021482d454401b86c84f3f2d.zip
Move Sql.wixext into ext
Diffstat (limited to 'src/ext/Sql/wixext/SqlCompiler.cs')
-rw-r--r--src/ext/Sql/wixext/SqlCompiler.cs804
1 files changed, 804 insertions, 0 deletions
diff --git a/src/ext/Sql/wixext/SqlCompiler.cs b/src/ext/Sql/wixext/SqlCompiler.cs
new file mode 100644
index 00000000..46196e95
--- /dev/null
+++ b/src/ext/Sql/wixext/SqlCompiler.cs
@@ -0,0 +1,804 @@
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
3namespace WixToolset.Sql
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Xml.Linq;
8 using WixToolset.Data;
9 using WixToolset.Extensibility;
10 using WixToolset.Extensibility.Data;
11 using WixToolset.Sql.Symbols;
12
13 /// <summary>
14 /// The compiler for the WiX Toolset SQL Server Extension.
15 /// </summary>
16 public sealed class SqlCompiler : BaseCompilerExtension
17 {
18 // sql database attributes definitions (from sca.h)
19 internal const int DbCreateOnInstall = 0x00000001;
20 internal const int DbDropOnUninstall = 0x00000002;
21 internal const int DbContinueOnError = 0x00000004;
22 internal const int DbDropOnInstall = 0x00000008;
23 internal const int DbCreateOnUninstall = 0x00000010;
24 internal const int DbConfirmOverwrite = 0x00000020;
25 internal const int DbCreateOnReinstall = 0x00000040;
26 internal const int DbDropOnReinstall = 0x00000080;
27
28 // sql string/script attributes definitions (from sca.h)
29 internal const int SqlExecuteOnInstall = 0x00000001;
30 internal const int SqlExecuteOnUninstall = 0x00000002;
31 internal const int SqlContinueOnError = 0x00000004;
32 internal const int SqlRollback = 0x00000008;
33 internal const int SqlExecuteOnReinstall = 0x00000010;
34
35 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/sql";
36
37 /// <summary>
38 /// Processes an element for the Compiler.
39 /// </summary>
40 /// <param name="intermediate"></param>
41 /// <param name="section"></param>
42 /// <param name="parentElement">Parent element of element to process.</param>
43 /// <param name="element">Element to process.</param>
44 /// <param name="context">Extra information about the context in which this element is being parsed.</param>
45 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
46 {
47 switch (parentElement.Name.LocalName)
48 {
49 case "Component":
50 var componentId = context["ComponentId"];
51
52 switch (element.Name.LocalName)
53 {
54 case "SqlDatabase":
55 this.ParseSqlDatabaseElement(intermediate, section, element, componentId);
56 break;
57 case "SqlScript":
58 this.ParseSqlScriptElement(intermediate, section, element, componentId, null);
59 break;
60 case "SqlString":
61 this.ParseSqlStringElement(intermediate, section, element, componentId, null);
62 break;
63 default:
64 this.ParseHelper.UnexpectedElement(parentElement, element);
65 break;
66 }
67 break;
68 case "Fragment":
69 case "Module":
70 case "Package":
71 switch (element.Name.LocalName)
72 {
73 case "SqlDatabase":
74 this.ParseSqlDatabaseElement(intermediate, section, element, null);
75 break;
76 default:
77 this.ParseHelper.UnexpectedElement(parentElement, element);
78 break;
79 }
80 break;
81 default:
82 this.ParseHelper.UnexpectedElement(parentElement, element);
83 break;
84 }
85 }
86
87 /// <summary>
88 /// Parses a sql database element
89 /// </summary>
90 /// <param name="intermediate"></param>
91 /// <param name="section"></param>
92 /// <param name="element">Element to parse.</param>
93 /// <param name="componentId">Identifier for parent component.</param>
94 private void ParseSqlDatabaseElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
95 {
96 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
97 Identifier id = null;
98 int attributes = 0;
99 string database = null;
100 Identifier fileSpec = null;
101 string instance = null;
102 Identifier logFileSpec = null;
103 string server = null;
104 string user = null;
105
106 foreach (var attrib in element.Attributes())
107 {
108 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
109 {
110 switch (attrib.Name.LocalName)
111 {
112 case "Id":
113 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
114 break;
115 case "ConfirmOverwrite":
116 if (null == componentId)
117 {
118 this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
119 }
120
121 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
122 {
123 attributes |= DbConfirmOverwrite;
124 }
125 break;
126 case "ContinueOnError":
127 if (null == componentId)
128 {
129 this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
130 }
131
132 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
133 {
134 attributes |= DbContinueOnError;
135 }
136 break;
137 case "CreateOnInstall":
138 if (null == componentId)
139 {
140 this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
141 }
142
143 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
144 {
145 attributes |= DbCreateOnInstall;
146 }
147 break;
148 case "CreateOnReinstall":
149 if (null == componentId)
150 {
151 this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
152 }
153
154 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
155 {
156 attributes |= DbCreateOnReinstall;
157 }
158 break;
159 case "CreateOnUninstall":
160 if (null == componentId)
161 {
162 this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
163 }
164
165 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
166 {
167 attributes |= DbCreateOnUninstall;
168 }
169 break;
170 case "Database":
171 database = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
172 break;
173 case "DropOnInstall":
174 if (null == componentId)
175 {
176 this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
177 }
178
179 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
180 {
181 attributes |= DbDropOnInstall;
182 }
183 break;
184 case "DropOnReinstall":
185 if (null == componentId)
186 {
187 this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
188 }
189
190 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
191 {
192 attributes |= DbDropOnReinstall;
193 }
194 break;
195
196 case "DropOnUninstall":
197 if (null == componentId)
198 {
199 this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
200 }
201
202 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
203 {
204 attributes |= DbDropOnUninstall;
205 }
206 break;
207 case "Instance":
208 instance = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
209 break;
210 case "Server":
211 server = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
212 break;
213 case "User":
214 user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
215 if (!this.ParseHelper.ContainsProperty(user))
216 {
217 user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
218 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user);
219 }
220 break;
221 default:
222 this.ParseHelper.UnexpectedAttribute(element, attrib);
223 break;
224 }
225 }
226 else
227 {
228 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
229 }
230 }
231
232 if (null == id)
233 {
234 id = this.ParseHelper.CreateIdentifier("sdb", componentId, server, database);
235 }
236
237 if (null == database)
238 {
239 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Database"));
240 }
241 else if (128 < database.Length)
242 {
243 this.Messaging.Write(ErrorMessages.IdentifierTooLongError(sourceLineNumbers, element.Name.LocalName, "Database", database, 128));
244 }
245
246 if (null == server)
247 {
248 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Server"));
249 }
250
251 if (0 == attributes && null != componentId)
252 {
253 this.Messaging.Write(SqlErrors.OneOfAttributesRequiredUnderComponent(sourceLineNumbers, element.Name.LocalName, "CreateOnInstall", "CreateOnUninstall", "DropOnInstall", "DropOnUninstall"));
254 }
255
256 foreach (var child in element.Elements())
257 {
258 if (this.Namespace == child.Name.Namespace)
259 {
260 var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
261 switch (child.Name.LocalName)
262 {
263 case "SqlScript":
264 if (null == componentId)
265 {
266 this.Messaging.Write(SqlErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
267 }
268
269 this.ParseSqlScriptElement(intermediate, section, child, componentId, id?.Id);
270 break;
271 case "SqlString":
272 if (null == componentId)
273 {
274 this.Messaging.Write(SqlErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
275 }
276
277 this.ParseSqlStringElement(intermediate, section, child, componentId, id?.Id);
278 break;
279 case "SqlFileSpec":
280 if (null == componentId)
281 {
282 this.Messaging.Write(SqlErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
283 }
284 else if (null != fileSpec)
285 {
286 this.Messaging.Write(ErrorMessages.TooManyElements(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName, 1));
287 }
288
289 fileSpec = this.ParseSqlFileSpecElement(intermediate, section, child, id?.Id);
290 break;
291 case "SqlLogFileSpec":
292 if (null == componentId)
293 {
294 this.Messaging.Write(SqlErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
295 }
296 else if (null != logFileSpec)
297 {
298 this.Messaging.Write(ErrorMessages.TooManyElements(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName, 1));
299 }
300
301 logFileSpec = this.ParseSqlFileSpecElement(intermediate, section, child, id?.Id);
302 break;
303 default:
304 this.ParseHelper.UnexpectedElement(element, child);
305 break;
306 }
307 }
308 else
309 {
310 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
311 }
312 }
313
314 if (null != componentId)
315 {
316 // Reference InstallSqlData and UninstallSqlData since nothing will happen without it
317 this.AddReferenceToInstallSqlData(section, sourceLineNumbers);
318 }
319
320 if (!this.Messaging.EncounteredError)
321 {
322 var symbol = section.AddSymbol(new SqlDatabaseSymbol(sourceLineNumbers, id)
323 {
324 Server = server,
325 Instance = instance,
326 Database = database,
327 ComponentRef = componentId,
328 UserRef = user,
329 FileSpecRef = fileSpec?.Id,
330 LogFileSpecRef = logFileSpec?.Id,
331 });
332
333 if (0 != attributes)
334 {
335 symbol.Attributes = attributes;
336 }
337 }
338 }
339
340 /// <summary>
341 /// Parses a sql file specification element.
342 /// </summary>
343 /// <param name="intermediate"></param>
344 /// <param name="section"></param>
345 /// <param name="element">Element to parse.</param>
346 /// <returns>Identifier of sql file specification.</returns>
347 private Identifier ParseSqlFileSpecElement(Intermediate intermediate, IntermediateSection section, XElement element, string parentId)
348 {
349 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
350 Identifier id = null;
351 string fileName = null;
352 string growthSize = null;
353 string maxSize = null;
354 string name = null;
355 string size = null;
356
357 foreach (var attrib in element.Attributes())
358 {
359 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
360 {
361 switch (attrib.Name.LocalName)
362 {
363 case "Id":
364 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
365 break;
366 case "Name":
367 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
368 break;
369 case "Filename":
370 fileName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
371 break;
372 case "Size":
373 size = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
374 break;
375 case "MaxSize":
376 maxSize = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
377 break;
378 case "GrowthSize":
379 growthSize = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
380 break;
381 default:
382 this.ParseHelper.UnexpectedAttribute(element, attrib);
383 break;
384 }
385 }
386 else
387 {
388 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
389 }
390 }
391
392 if (null == id)
393 {
394 id = this.ParseHelper.CreateIdentifier("sfs", parentId, name, fileName);
395 }
396
397 if (null == name)
398 {
399 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
400 }
401
402 if (null == fileName)
403 {
404 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Filename"));
405 }
406
407 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
408
409 if (!this.Messaging.EncounteredError)
410 {
411 var symbol = section.AddSymbol(new SqlFileSpecSymbol(sourceLineNumbers, id)
412 {
413 Name = name,
414 Filename = fileName,
415 });
416
417 if (null != size)
418 {
419 symbol.Size = size;
420 }
421
422 if (null != maxSize)
423 {
424 symbol.MaxSize = maxSize;
425 }
426
427 if (null != growthSize)
428 {
429 symbol.GrowthSize = growthSize;
430 }
431 }
432
433 return id;
434 }
435
436 /// <summary>
437 /// Parses a sql script element.
438 /// </summary>
439 /// <param name="element">Element to parse.</param>
440 /// <param name="componentId">Identifier for parent component.</param>
441 /// <param name="sqlDb">Optional database to execute script against.</param>
442 private void ParseSqlScriptElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string sqlDb)
443 {
444 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
445 Identifier id = null;
446 int attributes = 0;
447 var rollbackAttribute = false;
448 var nonRollbackAttribute = false;
449 string binaryRef = null;
450 var sequence = CompilerConstants.IntegerNotSet;
451 string user = null;
452
453 foreach (var attrib in element.Attributes())
454 {
455 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
456 {
457 switch (attrib.Name.LocalName)
458 {
459 case "Id":
460 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
461 break;
462 case "BinaryRef":
463 binaryRef = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
464 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Binary, binaryRef);
465 break;
466 case "Sequence":
467 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue);
468 break;
469 case "SqlDb":
470 if (null != sqlDb)
471 {
472 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
473 }
474 sqlDb = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
475 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SqlSymbolDefinitions.SqlDatabase, sqlDb);
476 break;
477 case "User":
478 user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
479 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user);
480 break;
481
482 // Flag-setting attributes
483 case "ContinueOnError":
484 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
485 {
486 attributes |= SqlContinueOnError;
487 }
488 break;
489 case "ExecuteOnInstall":
490 if (rollbackAttribute)
491 {
492 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall"));
493 }
494 nonRollbackAttribute = true;
495
496 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
497 {
498 attributes |= SqlExecuteOnInstall;
499 }
500 break;
501 case "ExecuteOnReinstall":
502 if (rollbackAttribute)
503 {
504 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall"));
505 }
506 nonRollbackAttribute = true;
507
508 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
509 {
510 attributes |= SqlExecuteOnReinstall;
511 }
512 break;
513 case "ExecuteOnUninstall":
514 if (rollbackAttribute)
515 {
516 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall"));
517 }
518 nonRollbackAttribute = true;
519
520 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
521 {
522 attributes |= SqlExecuteOnUninstall;
523 }
524 break;
525 case "RollbackOnInstall":
526 if (nonRollbackAttribute)
527 {
528 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall"));
529 }
530 rollbackAttribute = true;
531
532 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
533 {
534 attributes |= SqlExecuteOnInstall;
535 attributes |= SqlRollback;
536 }
537 break;
538 case "RollbackOnReinstall":
539 if (nonRollbackAttribute)
540 {
541 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall"));
542 }
543 rollbackAttribute = true;
544
545 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
546 {
547 attributes |= SqlExecuteOnReinstall;
548 attributes |= SqlRollback;
549 }
550 break;
551 case "RollbackOnUninstall":
552 if (nonRollbackAttribute)
553 {
554 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall"));
555 }
556 rollbackAttribute = true;
557
558 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
559 {
560 attributes |= SqlExecuteOnUninstall;
561 attributes |= SqlRollback;
562 }
563 break;
564 default:
565 this.ParseHelper.UnexpectedAttribute(element, attrib);
566 break;
567 }
568 }
569 else
570 {
571 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
572 }
573 }
574
575 if (null == id)
576 {
577 id = this.ParseHelper.CreateIdentifier("ssc", componentId, binaryRef, sqlDb);
578 }
579
580 if (null == binaryRef)
581 {
582 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryRef"));
583 }
584
585 if (null == sqlDb)
586 {
587 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "SqlDb"));
588 }
589
590 if (0 == attributes)
591 {
592 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall", "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall"));
593 }
594
595 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
596
597 // Reference InstallSqlData and UninstallSqlData since nothing will happen without it
598 this.AddReferenceToInstallSqlData(section, sourceLineNumbers);
599
600 if (!this.Messaging.EncounteredError)
601 {
602 var symbol = section.AddSymbol(new SqlScriptSymbol(sourceLineNumbers, id)
603 {
604 SqlDbRef = sqlDb,
605 ComponentRef = componentId,
606 ScriptBinaryRef = binaryRef,
607 UserRef = user,
608 Attributes = attributes,
609 });
610
611 if (CompilerConstants.IntegerNotSet != sequence)
612 {
613 symbol.Sequence = sequence;
614 }
615 }
616 }
617
618 /// <summary>
619 /// Parses a sql string element.
620 /// </summary>
621 /// <param name="element">Element to parse.</param>
622 /// <param name="componentId">Identifier for parent component.</param>
623 /// <param name="sqlDb">Optional database to execute string against.</param>
624 private void ParseSqlStringElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string sqlDb)
625 {
626 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
627 Identifier id = null;
628 int attributes = 0;
629 var rollbackAttribute = false;
630 var nonRollbackAttribute = false;
631 var sequence = CompilerConstants.IntegerNotSet;
632 string sql = null;
633 string user = null;
634
635 foreach (var attrib in element.Attributes())
636 {
637 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
638 {
639 switch (attrib.Name.LocalName)
640 {
641 case "Id":
642 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
643 break;
644 case "ContinueOnError":
645 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
646 {
647 attributes |= SqlContinueOnError;
648 }
649 break;
650 case "ExecuteOnInstall":
651 if (rollbackAttribute)
652 {
653 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall"));
654 }
655 nonRollbackAttribute = true;
656
657 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
658 {
659 attributes |= SqlExecuteOnInstall;
660 }
661 break;
662 case "ExecuteOnReinstall":
663 if (rollbackAttribute)
664 {
665 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall"));
666 }
667 nonRollbackAttribute = true;
668
669 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
670 {
671 attributes |= SqlExecuteOnReinstall;
672 }
673 break;
674 case "ExecuteOnUninstall":
675 if (rollbackAttribute)
676 {
677 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall"));
678 }
679 nonRollbackAttribute = true;
680
681 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
682 {
683 attributes |= SqlExecuteOnUninstall;
684 }
685 break;
686 case "RollbackOnInstall":
687 if (nonRollbackAttribute)
688 {
689 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall"));
690 }
691 rollbackAttribute = true;
692
693 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
694 {
695 attributes |= SqlExecuteOnInstall;
696 attributes |= SqlRollback;
697 }
698 break;
699 case "RollbackOnReinstall":
700 if (nonRollbackAttribute)
701 {
702 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall"));
703 }
704 rollbackAttribute = true;
705
706 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
707 {
708 attributes |= SqlExecuteOnReinstall;
709 attributes |= SqlRollback;
710 }
711 break;
712 case "RollbackOnUninstall":
713 if (nonRollbackAttribute)
714 {
715 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall"));
716 }
717 rollbackAttribute = true;
718
719 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
720 {
721 attributes |= SqlExecuteOnUninstall;
722 attributes |= SqlRollback;
723 }
724 break;
725 case "Sequence":
726 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue);
727 break;
728 case "SQL":
729 sql = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
730 break;
731 case "SqlDb":
732 if (null != sqlDb)
733 {
734 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "SqlDb", "SqlDatabase"));
735 }
736
737 sqlDb = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
738 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SqlSymbolDefinitions.SqlDatabase, sqlDb);
739 break;
740 case "User":
741 user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
742 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user);
743 break;
744 default:
745 this.ParseHelper.UnexpectedAttribute(element, attrib);
746 break;
747 }
748 }
749 else
750 {
751 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
752 }
753 }
754
755 if (null == id)
756 {
757 id = this.ParseHelper.CreateIdentifier("sst", componentId, sql, sqlDb);
758 }
759
760 if (null == sql)
761 {
762 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "SQL"));
763 }
764
765 if (null == sqlDb)
766 {
767 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "SqlDb"));
768 }
769
770 if (0 == attributes)
771 {
772 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall", "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall"));
773 }
774
775 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
776
777 // Reference InstallSqlData and UninstallSqlData since nothing will happen without it
778 this.AddReferenceToInstallSqlData(section, sourceLineNumbers);
779
780 if (!this.Messaging.EncounteredError)
781 {
782 var symbol = section.AddSymbol(new SqlStringSymbol(sourceLineNumbers, id)
783 {
784 SqlDbRef = sqlDb,
785 ComponentRef = componentId,
786 SQL = sql,
787 UserRef = user,
788 Attributes = attributes,
789 });
790
791 if (CompilerConstants.IntegerNotSet != sequence)
792 {
793 symbol.Sequence = sequence;
794 }
795 }
796 }
797
798 private void AddReferenceToInstallSqlData(IntermediateSection section, SourceLineNumber sourceLineNumbers)
799 {
800 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4InstallSqlData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
801 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4UninstallSqlData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
802 }
803 }
804}