From e713e6695bd531d1021482d454401b86c84f3f2d Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Tue, 4 May 2021 22:50:16 -0700 Subject: Move Sql.wixext into ext --- src/ext/Sql/wixext/SqlCompiler.cs | 804 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 804 insertions(+) create mode 100644 src/ext/Sql/wixext/SqlCompiler.cs (limited to 'src/ext/Sql/wixext/SqlCompiler.cs') 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 @@ +// 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. + +namespace WixToolset.Sql +{ + using System; + using System.Collections.Generic; + using System.Xml.Linq; + using WixToolset.Data; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; + using WixToolset.Sql.Symbols; + + /// + /// The compiler for the WiX Toolset SQL Server Extension. + /// + public sealed class SqlCompiler : BaseCompilerExtension + { + // sql database attributes definitions (from sca.h) + internal const int DbCreateOnInstall = 0x00000001; + internal const int DbDropOnUninstall = 0x00000002; + internal const int DbContinueOnError = 0x00000004; + internal const int DbDropOnInstall = 0x00000008; + internal const int DbCreateOnUninstall = 0x00000010; + internal const int DbConfirmOverwrite = 0x00000020; + internal const int DbCreateOnReinstall = 0x00000040; + internal const int DbDropOnReinstall = 0x00000080; + + // sql string/script attributes definitions (from sca.h) + internal const int SqlExecuteOnInstall = 0x00000001; + internal const int SqlExecuteOnUninstall = 0x00000002; + internal const int SqlContinueOnError = 0x00000004; + internal const int SqlRollback = 0x00000008; + internal const int SqlExecuteOnReinstall = 0x00000010; + + public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/sql"; + + /// + /// Processes an element for the Compiler. + /// + /// + /// + /// Parent element of element to process. + /// Element to process. + /// Extra information about the context in which this element is being parsed. + public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context) + { + switch (parentElement.Name.LocalName) + { + case "Component": + var componentId = context["ComponentId"]; + + switch (element.Name.LocalName) + { + case "SqlDatabase": + this.ParseSqlDatabaseElement(intermediate, section, element, componentId); + break; + case "SqlScript": + this.ParseSqlScriptElement(intermediate, section, element, componentId, null); + break; + case "SqlString": + this.ParseSqlStringElement(intermediate, section, element, componentId, null); + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + case "Fragment": + case "Module": + case "Package": + switch (element.Name.LocalName) + { + case "SqlDatabase": + this.ParseSqlDatabaseElement(intermediate, section, element, null); + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + } + + /// + /// Parses a sql database element + /// + /// + /// + /// Element to parse. + /// Identifier for parent component. + private void ParseSqlDatabaseElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + int attributes = 0; + string database = null; + Identifier fileSpec = null; + string instance = null; + Identifier logFileSpec = null; + string server = null; + string user = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "ConfirmOverwrite": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= DbConfirmOverwrite; + } + break; + case "ContinueOnError": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= DbContinueOnError; + } + break; + case "CreateOnInstall": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= DbCreateOnInstall; + } + break; + case "CreateOnReinstall": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= DbCreateOnReinstall; + } + break; + case "CreateOnUninstall": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= DbCreateOnUninstall; + } + break; + case "Database": + database = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "DropOnInstall": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= DbDropOnInstall; + } + break; + case "DropOnReinstall": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= DbDropOnReinstall; + } + break; + + case "DropOnUninstall": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= DbDropOnUninstall; + } + break; + case "Instance": + instance = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Server": + server = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "User": + user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + if (!this.ParseHelper.ContainsProperty(user)) + { + user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user); + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("sdb", componentId, server, database); + } + + if (null == database) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Database")); + } + else if (128 < database.Length) + { + this.Messaging.Write(ErrorMessages.IdentifierTooLongError(sourceLineNumbers, element.Name.LocalName, "Database", database, 128)); + } + + if (null == server) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Server")); + } + + if (0 == attributes && null != componentId) + { + this.Messaging.Write(SqlErrors.OneOfAttributesRequiredUnderComponent(sourceLineNumbers, element.Name.LocalName, "CreateOnInstall", "CreateOnUninstall", "DropOnInstall", "DropOnUninstall")); + } + + foreach (var child in element.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child); + switch (child.Name.LocalName) + { + case "SqlScript": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName)); + } + + this.ParseSqlScriptElement(intermediate, section, child, componentId, id?.Id); + break; + case "SqlString": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName)); + } + + this.ParseSqlStringElement(intermediate, section, child, componentId, id?.Id); + break; + case "SqlFileSpec": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName)); + } + else if (null != fileSpec) + { + this.Messaging.Write(ErrorMessages.TooManyElements(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName, 1)); + } + + fileSpec = this.ParseSqlFileSpecElement(intermediate, section, child, id?.Id); + break; + case "SqlLogFileSpec": + if (null == componentId) + { + this.Messaging.Write(SqlErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName)); + } + else if (null != logFileSpec) + { + this.Messaging.Write(ErrorMessages.TooManyElements(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName, 1)); + } + + logFileSpec = this.ParseSqlFileSpecElement(intermediate, section, child, id?.Id); + break; + default: + this.ParseHelper.UnexpectedElement(element, child); + break; + } + } + else + { + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); + } + } + + if (null != componentId) + { + // Reference InstallSqlData and UninstallSqlData since nothing will happen without it + this.AddReferenceToInstallSqlData(section, sourceLineNumbers); + } + + if (!this.Messaging.EncounteredError) + { + var symbol = section.AddSymbol(new SqlDatabaseSymbol(sourceLineNumbers, id) + { + Server = server, + Instance = instance, + Database = database, + ComponentRef = componentId, + UserRef = user, + FileSpecRef = fileSpec?.Id, + LogFileSpecRef = logFileSpec?.Id, + }); + + if (0 != attributes) + { + symbol.Attributes = attributes; + } + } + } + + /// + /// Parses a sql file specification element. + /// + /// + /// + /// Element to parse. + /// Identifier of sql file specification. + private Identifier ParseSqlFileSpecElement(Intermediate intermediate, IntermediateSection section, XElement element, string parentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string fileName = null; + string growthSize = null; + string maxSize = null; + string name = null; + string size = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Filename": + fileName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Size": + size = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "MaxSize": + maxSize = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "GrowthSize": + growthSize = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("sfs", parentId, name, fileName); + } + + if (null == name) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); + } + + if (null == fileName) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Filename")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + var symbol = section.AddSymbol(new SqlFileSpecSymbol(sourceLineNumbers, id) + { + Name = name, + Filename = fileName, + }); + + if (null != size) + { + symbol.Size = size; + } + + if (null != maxSize) + { + symbol.MaxSize = maxSize; + } + + if (null != growthSize) + { + symbol.GrowthSize = growthSize; + } + } + + return id; + } + + /// + /// Parses a sql script element. + /// + /// Element to parse. + /// Identifier for parent component. + /// Optional database to execute script against. + private void ParseSqlScriptElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string sqlDb) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + int attributes = 0; + var rollbackAttribute = false; + var nonRollbackAttribute = false; + string binaryRef = null; + var sequence = CompilerConstants.IntegerNotSet; + string user = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "BinaryRef": + binaryRef = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Binary, binaryRef); + break; + case "Sequence": + sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); + break; + case "SqlDb": + if (null != sqlDb) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName)); + } + sqlDb = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SqlSymbolDefinitions.SqlDatabase, sqlDb); + break; + case "User": + user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user); + break; + + // Flag-setting attributes + case "ContinueOnError": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlContinueOnError; + } + break; + case "ExecuteOnInstall": + if (rollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall")); + } + nonRollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnInstall; + } + break; + case "ExecuteOnReinstall": + if (rollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall")); + } + nonRollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnReinstall; + } + break; + case "ExecuteOnUninstall": + if (rollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall")); + } + nonRollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnUninstall; + } + break; + case "RollbackOnInstall": + if (nonRollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall")); + } + rollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnInstall; + attributes |= SqlRollback; + } + break; + case "RollbackOnReinstall": + if (nonRollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall")); + } + rollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnReinstall; + attributes |= SqlRollback; + } + break; + case "RollbackOnUninstall": + if (nonRollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall")); + } + rollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnUninstall; + attributes |= SqlRollback; + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("ssc", componentId, binaryRef, sqlDb); + } + + if (null == binaryRef) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryRef")); + } + + if (null == sqlDb) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "SqlDb")); + } + + if (0 == attributes) + { + this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall", "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + // Reference InstallSqlData and UninstallSqlData since nothing will happen without it + this.AddReferenceToInstallSqlData(section, sourceLineNumbers); + + if (!this.Messaging.EncounteredError) + { + var symbol = section.AddSymbol(new SqlScriptSymbol(sourceLineNumbers, id) + { + SqlDbRef = sqlDb, + ComponentRef = componentId, + ScriptBinaryRef = binaryRef, + UserRef = user, + Attributes = attributes, + }); + + if (CompilerConstants.IntegerNotSet != sequence) + { + symbol.Sequence = sequence; + } + } + } + + /// + /// Parses a sql string element. + /// + /// Element to parse. + /// Identifier for parent component. + /// Optional database to execute string against. + private void ParseSqlStringElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string sqlDb) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + int attributes = 0; + var rollbackAttribute = false; + var nonRollbackAttribute = false; + var sequence = CompilerConstants.IntegerNotSet; + string sql = null; + string user = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "ContinueOnError": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlContinueOnError; + } + break; + case "ExecuteOnInstall": + if (rollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall")); + } + nonRollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnInstall; + } + break; + case "ExecuteOnReinstall": + if (rollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall")); + } + nonRollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnReinstall; + } + break; + case "ExecuteOnUninstall": + if (rollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall")); + } + nonRollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnUninstall; + } + break; + case "RollbackOnInstall": + if (nonRollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall")); + } + rollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnInstall; + attributes |= SqlRollback; + } + break; + case "RollbackOnReinstall": + if (nonRollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall")); + } + rollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnReinstall; + attributes |= SqlRollback; + } + break; + case "RollbackOnUninstall": + if (nonRollbackAttribute) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall")); + } + rollbackAttribute = true; + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= SqlExecuteOnUninstall; + attributes |= SqlRollback; + } + break; + case "Sequence": + sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); + break; + case "SQL": + sql = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SqlDb": + if (null != sqlDb) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "SqlDb", "SqlDatabase")); + } + + sqlDb = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SqlSymbolDefinitions.SqlDatabase, sqlDb); + break; + case "User": + user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("sst", componentId, sql, sqlDb); + } + + if (null == sql) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "SQL")); + } + + if (null == sqlDb) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "SqlDb")); + } + + if (0 == attributes) + { + this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ExecuteOnInstall", "ExecuteOnReinstall", "ExecuteOnUninstall", "RollbackOnInstall", "RollbackOnReinstall", "RollbackOnUninstall")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + // Reference InstallSqlData and UninstallSqlData since nothing will happen without it + this.AddReferenceToInstallSqlData(section, sourceLineNumbers); + + if (!this.Messaging.EncounteredError) + { + var symbol = section.AddSymbol(new SqlStringSymbol(sourceLineNumbers, id) + { + SqlDbRef = sqlDb, + ComponentRef = componentId, + SQL = sql, + UserRef = user, + Attributes = attributes, + }); + + if (CompilerConstants.IntegerNotSet != sequence) + { + symbol.Sequence = sequence; + } + } + } + + private void AddReferenceToInstallSqlData(IntermediateSection section, SourceLineNumber sourceLineNumbers) + { + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4InstallSqlData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4UninstallSqlData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + } + } +} -- cgit v1.2.3-55-g6feb