// 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);
}
}
}