aboutsummaryrefslogtreecommitdiff
path: root/src/ext
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-05-11 08:08:54 -0700
committerRob Mensching <rob@firegiant.com>2021-05-11 08:08:54 -0700
commit8035cadb06c0ca91387d839f3452191f7d33869a (patch)
tree57eed7720caa596367d54c7b286727cbaa80c546 /src/ext
parent5b63db920c207d7115ff8f9ea19f36944766db7a (diff)
parente713e6695bd531d1021482d454401b86c84f3f2d (diff)
downloadwix-8035cadb06c0ca91387d839f3452191f7d33869a.tar.gz
wix-8035cadb06c0ca91387d839f3452191f7d33869a.tar.bz2
wix-8035cadb06c0ca91387d839f3452191f7d33869a.zip
Merge Sql.wixext
Diffstat (limited to 'src/ext')
-rw-r--r--src/ext/Sql/Directory.Build.props27
-rw-r--r--src/ext/Sql/Directory.Build.targets51
-rw-r--r--src/ext/Sql/Directory.csproj.props13
-rw-r--r--src/ext/Sql/Directory.csproj.targets26
-rw-r--r--src/ext/Sql/Directory.vcxproj.props111
-rw-r--r--src/ext/Sql/README.md2
-rw-r--r--src/ext/Sql/Sql.wixext.sln59
-rw-r--r--src/ext/Sql/appveyor.cmd19
-rw-r--r--src/ext/Sql/appveyor.yml40
-rw-r--r--src/ext/Sql/ca/CustomMsiErrors.h10
-rw-r--r--src/ext/Sql/ca/caDecor.h13
-rw-r--r--src/ext/Sql/ca/dllmain.cpp26
-rw-r--r--src/ext/Sql/ca/precomp.h28
-rw-r--r--src/ext/Sql/ca/sca.h33
-rw-r--r--src/ext/Sql/ca/scacost.h7
-rw-r--r--src/ext/Sql/ca/scadb.cpp588
-rw-r--r--src/ext/Sql/ca/scadb.h55
-rw-r--r--src/ext/Sql/ca/scaexec.cpp393
-rw-r--r--src/ext/Sql/ca/scasql.cpp113
-rw-r--r--src/ext/Sql/ca/scasqlstr.cpp728
-rw-r--r--src/ext/Sql/ca/scasqlstr.h51
-rw-r--r--src/ext/Sql/ca/scauser.cpp82
-rw-r--r--src/ext/Sql/ca/scauser.h40
-rw-r--r--src/ext/Sql/ca/sqlca.cpp3
-rw-r--r--src/ext/Sql/ca/sqlca.def13
-rw-r--r--src/ext/Sql/ca/sqlca.vcxproj83
-rw-r--r--src/ext/Sql/nuget.config17
-rw-r--r--src/ext/Sql/test/WixToolsetTest.Sql/SqlExtensionFixture.cs36
-rw-r--r--src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/Package.en-us.wxl11
-rw-r--r--src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/Package.wxs19
-rw-r--r--src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/PackageComponents.wxs22
-rw-r--r--src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/example.txt1
-rw-r--r--src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.csproj38
-rw-r--r--src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.v3.ncrunchproject5
-rw-r--r--src/ext/Sql/wix.snkbin0 -> 596 bytes
-rw-r--r--src/ext/Sql/wixext/SqlCompiler.cs804
-rw-r--r--src/ext/Sql/wixext/SqlDecompiler.cs514
-rw-r--r--src/ext/Sql/wixext/SqlErrors.cs48
-rw-r--r--src/ext/Sql/wixext/SqlExtensionData.cs30
-rw-r--r--src/ext/Sql/wixext/SqlExtensionFactory.cs18
-rw-r--r--src/ext/Sql/wixext/SqlTableDefinitions.cs82
-rw-r--r--src/ext/Sql/wixext/SqlWindowsInstallerBackendExtension.cs13
-rw-r--r--src/ext/Sql/wixext/Symbols/SqlDatabaseSymbol.cs103
-rw-r--r--src/ext/Sql/wixext/Symbols/SqlFileSpecSymbol.cs79
-rw-r--r--src/ext/Sql/wixext/Symbols/SqlScriptSymbol.cs87
-rw-r--r--src/ext/Sql/wixext/Symbols/SqlStringSymbol.cs87
-rw-r--r--src/ext/Sql/wixext/Symbols/SqlSymbolDefinitions.cs51
-rw-r--r--src/ext/Sql/wixext/WixToolset.Sql.wixext.csproj30
-rw-r--r--src/ext/Sql/wixext/WixToolset.Sql.wixext.nuspec25
-rw-r--r--src/ext/Sql/wixext/WixToolset.Sql.wixext.targets11
-rw-r--r--src/ext/Sql/wixlib/SqlExtension.wxi35
-rw-r--r--src/ext/Sql/wixlib/SqlExtension.wxs15
-rw-r--r--src/ext/Sql/wixlib/SqlExtension_arm64.wxs7
-rw-r--r--src/ext/Sql/wixlib/SqlExtension_x64.wxs7
-rw-r--r--src/ext/Sql/wixlib/SqlExtension_x86.wxs7
-rw-r--r--src/ext/Sql/wixlib/caDecor.wxi39
-rw-r--r--src/ext/Sql/wixlib/caerr.wxi96
-rw-r--r--src/ext/Sql/wixlib/de-de.wxl16
-rw-r--r--src/ext/Sql/wixlib/en-us.wxl16
-rw-r--r--src/ext/Sql/wixlib/es-es.wxl17
-rw-r--r--src/ext/Sql/wixlib/ja-jp.wxl16
-rw-r--r--src/ext/Sql/wixlib/pl-pl.wxl16
-rw-r--r--src/ext/Sql/wixlib/pt-br.wxl16
-rw-r--r--src/ext/Sql/wixlib/pt-pt.wxl16
-rw-r--r--src/ext/Sql/wixlib/sql.v3.ncrunchproject5
-rw-r--r--src/ext/Sql/wixlib/sql.wixproj24
66 files changed, 5093 insertions, 0 deletions
diff --git a/src/ext/Sql/Directory.Build.props b/src/ext/Sql/Directory.Build.props
new file mode 100644
index 00000000..b3c6287c
--- /dev/null
+++ b/src/ext/Sql/Directory.Build.props
@@ -0,0 +1,27 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3<!--
4 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.props
5 then update all of the repos.
6-->
7<Project>
8 <PropertyGroup>
9 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
10 <EnableSourceLink Condition=" '$(NCrunch)' == '1' ">false</EnableSourceLink>
11 <MSBuildWarningsAsMessages>MSB3246</MSBuildWarningsAsMessages>
12
13 <ProjectName Condition=" '$(ProjectName)' == '' ">$(MSBuildProjectName)</ProjectName>
14 <BaseOutputPath>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\))</BaseOutputPath>
15 <BaseIntermediateOutputPath>$(BaseOutputPath)obj\$(ProjectName)\</BaseIntermediateOutputPath>
16 <OutputPath>$(BaseOutputPath)$(Configuration)\</OutputPath>
17
18 <Authors>WiX Toolset Team</Authors>
19 <Company>WiX Toolset</Company>
20 <Copyright>Copyright (c) .NET Foundation and contributors. All rights reserved.</Copyright>
21 <PackageLicenseExpression>MS-RL</PackageLicenseExpression>
22 <Product>WiX Toolset</Product>
23 </PropertyGroup>
24
25 <Import Project="Directory$(MSBuildProjectExtension).props" Condition=" Exists('Directory$(MSBuildProjectExtension).props') " />
26 <Import Project="Custom.Build.props" Condition=" Exists('Custom.Build.props') " />
27</Project>
diff --git a/src/ext/Sql/Directory.Build.targets b/src/ext/Sql/Directory.Build.targets
new file mode 100644
index 00000000..2fcc765a
--- /dev/null
+++ b/src/ext/Sql/Directory.Build.targets
@@ -0,0 +1,51 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3<!--
4 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.targets
5 then update all of the repos.
6-->
7<!--
8 Replace PackageReferences with ProjectReferences when the projects can be found in .sln.
9 See the original here: https://github.com/dotnet/sdk/issues/1151#issuecomment-385133284
10-->
11<Project>
12 <PropertyGroup>
13 <ReplacePackageReferences>true</ReplacePackageReferences>
14 <TheSolutionPath Condition=" '$(NCrunch)'=='' ">$(SolutionPath)</TheSolutionPath>
15 <TheSolutionPath Condition=" '$(NCrunch)'=='1' ">$(NCrunchOriginalSolutionPath)</TheSolutionPath>
16 </PropertyGroup>
17
18 <Choose>
19 <When Condition="$(ReplacePackageReferences) AND '$(TheSolutionPath)' != '' AND '$(TheSolutionPath)' != '*undefined*' AND Exists('$(TheSolutionPath)')">
20
21 <PropertyGroup>
22 <SolutionFileContent>$([System.IO.File]::ReadAllText($(TheSolutionPath)))</SolutionFileContent>
23 <SmartSolutionDir>$([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) ))</SmartSolutionDir>
24 <RegexPattern>(?&lt;="[PackageName]", ")(.*)(?=", ")</RegexPattern>
25 </PropertyGroup>
26
27 <ItemGroup>
28 <!-- Keep the identity of the PackageReference -->
29 <SmartPackageReference Include="@(PackageReference)">
30 <PackageName>%(Identity)</PackageName>
31 <InSolution>$(SolutionFileContent.Contains('\%(Identity).csproj'))</InSolution>
32 </SmartPackageReference>
33
34 <!-- Filter them by mapping them to another ItemGroup using the WithMetadataValue item function -->
35 <PackageInSolution Include="@(SmartPackageReference->WithMetadataValue('InSolution', True))">
36 <Pattern>$(RegexPattern.Replace('[PackageName]','%(PackageName)') )</Pattern>
37 <SmartPath>$([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)'))</SmartPath>
38 </PackageInSolution>
39
40 <ProjectReference Include="@(PackageInSolution->'$(SmartSolutionDir)\%(SmartPath)' )"/>
41
42 <!-- Remove the package references that are now referenced as projects -->
43 <PackageReference Remove="@(PackageInSolution->'%(PackageName)')"/>
44 </ItemGroup>
45
46 </When>
47 </Choose>
48
49 <Import Project="Directory$(MSBuildProjectExtension).targets" Condition=" Exists('Directory$(MSBuildProjectExtension).targets') " />
50 <Import Project="Custom.Build.targets" Condition=" Exists('Custom.Build.targets') " />
51</Project>
diff --git a/src/ext/Sql/Directory.csproj.props b/src/ext/Sql/Directory.csproj.props
new file mode 100644
index 00000000..81d24ad1
--- /dev/null
+++ b/src/ext/Sql/Directory.csproj.props
@@ -0,0 +1,13 @@
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 Do NOT modify this file. Update the canonical version in Home\repo-template\src\CSharp.Build.props
4 then update all of the repos.
5-->
6<Project>
7 <PropertyGroup>
8 <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
9 <SignAssembly>true</SignAssembly>
10 <AssemblyOriginatorKeyFile>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)wix.snk))</AssemblyOriginatorKeyFile>
11 <NBGV_EmitThisAssemblyClass>false</NBGV_EmitThisAssemblyClass>
12 </PropertyGroup>
13</Project>
diff --git a/src/ext/Sql/Directory.csproj.targets b/src/ext/Sql/Directory.csproj.targets
new file mode 100644
index 00000000..c3270426
--- /dev/null
+++ b/src/ext/Sql/Directory.csproj.targets
@@ -0,0 +1,26 @@
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 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.csproj.targets
4 then update all of the repos.
5-->
6<Project>
7 <PropertyGroup>
8 <CreateDocumentation Condition=" '$(CreateDocumentationFile)'!='true' ">false</CreateDocumentation>
9 <DocumentationFile Condition=" '$(CreateDocumentationFile)'=='true' ">$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
10 </PropertyGroup>
11
12 <Target Name="SetNuspecProperties" DependsOnTargets="InitializeSourceControlInformation" AfterTargets="GetBuildVersion"
13 Condition=" Exists('$(MSBuildProjectName).nuspec') ">
14 <PropertyGroup>
15 <ProjectUrl Condition=" '$(ProjectUrl)'=='' and '$(PrivateRepositoryUrl)'!='' ">$(PrivateRepositoryUrl.Replace('.git',''))</ProjectUrl>
16
17 <NuspecFile>$(MSBuildProjectName).nuspec</NuspecFile>
18 <NuspecBasePath Condition=" '$(NuspecBasePath)'=='' ">$(OutputPath)..\</NuspecBasePath>
19 <NuspecProperties>$(NuspecProperties);Id=$(PackageId);Authors=$(Authors);Copyright=$(Copyright);Description=$(Description);Title=$(Title)</NuspecProperties>
20 <NuspecProperties>$(NuspecProperties);Version=$(PackageVersion);RepositoryCommit=$(SourceRevisionId);RepositoryType=$(RepositoryType);RepositoryUrl=$(PrivateRepositoryUrl);ProjectFolder=$(MSBuildProjectDirectory)\;ProjectUrl=$(ProjectUrl)</NuspecProperties>
21 <PublishRepositoryUrl>true</PublishRepositoryUrl>
22 <SymbolPackageFormat>snupkg</SymbolPackageFormat>
23 </PropertyGroup>
24 </Target>
25
26</Project>
diff --git a/src/ext/Sql/Directory.vcxproj.props b/src/ext/Sql/Directory.vcxproj.props
new file mode 100644
index 00000000..bcf26c57
--- /dev/null
+++ b/src/ext/Sql/Directory.vcxproj.props
@@ -0,0 +1,111 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project>
5 <PropertyGroup>
6 <Platform Condition=" '$(Platform)' == '' OR '$(Platform)' == 'AnyCPU' ">Win32</Platform>
7 <IntDir>$(BaseIntermediateOutputPath)$(Configuration)\$(Platform)\</IntDir>
8 <OutDir>$(OutputPath)$(Platform)\</OutDir>
9
10 <!-- NBGV properties -->
11 <AssemblyCompany>$(Company)</AssemblyCompany>
12 <AssemblyCopyright>$(Copyright)</AssemblyCopyright>
13
14 <RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
15 <NuGetTargetMoniker>native,Version=v0.0</NuGetTargetMoniker>
16 </PropertyGroup>
17
18 <PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'=='' AND '$(VisualStudioVersion)'>='15.0'">
19 <WindowsTargetPlatformVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</WindowsTargetPlatformVersion>
20 </PropertyGroup>
21
22 <ItemDefinitionGroup>
23 <ClCompile>
24 <DisableSpecificWarnings>$(DisableSpecificCompilerWarnings)</DisableSpecificWarnings>
25 <WarningLevel>Level4</WarningLevel>
26 <AdditionalIncludeDirectories>$(ProjectDir)inc;$(MSBuildProjectDirectory);$(IntDir);$(SqlCESdkIncludePath);$(ProjectAdditionalIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
27 <PreprocessorDefinitions>WIN32;_WINDOWS;_WIN32_MSI=500;_WIN32_WINNT=0x0501;$(ArmPreprocessorDefinitions);$(UnicodePreprocessorDefinitions);_CRT_STDIO_LEGACY_WIDE_SPECIFIERS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
28 <PrecompiledHeader>Use</PrecompiledHeader>
29 <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
30 <CallingConvention Condition="'$(Platform)'=='Win32'">StdCall</CallingConvention>
31 <TreatWarningAsError>true</TreatWarningAsError>
32 <ExceptionHandling>false</ExceptionHandling>
33 <AdditionalOptions>-YlprecompDefine</AdditionalOptions>
34 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
35 <MultiProcessorCompilation Condition=" $(NUMBER_OF_PROCESSORS) &gt; 4 ">true</MultiProcessorCompilation>
36 </ClCompile>
37 <ResourceCompile>
38 <PreprocessorDefinitions>$(ArmPreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
39 <AdditionalIncludeDirectories>$(ProjectAdditionalResourceIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
40 </ResourceCompile>
41 <Lib>
42 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ProjectAdditionalLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
43 </Lib>
44 <Link>
45 <SubSystem>$(ProjectSubSystem)</SubSystem>
46 <ModuleDefinitionFile>$(ProjectModuleDefinitionFile)</ModuleDefinitionFile>
47 <NoEntryPoint>$(ResourceOnlyDll)</NoEntryPoint>
48 <GenerateDebugInformation>true</GenerateDebugInformation>
49 <AdditionalDependencies>$(ProjectAdditionalLinkLibraries);advapi32.lib;comdlg32.lib;user32.lib;oleaut32.lib;gdi32.lib;shell32.lib;ole32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
50 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ArmLibraryDirectories);$(ProjectAdditionalLinkLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
51 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/IGNORE:4099 %(AdditionalOptions)</AdditionalOptions>
52 </Link>
53 </ItemDefinitionGroup>
54
55 <ItemDefinitionGroup Condition=" '$(Platform)'=='Win32' and '$(PlatformToolset)'!='v100'">
56 <ClCompile>
57 <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
58 </ClCompile>
59 </ItemDefinitionGroup>
60 <ItemDefinitionGroup Condition=" '$(Platform)'=='arm' ">
61 <ClCompile>
62 <CallingConvention>CDecl</CallingConvention>
63 </ClCompile>
64 </ItemDefinitionGroup>
65 <ItemDefinitionGroup Condition=" '$(ConfigurationType)'=='StaticLibrary' ">
66 <ClCompile>
67 <DebugInformationFormat>OldStyle</DebugInformationFormat>
68 <OmitDefaultLibName>true</OmitDefaultLibName>
69 <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
70 </ClCompile>
71 </ItemDefinitionGroup>
72 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Debug' ">
73 <ClCompile>
74 <Optimization>Disabled</Optimization>
75 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
76 <PreprocessorDefinitions>_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
77 <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
78 </ClCompile>
79 </ItemDefinitionGroup>
80 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Debug' and '$(CLRSupport)'=='true' ">
81 <ClCompile>
82 <BasicRuntimeChecks></BasicRuntimeChecks>
83 <RuntimeLibrary>MultiThreadedDebugDll</RuntimeLibrary>
84 </ClCompile>
85 </ItemDefinitionGroup>
86 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' ">
87 <ClCompile>
88 <Optimization>MinSpace</Optimization>
89 <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
90 <FunctionLevelLinking>true</FunctionLevelLinking>
91 <IntrinsicFunctions>true</IntrinsicFunctions>
92 <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
93 </ClCompile>
94 <Link>
95 <EnableCOMDATFolding>true</EnableCOMDATFolding>
96 <OptimizeReferences>true</OptimizeReferences>
97 </Link>
98 </ItemDefinitionGroup>
99 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' and '$(CLRSupport)'=='true' ">
100 <ClCompile>
101 <BasicRuntimeChecks></BasicRuntimeChecks>
102 <RuntimeLibrary>MultiThreadedDll</RuntimeLibrary>
103 </ClCompile>
104 </ItemDefinitionGroup>
105 <ItemDefinitionGroup Condition=" '$(CLRSupport)'=='true' ">
106 <Link>
107 <KeyFile>$(LinkKeyFile)</KeyFile>
108 <DelaySign>$(LinkDelaySign)</DelaySign>
109 </Link>
110 </ItemDefinitionGroup>
111</Project>
diff --git a/src/ext/Sql/README.md b/src/ext/Sql/README.md
new file mode 100644
index 00000000..377c9032
--- /dev/null
+++ b/src/ext/Sql/README.md
@@ -0,0 +1,2 @@
1# Sql.wixext
2WixToolset.Sql.wixext - Sql WiX Toolset Extension
diff --git a/src/ext/Sql/Sql.wixext.sln b/src/ext/Sql/Sql.wixext.sln
new file mode 100644
index 00000000..cfa9ad4f
--- /dev/null
+++ b/src/ext/Sql/Sql.wixext.sln
@@ -0,0 +1,59 @@
1
2Microsoft Visual Studio Solution File, Format Version 12.00
3# Visual Studio Version 16
4VisualStudioVersion = 16.0.30204.135
5MinimumVisualStudioVersion = 10.0.40219.1
6Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlca", "src\ca\sqlca.vcxproj", "{4DCA6E4B-A1F1-4450-BC2D-94AC20F31935}"
7EndProject
8Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "sql", "src\wixlib\sql.wixproj", "{9ACF1A20-D801-45CC-A463-F9D13E506AA3}"
9EndProject
10Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Sql.wixext", "src\wixext\WixToolset.Sql.wixext.csproj", "{0E05519A-0045-4AEC-BD0C-D9205FF1468F}"
11EndProject
12Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Sql", "src\test\WixToolsetTest.Sql\WixToolsetTest.Sql.csproj", "{FE72A369-03CA-4EBC-BC7B-A8BBF5BBD3E0}"
13EndProject
14Global
15 GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 Debug|Any CPU = Debug|Any CPU
17 Debug|x86 = Debug|x86
18 Release|Any CPU = Release|Any CPU
19 Release|x86 = Release|x86
20 EndGlobalSection
21 GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 {4DCA6E4B-A1F1-4450-BC2D-94AC20F31935}.Debug|Any CPU.ActiveCfg = Debug|Win32
23 {4DCA6E4B-A1F1-4450-BC2D-94AC20F31935}.Debug|Any CPU.Build.0 = Debug|Win32
24 {4DCA6E4B-A1F1-4450-BC2D-94AC20F31935}.Debug|x86.ActiveCfg = Debug|Win32
25 {4DCA6E4B-A1F1-4450-BC2D-94AC20F31935}.Debug|x86.Build.0 = Debug|Win32
26 {4DCA6E4B-A1F1-4450-BC2D-94AC20F31935}.Release|Any CPU.ActiveCfg = Release|Win32
27 {4DCA6E4B-A1F1-4450-BC2D-94AC20F31935}.Release|x86.ActiveCfg = Release|Win32
28 {4DCA6E4B-A1F1-4450-BC2D-94AC20F31935}.Release|x86.Build.0 = Release|Win32
29 {9ACF1A20-D801-45CC-A463-F9D13E506AA3}.Debug|Any CPU.ActiveCfg = Debug|x86
30 {9ACF1A20-D801-45CC-A463-F9D13E506AA3}.Debug|Any CPU.Build.0 = Debug|x86
31 {9ACF1A20-D801-45CC-A463-F9D13E506AA3}.Debug|x86.ActiveCfg = Debug|x86
32 {9ACF1A20-D801-45CC-A463-F9D13E506AA3}.Debug|x86.Build.0 = Debug|x86
33 {9ACF1A20-D801-45CC-A463-F9D13E506AA3}.Release|Any CPU.ActiveCfg = Release|x86
34 {9ACF1A20-D801-45CC-A463-F9D13E506AA3}.Release|x86.ActiveCfg = Release|x86
35 {9ACF1A20-D801-45CC-A463-F9D13E506AA3}.Release|x86.Build.0 = Release|x86
36 {0E05519A-0045-4AEC-BD0C-D9205FF1468F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 {0E05519A-0045-4AEC-BD0C-D9205FF1468F}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 {0E05519A-0045-4AEC-BD0C-D9205FF1468F}.Debug|x86.ActiveCfg = Debug|Any CPU
39 {0E05519A-0045-4AEC-BD0C-D9205FF1468F}.Debug|x86.Build.0 = Debug|Any CPU
40 {0E05519A-0045-4AEC-BD0C-D9205FF1468F}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 {0E05519A-0045-4AEC-BD0C-D9205FF1468F}.Release|Any CPU.Build.0 = Release|Any CPU
42 {0E05519A-0045-4AEC-BD0C-D9205FF1468F}.Release|x86.ActiveCfg = Release|Any CPU
43 {0E05519A-0045-4AEC-BD0C-D9205FF1468F}.Release|x86.Build.0 = Release|Any CPU
44 {FE72A369-03CA-4EBC-BC7B-A8BBF5BBD3E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 {FE72A369-03CA-4EBC-BC7B-A8BBF5BBD3E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 {FE72A369-03CA-4EBC-BC7B-A8BBF5BBD3E0}.Debug|x86.ActiveCfg = Debug|Any CPU
47 {FE72A369-03CA-4EBC-BC7B-A8BBF5BBD3E0}.Debug|x86.Build.0 = Debug|Any CPU
48 {FE72A369-03CA-4EBC-BC7B-A8BBF5BBD3E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 {FE72A369-03CA-4EBC-BC7B-A8BBF5BBD3E0}.Release|Any CPU.Build.0 = Release|Any CPU
50 {FE72A369-03CA-4EBC-BC7B-A8BBF5BBD3E0}.Release|x86.ActiveCfg = Release|Any CPU
51 {FE72A369-03CA-4EBC-BC7B-A8BBF5BBD3E0}.Release|x86.Build.0 = Release|Any CPU
52 EndGlobalSection
53 GlobalSection(SolutionProperties) = preSolution
54 HideSolutionNode = FALSE
55 EndGlobalSection
56 GlobalSection(ExtensibilityGlobals) = postSolution
57 SolutionGuid = {DEFEE3BB-E557-4B77-A85C-ECA19D6F5DF5}
58 EndGlobalSection
59EndGlobal
diff --git a/src/ext/Sql/appveyor.cmd b/src/ext/Sql/appveyor.cmd
new file mode 100644
index 00000000..f21449d2
--- /dev/null
+++ b/src/ext/Sql/appveyor.cmd
@@ -0,0 +1,19 @@
1@setlocal
2@pushd %~dp0
3@set _C=Release
4@if /i "%1"=="debug" set _C=Debug
5
6:: Restore
7msbuild -p:Configuration=%_C% -t:Restore || exit /b
8
9:: Build
10msbuild -p:Configuration=%_C% src\test\WixToolsetTest.Sql\WixToolsetTest.Sql.csproj || exit /b
11
12:: Test
13dotnet test -c %_C% --no-build src\test\WixToolsetTest.Sql || exit /b
14
15:: Pack
16msbuild -p:Configuration=%_C% -p:NoBuild=true -t:Pack src\wixext\WixToolset.Sql.wixext.csproj || exit /b
17
18@popd
19@endlocal
diff --git a/src/ext/Sql/appveyor.yml b/src/ext/Sql/appveyor.yml
new file mode 100644
index 00000000..7c686b04
--- /dev/null
+++ b/src/ext/Sql/appveyor.yml
@@ -0,0 +1,40 @@
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# Do NOT modify this file. Update the canonical version in Home\repo-template\src\appveyor.yml
4# then update all of the repos.
5
6branches:
7 only:
8 - master
9 - develop
10
11image: Visual Studio 2019
12
13version: 0.0.0.{build}
14configuration: Release
15
16environment:
17 DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
18 DOTNET_CLI_TELEMETRY_OPTOUT: 1
19 NUGET_XMLDOC_MODE: skip
20
21build_script:
22 - appveyor.cmd
23
24pull_requests:
25 do_not_increment_build_number: true
26
27nuget:
28 disable_publish_on_pr: true
29
30skip_branch_with_pr: true
31skip_tags: true
32
33artifacts:
34- path: build\Release\**\*.nupkg
35 name: nuget
36
37notifications:
38- provider: Slack
39 incoming_webhook:
40 secure: p5xuu+4x2JHfwGDMDe5KcG1k7gZxqYc4jWVwvyNZv5cvkubPD2waJs5yXMAXZNN7Z63/3PWHb7q4KoY/99AjauYa1nZ4c5qYqRPFRBKTHfA=
diff --git a/src/ext/Sql/ca/CustomMsiErrors.h b/src/ext/Sql/ca/CustomMsiErrors.h
new file mode 100644
index 00000000..b568d01c
--- /dev/null
+++ b/src/ext/Sql/ca/CustomMsiErrors.h
@@ -0,0 +1,10 @@
1#pragma once
2// 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.
3
4#define msierrSQLFailedCreateDatabase 26201
5#define msierrSQLFailedDropDatabase 26202
6#define msierrSQLFailedConnectDatabase 26203
7#define msierrSQLFailedExecString 26204
8#define msierrSQLDatabaseAlreadyExists 26205
9
10//Last available is 26250 \ No newline at end of file
diff --git a/src/ext/Sql/ca/caDecor.h b/src/ext/Sql/ca/caDecor.h
new file mode 100644
index 00000000..da274650
--- /dev/null
+++ b/src/ext/Sql/ca/caDecor.h
@@ -0,0 +1,13 @@
1#pragma once
2// 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.
3
4
5#if defined(_M_ARM64)
6#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_A64"
7#elif defined(_M_AMD64)
8#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X64"
9#elif defined(_M_ARM)
10#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_ARM"
11#else
12#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X86"
13#endif
diff --git a/src/ext/Sql/ca/dllmain.cpp b/src/ext/Sql/ca/dllmain.cpp
new file mode 100644
index 00000000..35ae6d1c
--- /dev/null
+++ b/src/ext/Sql/ca/dllmain.cpp
@@ -0,0 +1,26 @@
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/********************************************************************
6DllMain - standard entry point for all WiX custom actions
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInst,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInst);
18 break;
19
20 case DLL_PROCESS_DETACH:
21 WcaGlobalFinalize();
22 break;
23 }
24
25 return TRUE;
26}
diff --git a/src/ext/Sql/ca/precomp.h b/src/ext/Sql/ca/precomp.h
new file mode 100644
index 00000000..266d543c
--- /dev/null
+++ b/src/ext/Sql/ca/precomp.h
@@ -0,0 +1,28 @@
1#pragma once
2// 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.
3
4
5#if _WIN32_MSI < 150
6#define _WIN32_MSI 150
7#endif
8
9#include <windows.h>
10#include <msiquery.h>
11
12#include <strsafe.h>
13
14#define MAXUINT USHRT_MAX
15
16#include "wcautil.h"
17#include "fileutil.h"
18#include "memutil.h"
19#include "strutil.h"
20#include "wiutil.h"
21
22#include "CustomMsiErrors.h"
23
24#include "sca.h"
25#include "scacost.h"
26#include "scasqlstr.h"
27
28#include "caDecor.h"
diff --git a/src/ext/Sql/ca/sca.h b/src/ext/Sql/ca/sca.h
new file mode 100644
index 00000000..bc36344e
--- /dev/null
+++ b/src/ext/Sql/ca/sca.h
@@ -0,0 +1,33 @@
1#pragma once
2// 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.
3
4// Generic action enum.
5enum SCA_ACTION
6{
7 SCA_ACTION_NONE,
8 SCA_ACTION_INSTALL,
9 SCA_ACTION_UNINSTALL
10};
11
12// sql database attributes definitions
13enum SCADB_ATTRIBUTES
14{
15 SCADB_CREATE_ON_INSTALL = 0x00000001,
16 SCADB_DROP_ON_UNINSTALL = 0x00000002,
17 SCADB_CONTINUE_ON_ERROR = 0x00000004,
18 SCADB_DROP_ON_INSTALL = 0x00000008,
19 SCADB_CREATE_ON_UNINSTALL = 0x00000010,
20 SCADB_CONFIRM_OVERWRITE = 0x00000020,
21 SCADB_CREATE_ON_REINSTALL = 0x00000040,
22 SCADB_DROP_ON_REINSTALL = 0x00000080,
23};
24
25// sql string/script attributes definitions
26enum SCASQL_ATTRIBUTES
27{
28 SCASQL_EXECUTE_ON_INSTALL = 0x00000001,
29 SCASQL_EXECUTE_ON_UNINSTALL = 0x00000002,
30 SCASQL_CONTINUE_ON_ERROR = 0x00000004,
31 SCASQL_ROLLBACK = 0x00000008,
32 SCASQL_EXECUTE_ON_REINSTALL = 0x00000010,
33};
diff --git a/src/ext/Sql/ca/scacost.h b/src/ext/Sql/ca/scacost.h
new file mode 100644
index 00000000..6ea7e465
--- /dev/null
+++ b/src/ext/Sql/ca/scacost.h
@@ -0,0 +1,7 @@
1#pragma once
2// 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.
3
4const UINT COST_SQL_CREATEDB = 10000;
5const UINT COST_SQL_DROPDB = 5000;
6const UINT COST_SQL_CONNECTDB = 5000;
7const UINT COST_SQL_STRING = 5000;
diff --git a/src/ext/Sql/ca/scadb.cpp b/src/ext/Sql/ca/scadb.cpp
new file mode 100644
index 00000000..288b9efe
--- /dev/null
+++ b/src/ext/Sql/ca/scadb.cpp
@@ -0,0 +1,588 @@
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 vcsSqlDatabaseQuery = L"SELECT `SqlDb`, `Server`, `Instance`, `Database`, "
7 L"`Component_`, `User_`, `FileSpec_`, `FileSpec_Log`, `Attributes` "
8 L"FROM `Wix4SqlDatabase`";
9enum eSqlDatabaseQuery { sdqSqlDb = 1, sdqServer, sdqInstance, sdqDatabase,
10 sdqComponent, sdqUser, sdqDbFileSpec, sdqLogFileSpec, sdqAttributes };
11
12LPCWSTR vcsSqlFileSpecQuery = L"SELECT `FileSpec`, `Name`, `Filename`, `Size`, "
13 L"`MaxSize`, `GrowthSize` FROM `Wix4SqlFileSpec` WHERE `FileSpec`=?";
14enum eSqlFileSpecQuery { sfsqFileSpec = 1, sfsqName, sfsqFilename, sfsqSize,
15 sfsqMaxSize, sfsqGrowth };
16
17
18// prototypes for private helper functions
19static HRESULT NewDb(
20 __out SCA_DB** ppsd
21 );
22
23static SCA_DB* AddDbToList(
24 __in SCA_DB* psdList,
25 __in SCA_DB* psd
26 );
27
28static HRESULT SchedCreateDatabase(
29 __in SCA_DB* psd
30 );
31
32static HRESULT SchedDropDatabase(
33 __in LPCWSTR wzKey, LPCWSTR wzServer,
34 __in LPCWSTR wzInstance,
35 __in LPCWSTR wzDatabase,
36 __in int iAttributes,
37 __in BOOL fIntegratedAuth,
38 __in LPCWSTR wzUser,
39 __in LPCWSTR wzPassword
40 );
41
42static HRESULT GetFileSpec(
43 __in MSIHANDLE hViewFileSpec,
44 __in LPCWSTR wzKey,
45 __in SQL_FILESPEC* psf
46 );
47
48
49HRESULT ScaDbsRead(
50 __inout SCA_DB** ppsdList,
51 __in SCA_ACTION saAction
52 )
53{
54 HRESULT hr = S_OK;
55 UINT er = ERROR_SUCCESS;
56 PMSIHANDLE hView;
57 PMSIHANDLE hRec;
58 PMSIHANDLE hViewFileSpec = NULL;
59
60 LPWSTR pwzData = NULL;
61 LPWSTR pwzId = NULL;
62 LPWSTR pwzComponent = NULL;
63
64 SCA_DB* psd = NULL;
65
66 if (S_OK != WcaTableExists(L"Wix4SqlDatabase"))
67 {
68 WcaLog(LOGMSG_VERBOSE, "Skipping ScaCreateDatabase() - Wix4SqlDatabase table not present");
69 ExitFunction1(hr = S_FALSE);
70 }
71
72 if (S_OK == WcaTableExists(L"Wix4SqlFileSpec"))
73 {
74 hr = WcaOpenView(vcsSqlFileSpecQuery, &hViewFileSpec);
75 ExitOnFailure(hr, "failed to open view on Wix4SqlFileSpec table");
76 }
77
78 // loop through all the sql databases
79 hr = WcaOpenExecuteView(vcsSqlDatabaseQuery, &hView);
80 ExitOnFailure(hr, "Failed to open view on Wix4SqlDatabase table");
81 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
82 {
83 BOOL fHasComponent = FALSE;
84 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
85 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
86
87 hr = WcaGetRecordString(hRec, sdqSqlDb, &pwzId);
88 ExitOnFailure(hr, "Failed to get Wix4SqlDatabase.SqlDb");
89
90 hr = WcaGetRecordString(hRec, sdqComponent, &pwzComponent);
91 ExitOnFailure(hr, "Failed to get Component for database: '%ls'", psd->wzKey);
92 if (pwzComponent && *pwzComponent)
93 {
94 fHasComponent = TRUE;
95
96 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction);
97 hr = HRESULT_FROM_WIN32(er);
98 ExitOnFailure(hr, "Failed to get state for component: %ls", pwzComponent);
99
100 // If we're doing install but the Component is not being installed or we're doing
101 // uninstall but the Component is not being uninstalled, skip it.
102 if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) ||
103 (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction))
104 {
105 continue;
106 }
107 }
108
109 hr = NewDb(&psd);
110 ExitOnFailure(hr, "Failed to allocate memory for new database: %D", pwzId);
111
112 hr = ::StringCchCopyW(psd->wzKey, countof(psd->wzKey), pwzId);
113 ExitOnFailure(hr, "Failed to copy Wix4SqlDatabase.SqlDbL: %ls", pwzId);
114
115 hr = ::StringCchCopyW(psd->wzComponent, countof(psd->wzComponent), pwzComponent);
116 ExitOnFailure(hr, "Failed to copy Wix4SqlDatabase.Component_: %ls", pwzComponent);
117
118 psd->fHasComponent = fHasComponent;
119 psd->isInstalled = isInstalled;
120 psd->isAction = isAction;
121
122 hr = WcaGetRecordFormattedString(hRec, sdqServer, &pwzData);
123 ExitOnFailure(hr, "Failed to get Server for database: '%ls'", psd->wzKey);
124 hr = ::StringCchCopyW(psd->wzServer, countof(psd->wzServer), pwzData);
125 ExitOnFailure(hr, "Failed to copy server string to database object:%ls", pwzData);
126
127 hr = WcaGetRecordFormattedString(hRec, sdqInstance, &pwzData);
128 ExitOnFailure(hr, "Failed to get Instance for database: '%ls'", psd->wzKey);
129 hr = ::StringCchCopyW(psd->wzInstance, countof(psd->wzInstance), pwzData);
130 ExitOnFailure(hr, "Failed to copy instance string to database object:%ls", pwzData);
131
132 hr = WcaGetRecordFormattedString(hRec, sdqDatabase, &pwzData);
133 ExitOnFailure(hr, "Failed to get Database for database: '%ls'", psd->wzKey);
134 hr = ::StringCchCopyW(psd->wzDatabase, countof(psd->wzDatabase), pwzData);
135 ExitOnFailure(hr, "Failed to copy database string to database object:%ls", pwzData);
136
137 hr = WcaGetRecordInteger(hRec, sdqAttributes, &psd->iAttributes);
138 ExitOnFailure(hr, "Failed to get Wix4SqlDatabase.Attributes");
139
140 hr = WcaGetRecordFormattedString(hRec, sdqUser, &pwzData);
141 ExitOnFailure(hr, "Failed to get User record for database: '%ls'", psd->wzKey);
142
143 // if a user was specified
144 if (*pwzData)
145 {
146 psd->fUseIntegratedAuth = FALSE;
147 hr = ScaGetUser(pwzData, &psd->scau);
148 ExitOnFailure(hr, "Failed to get user information for database: '%ls'", psd->wzKey);
149 }
150 else
151 {
152 psd->fUseIntegratedAuth = TRUE;
153 // integrated authorization doesn't have a User record
154 }
155
156 hr = WcaGetRecordString(hRec, sdqDbFileSpec, &pwzData);
157 ExitOnFailure(hr, "Failed to get Database FileSpec for database: '%ls'", psd->wzKey);
158
159 // if a database filespec was specified
160 if (*pwzData)
161 {
162 hr = GetFileSpec(hViewFileSpec, pwzData, &psd->sfDb);
163 ExitOnFailure(hr, "failed to get FileSpec for: %ls", pwzData);
164 if (S_OK == hr)
165 {
166 psd->fHasDbSpec = TRUE;
167 }
168 }
169
170 hr = WcaGetRecordString(hRec, sdqLogFileSpec, &pwzData);
171 ExitOnFailure(hr, "Failed to get Log FileSpec for database: '%ls'", psd->wzKey);
172
173 // if a log filespec was specified
174 if (*pwzData)
175 {
176 hr = GetFileSpec(hViewFileSpec, pwzData, &psd->sfLog);
177 ExitOnFailure(hr, "failed to get FileSpec for: %ls", pwzData);
178 if (S_OK == hr)
179 {
180 psd->fHasLogSpec = TRUE;
181 }
182 }
183
184 *ppsdList = AddDbToList(*ppsdList, psd);
185 psd = NULL; // set the db NULL so it doesn't accidentally get freed below
186 }
187
188 if (E_NOMOREITEMS == hr)
189 {
190 hr = S_OK;
191 }
192 ExitOnFailure(hr, "Failure occured while processing Wix4SqlDatabase table");
193
194LExit:
195 if (psd)
196 {
197 ScaDbsFreeList(psd);
198 }
199
200 ReleaseStr(pwzComponent);
201 ReleaseStr(pwzId);
202 ReleaseStr(pwzData);
203 return hr;
204}
205
206
207SCA_DB* ScaDbsFindDatabase(
208 __in LPCWSTR wzSqlDb,
209 __in SCA_DB* psdList
210 )
211{
212 SCA_DB* psd = NULL;
213
214 for (psd = psdList; psd; psd = psd->psdNext)
215 {
216 if (0 == lstrcmpW(wzSqlDb, psd->wzKey))
217 {
218 break;
219 }
220 }
221
222 return psd;
223}
224
225
226HRESULT ScaDbsInstall(
227 __in SCA_DB* psdList
228 )
229{
230 HRESULT hr = S_FALSE; // assume nothing will be done
231 SCA_DB* psd = NULL;
232
233 for (psd = psdList; psd; psd = psd->psdNext)
234 {
235 if (psd->fHasComponent)
236 {
237 // if we need to drop, do that first
238 if (((psd->iAttributes & SCADB_DROP_ON_INSTALL) && WcaIsInstalling(psd->isInstalled, psd->isAction) && !WcaIsReInstalling(psd->isInstalled, psd->isAction)) ||
239 ((psd->iAttributes & SCADB_DROP_ON_REINSTALL) && WcaIsReInstalling(psd->isInstalled, psd->isAction)))
240 {
241 hr = SchedDropDatabase(psd->wzKey, psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->iAttributes, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword);
242 ExitOnFailure(hr, "Failed to drop database %ls", psd->wzKey);
243 }
244
245 // if installing this component
246 if (((psd->iAttributes & SCADB_CREATE_ON_INSTALL) && WcaIsInstalling(psd->isInstalled, psd->isAction) && !WcaIsReInstalling(psd->isInstalled, psd->isAction)) ||
247 ((psd->iAttributes & SCADB_CREATE_ON_REINSTALL) && WcaIsReInstalling(psd->isInstalled, psd->isAction)))
248 {
249 hr = SchedCreateDatabase(psd);
250 ExitOnFailure(hr, "Failed to ensure database %ls exists", psd->wzKey);
251 }
252 }
253 }
254
255LExit:
256 return hr;
257}
258
259
260HRESULT ScaDbsUninstall(
261 __in SCA_DB* psdList
262 )
263{
264 HRESULT hr = S_FALSE; // assume nothing will be done
265 SCA_DB* psd = NULL;
266
267 for (psd = psdList; psd; psd = psd->psdNext)
268 {
269 if (psd->fHasComponent)
270 {
271 // if we need to drop do that first
272 if ((psd->iAttributes & SCADB_DROP_ON_UNINSTALL) && WcaIsUninstalling(psd->isInstalled, psd->isAction))
273 {
274 hr = SchedDropDatabase(psd->wzKey, psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->iAttributes, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword);
275 ExitOnFailure(hr, "Failed to drop database %ls", psd->wzKey);
276 }
277
278 // install the db
279 if ((psd->iAttributes & SCADB_CREATE_ON_UNINSTALL) && WcaIsUninstalling(psd->isInstalled, psd->isAction))
280 {
281 hr = SchedCreateDatabase(psd);
282 ExitOnFailure(hr, "Failed to ensure database %ls exists", psd->wzKey);
283 }
284 }
285 }
286
287LExit:
288 return hr;
289}
290
291
292void ScaDbsFreeList(
293 __in SCA_DB* psdList
294 )
295{
296 SCA_DB* psdDelete = psdList;
297 while (psdList)
298 {
299 psdDelete = psdList;
300 psdList = psdList->psdNext;
301
302 MemFree(psdDelete);
303 }
304}
305
306
307// private helper functions
308
309static HRESULT NewDb(
310 __out SCA_DB** ppsd
311 )
312{
313 HRESULT hr = S_OK;
314 SCA_DB* psd = static_cast<SCA_DB*>(MemAlloc(sizeof(SCA_DB), TRUE));
315 ExitOnNull(psd, hr, E_OUTOFMEMORY, "failed to allocate memory for new database element");
316
317 *ppsd = psd;
318
319LExit:
320 return hr;
321}
322
323
324static SCA_DB* AddDbToList(
325 __in SCA_DB* psdList,
326 __in SCA_DB* psd
327 )
328{
329 if (psdList)
330 {
331 SCA_DB* psdT = psdList;
332 while (psdT->psdNext)
333 {
334 psdT = psdT->psdNext;
335 }
336
337 psdT->psdNext = psd;
338 }
339 else
340 {
341 psdList = psd;
342 }
343
344 return psdList;
345}
346
347
348static HRESULT SchedCreateDatabase(
349 __in SCA_DB* psd
350 )
351{
352 HRESULT hr = S_OK;
353 WCHAR* pwzCustomActionData = NULL;
354
355 hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData);
356 ExitOnFailure(hr, "failed to add DBKey to CustomActionData");
357
358 hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData);
359 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
360
361 hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData);
362 ExitOnFailure(hr, "Failed to add server instance to CustomActionData");
363
364 hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData);
365 ExitOnFailure(hr, "Failed to add database name to CustomActionData");
366
367 hr = WcaWriteIntegerToCaData(psd->iAttributes, &pwzCustomActionData);
368 ExitOnFailure(hr, "Failed to add Sql attributes to CustomActionData");
369
370 hr = WcaWriteStringToCaData(psd->fUseIntegratedAuth ? L"1" : L"0", &pwzCustomActionData);
371 ExitOnFailure(hr, "Failed to add if integrated connection to CustomActionData");
372
373 hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData);
374 ExitOnFailure(hr, "Failed to add server user to CustomActionData");
375
376 hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData);
377 ExitOnFailure(hr, "Failed to add user password to CustomActionData");
378
379 // Check to see if the database exists, if it does not then schedule a rollback
380 // so we clean up after ourselves if the creation of the database fails or is
381 // aborted. It is interesting to note that we can do this check here because the
382 // deferred CustomActions are Impersonated. That means this scheduling action and
383 // the execution actions all run with the same user context, so it is safe to
384 // to do the check.
385 hr = SqlDatabaseExists(psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword, NULL);
386 if (S_FALSE == hr)
387 {
388 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackCreateDatabase"), pwzCustomActionData, COST_SQL_CREATEDB);
389 ExitOnFailure(hr, "Failed to schedule RollbackCreateDatabase action");
390 }
391
392 // database filespec
393 if (psd->fHasDbSpec)
394 {
395 hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData);
396 ExitOnFailure(hr, "failed to specify that do have db.filespec to CustomActionData");
397
398 hr = WcaWriteStringToCaData(psd->sfDb.wzName, &pwzCustomActionData);
399 ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData");
400
401 hr = WcaWriteStringToCaData(psd->sfDb.wzFilename, &pwzCustomActionData);
402 ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData");
403
404 hr = WcaWriteStringToCaData(psd->sfDb.wzSize, &pwzCustomActionData);
405 ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData");
406
407 hr = WcaWriteStringToCaData(psd->sfDb.wzMaxSize, &pwzCustomActionData);
408 ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData");
409
410 hr = WcaWriteStringToCaData(psd->sfDb.wzGrow, &pwzCustomActionData);
411 ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData");
412 }
413 else
414 {
415 hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData);
416 ExitOnFailure(hr, "failed to specify that do not have db.filespec to CustomActionData");
417 }
418
419 // log filespec
420 if (psd->fHasLogSpec)
421 {
422 hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData);
423 ExitOnFailure(hr, "failed to specify that do have log.filespec to CustomActionData");
424
425 hr = WcaWriteStringToCaData(psd->sfLog.wzName, &pwzCustomActionData);
426 ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData");
427
428 hr = WcaWriteStringToCaData(psd->sfLog.wzFilename, &pwzCustomActionData);
429 ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData");
430
431 hr = WcaWriteStringToCaData(psd->sfLog.wzSize, &pwzCustomActionData);
432 ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData");
433
434 hr = WcaWriteStringToCaData(psd->sfLog.wzMaxSize, &pwzCustomActionData);
435 ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData");
436
437 hr = WcaWriteStringToCaData(psd->sfLog.wzGrow, &pwzCustomActionData);
438 ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData");
439 }
440 else
441 {
442 hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData);
443 ExitOnFailure(hr, "failed to specify that do not have log.filespec to CustomActionData");
444 }
445
446 // schedule the CreateDatabase action
447 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateDatabase"), pwzCustomActionData, COST_SQL_CREATEDB);
448 ExitOnFailure(hr, "Failed to schedule CreateDatabase action");
449
450LExit:
451 ReleaseStr(pwzCustomActionData);
452 return hr;
453}
454
455
456HRESULT SchedDropDatabase(
457 __in LPCWSTR wzKey,
458 __in LPCWSTR wzServer,
459 __in LPCWSTR wzInstance,
460 __in LPCWSTR wzDatabase,
461 __in int iAttributes,
462 __in BOOL fIntegratedAuth,
463 __in LPCWSTR wzUser,
464 __in LPCWSTR wzPassword
465 )
466{
467 HRESULT hr = S_OK;
468 WCHAR* pwzCustomActionData = NULL;
469
470 hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData);
471 ExitOnFailure(hr, "failed to add DBKey to CustomActionData");
472
473 hr = WcaWriteStringToCaData(wzServer, &pwzCustomActionData);
474 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
475
476 hr = WcaWriteStringToCaData(wzInstance, &pwzCustomActionData);
477 ExitOnFailure(hr, "Failed to add server instance to CustomActionData");
478
479 hr = WcaWriteStringToCaData(wzDatabase, &pwzCustomActionData);
480 ExitOnFailure(hr, "Failed to add database name to CustomActionData");
481
482 hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData);
483 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
484
485 hr = WcaWriteStringToCaData(fIntegratedAuth ? L"1" : L"0", &pwzCustomActionData);
486 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
487
488 hr = WcaWriteStringToCaData(wzUser, &pwzCustomActionData);
489 ExitOnFailure(hr, "Failed to add server user to CustomActionData");
490
491 hr = WcaWriteStringToCaData(wzPassword, &pwzCustomActionData);
492 ExitOnFailure(hr, "Failed to add user password to CustomActionData");
493
494 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"DropDatabase"), pwzCustomActionData, COST_SQL_DROPDB);
495 ExitOnFailure(hr, "Failed to schedule DropDatabase action");
496
497LExit:
498 ReleaseStr(pwzCustomActionData);
499 return hr;
500}
501
502
503HRESULT GetFileSpec(
504 __in MSIHANDLE hViewFileSpec,
505 __in LPCWSTR wzKey,
506 __in SQL_FILESPEC* psf
507 )
508{
509 HRESULT hr = S_OK;
510 PMSIHANDLE hRecFileSpec, hRec;
511 LPWSTR pwzData = NULL;
512
513 // create a record to do the fetch
514 hRecFileSpec = ::MsiCreateRecord(1);
515 if (!hRecFileSpec)
516 {
517 ExitOnFailure(hr = E_UNEXPECTED, "failed to create record for filespec: %ls", wzKey);
518 }
519 hr = WcaSetRecordString(hRecFileSpec, 1, wzKey);
520 ExitOnFailure(hr, "failed to set record string for filespec: %ls", wzKey);
521
522 // get the FileSpec record
523 hr = WcaExecuteView(hViewFileSpec, hRecFileSpec);
524 ExitOnFailure(hr, "failed to execute view on Wix4SqlFileSpec table for filespec: %ls", wzKey);
525 hr = WcaFetchSingleRecord(hViewFileSpec, &hRec);
526 ExitOnFailure(hr, "failed to get record for filespec: %ls", wzKey);
527
528 // read the data out of the filespec record
529 hr = WcaGetRecordFormattedString(hRec, sfsqName, &pwzData);
530 ExitOnFailure(hr, "Failed to get Wix4SqlFileSpec.Name for filespec: %ls", wzKey);
531 hr = ::StringCchCopyW(psf->wzName, countof(psf->wzName), pwzData);
532 ExitOnFailure(hr, "Failed to copy Wix4SqlFileSpec.Name string: %ls", pwzData);
533
534 hr = WcaGetRecordFormattedString(hRec, sfsqFilename, &pwzData);
535 ExitOnFailure(hr, "Failed to get Wix4SqlFileSpec.Filename for filespec: %ls", wzKey);
536 if (*pwzData)
537 {
538 hr = ::StringCchCopyW(psf->wzFilename, countof(psf->wzFilename), pwzData);
539 ExitOnFailure(hr, "Failed to copy filename to filespec object: %ls", pwzData);
540 }
541 else // if there is no file, skip this FILESPEC
542 {
543 WcaLog(LOGMSG_VERBOSE, "No filename specified, skipping FileSpec: %ls", psf->wzName);
544 ExitFunction1(hr = S_FALSE);
545 }
546
547 hr = WcaGetRecordFormattedString(hRec, sfsqSize, &pwzData);
548 ExitOnFailure(hr, "Failed to get Wix4SqlFileSpec.Size for filespec: %ls", wzKey);
549 if (*pwzData)
550 {
551 hr = ::StringCchCopyW(psf->wzSize, countof(psf->wzSize), pwzData);
552 ExitOnFailure(hr, "Failed to copy size to filespec object: %ls", pwzData);
553 }
554 else
555 {
556 psf->wzSize[0] = 0;
557 }
558
559 hr = WcaGetRecordFormattedString(hRec, sfsqMaxSize, &pwzData);
560 ExitOnFailure(hr, "Failed to get Wix4SqlFileSpec.MaxSize for filespec: %ls", wzKey);
561 if (*pwzData)
562 {
563 hr = ::StringCchCopyW(psf->wzMaxSize, countof(psf->wzMaxSize), pwzData);
564 ExitOnFailure(hr, "Failed to copy max size to filespec object: %ls", pwzData);
565 }
566 else
567 {
568 psf->wzMaxSize[0] = 0;
569 }
570
571 hr = WcaGetRecordFormattedString(hRec, sfsqGrowth, &pwzData);
572 ExitOnFailure(hr, "Failed to get Wix4SqlFileSpec.GrowthSize for filespec: %ls", wzKey);
573 if (*pwzData)
574 {
575 hr = ::StringCchCopyW(psf->wzGrow, countof(psf->wzGrow), pwzData);
576 ExitOnFailure(hr, "Failed to copy growth size to filespec object: %ls", pwzData);
577 }
578 else
579 {
580 psf->wzGrow[0] = 0;
581 }
582
583 hr = S_OK;
584
585LExit:
586 ReleaseStr(pwzData);
587 return hr;
588}
diff --git a/src/ext/Sql/ca/scadb.h b/src/ext/Sql/ca/scadb.h
new file mode 100644
index 00000000..885e84c2
--- /dev/null
+++ b/src/ext/Sql/ca/scadb.h
@@ -0,0 +1,55 @@
1#pragma once
2// 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.
3
4
5#include "scauser.h"
6#include "sqlutil.h"
7
8struct SCA_DB
9{
10 // darwin information
11 WCHAR wzKey[MAX_DARWIN_KEY + 1];
12 BOOL fHasComponent;
13 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
14 INSTALLSTATE isInstalled, isAction;
15
16 WCHAR wzServer[MAX_DARWIN_COLUMN + 1];
17 WCHAR wzInstance[MAX_DARWIN_COLUMN + 1];
18 WCHAR wzDatabase[MAX_DARWIN_COLUMN + 1];
19
20 int iAttributes;
21
22 BOOL fUseIntegratedAuth;
23 SCA_USER scau;
24
25 BOOL fHasDbSpec;
26 SQL_FILESPEC sfDb;
27 BOOL fHasLogSpec;
28 SQL_FILESPEC sfLog;
29
30 SCA_DB* psdNext;
31};
32
33
34// prototypes
35HRESULT ScaDbsRead(
36 __inout SCA_DB** ppsdList,
37 __in SCA_ACTION saAction
38 );
39
40SCA_DB* ScaDbsFindDatabase(
41 __in LPCWSTR wzSqlDb,
42 __in SCA_DB* psdList
43 );
44
45HRESULT ScaDbsInstall(
46 __in SCA_DB* psdList
47 );
48
49HRESULT ScaDbsUninstall(
50 __in SCA_DB* psdList
51 );
52
53void ScaDbsFreeList(
54 __in SCA_DB* psdList
55 );
diff --git a/src/ext/Sql/ca/scaexec.cpp b/src/ext/Sql/ca/scaexec.cpp
new file mode 100644
index 00000000..b2648361
--- /dev/null
+++ b/src/ext/Sql/ca/scaexec.cpp
@@ -0,0 +1,393 @@
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
6/********************************************************************
7 * CreateDatabase - CUSTOM ACTION ENTRY POINT for creating databases
8 *
9 * Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword
10 * ****************************************************************/
11extern "C" UINT __stdcall CreateDatabase(MSIHANDLE hInstall)
12{
13//AssertSz(FALSE, "debug CreateDatabase here");
14 UINT er = ERROR_SUCCESS;
15 HRESULT hr = S_OK;
16
17 LPWSTR pwzData = NULL;
18 IDBCreateSession* pidbSession = NULL;
19 BSTR bstrErrorDescription = NULL;
20 LPWSTR pwz = NULL;
21 LPWSTR pwzDatabaseKey = NULL;
22 LPWSTR pwzServer = NULL;
23 LPWSTR pwzInstance = NULL;
24 LPWSTR pwzDatabase = NULL;
25 LPWSTR pwzTemp = NULL;
26 int iAttributes;
27 BOOL fIntegratedAuth;
28 LPWSTR pwzUser = NULL;
29 LPWSTR pwzPassword = NULL;
30 BOOL fHaveDbFileSpec = FALSE;
31 SQL_FILESPEC sfDb;
32 BOOL fHaveLogFileSpec = FALSE;
33 SQL_FILESPEC sfLog;
34 BOOL fInitializedCom = FALSE;
35
36 memset(&sfDb, 0, sizeof(sfDb));
37 memset(&sfLog, 0, sizeof(sfLog));
38
39 hr = WcaInitialize(hInstall, "CreateDatabase");
40 ExitOnFailure(hr, "failed to initialize");
41
42 hr = ::CoInitialize(NULL);
43 ExitOnFailure(hr, "failed to intialize COM");
44 fInitializedCom = TRUE;
45
46 hr = WcaGetProperty( L"CustomActionData", &pwzData);
47 ExitOnFailure(hr, "failed to get CustomActionData");
48
49 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
50
51 pwz = pwzData;
52 hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); // SQL Server
53 ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz);
54 hr = WcaReadStringFromCaData(&pwz, &pwzServer); // SQL Server
55 ExitOnFailure(hr, "failed to read server from custom action data: %ls", pwz);
56 hr = WcaReadStringFromCaData(&pwz, &pwzInstance); // SQL Server Instance
57 ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz);
58 hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); // SQL Database
59 ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz);
60 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
61 ExitOnFailure(hr, "failed to read attributes from custom action data: %ls", pwz);
62 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth)); // Integrated Windows Authentication?
63 ExitOnFailure(hr, "failed to read integrated auth flag from custom action data: %ls", pwz);
64 hr = WcaReadStringFromCaData(&pwz, &pwzUser); // SQL User
65 ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz);
66 hr = WcaReadStringFromCaData(&pwz, &pwzPassword); // SQL User Password
67 ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz);
68
69 // db file spec
70 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fHaveDbFileSpec));
71 ExitOnFailure(hr, "failed to read db file spec from custom action data: %ls", pwz);
72
73 if (fHaveDbFileSpec)
74 {
75 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
76 ExitOnFailure(hr, "failed to read db file spec name from custom action data: %ls", pwz);
77 hr = ::StringCchCopyW(sfDb.wzName, countof(sfDb.wzName), pwzTemp);
78 ExitOnFailure(hr, "failed to copy db file spec name: %ls", pwzTemp);
79
80 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
81 ExitOnFailure(hr, "failed to read db file spec filename from custom action data: %ls", pwz);
82 hr = ::StringCchCopyW(sfDb.wzFilename, countof(sfDb.wzFilename), pwzTemp);
83 ExitOnFailure(hr, "failed to copy db file spec filename: %ls", pwzTemp);
84
85 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
86 ExitOnFailure(hr, "failed to read db file spec size from custom action data: %ls", pwz);
87 hr = ::StringCchCopyW(sfDb.wzSize, countof(sfDb.wzSize), pwzTemp);
88 ExitOnFailure(hr, "failed to copy db file spec size value: %ls", pwzTemp);
89
90 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
91 ExitOnFailure(hr, "failed to read db file spec max size from custom action data: %ls", pwz);
92 hr = ::StringCchCopyW(sfDb.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp);
93 ExitOnFailure(hr, "failed to copy db file spec max size: %ls", pwzTemp);
94
95 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
96 ExitOnFailure(hr, "failed to read db file spec grow from custom action data: %ls", pwz);
97 hr = ::StringCchCopyW(sfDb.wzGrow, countof(sfDb.wzGrow), pwzTemp);
98 ExitOnFailure(hr, "failed to copy db file spec grow value: %ls", pwzTemp);
99 }
100
101 // log file spec
102 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fHaveLogFileSpec));
103 ExitOnFailure(hr, "failed to read log file spec from custom action data: %ls", pwz);
104 if (fHaveLogFileSpec)
105 {
106 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
107 ExitOnFailure(hr, "failed to read log file spec name from custom action data: %ls", pwz);
108 hr = ::StringCchCopyW(sfLog.wzName, countof(sfDb.wzName), pwzTemp);
109 ExitOnFailure(hr, "failed to copy log file spec name: %ls", pwzTemp);
110
111 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
112 ExitOnFailure(hr, "failed to read log file spec filename from custom action data: %ls", pwz);
113 hr = ::StringCchCopyW(sfLog.wzFilename, countof(sfDb.wzFilename), pwzTemp);
114 ExitOnFailure(hr, "failed to copy log file spec filename: %ls", pwzTemp);
115
116 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
117 ExitOnFailure(hr, "failed to read log file spec size from custom action data: %ls", pwz);
118 hr = ::StringCchCopyW(sfLog.wzSize, countof(sfDb.wzSize), pwzTemp);
119 ExitOnFailure(hr, "failed to copy log file spec size value: %ls", pwzTemp);
120
121 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
122 ExitOnFailure(hr, "failed to read log file spec max size from custom action data: %ls", pwz);
123 hr = ::StringCchCopyW(sfLog.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp);
124 ExitOnFailure(hr, "failed to copy log file spec max size: %ls", pwzTemp);
125
126 hr = WcaReadStringFromCaData(&pwz, &pwzTemp);
127 ExitOnFailure(hr, "failed to read log file spec grow from custom action data: %ls", pwz);
128 hr = ::StringCchCopyW(sfLog.wzGrow, countof(sfDb.wzGrow), pwzTemp);
129 ExitOnFailure(hr, "failed to copy log file spec grow value: %ls", pwzTemp);
130 }
131
132 if (iAttributes & SCADB_CONFIRM_OVERWRITE)
133 {
134 // Check if the database already exists
135 hr = SqlDatabaseExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription);
136 MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to check if database exists: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription);
137
138 if (S_OK == hr) // found an existing database, confirm that they don't want to stop before it gets trampled, in no UI case just continue anyways
139 {
140 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
141 if (IDNO == WcaErrorMessage(msierrSQLDatabaseAlreadyExists, hr, MB_YESNO, 1, pwzDatabase))
142 ExitOnFailure(hr, "failed to initialize");
143 }
144 }
145
146 hr = SqlDatabaseEnsureExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, fHaveDbFileSpec ? &sfDb : NULL, fHaveLogFileSpec ? &sfLog : NULL, &bstrErrorDescription);
147 if ((iAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr))
148 {
149 WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to create SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase);
150 hr = S_OK;
151 }
152 MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to create to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription);
153
154 hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE);
155LExit:
156 ReleaseStr(pwzDatabaseKey);
157 ReleaseStr(pwzServer);
158 ReleaseStr(pwzInstance);
159 ReleaseStr(pwzDatabase);
160 ReleaseStr(pwzUser);
161 ReleaseStr(pwzPassword);
162 ReleaseObject(pidbSession);
163 ReleaseBSTR(bstrErrorDescription);
164
165 if (fInitializedCom)
166 {
167 ::CoUninitialize();
168 }
169
170 if (FAILED(hr))
171 {
172 er = ERROR_INSTALL_FAILURE;
173 }
174 return WcaFinalize(er);
175}
176
177
178/********************************************************************
179 DropDatabase - CUSTOM ACTION ENTRY POINT for removing databases
180
181 Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword
182 * ****************************************************************/
183extern "C" UINT __stdcall DropDatabase(MSIHANDLE hInstall)
184{
185//Assert(FALSE);
186 UINT er = ERROR_SUCCESS;
187 HRESULT hr = S_OK;
188
189 LPWSTR pwzData = NULL;
190 IDBCreateSession* pidbSession = NULL;
191 BSTR bstrErrorDescription = NULL;
192 LPWSTR pwz = NULL;
193 LPWSTR pwzDatabaseKey = NULL;
194 LPWSTR pwzServer = NULL;
195 LPWSTR pwzInstance = NULL;
196 LPWSTR pwzDatabase = NULL;
197 long lAttributes;
198 BOOL fIntegratedAuth;
199 LPWSTR pwzUser = NULL;
200 LPWSTR pwzPassword = NULL;
201 BOOL fInitializedCom = TRUE;
202
203 hr = WcaInitialize(hInstall, "DropDatabase");
204 ExitOnFailure(hr, "failed to initialize");
205
206 hr = ::CoInitialize(NULL);
207 ExitOnFailure(hr, "failed to intialize COM");
208 fInitializedCom = TRUE;
209
210 hr = WcaGetProperty( L"CustomActionData", &pwzData);
211 ExitOnFailure(hr, "failed to get CustomActionData");
212
213 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
214
215 pwz = pwzData;
216 hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey);
217 ExitOnFailure(hr, "failed to read database key");
218 hr = WcaReadStringFromCaData(&pwz, &pwzServer);
219 ExitOnFailure(hr, "failed to read server");
220 hr = WcaReadStringFromCaData(&pwz, &pwzInstance);
221 ExitOnFailure(hr, "failed to read instance");
222 hr = WcaReadStringFromCaData(&pwz, &pwzDatabase);
223 ExitOnFailure(hr, "failed to read database");
224 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&lAttributes));
225 ExitOnFailure(hr, "failed to read attributes");
226 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth)); // Integrated Windows Authentication?
227 ExitOnFailure(hr, "failed to read integrated auth flag");
228 hr = WcaReadStringFromCaData(&pwz, &pwzUser);
229 ExitOnFailure(hr, "failed to read user");
230 hr = WcaReadStringFromCaData(&pwz, &pwzPassword);
231 ExitOnFailure(hr, "failed to read password");
232
233 hr = SqlDropDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription);
234 if ((lAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr))
235 {
236 WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to drop SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase);
237 hr = S_OK;
238 }
239 MessageExitOnFailure(hr, msierrSQLFailedDropDatabase, "failed to drop to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription);
240
241 hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE);
242
243LExit:
244 ReleaseStr(pwzDatabaseKey);
245 ReleaseStr(pwzServer);
246 ReleaseStr(pwzInstance);
247 ReleaseStr(pwzDatabase);
248 ReleaseStr(pwzUser);
249 ReleaseStr(pwzPassword);
250 ReleaseStr(pwzData);
251 ReleaseObject(pidbSession);
252 ReleaseBSTR(bstrErrorDescription);
253
254 if (fInitializedCom)
255 {
256 ::CoUninitialize();
257 }
258
259 if (FAILED(hr))
260 {
261 er = ERROR_INSTALL_FAILURE;
262 }
263 return WcaFinalize(er);
264}
265
266
267/********************************************************************
268 ExecuteSqlStrings - CUSTOM ACTION ENTRY POINT for running SQL strings
269
270 Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword\tSQLKey1\tSQLString1\tSQLKey2\tSQLString2\tSQLKey3\tSQLString3\t...
271 rollback CustomActionData - same as above
272 * ****************************************************************/
273extern "C" UINT __stdcall ExecuteSqlStrings(MSIHANDLE hInstall)
274{
275//Assert(FALSE);
276 UINT er = ERROR_SUCCESS;
277 HRESULT hr = S_OK;
278 HRESULT hrDB = S_OK;
279
280 LPWSTR pwzData = NULL;
281 IDBCreateSession* pidbSession = NULL;
282 BSTR bstrErrorDescription = NULL;
283
284 LPWSTR pwz = NULL;
285 LPWSTR pwzDatabaseKey = NULL;
286 LPWSTR pwzServer = NULL;
287 LPWSTR pwzInstance = NULL;
288 LPWSTR pwzDatabase = NULL;
289 int iAttributesDB;
290 int iAttributesSQL;
291 BOOL fIntegratedAuth;
292 LPWSTR pwzUser = NULL;
293 LPWSTR pwzPassword = NULL;
294 LPWSTR pwzSqlKey = NULL;
295 LPWSTR pwzSql = NULL;
296 BOOL fInitializedCom = FALSE;
297
298 hr = WcaInitialize(hInstall, "ExecuteSqlStrings");
299 ExitOnFailure(hr, "failed to initialize");
300
301 hr = ::CoInitialize(NULL);
302 ExitOnFailure(hr, "failed to intialize COM");
303 fInitializedCom = TRUE;
304
305 hr = WcaGetProperty( L"CustomActionData", &pwzData);
306 ExitOnFailure(hr, "failed to get CustomActionData");
307
308 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
309
310 pwz = pwzData;
311 hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey);
312 ExitOnFailure(hr, "failed to read database key");
313 hr = WcaReadStringFromCaData(&pwz, &pwzServer);
314 ExitOnFailure(hr, "failed to read server");
315 hr = WcaReadStringFromCaData(&pwz, &pwzInstance);
316 ExitOnFailure(hr, "failed to read instance");
317 hr = WcaReadStringFromCaData(&pwz, &pwzDatabase);
318 ExitOnFailure(hr, "failed to read database");
319 hr = WcaReadIntegerFromCaData(&pwz, &iAttributesDB);
320 ExitOnFailure(hr, "failed to read attributes");
321 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth)); // Integrated Windows Authentication?
322 ExitOnFailure(hr, "failed to read integrated auth flag");
323 hr = WcaReadStringFromCaData(&pwz, &pwzUser);
324 ExitOnFailure(hr, "failed to read user");
325 hr = WcaReadStringFromCaData(&pwz, &pwzPassword);
326 ExitOnFailure(hr, "failed to read password");
327
328 // Store off the result of the connect, only exit if we don't care if the database connection succeeds
329 // Wait to fail until later to see if we actually have work to do that is not set to continue on error
330 hrDB = SqlConnectDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &pidbSession);
331 if ((iAttributesDB & SCADB_CONTINUE_ON_ERROR) && FAILED(hrDB))
332 {
333 WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase);
334 ExitFunction1(hr = S_OK);
335 }
336
337 while (S_OK == hr && S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzSqlKey)))
338 {
339 hr = WcaReadIntegerFromCaData(&pwz, &iAttributesSQL);
340 ExitOnFailure(hr, "failed to read attributes for SQL string: %ls", pwzSqlKey);
341
342 hr = WcaReadStringFromCaData(&pwz, &pwzSql);
343 ExitOnFailure(hr, "failed to read SQL string for key: %ls", pwzSqlKey);
344
345 // If the Wix4SqlString row is set to continue on error and the DB connection failed, skip attempting to execute
346 if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hrDB))
347 {
348 WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase);
349 continue;
350 }
351
352 // Now check if the DB connection succeeded
353 MessageExitOnFailure(hr = hrDB, msierrSQLFailedConnectDatabase, "failed to connect to database: '%ls'", pwzDatabase);
354
355 WcaLog(LOGMSG_VERBOSE, "Executing SQL string: %ls", pwzSql);
356 hr = SqlSessionExecuteQuery(pidbSession, pwzSql, NULL, NULL, &bstrErrorDescription);
357 if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hr))
358 {
359 WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to execute SQL string but continuing, error: %ls, SQL key: %ls SQL string: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql);
360 hr = S_OK;
361 }
362 MessageExitOnFailure(hr, msierrSQLFailedExecString, "failed to execute SQL string, error: %ls, SQL key: %ls SQL string: %ls", NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql);
363
364 WcaProgressMessage(COST_SQL_STRING, FALSE);
365 }
366 if (E_NOMOREITEMS == hr)
367 {
368 hr = S_OK;
369 }
370
371LExit:
372 ReleaseStr(pwzDatabaseKey);
373 ReleaseStr(pwzServer);
374 ReleaseStr(pwzInstance);
375 ReleaseStr(pwzDatabase);
376 ReleaseStr(pwzUser);
377 ReleaseStr(pwzPassword);
378 ReleaseStr(pwzData);
379
380 ReleaseBSTR(bstrErrorDescription);
381 ReleaseObject(pidbSession);
382
383 if (fInitializedCom)
384 {
385 ::CoUninitialize();
386 }
387
388 if (FAILED(hr))
389 {
390 er = ERROR_INSTALL_FAILURE;
391 }
392 return WcaFinalize(er);
393}
diff --git a/src/ext/Sql/ca/scasql.cpp b/src/ext/Sql/ca/scasql.cpp
new file mode 100644
index 00000000..b0216950
--- /dev/null
+++ b/src/ext/Sql/ca/scasql.cpp
@@ -0,0 +1,113 @@
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// prototypes
6static HRESULT ConfigureSqlData(
7 __in SCA_ACTION saAction
8 );
9
10
11/********************************************************************
12InstallSqlData - CUSTOM ACTION ENTRY POINT for installing
13 SQL data
14
15********************************************************************/
16extern "C" UINT __stdcall InstallSqlData(
17 __in MSIHANDLE hInstall
18 )
19{
20 HRESULT hr = S_OK;
21 UINT er = ERROR_SUCCESS;
22
23 // initialize
24 hr = WcaInitialize(hInstall, "InstallSqlData");
25 ExitOnFailure(hr, "Failed to initialize");
26
27 hr = ConfigureSqlData(SCA_ACTION_INSTALL);
28
29LExit:
30 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
31 return WcaFinalize(er);
32}
33
34
35/********************************************************************
36UninstallSqlData - CUSTOM ACTION ENTRY POINT for uninstalling
37 SQL data
38
39********************************************************************/
40extern "C" UINT __stdcall UninstallSqlData(
41 __in MSIHANDLE hInstall
42 )
43{
44 HRESULT hr = S_OK;
45 UINT er = ERROR_SUCCESS;
46
47 // initialize
48 hr = WcaInitialize(hInstall, "UninstallCertificates");
49 ExitOnFailure(hr, "Failed to initialize");
50
51 hr = ConfigureSqlData(SCA_ACTION_UNINSTALL);
52
53LExit:
54 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
55 return WcaFinalize(er);
56}
57
58
59static HRESULT ConfigureSqlData(
60 __in SCA_ACTION saAction
61 )
62{
63 //AssertSz(FALSE, "debug ConfigureSqlData()");
64 HRESULT hr = S_OK;
65
66 SCA_DB* psdList = NULL;
67 SCA_SQLSTR* psssList = NULL;
68
69 // check for the prerequsite tables
70 if (S_OK != WcaTableExists(L"Wix4SqlDatabase"))
71 {
72 WcaLog(LOGMSG_VERBOSE, "skipping SQL CustomAction, no Wix4SqlDatabase table");
73 ExitFunction1(hr = S_FALSE);
74 }
75
76 // read tables
77 hr = ScaDbsRead(&psdList, saAction);
78 ExitOnFailure(hr, "failed to read Wix4SqlDatabase table");
79
80 hr = ScaSqlStrsRead(&psssList, saAction);
81 ExitOnFailure(hr, "failed to read Wix4SqlString table");
82
83 hr = ScaSqlStrsReadScripts(&psssList, saAction);
84 ExitOnFailure(hr, "failed to read Wix4SqlScript table");
85
86 if (SCA_ACTION_UNINSTALL == saAction)
87 {
88 // do uninstall actions (order is important!)
89 hr = ScaSqlStrsUninstall(psdList, psssList);
90 ExitOnFailure(hr, "failed to execute uninstall SQL strings");
91
92 hr = ScaDbsUninstall(psdList);
93 ExitOnFailure(hr, "failed to uninstall databases");
94 }
95 else
96 {
97 // do install actions (order is important!)
98 hr = ScaDbsInstall(psdList);
99 ExitOnFailure(hr, "failed to install databases");
100
101 hr = ScaSqlStrsInstall(psdList, psssList);
102 ExitOnFailure(hr, "failed to execute install SQL strings, length may be too long, try add GO to break up");
103 }
104
105LExit:
106 if (psssList)
107 ScaSqlStrsFreeList(psssList);
108
109 if (psdList)
110 ScaDbsFreeList(psdList);
111
112 return hr;
113}
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}
diff --git a/src/ext/Sql/ca/scasqlstr.h b/src/ext/Sql/ca/scasqlstr.h
new file mode 100644
index 00000000..72c1d770
--- /dev/null
+++ b/src/ext/Sql/ca/scasqlstr.h
@@ -0,0 +1,51 @@
1#pragma once
2// 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.
3
4
5#include "scadb.h"
6
7struct SCA_SQLSTR
8{
9 // darwin information
10 WCHAR wzKey[MAX_DARWIN_KEY + 1];
11 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
12 INSTALLSTATE isInstalled, isAction;
13
14 WCHAR wzSqlDb[MAX_DARWIN_COLUMN + 1];
15
16 BOOL fHasUser;
17 SCA_USER scau;
18
19 LPWSTR pwzSql;
20 int iAttributes;
21 int iSequence; //used to sequence Wix4SqlString and Wix4SqlScript tables together
22
23 SCA_SQLSTR* psssNext;
24};
25
26
27// prototypes
28HRESULT ScaSqlStrsRead(
29 __inout SCA_SQLSTR** ppsssList,
30 __in SCA_ACTION saAction
31 );
32
33HRESULT ScaSqlStrsReadScripts(
34 __inout SCA_SQLSTR** ppsssList,
35 __in SCA_ACTION saAction
36 );
37
38HRESULT ScaSqlStrsInstall(
39 __in SCA_DB* psdList,
40 __in SCA_SQLSTR* psssList
41 );
42
43HRESULT ScaSqlStrsUninstall(
44 __in SCA_DB* psdList,
45 __in SCA_SQLSTR* psssList
46 );
47
48void ScaSqlStrsFreeList(
49 __in SCA_SQLSTR* psssList
50 );
51
diff --git a/src/ext/Sql/ca/scauser.cpp b/src/ext/Sql/ca/scauser.cpp
new file mode 100644
index 00000000..4d74e4d4
--- /dev/null
+++ b/src/ext/Sql/ca/scauser.cpp
@@ -0,0 +1,82 @@
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
5LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `User` WHERE `User`=?";
6enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword };
7
8
9HRESULT __stdcall ScaGetUser(
10 __in LPCWSTR wzUser,
11 __out SCA_USER* pscau
12 )
13{
14 if (!wzUser || !pscau)
15 {
16 return E_INVALIDARG;
17 }
18
19 HRESULT hr = S_OK;
20 PMSIHANDLE hView, hRec;
21
22 LPWSTR pwzData = NULL;
23
24 // clear struct and bail right away if no user key was passed to search for
25 ::ZeroMemory(pscau, sizeof(*pscau));
26 if (!*wzUser)
27 {
28 ExitFunction1(hr = S_OK);
29 }
30
31 hRec = ::MsiCreateRecord(1);
32 hr = WcaSetRecordString(hRec, 1, wzUser);
33 ExitOnFailure(hr, "Failed to look up User");
34
35 hr = WcaOpenView(vcsUserQuery, &hView);
36 ExitOnFailure(hr, "Failed to open view on User table");
37 hr = WcaExecuteView(hView, hRec);
38 ExitOnFailure(hr, "Failed to execute view on User table");
39
40 hr = WcaFetchSingleRecord(hView, &hRec);
41 if (S_OK == hr)
42 {
43 hr = WcaGetRecordString(hRec, vuqUser, &pwzData);
44 ExitOnFailure(hr, "Failed to get User.User");
45 hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData);
46 ExitOnFailure(hr, "Failed to copy key string to user object");
47
48 hr = WcaGetRecordString(hRec, vuqComponent, &pwzData);
49 ExitOnFailure(hr, "Failed to get User.Component_");
50 hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData);
51 ExitOnFailure(hr, "Failed to copy component string to user object");
52
53 hr = WcaGetRecordFormattedString(hRec, vuqName, &pwzData);
54 ExitOnFailure(hr, "Failed to get User.Name");
55 hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData);
56 ExitOnFailure(hr, "Failed to copy name string to user object");
57
58 hr = WcaGetRecordFormattedString(hRec, vuqDomain, &pwzData);
59 ExitOnFailure(hr, "Failed to get User.Domain");
60 hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData);
61 ExitOnFailure(hr, "Failed to copy domain string to user object");
62
63 hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData);
64 ExitOnFailure(hr, "Failed to get User.Password");
65 hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData);
66 ExitOnFailure(hr, "Failed to copy password string to user object");
67 }
68 else if (E_NOMOREITEMS == hr)
69 {
70 WcaLog(LOGMSG_STANDARD, "Error: Cannot locate User.User='%ls'", wzUser);
71 hr = E_FAIL;
72 }
73 else
74 {
75 ExitOnFailure(hr, "Error or found multiple matching User rows");
76 }
77
78LExit:
79 ReleaseStr(pwzData);
80
81 return hr;
82}
diff --git a/src/ext/Sql/ca/scauser.h b/src/ext/Sql/ca/scauser.h
new file mode 100644
index 00000000..20e561f2
--- /dev/null
+++ b/src/ext/Sql/ca/scauser.h
@@ -0,0 +1,40 @@
1#pragma once
2// 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.
3
4
5
6// structs
7struct SCA_GROUP
8{
9 WCHAR wzKey[MAX_DARWIN_KEY + 1];
10 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
11
12 WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
13 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
14
15 SCA_GROUP *psgNext;
16};
17
18struct SCA_USER
19{
20 WCHAR wzKey[MAX_DARWIN_KEY + 1];
21 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
22 INSTALLSTATE isInstalled;
23 INSTALLSTATE isAction;
24
25 WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
26 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
27 WCHAR wzPassword[MAX_DARWIN_COLUMN + 1];
28 INT iAttributes;
29
30 SCA_GROUP *psgGroups;
31
32 SCA_USER *psuNext;
33};
34
35
36// prototypes
37HRESULT __stdcall ScaGetUser(
38 __in LPCWSTR wzUser,
39 __out SCA_USER* pscau
40 );
diff --git a/src/ext/Sql/ca/sqlca.cpp b/src/ext/Sql/ca/sqlca.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/ext/Sql/ca/sqlca.cpp
@@ -0,0 +1,3 @@
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"
diff --git a/src/ext/Sql/ca/sqlca.def b/src/ext/Sql/ca/sqlca.def
new file mode 100644
index 00000000..e899d560
--- /dev/null
+++ b/src/ext/Sql/ca/sqlca.def
@@ -0,0 +1,13 @@
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
4LIBRARY "sqlca"
5
6EXPORTS
7;scaexec.cpp
8 CreateDatabase
9 DropDatabase
10 ExecuteSqlStrings
11;scasql.cpp
12 InstallSqlData
13 UninstallSqlData
diff --git a/src/ext/Sql/ca/sqlca.vcxproj b/src/ext/Sql/ca/sqlca.vcxproj
new file mode 100644
index 00000000..18becc5f
--- /dev/null
+++ b/src/ext/Sql/ca/sqlca.vcxproj
@@ -0,0 +1,83 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup Label="ProjectConfigurations">
6 <ProjectConfiguration Include="Debug|Win32">
7 <Configuration>Debug</Configuration>
8 <Platform>Win32</Platform>
9 </ProjectConfiguration>
10 <ProjectConfiguration Include="Release|Win32">
11 <Configuration>Release</Configuration>
12 <Platform>Win32</Platform>
13 </ProjectConfiguration>
14 <ProjectConfiguration Include="Debug|x64">
15 <Configuration>Debug</Configuration>
16 <Platform>x64</Platform>
17 </ProjectConfiguration>
18 <ProjectConfiguration Include="Release|x64">
19 <Configuration>Release</Configuration>
20 <Platform>x64</Platform>
21 </ProjectConfiguration>
22 <ProjectConfiguration Include="Debug|ARM64">
23 <Configuration>Debug</Configuration>
24 <Platform>ARM64</Platform>
25 </ProjectConfiguration>
26 <ProjectConfiguration Include="Release|ARM64">
27 <Configuration>Release</Configuration>
28 <Platform>ARM64</Platform>
29 </ProjectConfiguration>
30 </ItemGroup>
31
32 <PropertyGroup Label="Globals">
33 <ProjectGuid>{4DCA6E4B-A1F1-4450-BC2D-94AC20F31935}</ProjectGuid>
34 <ConfigurationType>DynamicLibrary</ConfigurationType>
35 <TargetName>sqlca</TargetName>
36 <PlatformToolset>v142</PlatformToolset>
37 <CharacterSet>Unicode</CharacterSet>
38 <ProjectModuleDefinitionFile>sqlca.def</ProjectModuleDefinitionFile>
39 <Description>WiX Toolset Sql CustomAction</Description>
40 </PropertyGroup>
41
42 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
43 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
44
45 <PropertyGroup>
46 <ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries>
47 </PropertyGroup>
48
49 <ItemGroup>
50 <ClCompile Include="dllmain.cpp">
51 <PrecompiledHeader>Create</PrecompiledHeader>
52 </ClCompile>
53 <ClCompile Include="scadb.cpp" />
54 <ClCompile Include="scaexec.cpp" />
55 <ClCompile Include="scasql.cpp" />
56 <ClCompile Include="scasqlstr.cpp" />
57 <ClCompile Include="scauser.cpp" />
58 <ClCompile Include="sqlca.cpp" />
59 </ItemGroup>
60
61 <ItemGroup>
62 <ClInclude Include="CustomMsiErrors.h" />
63 <ClInclude Include="precomp.h" />
64 <ClInclude Include="sca.h" />
65 <ClInclude Include="scacost.h" />
66 <ClInclude Include="scadb.h" />
67 <ClInclude Include="scasqlstr.h" />
68 <ClInclude Include="scauser.h" />
69 </ItemGroup>
70
71 <ItemGroup>
72 <None Include="sqlca.def" />
73 </ItemGroup>
74
75 <ItemGroup>
76 <PackageReference Include="WixToolset.Dutil" Version="4.0.65" />
77 <PackageReference Include="WixToolset.WcaUtil" Version="4.0.18" />
78 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" />
79 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" />
80 </ItemGroup>
81
82 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
83</Project>
diff --git a/src/ext/Sql/nuget.config b/src/ext/Sql/nuget.config
new file mode 100644
index 00000000..db7aba29
--- /dev/null
+++ b/src/ext/Sql/nuget.config
@@ -0,0 +1,17 @@
1<?xml version="1.0" encoding="utf-8"?>
2<configuration>
3 <packageSources>
4 <clear />
5 <add key="wixtoolset-burn" value="https://ci.appveyor.com/nuget/wixtoolset-burn" />
6 <add key="wixtoolset-data" value="https://ci.appveyor.com/nuget/wixtoolset-data" />
7 <add key="wixtoolset-extensibility" value="https://ci.appveyor.com/nuget/wixtoolset-extensibility" />
8 <add key="wixtoolset-core" value="https://ci.appveyor.com/nuget/wixtoolset-core" />
9 <add key="wixtoolset-core-native" value="https://ci.appveyor.com/nuget/wixtoolset-core-native" />
10 <add key="wixtoolset-dtf" value="https://ci.appveyor.com/nuget/wixtoolset-dtf" />
11 <add key="wixtoolset-dutil" value="https://ci.appveyor.com/nuget/wixtoolset-dutil" />
12 <add key="wixtoolset-wcautil" value="https://ci.appveyor.com/nuget/wixtoolset-wcautil" />
13 <add key="wixtoolset-tools" value="https://ci.appveyor.com/nuget/wixtoolset-tools" />
14 <add key="wixbuildtools" value="https://ci.appveyor.com/nuget/wixbuildtools" />
15 <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
16 </packageSources>
17</configuration> \ No newline at end of file
diff --git a/src/ext/Sql/test/WixToolsetTest.Sql/SqlExtensionFixture.cs b/src/ext/Sql/test/WixToolsetTest.Sql/SqlExtensionFixture.cs
new file mode 100644
index 00000000..aa9d7a1f
--- /dev/null
+++ b/src/ext/Sql/test/WixToolsetTest.Sql/SqlExtensionFixture.cs
@@ -0,0 +1,36 @@
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 WixToolsetTest.Sql
4{
5 using System.Linq;
6 using WixBuildTools.TestSupport;
7 using WixToolset.Core.TestPackage;
8 using WixToolset.Sql;
9 using Xunit;
10
11 public class SqlExtensionFixture
12 {
13 [Fact]
14 public void CanBuildUsingSqlStuff()
15 {
16 var folder = TestData.Get(@"TestData\UsingSql");
17 var build = new Builder(folder, typeof(SqlExtensionFactory), new[] { folder });
18
19 var results = build.BuildAndQuery(Build, "Wix4SqlDatabase", "Wix4SqlFileSpec", "Wix4SqlScript", "Wix4SqlString");
20 WixAssert.CompareLineByLine(new[]
21 {
22 "Wix4SqlDatabase:TestDB\tMySQLHostName\tMyInstanceName\tMyDB\tDatabaseComponent\t\tTestFileSpecId\tTestLogFileSpecId\t35",
23 "Wix4SqlFileSpec:TestFileSpecId\tTestFileSpecLogicalName\tTestFileSpec\t10MB\t100MB\t10%",
24 "Wix4SqlFileSpec:TestLogFileSpecId\tTestLogFileSpecLogicalName\tTestLogFileSpec\t1MB\t10MB\t1%",
25 "Wix4SqlScript:TestScript\tTestDB\tDatabaseComponent\tScriptBinary\t\t1\t",
26 "Wix4SqlString:TestString\tTestDB\tDatabaseComponent\tCREATE TABLE TestTable1(name varchar(20), value varchar(20))\t\t1\t",
27 }, results.ToArray());
28 }
29
30 private static void Build(string[] args)
31 {
32 var result = WixRunner.Execute(args)
33 .AssertSuccess();
34 }
35 }
36}
diff --git a/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/Package.en-us.wxl b/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/Package.en-us.wxl
new file mode 100644
index 00000000..38c12ac1
--- /dev/null
+++ b/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/Package.en-us.wxl
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2
3<!--
4This file contains the declaration of all the localizable strings.
5-->
6<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7
8 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
9 <String Id="FeatureTitle">MsiPackage</String>
10
11</WixLocalization>
diff --git a/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/Package.wxs b/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/Package.wxs
new file mode 100644
index 00000000..ee3bc921
--- /dev/null
+++ b/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/Package.wxs
@@ -0,0 +1,19 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" InstallerVersion="200">
3
4
5 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
6
7
8 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
9 <ComponentGroupRef Id="ProductComponents" />
10 </Feature>
11
12 </Package>
13
14 <Fragment>
15 <StandardDirectory Id="ProgramFilesFolder">
16 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
17 </StandardDirectory>
18 </Fragment>
19</Wix>
diff --git a/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/PackageComponents.wxs b/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/PackageComponents.wxs
new file mode 100644
index 00000000..f7626926
--- /dev/null
+++ b/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/PackageComponents.wxs
@@ -0,0 +1,22 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 xmlns:sql="http://wixtoolset.org/schemas/v4/wxs/sql">
4 <Fragment>
5 <Binary Id="ScriptBinary" SourceFile="example.txt" />
6
7 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
8 <Component Id="DatabaseComponent" Guid="{322802E7-D65E-4C91-924F-FC6D30FEEB34}">
9 <File Id="TestFileSpec" Source="example.txt" />
10 <File Id="TestLogFileSpec" Source="example.txt" />
11
12 <sql:SqlDatabase Id="TestDB" Database="MyDB" Server="MySQLHostName" Instance="MyInstanceName" CreateOnInstall="yes" DropOnUninstall="yes" ConfirmOverwrite="yes">
13 <sql:SqlString Id="TestString" SQL="CREATE TABLE TestTable1(name varchar(20), value varchar(20))" ExecuteOnInstall="yes" />
14 <sql:SqlFileSpec Id="TestFileSpecId" Filename="TestFileSpec" Name="TestFileSpecLogicalName" Size="10MB" GrowthSize="10%" MaxSize="100MB" />
15 <sql:SqlLogFileSpec Id="TestLogFileSpecId" Filename="TestLogFileSpec" Name="TestLogFileSpecLogicalName" Size="1MB" GrowthSize="1%" MaxSize="10MB" />
16 </sql:SqlDatabase>
17
18 <sql:SqlScript Id="TestScript" BinaryRef="ScriptBinary" SqlDb="TestDB" ExecuteOnInstall="yes" />
19 </Component>
20 </ComponentGroup>
21 </Fragment>
22</Wix>
diff --git a/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/example.txt b/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/example.txt
new file mode 100644
index 00000000..1b4ffe8a
--- /dev/null
+++ b/src/ext/Sql/test/WixToolsetTest.Sql/TestData/UsingSql/example.txt
@@ -0,0 +1 @@
This is example.txt. \ No newline at end of file
diff --git a/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.csproj b/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.csproj
new file mode 100644
index 00000000..bbf3041d
--- /dev/null
+++ b/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.csproj
@@ -0,0 +1,38 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netcoreapp3.1</TargetFramework>
7 <IsPackable>false</IsPackable>
8 </PropertyGroup>
9
10 <PropertyGroup>
11 <NoWarn>NU1701</NoWarn>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <Content Include="TestData\**" CopyToOutputDirectory="PreserveNewest" />
16 </ItemGroup>
17
18 <ItemGroup>
19 <ProjectReference Include="..\..\wixext\WixToolset.Sql.wixext.csproj" />
20 </ItemGroup>
21
22 <ItemGroup>
23 <PackageReference Include="WixToolset.Core" Version="4.0.*" />
24 <PackageReference Include="WixToolset.Core.Burn" Version="4.0.*" />
25 <PackageReference Include="WixToolset.Core.WindowsInstaller" Version="4.0.*" />
26 <PackageReference Include="WixToolset.Core.TestPackage" Version="4.0.*" />
27 </ItemGroup>
28
29 <ItemGroup>
30 <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" />
31 </ItemGroup>
32
33 <ItemGroup>
34 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
35 <PackageReference Include="xunit" Version="2.4.1" />
36 <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" />
37 </ItemGroup>
38</Project>
diff --git a/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.v3.ncrunchproject b/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.v3.ncrunchproject
new file mode 100644
index 00000000..7b5b2139
--- /dev/null
+++ b/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.v3.ncrunchproject
@@ -0,0 +1,5 @@
1<ProjectConfiguration>
2 <Settings>
3 <CopyReferencedAssembliesToWorkspace>True</CopyReferencedAssembliesToWorkspace>
4 </Settings>
5</ProjectConfiguration> \ No newline at end of file
diff --git a/src/ext/Sql/wix.snk b/src/ext/Sql/wix.snk
new file mode 100644
index 00000000..3908a66a
--- /dev/null
+++ b/src/ext/Sql/wix.snk
Binary files differ
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}
diff --git a/src/ext/Sql/wixext/SqlDecompiler.cs b/src/ext/Sql/wixext/SqlDecompiler.cs
new file mode 100644
index 00000000..52436b87
--- /dev/null
+++ b/src/ext/Sql/wixext/SqlDecompiler.cs
@@ -0,0 +1,514 @@
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#if TODO_CONSIDER_DECOMPILER
6 using System.Collections;
7 using WixToolset.Data;
8 using WixToolset.Extensibility;
9 using Sql = WixToolset.Extensions.Serialize.Sql;
10 using Wix = WixToolset.Data.Serialize;
11
12 /// <summary>
13 /// The decompiler for the WiX Toolset SQL Server Extension.
14 /// </summary>
15 public sealed class SqlDecompiler : DecompilerExtension
16 {
17 /// <summary>
18 /// Creates a decompiler for SQL Extension.
19 /// </summary>
20 public SqlDecompiler()
21 {
22 this.TableDefinitions = SqlExtensionData.GetExtensionTableDefinitions();
23 }
24
25 /// <summary>
26 /// Get the extensions library to be removed.
27 /// </summary>
28 /// <param name="tableDefinitions">Table definitions for library.</param>
29 /// <returns>Library to remove from decompiled output.</returns>
30 public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions)
31 {
32 return SqlExtensionData.GetExtensionLibrary(tableDefinitions);
33 }
34
35 /// <summary>
36 /// Decompiles an extension table.
37 /// </summary>
38 /// <param name="table">The table to decompile.</param>
39 public override void DecompileTable(Table table)
40 {
41 switch (table.Name)
42 {
43 case "SqlDatabase":
44 this.DecompileSqlDatabaseTable(table);
45 break;
46 case "SqlFileSpec":
47 // handled in FinalizeSqlFileSpecTable
48 break;
49 case "SqlScript":
50 this.DecompileSqlScriptTable(table);
51 break;
52 case "SqlString":
53 this.DecompileSqlStringTable(table);
54 break;
55 default:
56 base.DecompileTable(table);
57 break;
58 }
59 }
60
61 /// <summary>
62 /// Finalize decompilation.
63 /// </summary>
64 /// <param name="tables">The collection of all tables.</param>
65 public override void Finish(TableIndexedCollection tables)
66 {
67 this.FinalizeSqlFileSpecTable(tables);
68 this.FinalizeSqlScriptAndSqlStringTables(tables);
69 }
70
71 /// <summary>
72 /// Decompile the SqlDatabase table.
73 /// </summary>
74 /// <param name="table">The table to decompile.</param>
75 private void DecompileSqlDatabaseTable(Table table)
76 {
77 foreach (Row row in table.Rows)
78 {
79 Sql.SqlDatabase sqlDatabase = new Sql.SqlDatabase();
80
81 sqlDatabase.Id = (string)row[0];
82
83 if (null != row[1])
84 {
85 sqlDatabase.Server = (string)row[1];
86 }
87
88 if (null != row[2])
89 {
90 sqlDatabase.Instance = (string)row[2];
91 }
92
93 sqlDatabase.Database = (string)row[3];
94
95 if (null != row[5])
96 {
97 sqlDatabase.User = (string)row[5];
98 }
99
100 // the FileSpec_ and FileSpec_Log columns will be handled in FinalizeSqlFileSpecTable
101
102 if (null != row[8])
103 {
104 int attributes = (int)row[8];
105
106 if (SqlCompiler.DbCreateOnInstall == (attributes & SqlCompiler.DbCreateOnInstall))
107 {
108 sqlDatabase.CreateOnInstall = Sql.YesNoType.yes;
109 }
110
111 if (SqlCompiler.DbDropOnUninstall == (attributes & SqlCompiler.DbDropOnUninstall))
112 {
113 sqlDatabase.DropOnUninstall = Sql.YesNoType.yes;
114 }
115
116 if (SqlCompiler.DbContinueOnError == (attributes & SqlCompiler.DbContinueOnError))
117 {
118 sqlDatabase.ContinueOnError = Sql.YesNoType.yes;
119 }
120
121 if (SqlCompiler.DbDropOnInstall == (attributes & SqlCompiler.DbDropOnInstall))
122 {
123 sqlDatabase.DropOnInstall = Sql.YesNoType.yes;
124 }
125
126 if (SqlCompiler.DbCreateOnUninstall == (attributes & SqlCompiler.DbCreateOnUninstall))
127 {
128 sqlDatabase.CreateOnUninstall = Sql.YesNoType.yes;
129 }
130
131 if (SqlCompiler.DbConfirmOverwrite == (attributes & SqlCompiler.DbConfirmOverwrite))
132 {
133 sqlDatabase.ConfirmOverwrite = Sql.YesNoType.yes;
134 }
135
136 if (SqlCompiler.DbCreateOnReinstall == (attributes & SqlCompiler.DbCreateOnReinstall))
137 {
138 sqlDatabase.CreateOnReinstall = Sql.YesNoType.yes;
139 }
140
141 if (SqlCompiler.DbDropOnReinstall == (attributes & SqlCompiler.DbDropOnReinstall))
142 {
143 sqlDatabase.DropOnReinstall = Sql.YesNoType.yes;
144 }
145 }
146
147 if (null != row[4])
148 {
149 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[4]);
150
151 if (null != component)
152 {
153 component.AddChild(sqlDatabase);
154 }
155 else
156 {
157 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[4], "Component"));
158 }
159 }
160 else
161 {
162 this.Core.RootElement.AddChild(sqlDatabase);
163 }
164 this.Core.IndexElement(row, sqlDatabase);
165 }
166 }
167
168 /// <summary>
169 /// Decompile the SqlScript table.
170 /// </summary>
171 /// <param name="table">The table to decompile.</param>
172 private void DecompileSqlScriptTable(Table table)
173 {
174 foreach (Row row in table.Rows)
175 {
176 Sql.SqlScript sqlScript = new Sql.SqlScript();
177
178 sqlScript.Id = (string)row[0];
179
180 // the Db_ and Component_ columns are handled in FinalizeSqlScriptAndSqlStringTables
181
182 sqlScript.BinaryKey = (string)row[3];
183
184 if (null != row[4])
185 {
186 sqlScript.User = (string)row[4];
187 }
188
189 int attributes = (int)row[5];
190
191 if (SqlCompiler.SqlContinueOnError == (attributes & SqlCompiler.SqlContinueOnError))
192 {
193 sqlScript.ContinueOnError = Sql.YesNoType.yes;
194 }
195
196 if (SqlCompiler.SqlExecuteOnInstall == (attributes & SqlCompiler.SqlExecuteOnInstall))
197 {
198 sqlScript.ExecuteOnInstall = Sql.YesNoType.yes;
199 }
200
201 if (SqlCompiler.SqlExecuteOnReinstall == (attributes & SqlCompiler.SqlExecuteOnReinstall))
202 {
203 sqlScript.ExecuteOnReinstall = Sql.YesNoType.yes;
204 }
205
206 if (SqlCompiler.SqlExecuteOnUninstall == (attributes & SqlCompiler.SqlExecuteOnUninstall))
207 {
208 sqlScript.ExecuteOnUninstall = Sql.YesNoType.yes;
209 }
210
211 if ((SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnInstall) == (attributes & (SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnInstall)))
212 {
213 sqlScript.RollbackOnInstall = Sql.YesNoType.yes;
214 }
215
216 if ((SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnReinstall) == (attributes & (SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnReinstall)))
217 {
218 sqlScript.RollbackOnReinstall = Sql.YesNoType.yes;
219 }
220
221 if ((SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnUninstall) == (attributes & (SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnUninstall)))
222 {
223 sqlScript.RollbackOnUninstall = Sql.YesNoType.yes;
224 }
225
226 if (null != row[6])
227 {
228 sqlScript.Sequence = (int)row[6];
229 }
230
231 this.Core.IndexElement(row, sqlScript);
232 }
233 }
234
235 /// <summary>
236 /// Decompile the SqlString table.
237 /// </summary>
238 /// <param name="table">The table to decompile.</param>
239 private void DecompileSqlStringTable(Table table)
240 {
241 foreach (Row row in table.Rows)
242 {
243 Sql.SqlString sqlString = new Sql.SqlString();
244
245 sqlString.Id = (string)row[0];
246
247 // the Db_ and Component_ columns are handled in FinalizeSqlScriptAndSqlStringTables
248
249 sqlString.SQL = (string)row[3];
250
251 if (null != row[4])
252 {
253 sqlString.User = (string)row[4];
254 }
255
256 int attributes = (int)row[5];
257
258 if (SqlCompiler.SqlContinueOnError == (attributes & SqlCompiler.SqlContinueOnError))
259 {
260 sqlString.ContinueOnError = Sql.YesNoType.yes;
261 }
262
263 if (SqlCompiler.SqlExecuteOnInstall == (attributes & SqlCompiler.SqlExecuteOnInstall))
264 {
265 sqlString.ExecuteOnInstall = Sql.YesNoType.yes;
266 }
267
268 if (SqlCompiler.SqlExecuteOnReinstall == (attributes & SqlCompiler.SqlExecuteOnReinstall))
269 {
270 sqlString.ExecuteOnReinstall = Sql.YesNoType.yes;
271 }
272
273 if (SqlCompiler.SqlExecuteOnUninstall == (attributes & SqlCompiler.SqlExecuteOnUninstall))
274 {
275 sqlString.ExecuteOnUninstall = Sql.YesNoType.yes;
276 }
277
278 if ((SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnInstall) == (attributes & (SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnInstall)))
279 {
280 sqlString.RollbackOnInstall = Sql.YesNoType.yes;
281 }
282
283 if ((SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnReinstall) == (attributes & (SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnReinstall)))
284 {
285 sqlString.RollbackOnReinstall = Sql.YesNoType.yes;
286 }
287
288 if ((SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnUninstall) == (attributes & (SqlCompiler.SqlRollback | SqlCompiler.SqlExecuteOnUninstall)))
289 {
290 sqlString.RollbackOnUninstall = Sql.YesNoType.yes;
291 }
292
293 if (null != row[6])
294 {
295 sqlString.Sequence = (int)row[6];
296 }
297
298 this.Core.IndexElement(row, sqlString);
299 }
300 }
301
302 /// <summary>
303 /// Finalize the SqlFileSpec table.
304 /// </summary>
305 /// <param name="tables">The collection of all tables.</param>
306 /// <remarks>
307 /// Since rows of the SqlFileSpec table are represented by either
308 /// the SqlFileSpec or SqlLogFileSpec depending upon the context in
309 /// which they are used in the SqlDatabase table, decompilation of this
310 /// table must occur after the SqlDatbase parents are decompiled.
311 /// </remarks>
312 private void FinalizeSqlFileSpecTable(TableIndexedCollection tables)
313 {
314 Table sqlDatabaseTable = tables["SqlDatabase"];
315 Table sqlFileSpecTable = tables["SqlFileSpec"];
316
317 if (null != sqlDatabaseTable && null != sqlFileSpecTable)
318 {
319 Hashtable sqlFileSpecRows = new Hashtable();
320
321 // index each SqlFileSpec row by its primary key
322 foreach (Row row in sqlFileSpecTable.Rows)
323 {
324 sqlFileSpecRows.Add(row[0], row);
325 }
326
327 // create the necessary SqlFileSpec and SqlLogFileSpec elements for each row
328 foreach (Row row in sqlDatabaseTable.Rows)
329 {
330 Sql.SqlDatabase sqlDatabase = (Sql.SqlDatabase)this.Core.GetIndexedElement(row);
331
332 if (null != row[6])
333 {
334 Row sqlFileSpecRow = (Row)sqlFileSpecRows[row[6]];
335
336 if (null != sqlFileSpecRow)
337 {
338 Sql.SqlFileSpec sqlFileSpec = new Sql.SqlFileSpec();
339
340 sqlFileSpec.Id = (string)sqlFileSpecRow[0];
341
342 if (null != sqlFileSpecRow[1])
343 {
344 sqlFileSpec.Name = (string)sqlFileSpecRow[1];
345 }
346
347 sqlFileSpec.Filename = (string)sqlFileSpecRow[2];
348
349 if (null != sqlFileSpecRow[3])
350 {
351 sqlFileSpec.Size = (string)sqlFileSpecRow[3];
352 }
353
354 if (null != sqlFileSpecRow[4])
355 {
356 sqlFileSpec.MaxSize = (string)sqlFileSpecRow[4];
357 }
358
359 if (null != sqlFileSpecRow[5])
360 {
361 sqlFileSpec.GrowthSize = (string)sqlFileSpecRow[5];
362 }
363
364 sqlDatabase.AddChild(sqlFileSpec);
365 }
366 else
367 {
368 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, sqlDatabaseTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "FileSpec_", (string)row[6], "SqlFileSpec"));
369 }
370 }
371
372 if (null != row[7])
373 {
374 Row sqlFileSpecRow = (Row)sqlFileSpecRows[row[7]];
375
376 if (null != sqlFileSpecRow)
377 {
378 Sql.SqlLogFileSpec sqlLogFileSpec = new Sql.SqlLogFileSpec();
379
380 sqlLogFileSpec.Id = (string)sqlFileSpecRow[0];
381
382 if (null != sqlFileSpecRow[1])
383 {
384 sqlLogFileSpec.Name = (string)sqlFileSpecRow[1];
385 }
386
387 sqlLogFileSpec.Filename = (string)sqlFileSpecRow[2];
388
389 if (null != sqlFileSpecRow[3])
390 {
391 sqlLogFileSpec.Size = (string)sqlFileSpecRow[3];
392 }
393
394 if (null != sqlFileSpecRow[4])
395 {
396 sqlLogFileSpec.MaxSize = (string)sqlFileSpecRow[4];
397 }
398
399 if (null != sqlFileSpecRow[5])
400 {
401 sqlLogFileSpec.GrowthSize = (string)sqlFileSpecRow[5];
402 }
403
404 sqlDatabase.AddChild(sqlLogFileSpec);
405 }
406 else
407 {
408 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, sqlDatabaseTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "FileSpec_Log", (string)row[7], "SqlFileSpec"));
409 }
410 }
411 }
412 }
413 }
414
415 /// <summary>
416 /// Finalize the SqlScript table.
417 /// </summary>
418 /// <param name="tables">The collection of all tables.</param>
419 /// <remarks>
420 /// The SqlScript and SqlString tables contain a foreign key into the SqlDatabase
421 /// and Component tables. Depending upon the parent of the SqlDatabase
422 /// element, the SqlScript and SqlString elements are nested under either the
423 /// SqlDatabase or the Component element.
424 /// </remarks>
425 private void FinalizeSqlScriptAndSqlStringTables(TableIndexedCollection tables)
426 {
427 Table sqlDatabaseTable = tables["SqlDatabase"];
428 Table sqlScriptTable = tables["SqlScript"];
429 Table sqlStringTable = tables["SqlString"];
430
431 Hashtable sqlDatabaseRows = new Hashtable();
432
433 // index each SqlDatabase row by its primary key
434 if (null != sqlDatabaseTable)
435 {
436 foreach (Row row in sqlDatabaseTable.Rows)
437 {
438 sqlDatabaseRows.Add(row[0], row);
439 }
440 }
441
442 if (null != sqlScriptTable)
443 {
444 foreach (Row row in sqlScriptTable.Rows)
445 {
446 Sql.SqlScript sqlScript = (Sql.SqlScript)this.Core.GetIndexedElement(row);
447
448 Row sqlDatabaseRow = (Row)sqlDatabaseRows[row[1]];
449 string databaseComponent = (string)sqlDatabaseRow[4];
450
451 // determine if the SqlScript element should be nested under the database or another component
452 if (null != databaseComponent && databaseComponent == (string)row[2])
453 {
454 Sql.SqlDatabase sqlDatabase = (Sql.SqlDatabase)this.Core.GetIndexedElement(sqlDatabaseRow);
455
456 sqlDatabase.AddChild(sqlScript);
457 }
458 else // nest under the component of the SqlDatabase row
459 {
460 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]);
461
462 // set the Database value
463 sqlScript.SqlDb = (string)row[1];
464
465 if (null != component)
466 {
467 component.AddChild(sqlScript);
468 }
469 else
470 {
471 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, sqlScriptTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component"));
472 }
473 }
474 }
475 }
476
477 if (null != sqlStringTable)
478 {
479 foreach (Row row in sqlStringTable.Rows)
480 {
481 Sql.SqlString sqlString = (Sql.SqlString)this.Core.GetIndexedElement(row);
482
483 Row sqlDatabaseRow = (Row)sqlDatabaseRows[row[1]];
484 string databaseComponent = (string)sqlDatabaseRow[4];
485
486 // determine if the SqlScript element should be nested under the database or another component
487 if (null != databaseComponent && databaseComponent == (string)row[2])
488 {
489 Sql.SqlDatabase sqlDatabase = (Sql.SqlDatabase)this.Core.GetIndexedElement(sqlDatabaseRow);
490
491 sqlDatabase.AddChild(sqlString);
492 }
493 else // nest under the component of the SqlDatabase row
494 {
495 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]);
496
497 // set the Database value
498 sqlString.SqlDb = (string)row[1];
499
500 if (null != component)
501 {
502 component.AddChild(sqlString);
503 }
504 else
505 {
506 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, sqlStringTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component"));
507 }
508 }
509 }
510 }
511 }
512 }
513#endif
514}
diff --git a/src/ext/Sql/wixext/SqlErrors.cs b/src/ext/Sql/wixext/SqlErrors.cs
new file mode 100644
index 00000000..f25728bd
--- /dev/null
+++ b/src/ext/Sql/wixext/SqlErrors.cs
@@ -0,0 +1,48 @@
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.Resources;
6 using WixToolset.Data;
7
8 public static class SqlErrors
9 {
10 public static Message IllegalAttributeWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName)
11 {
12 return Message(sourceLineNumbers, Ids.IllegalAttributeWithoutComponent, "The {0}/@{1} attribute cannot be specified unless the element has a Component as an ancestor. A {0} that does not have a Component ancestor is not installed.", elementName, attributeName);
13 }
14
15 public static Message IllegalElementWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName)
16 {
17 return Message(sourceLineNumbers, Ids.IllegalElementWithoutComponent, "The {0} element cannot be specified unless the element has a Component as an ancestor. A {0} that does not have a Component ancestor is not installed.", elementName);
18 }
19
20 public static Message OneOfAttributesRequiredUnderComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName1, string attributeName2, string attributeName3, string attributeName4)
21 {
22 return Message(sourceLineNumbers, Ids.OneOfAttributesRequiredUnderComponent, "When nested under a Component, the {0} element must have one of the following attributes specified: {1}, {2}, {3} or {4}.", elementName, attributeName1, attributeName2, attributeName3, attributeName4);
23 }
24
25 public static Message DeprecatedBinaryChildElement(SourceLineNumber sourceLineNumbers, string elementName)
26 {
27 return Message(sourceLineNumbers, Ids.DeprecatedBinaryChildElement, "The {0} element contains a deprecated child Binary element. Please move the Binary element under a Fragment, Module, or Product element and set the {0}/@BinaryKey attribute to the value of the Binary/@Id attribute.", elementName);
28 }
29
30 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
31 {
32 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args);
33 }
34
35 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)
36 {
37 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args);
38 }
39
40 public enum Ids
41 {
42 IllegalAttributeWithoutComponent = 5100,
43 IllegalElementWithoutComponent = 5101,
44 OneOfAttributesRequiredUnderComponent = 5102,
45 DeprecatedBinaryChildElement = 5103,
46 }
47 }
48} \ No newline at end of file
diff --git a/src/ext/Sql/wixext/SqlExtensionData.cs b/src/ext/Sql/wixext/SqlExtensionData.cs
new file mode 100644
index 00000000..60de94fe
--- /dev/null
+++ b/src/ext/Sql/wixext/SqlExtensionData.cs
@@ -0,0 +1,30 @@
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 WixToolset.Data;
6 using WixToolset.Extensibility;
7
8 /// <summary>
9 /// The WiX Toolset SQL Server Extension.
10 /// </summary>
11 public sealed class SqlExtensionData : BaseExtensionData
12 {
13 /// <summary>
14 /// Gets the default culture.
15 /// </summary>
16 /// <value>The default culture.</value>
17 public override string DefaultCulture => "en-US";
18
19 public override bool TryGetSymbolDefinitionByName(string name, out IntermediateSymbolDefinition symbolDefinition)
20 {
21 symbolDefinition = SqlSymbolDefinitions.ByName(name);
22 return symbolDefinition != null;
23 }
24
25 public override Intermediate GetLibrary(ISymbolDefinitionCreator symbolDefinitions)
26 {
27 return Intermediate.Load(typeof(SqlExtensionData).Assembly, "WixToolset.Sql.sql.wixlib", symbolDefinitions);
28 }
29 }
30}
diff --git a/src/ext/Sql/wixext/SqlExtensionFactory.cs b/src/ext/Sql/wixext/SqlExtensionFactory.cs
new file mode 100644
index 00000000..279106d3
--- /dev/null
+++ b/src/ext/Sql/wixext/SqlExtensionFactory.cs
@@ -0,0 +1,18 @@
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 WixToolset.Extensibility;
8
9 public class SqlExtensionFactory : BaseExtensionFactory
10 {
11 protected override IReadOnlyCollection<Type> ExtensionTypes => new[]
12 {
13 typeof(SqlCompiler),
14 typeof(SqlExtensionData),
15 typeof(SqlWindowsInstallerBackendBinderExtension),
16 };
17 }
18}
diff --git a/src/ext/Sql/wixext/SqlTableDefinitions.cs b/src/ext/Sql/wixext/SqlTableDefinitions.cs
new file mode 100644
index 00000000..029a092e
--- /dev/null
+++ b/src/ext/Sql/wixext/SqlTableDefinitions.cs
@@ -0,0 +1,82 @@
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 WixToolset.Data.WindowsInstaller;
6
7 public static class SqlTableDefinitions
8 {
9 public static readonly TableDefinition SqlDatabase = new TableDefinition(
10 "Wix4SqlDatabase",
11 SqlSymbolDefinitions.SqlDatabase,
12 new[]
13 {
14 new ColumnDefinition("SqlDb", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
15 new ColumnDefinition("Server", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Primary key, name of server running SQL Server"),
16 new ColumnDefinition("Instance", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Primary key, name of SQL Server instance"),
17 new ColumnDefinition("Database", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Primary key, name of database in a SQL Server"),
18 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key, Component used to determine install state ", modularizeType: ColumnModularizeType.Column),
19 new ColumnDefinition("User_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "User", keyColumn: 1, description: "Foreign key, User used to log into database", modularizeType: ColumnModularizeType.Column),
20 new ColumnDefinition("FileSpec_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Wix4SqlFileSpec", keyColumn: 1, description: "Foreign key referencing SqlFileSpec.", modularizeType: ColumnModularizeType.Column),
21 new ColumnDefinition("FileSpec_Log", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Wix4SqlFileSpec", keyColumn: 1, description: "Foreign key referencing SqlFileSpec.", modularizeType: ColumnModularizeType.Column),
22 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 255, description: "1 == create on install, 2 == drop on uninstall, 4 == continue on error, 8 == drop on install, 16 == create on uninstall, 32 == confirm update existing table, 64 == create on reinstall, 128 == drop on reinstall"),
23 },
24 symbolIdIsPrimaryKey: true
25 );
26
27 public static readonly TableDefinition SqlFileSpec = new TableDefinition(
28 "Wix4SqlFileSpec",
29 SqlSymbolDefinitions.SqlFileSpec,
30 new[]
31 {
32 new ColumnDefinition("FileSpec", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
33 new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Logical name of filespec", modularizeType: ColumnModularizeType.Property),
34 new ColumnDefinition("Filename", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Filename to use (path must exist)", modularizeType: ColumnModularizeType.Property),
35 new ColumnDefinition("Size", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Initial size for file", modularizeType: ColumnModularizeType.Property),
36 new ColumnDefinition("MaxSize", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Maximum size for file", modularizeType: ColumnModularizeType.Property),
37 new ColumnDefinition("GrowthSize", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Size file should grow when necessary", modularizeType: ColumnModularizeType.Property),
38 },
39 symbolIdIsPrimaryKey: true
40 );
41
42 public static readonly TableDefinition SqlScript = new TableDefinition(
43 "Wix4SqlScript",
44 SqlSymbolDefinitions.SqlScript,
45 new[]
46 {
47 new ColumnDefinition("Script", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token"),
48 new ColumnDefinition("SqlDb_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Wix4SqlDatabase", keyColumn: 1, description: "Foreign key, SQL Server key", modularizeType: ColumnModularizeType.Column),
49 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key, Component used to determine install state", modularizeType: ColumnModularizeType.Column),
50 new ColumnDefinition("ScriptBinary_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Binary", keyColumn: 1, description: "Foreign key, Binary stream that contains SQL Script to execute", modularizeType: ColumnModularizeType.Column),
51 new ColumnDefinition("User_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "User", keyColumn: 1, description: "Foreign key, User used to log into database", modularizeType: ColumnModularizeType.Column),
52 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, possibilities: "1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;31", description: "1 == execute on install, 2 == execute on uninstall, 4 == continue on error, 8 == rollback on install, 16 == rollback on uninstall"),
53 new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Order to execute SQL Queries in"),
54 },
55 symbolIdIsPrimaryKey: true
56 );
57
58 public static readonly TableDefinition SqlString = new TableDefinition(
59 "Wix4SqlString",
60 SqlSymbolDefinitions.SqlString,
61 new[]
62 {
63 new ColumnDefinition("String", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Id for the Wix4SqlString", modularizeType: ColumnModularizeType.Column),
64 new ColumnDefinition("SqlDb_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Wix4SqlDatabase", keyColumn: 1, description: "Foreign key, SQL Server key", modularizeType: ColumnModularizeType.Column),
65 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key, Component used to determine install state", modularizeType: ColumnModularizeType.Column),
66 new ColumnDefinition("SQL", ColumnType.String, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "SQL query to execute"),
67 new ColumnDefinition("User_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "User", keyColumn: 1, description: "Foreign key, User used to log into database", modularizeType: ColumnModularizeType.Column),
68 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, possibilities: "1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;31", description: "1 == execute on install, 2 == execute on uninstall, 4 == continue on error, 8 == rollback on install, 16 == rollback on uninstall"),
69 new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Order to execute SQL Queries in"),
70 },
71 symbolIdIsPrimaryKey: true
72 );
73
74 public static readonly TableDefinition[] All = new[]
75 {
76 SqlDatabase,
77 SqlFileSpec,
78 SqlScript,
79 SqlString,
80 };
81 }
82}
diff --git a/src/ext/Sql/wixext/SqlWindowsInstallerBackendExtension.cs b/src/ext/Sql/wixext/SqlWindowsInstallerBackendExtension.cs
new file mode 100644
index 00000000..2ccdcc56
--- /dev/null
+++ b/src/ext/Sql/wixext/SqlWindowsInstallerBackendExtension.cs
@@ -0,0 +1,13 @@
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.Collections.Generic;
6 using WixToolset.Data.WindowsInstaller;
7 using WixToolset.Extensibility;
8
9 public class SqlWindowsInstallerBackendBinderExtension : BaseWindowsInstallerBackendBinderExtension
10 {
11 public override IReadOnlyCollection<TableDefinition> TableDefinitions => SqlTableDefinitions.All;
12 }
13}
diff --git a/src/ext/Sql/wixext/Symbols/SqlDatabaseSymbol.cs b/src/ext/Sql/wixext/Symbols/SqlDatabaseSymbol.cs
new file mode 100644
index 00000000..6f0820ac
--- /dev/null
+++ b/src/ext/Sql/wixext/Symbols/SqlDatabaseSymbol.cs
@@ -0,0 +1,103 @@
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 WixToolset.Data;
6 using WixToolset.Sql.Symbols;
7
8 public static partial class SqlSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition SqlDatabase = new IntermediateSymbolDefinition(
11 SqlSymbolDefinitionType.SqlDatabase.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(SqlDatabaseSymbolFields.Server), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(SqlDatabaseSymbolFields.Instance), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(SqlDatabaseSymbolFields.Database), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(SqlDatabaseSymbolFields.ComponentRef), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(SqlDatabaseSymbolFields.UserRef), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(SqlDatabaseSymbolFields.FileSpecRef), IntermediateFieldType.String),
20 new IntermediateFieldDefinition(nameof(SqlDatabaseSymbolFields.LogFileSpecRef), IntermediateFieldType.String),
21 new IntermediateFieldDefinition(nameof(SqlDatabaseSymbolFields.Attributes), IntermediateFieldType.Number),
22 },
23 typeof(SqlDatabaseSymbol));
24 }
25}
26
27namespace WixToolset.Sql.Symbols
28{
29 using WixToolset.Data;
30
31 public enum SqlDatabaseSymbolFields
32 {
33 Server,
34 Instance,
35 Database,
36 ComponentRef,
37 UserRef,
38 FileSpecRef,
39 LogFileSpecRef,
40 Attributes,
41 }
42
43 public class SqlDatabaseSymbol : IntermediateSymbol
44 {
45 public SqlDatabaseSymbol() : base(SqlSymbolDefinitions.SqlDatabase, null, null)
46 {
47 }
48
49 public SqlDatabaseSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(SqlSymbolDefinitions.SqlDatabase, sourceLineNumber, id)
50 {
51 }
52
53 public IntermediateField this[SqlDatabaseSymbolFields index] => this.Fields[(int)index];
54
55 public string Server
56 {
57 get => this.Fields[(int)SqlDatabaseSymbolFields.Server].AsString();
58 set => this.Set((int)SqlDatabaseSymbolFields.Server, value);
59 }
60
61 public string Instance
62 {
63 get => this.Fields[(int)SqlDatabaseSymbolFields.Instance].AsString();
64 set => this.Set((int)SqlDatabaseSymbolFields.Instance, value);
65 }
66
67 public string Database
68 {
69 get => this.Fields[(int)SqlDatabaseSymbolFields.Database].AsString();
70 set => this.Set((int)SqlDatabaseSymbolFields.Database, value);
71 }
72
73 public string ComponentRef
74 {
75 get => this.Fields[(int)SqlDatabaseSymbolFields.ComponentRef].AsString();
76 set => this.Set((int)SqlDatabaseSymbolFields.ComponentRef, value);
77 }
78
79 public string UserRef
80 {
81 get => this.Fields[(int)SqlDatabaseSymbolFields.UserRef].AsString();
82 set => this.Set((int)SqlDatabaseSymbolFields.UserRef, value);
83 }
84
85 public string FileSpecRef
86 {
87 get => this.Fields[(int)SqlDatabaseSymbolFields.FileSpecRef].AsString();
88 set => this.Set((int)SqlDatabaseSymbolFields.FileSpecRef, value);
89 }
90
91 public string LogFileSpecRef
92 {
93 get => this.Fields[(int)SqlDatabaseSymbolFields.LogFileSpecRef].AsString();
94 set => this.Set((int)SqlDatabaseSymbolFields.LogFileSpecRef, value);
95 }
96
97 public int Attributes
98 {
99 get => this.Fields[(int)SqlDatabaseSymbolFields.Attributes].AsNumber();
100 set => this.Set((int)SqlDatabaseSymbolFields.Attributes, value);
101 }
102 }
103} \ No newline at end of file
diff --git a/src/ext/Sql/wixext/Symbols/SqlFileSpecSymbol.cs b/src/ext/Sql/wixext/Symbols/SqlFileSpecSymbol.cs
new file mode 100644
index 00000000..d9eecc62
--- /dev/null
+++ b/src/ext/Sql/wixext/Symbols/SqlFileSpecSymbol.cs
@@ -0,0 +1,79 @@
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 WixToolset.Data;
6 using WixToolset.Sql.Symbols;
7
8 public static partial class SqlSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition SqlFileSpec = new IntermediateSymbolDefinition(
11 SqlSymbolDefinitionType.SqlFileSpec.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(SqlFileSpecSymbolFields.Name), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(SqlFileSpecSymbolFields.Filename), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(SqlFileSpecSymbolFields.Size), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(SqlFileSpecSymbolFields.MaxSize), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(SqlFileSpecSymbolFields.GrowthSize), IntermediateFieldType.String),
19 },
20 typeof(SqlFileSpecSymbol));
21 }
22}
23
24namespace WixToolset.Sql.Symbols
25{
26 using WixToolset.Data;
27
28 public enum SqlFileSpecSymbolFields
29 {
30 Name,
31 Filename,
32 Size,
33 MaxSize,
34 GrowthSize,
35 }
36
37 public class SqlFileSpecSymbol : IntermediateSymbol
38 {
39 public SqlFileSpecSymbol() : base(SqlSymbolDefinitions.SqlFileSpec, null, null)
40 {
41 }
42
43 public SqlFileSpecSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(SqlSymbolDefinitions.SqlFileSpec, sourceLineNumber, id)
44 {
45 }
46
47 public IntermediateField this[SqlFileSpecSymbolFields index] => this.Fields[(int)index];
48
49 public string Name
50 {
51 get => this.Fields[(int)SqlFileSpecSymbolFields.Name].AsString();
52 set => this.Set((int)SqlFileSpecSymbolFields.Name, value);
53 }
54
55 public string Filename
56 {
57 get => this.Fields[(int)SqlFileSpecSymbolFields.Filename].AsString();
58 set => this.Set((int)SqlFileSpecSymbolFields.Filename, value);
59 }
60
61 public string Size
62 {
63 get => this.Fields[(int)SqlFileSpecSymbolFields.Size].AsString();
64 set => this.Set((int)SqlFileSpecSymbolFields.Size, value);
65 }
66
67 public string MaxSize
68 {
69 get => this.Fields[(int)SqlFileSpecSymbolFields.MaxSize].AsString();
70 set => this.Set((int)SqlFileSpecSymbolFields.MaxSize, value);
71 }
72
73 public string GrowthSize
74 {
75 get => this.Fields[(int)SqlFileSpecSymbolFields.GrowthSize].AsString();
76 set => this.Set((int)SqlFileSpecSymbolFields.GrowthSize, value);
77 }
78 }
79} \ No newline at end of file
diff --git a/src/ext/Sql/wixext/Symbols/SqlScriptSymbol.cs b/src/ext/Sql/wixext/Symbols/SqlScriptSymbol.cs
new file mode 100644
index 00000000..94c70390
--- /dev/null
+++ b/src/ext/Sql/wixext/Symbols/SqlScriptSymbol.cs
@@ -0,0 +1,87 @@
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 WixToolset.Data;
6 using WixToolset.Sql.Symbols;
7
8 public static partial class SqlSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition SqlScript = new IntermediateSymbolDefinition(
11 SqlSymbolDefinitionType.SqlScript.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(SqlScriptSymbolFields.SqlDbRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(SqlScriptSymbolFields.ComponentRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(SqlScriptSymbolFields.ScriptBinaryRef), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(SqlScriptSymbolFields.UserRef), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(SqlScriptSymbolFields.Attributes), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(SqlScriptSymbolFields.Sequence), IntermediateFieldType.Number),
20 },
21 typeof(SqlScriptSymbol));
22 }
23}
24
25namespace WixToolset.Sql.Symbols
26{
27 using WixToolset.Data;
28
29 public enum SqlScriptSymbolFields
30 {
31 SqlDbRef,
32 ComponentRef,
33 ScriptBinaryRef,
34 UserRef,
35 Attributes,
36 Sequence,
37 }
38
39 public class SqlScriptSymbol : IntermediateSymbol
40 {
41 public SqlScriptSymbol() : base(SqlSymbolDefinitions.SqlScript, null, null)
42 {
43 }
44
45 public SqlScriptSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(SqlSymbolDefinitions.SqlScript, sourceLineNumber, id)
46 {
47 }
48
49 public IntermediateField this[SqlScriptSymbolFields index] => this.Fields[(int)index];
50
51 public string SqlDbRef
52 {
53 get => this.Fields[(int)SqlScriptSymbolFields.SqlDbRef].AsString();
54 set => this.Set((int)SqlScriptSymbolFields.SqlDbRef, value);
55 }
56
57 public string ComponentRef
58 {
59 get => this.Fields[(int)SqlScriptSymbolFields.ComponentRef].AsString();
60 set => this.Set((int)SqlScriptSymbolFields.ComponentRef, value);
61 }
62
63 public string ScriptBinaryRef
64 {
65 get => this.Fields[(int)SqlScriptSymbolFields.ScriptBinaryRef].AsString();
66 set => this.Set((int)SqlScriptSymbolFields.ScriptBinaryRef, value);
67 }
68
69 public string UserRef
70 {
71 get => this.Fields[(int)SqlScriptSymbolFields.UserRef].AsString();
72 set => this.Set((int)SqlScriptSymbolFields.UserRef, value);
73 }
74
75 public int Attributes
76 {
77 get => this.Fields[(int)SqlScriptSymbolFields.Attributes].AsNumber();
78 set => this.Set((int)SqlScriptSymbolFields.Attributes, value);
79 }
80
81 public int? Sequence
82 {
83 get => this.Fields[(int)SqlScriptSymbolFields.Sequence].AsNullableNumber();
84 set => this.Set((int)SqlScriptSymbolFields.Sequence, value);
85 }
86 }
87} \ No newline at end of file
diff --git a/src/ext/Sql/wixext/Symbols/SqlStringSymbol.cs b/src/ext/Sql/wixext/Symbols/SqlStringSymbol.cs
new file mode 100644
index 00000000..73a8206e
--- /dev/null
+++ b/src/ext/Sql/wixext/Symbols/SqlStringSymbol.cs
@@ -0,0 +1,87 @@
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 WixToolset.Data;
6 using WixToolset.Sql.Symbols;
7
8 public static partial class SqlSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition SqlString = new IntermediateSymbolDefinition(
11 SqlSymbolDefinitionType.SqlString.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(SqlStringSymbolFields.SqlDbRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(SqlStringSymbolFields.ComponentRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(SqlStringSymbolFields.SQL), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(SqlStringSymbolFields.UserRef), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(SqlStringSymbolFields.Attributes), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(SqlStringSymbolFields.Sequence), IntermediateFieldType.Number),
20 },
21 typeof(SqlStringSymbol));
22 }
23}
24
25namespace WixToolset.Sql.Symbols
26{
27 using WixToolset.Data;
28
29 public enum SqlStringSymbolFields
30 {
31 SqlDbRef,
32 ComponentRef,
33 SQL,
34 UserRef,
35 Attributes,
36 Sequence,
37 }
38
39 public class SqlStringSymbol : IntermediateSymbol
40 {
41 public SqlStringSymbol() : base(SqlSymbolDefinitions.SqlString, null, null)
42 {
43 }
44
45 public SqlStringSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(SqlSymbolDefinitions.SqlString, sourceLineNumber, id)
46 {
47 }
48
49 public IntermediateField this[SqlStringSymbolFields index] => this.Fields[(int)index];
50
51 public string SqlDbRef
52 {
53 get => this.Fields[(int)SqlStringSymbolFields.SqlDbRef].AsString();
54 set => this.Set((int)SqlStringSymbolFields.SqlDbRef, value);
55 }
56
57 public string ComponentRef
58 {
59 get => this.Fields[(int)SqlStringSymbolFields.ComponentRef].AsString();
60 set => this.Set((int)SqlStringSymbolFields.ComponentRef, value);
61 }
62
63 public string SQL
64 {
65 get => this.Fields[(int)SqlStringSymbolFields.SQL].AsString();
66 set => this.Set((int)SqlStringSymbolFields.SQL, value);
67 }
68
69 public string UserRef
70 {
71 get => this.Fields[(int)SqlStringSymbolFields.UserRef].AsString();
72 set => this.Set((int)SqlStringSymbolFields.UserRef, value);
73 }
74
75 public int Attributes
76 {
77 get => this.Fields[(int)SqlStringSymbolFields.Attributes].AsNumber();
78 set => this.Set((int)SqlStringSymbolFields.Attributes, value);
79 }
80
81 public int? Sequence
82 {
83 get => this.Fields[(int)SqlStringSymbolFields.Sequence].AsNullableNumber();
84 set => this.Set((int)SqlStringSymbolFields.Sequence, value);
85 }
86 }
87} \ No newline at end of file
diff --git a/src/ext/Sql/wixext/Symbols/SqlSymbolDefinitions.cs b/src/ext/Sql/wixext/Symbols/SqlSymbolDefinitions.cs
new file mode 100644
index 00000000..336f1546
--- /dev/null
+++ b/src/ext/Sql/wixext/Symbols/SqlSymbolDefinitions.cs
@@ -0,0 +1,51 @@
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 WixToolset.Data;
7
8 public enum SqlSymbolDefinitionType
9 {
10 SqlDatabase,
11 SqlFileSpec,
12 SqlScript,
13 SqlString,
14 }
15
16 public static partial class SqlSymbolDefinitions
17 {
18 public static readonly Version Version = new Version("4.0.0");
19
20 public static IntermediateSymbolDefinition ByName(string name)
21 {
22 if (!Enum.TryParse(name, out SqlSymbolDefinitionType type))
23 {
24 return null;
25 }
26
27 return ByType(type);
28 }
29
30 public static IntermediateSymbolDefinition ByType(SqlSymbolDefinitionType type)
31 {
32 switch (type)
33 {
34 case SqlSymbolDefinitionType.SqlDatabase:
35 return SqlSymbolDefinitions.SqlDatabase;
36
37 case SqlSymbolDefinitionType.SqlFileSpec:
38 return SqlSymbolDefinitions.SqlFileSpec;
39
40 case SqlSymbolDefinitionType.SqlScript:
41 return SqlSymbolDefinitions.SqlScript;
42
43 case SqlSymbolDefinitionType.SqlString:
44 return SqlSymbolDefinitions.SqlString;
45
46 default:
47 throw new ArgumentOutOfRangeException(nameof(type));
48 }
49 }
50 }
51}
diff --git a/src/ext/Sql/wixext/WixToolset.Sql.wixext.csproj b/src/ext/Sql/wixext/WixToolset.Sql.wixext.csproj
new file mode 100644
index 00000000..5a1ebeb0
--- /dev/null
+++ b/src/ext/Sql/wixext/WixToolset.Sql.wixext.csproj
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netstandard2.0</TargetFramework>
7 <RootNamespace>WixToolset.Sql</RootNamespace>
8 <Description>WiX Toolset Sql Extension</Description>
9 <Title>WiX Toolset Sql Extension</Title>
10 <DebugType>embedded</DebugType>
11 <IncludeSymbols>true</IncludeSymbols>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <EmbeddedResource Include="$(OutputPath)..\sql.wixlib" />
16 </ItemGroup>
17
18 <ItemGroup>
19 <ProjectReference Include="..\wixlib\sql.wixproj" ReferenceOutputAssembly="false" Condition=" '$(NCrunch)'=='' " />
20 </ItemGroup>
21
22 <ItemGroup>
23 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" PrivateAssets="All" />
24 </ItemGroup>
25
26 <ItemGroup>
27 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
28 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="All" />
29 </ItemGroup>
30</Project>
diff --git a/src/ext/Sql/wixext/WixToolset.Sql.wixext.nuspec b/src/ext/Sql/wixext/WixToolset.Sql.wixext.nuspec
new file mode 100644
index 00000000..ba3eaade
--- /dev/null
+++ b/src/ext/Sql/wixext/WixToolset.Sql.wixext.nuspec
@@ -0,0 +1,25 @@
1<?xml version="1.0"?>
2<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
3 <metadata minClientVersion="4.0">
4 <id>$id$</id>
5 <version>$version$</version>
6 <title>$title$</title>
7 <description>$description$</description>
8 <authors>$authors$</authors>
9 <license type="expression">MS-RL</license>
10 <requireLicenseAcceptance>false</requireLicenseAcceptance>
11 <copyright>$copyright$</copyright>
12 <projectUrl>$projectUrl$</projectUrl>
13 <repository type="$repositorytype$" url="$repositoryurl$" commit="$repositorycommit$" />
14 </metadata>
15
16 <files>
17 <file src="$projectFolder$$id$.targets" target="build" />
18
19 <file src="netstandard2.0\$id$.dll" target="tools" />
20
21 <file src="ARM64\*.pdb" target="pdbs\ARM64" />
22 <file src="x86\*.pdb" target="pdbs\x86" />
23 <file src="x64\*.pdb" target="pdbs\x64" />
24 </files>
25</package>
diff --git a/src/ext/Sql/wixext/WixToolset.Sql.wixext.targets b/src/ext/Sql/wixext/WixToolset.Sql.wixext.targets
new file mode 100644
index 00000000..4950e119
--- /dev/null
+++ b/src/ext/Sql/wixext/WixToolset.Sql.wixext.targets
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
5 <PropertyGroup>
6 <WixToolsetSqlWixextPath Condition=" '$(WixToolsetSqlWixextPath)' == '' ">$(MSBuildThisFileDirectory)..\tools\WixToolset.Sql.wixext.dll</WixToolsetSqlWixextPath>
7 </PropertyGroup>
8 <ItemGroup>
9 <WixExtension Include="$(WixToolsetSqlWixextPath)" />
10 </ItemGroup>
11</Project>
diff --git a/src/ext/Sql/wixlib/SqlExtension.wxi b/src/ext/Sql/wixlib/SqlExtension.wxi
new file mode 100644
index 00000000..c9261f1d
--- /dev/null
+++ b/src/ext/Sql/wixlib/SqlExtension.wxi
@@ -0,0 +1,35 @@
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 xmlns="http://wixtoolset.org/schemas/v4/wxs">
4 <?include caDecor.wxi ?>
5
6 <Fragment>
7 <UI>
8 <ProgressText Action="$(var.Prefix)InstallSqlData$(var.Suffix)" Message="!(loc.ConfigureSql)" />
9 <ProgressText Action="$(var.Prefix)UninstallSqlData$(var.Suffix)" Message="!(loc.ConfigureSql)" />
10 <ProgressText Action="$(var.Prefix)CreateDatabase$(var.Suffix)" Message="!(loc.CreateDatabase)" />
11 <ProgressText Action="$(var.Prefix)DropDatabase$(var.Suffix)" Message="!(loc.DropDatabase)" />
12 <ProgressText Action="$(var.Prefix)ExecuteSqlStrings$(var.Suffix)" Message="!(loc.ExecuteSqlStrings)" />
13 <ProgressText Action="$(var.Prefix)RollbackExecuteSqlStrings$(var.Suffix)" Message="!(loc.RollbackExecuteSqlStrings)" />
14 </UI>
15
16 <!-- The SQL custom actions impersonate the user because the user's credentials are used when connecting to the database if none are provided. -->
17 <CustomAction Id="$(var.Prefix)InstallSqlData$(var.Suffix)" DllEntry="InstallSqlData" Execute="immediate" Return="check" BinaryRef="SqlCA$(var.Suffix)" />
18 <CustomAction Id="$(var.Prefix)UninstallSqlData$(var.Suffix)" DllEntry="UninstallSqlData" Execute="immediate" Return="check" BinaryRef="SqlCA$(var.Suffix)" />
19 <CustomAction Id="$(var.Prefix)CreateDatabase$(var.Suffix)" DllEntry="CreateDatabase" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" TerminalServerAware="yes" BinaryRef="SqlCA$(var.Suffix)" />
20 <CustomAction Id="$(var.Prefix)RollbackCreateDatabase$(var.Suffix)" DllEntry="DropDatabase" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" TerminalServerAware="yes" BinaryRef="SqlCA$(var.Suffix)" />
21 <CustomAction Id="$(var.Prefix)DropDatabase$(var.Suffix)" DllEntry="DropDatabase" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" TerminalServerAware="yes" BinaryRef="SqlCA$(var.Suffix)" />
22 <CustomAction Id="$(var.Prefix)ExecuteSqlStrings$(var.Suffix)" DllEntry="ExecuteSqlStrings" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" TerminalServerAware="yes" BinaryRef="SqlCA$(var.Suffix)" />
23 <CustomAction Id="$(var.Prefix)RollbackExecuteSqlStrings$(var.Suffix)" DllEntry="ExecuteSqlStrings" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" TerminalServerAware="yes" BinaryRef="SqlCA$(var.Suffix)" />
24
25 <InstallExecuteSequence>
26 <Custom Action="$(var.Prefix)UninstallSqlData$(var.Suffix)" Before="RemoveFiles" Overridable="yes" Condition="NOT SKIPUNINSTALLSQLDATA AND VersionNT &gt; 400" />
27 <Custom Action="$(var.Prefix)InstallSqlData$(var.Suffix)" After="InstallFiles" Overridable="yes" Condition="NOT SKIPINSTALLSQLDATA AND VersionNT &gt; 400" />
28 </InstallExecuteSequence>
29 </Fragment>
30
31 <!-- Server Custom Action DLL Definitions -->
32 <Fragment>
33 <Binary Id="SqlCA$(var.Suffix)" SourceFile="!(bindpath.$(var.platform))sqlca.dll" />
34 </Fragment>
35</Include>
diff --git a/src/ext/Sql/wixlib/SqlExtension.wxs b/src/ext/Sql/wixlib/SqlExtension.wxs
new file mode 100644
index 00000000..8b5320fa
--- /dev/null
+++ b/src/ext/Sql/wixlib/SqlExtension.wxs
@@ -0,0 +1,15 @@
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<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
4 <?include caerr.wxi ?>
5
6 <Fragment>
7 <UI>
8 <Error Id="$(var.msierrSQLFailedCreateDatabase)" Message="!(loc.msierrSQLFailedCreateDatabase)" />
9 <Error Id="$(var.msierrSQLFailedDropDatabase)" Message="!(loc.msierrSQLFailedDropDatabase)" />
10 <Error Id="$(var.msierrSQLFailedConnectDatabase)" Message="!(loc.msierrSQLFailedConnectDatabase)" />
11 <Error Id="$(var.msierrSQLFailedExecString)" Message="!(loc.msierrSQLFailedExecString)" />
12 <Error Id="$(var.msierrSQLDatabaseAlreadyExists)" Message="!(loc.msierrSQLDatabaseAlreadyExists)" />
13 </UI>
14 </Fragment>
15</Wix>
diff --git a/src/ext/Sql/wixlib/SqlExtension_arm64.wxs b/src/ext/Sql/wixlib/SqlExtension_arm64.wxs
new file mode 100644
index 00000000..e8d22f69
--- /dev/null
+++ b/src/ext/Sql/wixlib/SqlExtension_arm64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=arm64 ?>
6 <?include SqlExtension.wxi ?>
7</Wix>
diff --git a/src/ext/Sql/wixlib/SqlExtension_x64.wxs b/src/ext/Sql/wixlib/SqlExtension_x64.wxs
new file mode 100644
index 00000000..e55a14e4
--- /dev/null
+++ b/src/ext/Sql/wixlib/SqlExtension_x64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x64 ?>
6 <?include SqlExtension.wxi ?>
7</Wix>
diff --git a/src/ext/Sql/wixlib/SqlExtension_x86.wxs b/src/ext/Sql/wixlib/SqlExtension_x86.wxs
new file mode 100644
index 00000000..1a51ed91
--- /dev/null
+++ b/src/ext/Sql/wixlib/SqlExtension_x86.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x86 ?>
6 <?include SqlExtension.wxi ?>
7</Wix>
diff --git a/src/ext/Sql/wixlib/caDecor.wxi b/src/ext/Sql/wixlib/caDecor.wxi
new file mode 100644
index 00000000..b1711518
--- /dev/null
+++ b/src/ext/Sql/wixlib/caDecor.wxi
@@ -0,0 +1,39 @@
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
4<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?ifdef Prefix ?>
6 <?undef Prefix ?>
7 <?endif?>
8
9 <?define Prefix="Wix4" ?>
10
11 <?ifndef platform ?>
12 <?define platform="x86" ?>
13 <?endif?>
14
15 <?if $(var.platform)="" ?>
16 <?undef platform ?>
17 <?define platform="x86" ?>
18 <?endif?>
19
20 <?ifdef Suffix ?>
21 <?undef Suffix ?>
22 <?endif?>
23
24 <?if $(var.platform)~="x86" ?>
25 <?define Suffix="_X86" ?>
26 <?endif?>
27
28 <?if $(var.platform)~="x64" ?>
29 <?define Suffix="_X64" ?>
30 <?endif?>
31
32 <?if $(var.platform)~="arm" ?>
33 <?define Suffix="_A32" ?>
34 <?endif?>
35
36 <?if $(var.platform)~="arm64" ?>
37 <?define Suffix="_A64" ?>
38 <?endif?>
39</Include>
diff --git a/src/ext/Sql/wixlib/caerr.wxi b/src/ext/Sql/wixlib/caerr.wxi
new file mode 100644
index 00000000..ff7ec121
--- /dev/null
+++ b/src/ext/Sql/wixlib/caerr.wxi
@@ -0,0 +1,96 @@
1<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <?define msierrSecureObjectsFailedCreateSD = 25520?>
3 <?define msierrSecureObjectsFailedSet = 25521?>
4 <?define msierrSecureObjectsUnknownType = 25522?>
5 <?define msierrXmlFileFailedRead = 25530?>
6 <?define msierrXmlFileFailedOpen = 25531?>
7 <?define msierrXmlFileFailedSelect = 25532?>
8 <?define msierrXmlFileFailedSave = 25533?>
9 <?define msierrXmlConfigFailedRead = 25540?>
10 <?define msierrXmlConfigFailedOpen = 25541?>
11 <?define msierrXmlConfigFailedSelect = 25542?>
12 <?define msierrXmlConfigFailedSave = 25543?>
13 <?define msierrFirewallCannotConnect = 25580?>
14 <?define msierrIISCannotConnect = 26001?>
15 <?define msierrIISFailedReadWebSite = 26002?>
16 <?define msierrIISFailedReadWebDirs = 26003?>
17 <?define msierrIISFailedReadVDirs = 26004?>
18 <?define msierrIISFailedReadFilters = 26005?>
19 <?define msierrIISFailedReadAppPool = 26006?>
20 <?define msierrIISFailedReadMimeMap = 26007?>
21 <?define msierrIISFailedReadProp = 26008?>
22 <?define msierrIISFailedReadWebSvcExt = 26009?>
23 <?define msierrIISFailedReadWebError = 26010?>
24 <?define msierrIISFailedReadHttpHeader = 26011?>
25 <?define msierrIISFailedSchedTransaction = 26031?>
26 <?define msierrIISFailedSchedInstallWebs = 26032?>
27 <?define msierrIISFailedSchedInstallWebDirs = 26033?>
28 <?define msierrIISFailedSchedInstallVDirs = 26034?>
29 <?define msierrIISFailedSchedInstallFilters = 26035?>
30 <?define msierrIISFailedSchedInstallAppPool = 26036?>
31 <?define msierrIISFailedSchedInstallProp = 26037?>
32 <?define msierrIISFailedSchedInstallWebSvcExt = 26038?>
33 <?define msierrIISFailedSchedUninstallWebs = 26051?>
34 <?define msierrIISFailedSchedUninstallWebDirs = 26052?>
35 <?define msierrIISFailedSchedUninstallVDirs = 26053?>
36 <?define msierrIISFailedSchedUninstallFilters = 26054?>
37 <?define msierrIISFailedSchedUninstallAppPool = 26055?>
38 <?define msierrIISFailedSchedUninstallProp = 26056?>
39 <?define msierrIISFailedSchedUninstallWebSvcExt = 26057?>
40 <?define msierrIISFailedStartTransaction = 26101?>
41 <?define msierrIISFailedOpenKey = 26102?>
42 <?define msierrIISFailedCreateKey = 26103?>
43 <?define msierrIISFailedWriteData = 26104?>
44 <?define msierrIISFailedCreateApp = 26105?>
45 <?define msierrIISFailedDeleteKey = 26106?>
46 <?define msierrIISFailedDeleteApp = 26107?>
47 <?define msierrIISFailedDeleteValue = 26108?>
48 <?define msierrIISFailedCommitInUse = 26109?>
49 <?define msierrSQLFailedCreateDatabase = 26201?>
50 <?define msierrSQLFailedDropDatabase = 26202?>
51 <?define msierrSQLFailedConnectDatabase = 26203?>
52 <?define msierrSQLFailedExecString = 26204?>
53 <?define msierrSQLDatabaseAlreadyExists = 26205?>
54 <?define msierrPERFMONFailedRegisterDLL = 26251?>
55 <?define msierrPERFMONFailedUnregisterDLL = 26252?>
56 <?define msierrInstallPerfCounterData = 26253?>
57 <?define msierrUninstallPerfCounterData = 26254?>
58 <?define msierrSMBFailedCreate = 26301?>
59 <?define msierrSMBFailedDrop = 26302?>
60 <?define msierrCERTFailedOpen = 26351?>
61 <?define msierrCERTFailedAdd = 26352?>
62 <?define msierrUSRFailedUserCreate = 26401?>
63 <?define msierrUSRFailedUserCreatePswd = 26402?>
64 <?define msierrUSRFailedUserGroupAdd = 26403?>
65 <?define msierrUSRFailedUserCreateExists = 26404?>
66 <?define msierrUSRFailedGrantLogonAsService = 26405?>
67 <?define msierrDependencyMissingDependencies = 26451?>
68 <?define msierrDependencyHasDependents = 26452?>
69 <?define msierrDotNetRuntimeRequired = 27000?>
70 <?define msierrComPlusCannotConnect = 28001?>
71 <?define msierrComPlusPartitionReadFailed = 28002?>
72 <?define msierrComPlusPartitionRoleReadFailed = 28003?>
73 <?define msierrComPlusUserInPartitionRoleReadFailed = 28004?>
74 <?define msierrComPlusPartitionUserReadFailed = 28005?>
75 <?define msierrComPlusApplicationReadFailed = 28006?>
76 <?define msierrComPlusApplicationRoleReadFailed = 28007?>
77 <?define msierrComPlusUserInApplicationRoleReadFailed = 28008?>
78 <?define msierrComPlusAssembliesReadFailed = 28009?>
79 <?define msierrComPlusSubscriptionReadFailed = 28010?>
80 <?define msierrComPlusPartitionDependency = 28011?>
81 <?define msierrComPlusPartitionNotFound = 28012?>
82 <?define msierrComPlusPartitionIdConflict = 28013?>
83 <?define msierrComPlusPartitionNameConflict = 28014?>
84 <?define msierrComPlusApplicationDependency = 28015?>
85 <?define msierrComPlusApplicationNotFound = 28016?>
86 <?define msierrComPlusApplicationIdConflict = 28017?>
87 <?define msierrComPlusApplicationNameConflict = 28018?>
88 <?define msierrComPlusApplicationRoleDependency = 28019?>
89 <?define msierrComPlusApplicationRoleNotFound = 28020?>
90 <?define msierrComPlusApplicationRoleConflict = 28021?>
91 <?define msierrComPlusAssemblyDependency = 28022?>
92 <?define msierrComPlusSubscriptionIdConflict = 28023?>
93 <?define msierrComPlusSubscriptionNameConflict = 28024?>
94 <?define msierrComPlusFailedLookupNames = 28025?>
95 <?define msierrMsmqCannotConnect = 28101?>
96</Include> \ No newline at end of file
diff --git a/src/ext/Sql/wixlib/de-de.wxl b/src/ext/Sql/wixlib/de-de.wxl
new file mode 100644
index 00000000..ed2313a4
--- /dev/null
+++ b/src/ext/Sql/wixlib/de-de.wxl
@@ -0,0 +1,16 @@
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
4<WixLocalization Culture="en-us" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrSQLFailedCreateDatabase" Overridable="yes">Fehler [2]: Erstellen der SQL-Datenbank fehlgeschlagen: [3], Fehlerbeschreibung: [4].</String>
6 <String Id="msierrSQLFailedDropDatabase" Overridable="yes">Fehler [2]: Löschen der SQL-Datenbank fehlgeschlagen: [3], Fehlerbeschreibung: [4].</String>
7 <String Id="msierrSQLFailedConnectDatabase" Overridable="yes">Verbinden mit der SQL-Datenbank fehlgeschlagen. ([2] [3] [4] [5])</String>
8 <String Id="msierrSQLFailedExecString" Overridable="yes">Fehler [2]: Das Erstellen der SQL Zeichenfolge ist fehlgeschlagen, Fehlerbeschreibung: [3], SQL-Schlüssel: [4] SQL-Zeichenfolge: [5]</String>
9 <String Id="msierrSQLDatabaseAlreadyExists" Overridable="yes">Die Datenbank [3] existiert bereits. Wollen Sie fortfahren?</String>
10
11 <String Id="ConfigureSql" Overridable="yes">Konfiguriere SQL Server</String>
12 <String Id="CreateDatabase" Overridable="yes">Erstelle Datenbanken</String>
13 <String Id="DropDatabase" Overridable="yes">Lösche Datenbanken</String>
14 <String Id="ExecuteSqlStrings" Overridable="yes">SQL-Zeichenfolgen werden erstellt</String>
15 <String Id="RollbackExecuteSqlStrings" Overridable="yes">SQL-Zeichenfolgen werden zurückgesetzt</String>
16</WixLocalization>
diff --git a/src/ext/Sql/wixlib/en-us.wxl b/src/ext/Sql/wixlib/en-us.wxl
new file mode 100644
index 00000000..d3ffd5eb
--- /dev/null
+++ b/src/ext/Sql/wixlib/en-us.wxl
@@ -0,0 +1,16 @@
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
4<WixLocalization Culture="en-us" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrSQLFailedCreateDatabase" Overridable="yes">Error [2]: failed to create SQL database: [3], error detail: [4].</String>
6 <String Id="msierrSQLFailedDropDatabase" Overridable="yes">Error [2]: failed to drop SQL database: [3], error detail: [4].</String>
7 <String Id="msierrSQLFailedConnectDatabase" Overridable="yes">Failed to connect to SQL database. ([2] [3] [4] [5])</String>
8 <String Id="msierrSQLFailedExecString" Overridable="yes">Error [2]: failed to execute SQL string, error detail: [3], SQL key: [4] SQL string: [5]</String>
9 <String Id="msierrSQLDatabaseAlreadyExists" Overridable="yes">The database [3] already exists. Do you want to continue?</String>
10
11 <String Id="ConfigureSql" Overridable="yes">Configuring SQL Server</String>
12 <String Id="CreateDatabase" Overridable="yes">Creating Databases</String>
13 <String Id="DropDatabase" Overridable="yes">Dropping Databases</String>
14 <String Id="ExecuteSqlStrings" Overridable="yes">Executing SQL Strings</String>
15 <String Id="RollbackExecuteSqlStrings" Overridable="yes">Rolling back SQL Strings</String>
16</WixLocalization>
diff --git a/src/ext/Sql/wixlib/es-es.wxl b/src/ext/Sql/wixlib/es-es.wxl
new file mode 100644
index 00000000..b2e5d499
--- /dev/null
+++ b/src/ext/Sql/wixlib/es-es.wxl
@@ -0,0 +1,17 @@
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
4<WixLocalization Culture="es-es" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrSQLFailedCreateDatabase" Overridable="yes">Error [2]: falla al crear la base de datos SQL: [3], detalle del error: [4].</String>
6 <String Id="msierrSQLFailedDropDatabase" Overridable="yes">Error [2]: falla al poner la base de datos SQL: [3], detalle del error: [4].</String>
7 <String Id="msierrSQLFailedConnectDatabase" Overridable="yes">Falla al conectarse con la base de datos SQL. ([2] [3] [4] [5])</String>
8 <String Id="msierrSQLFailedExecString" Overridable="yes">Error [2]: falla al ejecutar la cadena SQL, detalle del error: [3], Clave SQL: [4] Cadena SQL: [5]</String>
9 <String Id="msierrSQLDatabaseAlreadyExists" Overridable="yes">La base de datos [3] ya existe. ¿Desea continuar?</String>
10
11 <String Id="ConfigureSql" Overridable="yes">Configurando SQL Server</String>
12 <String Id="CreateDatabase" Overridable="yes">Creando Bases de Datos</String>
13 <String Id="DropDatabase" Overridable="yes">Colocando Bases de Datos</String>
14 <String Id="ExecuteSqlStrings" Overridable="yes">Ejecutando cadenas SQL</String>
15 <String Id="RollbackExecuteSqlStrings" Overridable="yes">Revirtiendo cadenas SQL</String>
16</WixLocalization>
17
diff --git a/src/ext/Sql/wixlib/ja-jp.wxl b/src/ext/Sql/wixlib/ja-jp.wxl
new file mode 100644
index 00000000..6e35fd17
--- /dev/null
+++ b/src/ext/Sql/wixlib/ja-jp.wxl
@@ -0,0 +1,16 @@
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
4<WixLocalization Culture="ja-jp" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrSQLFailedCreateDatabase" Overridable="yes">エラー [2]: SQL データベース [3] 作成に失敗しました、エラー詳細: [4]。</String>
6 <String Id="msierrSQLFailedDropDatabase" Overridable="yes">エラー [2]: SQL データベース [3] の削除に失敗しました、エラー詳細: [4]。</String>
7 <String Id="msierrSQLFailedConnectDatabase" Overridable="yes">SQL データベースへ接続できませんでした。 ([2] [3] [4] [5])</String>
8 <String Id="msierrSQLFailedExecString" Overridable="yes">エラー [2]: SQL ストリングの実行に失敗しました、エラー詳細: [3]、 SQL キー: [4] SQL ストリング: [5]</String>
9 <String Id="msierrSQLDatabaseAlreadyExists" Overridable="yes">データベース [3] は既に存在します。続行しますか?</String>
10
11 <String Id="ConfigureSql" Overridable="yes">SQL サーバーを構成しています</String>
12 <String Id="CreateDatabase" Overridable="yes">データベースを作成しています</String>
13 <String Id="DropDatabase" Overridable="yes">データベースを削除しています</String>
14 <String Id="ExecuteSqlStrings" Overridable="yes">SQL ストリングを実行しています</String>
15 <String Id="RollbackExecuteSqlStrings" Overridable="yes">SQL ストリングをロールバックしています</String>
16</WixLocalization>
diff --git a/src/ext/Sql/wixlib/pl-pl.wxl b/src/ext/Sql/wixlib/pl-pl.wxl
new file mode 100644
index 00000000..6200e0e9
--- /dev/null
+++ b/src/ext/Sql/wixlib/pl-pl.wxl
@@ -0,0 +1,16 @@
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
4<WixLocalization Culture="pl-pl" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrSQLFailedCreateDatabase" Overridable="yes">Błąd [2]: nie udało się utworzyć bazy danych: [3]. Szczegóły błędu: [4].</String>
6 <String Id="msierrSQLFailedDropDatabase" Overridable="yes">Błąd [2]: nie udało się usunąć bazy danych: [3]. Szczegóły błędu: [4].</String>
7 <String Id="msierrSQLFailedConnectDatabase" Overridable="yes">Nie udało się połączyć z bazą danych. ([2] [3] [4] [5])</String>
8 <String Id="msierrSQLFailedExecString" Overridable="yes">Błąd [2]: nie udało się wykonać zapytania SQL. Szczegóły błędu: [3], klucz: [4] zapytanie SQL: [5]</String>
9 <String Id="msierrSQLDatabaseAlreadyExists" Overridable="yes">Baza danych [3] już istnieje. Czy chcesz kontynuować?</String>
10
11 <String Id="ConfigureSql" Overridable="yes">Konfigurowanie programu SQL Server</String>
12 <String Id="CreateDatabase" Overridable="yes">Tworzenie baz danych</String>
13 <String Id="DropDatabase" Overridable="yes">Usuwanie baz danych</String>
14 <String Id="ExecuteSqlStrings" Overridable="yes">Wykonywanie zapytań SQL</String>
15 <String Id="RollbackExecuteSqlStrings" Overridable="yes">Cofanie zapytań SQL</String>
16</WixLocalization>
diff --git a/src/ext/Sql/wixlib/pt-br.wxl b/src/ext/Sql/wixlib/pt-br.wxl
new file mode 100644
index 00000000..74c53313
--- /dev/null
+++ b/src/ext/Sql/wixlib/pt-br.wxl
@@ -0,0 +1,16 @@
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
4<WixLocalization Culture="pt-br" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrSQLFailedCreateDatabase" Overridable="yes">Error [2]: falha ao criar o Banco de Dados: [3], detalhes: [4].</String>
6 <String Id="msierrSQLFailedDropDatabase" Overridable="yes">Error [2]: falha ao remover o Banco de Dados: [3], detalhes: [4].</String>
7 <String Id="msierrSQLFailedConnectDatabase" Overridable="yes">Falhou a ligação ao Banco de Dados. ([2] [3] [4] [5])</String>
8 <String Id="msierrSQLFailedExecString" Overridable="yes">Erro [2]: falha ao executar o comando de SQL, detalhes: [3], Comando: [4] Conteúdo: [5]</String>
9 <String Id="msierrSQLDatabaseAlreadyExists" Overridable="yes">O Banco de Dados [3] já existe. Deseja continuar?</String>
10
11 <String Id="ConfigureSql" Overridable="yes">Configurando o Servidor de SQL</String>
12 <String Id="CreateDatabase" Overridable="yes">Criando os Bancos de Dados</String>
13 <String Id="DropDatabase" Overridable="yes">Removendo os Bancos de Dados</String>
14 <String Id="ExecuteSqlStrings" Overridable="yes">Executando comandos de SQL</String>
15 <String Id="RollbackExecuteSqlStrings" Overridable="yes">Revertendo os comandos de SQL</String>
16</WixLocalization>
diff --git a/src/ext/Sql/wixlib/pt-pt.wxl b/src/ext/Sql/wixlib/pt-pt.wxl
new file mode 100644
index 00000000..90d9df4f
--- /dev/null
+++ b/src/ext/Sql/wixlib/pt-pt.wxl
@@ -0,0 +1,16 @@
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
4<WixLocalization Culture="pt-pt" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrSQLFailedCreateDatabase" Overridable="yes">Error [2]: falha ao criar a Base de Dados: [3], detalhes: [4].</String>
6 <String Id="msierrSQLFailedDropDatabase" Overridable="yes">Error [2]: falha ao remover a Base de Dados: [3], detalhes: [4].</String>
7 <String Id="msierrSQLFailedConnectDatabase" Overridable="yes">Falhou a ligação à Base de Dados. ([2] [3] [4] [5])</String>
8 <String Id="msierrSQLFailedExecString" Overridable="yes">Erro [2]: falha ao executar o comando de SQL, detalhes: [3], Comando: [4] Conteúdo: [5]</String>
9 <String Id="msierrSQLDatabaseAlreadyExists" Overridable="yes">A Base de Dados [3] já existe. Deseja continuar?</String>
10
11 <String Id="ConfigureSql" Overridable="yes">Configurar o Servidor de SQL</String>
12 <String Id="CreateDatabase" Overridable="yes">Criar as Bases de Dados</String>
13 <String Id="DropDatabase" Overridable="yes">Remover as Bases de Dados</String>
14 <String Id="ExecuteSqlStrings" Overridable="yes">Executar comandos de SQL</String>
15 <String Id="RollbackExecuteSqlStrings" Overridable="yes">Reverter os comandos de SQL</String>
16</WixLocalization>
diff --git a/src/ext/Sql/wixlib/sql.v3.ncrunchproject b/src/ext/Sql/wixlib/sql.v3.ncrunchproject
new file mode 100644
index 00000000..319cd523
--- /dev/null
+++ b/src/ext/Sql/wixlib/sql.v3.ncrunchproject
@@ -0,0 +1,5 @@
1<ProjectConfiguration>
2 <Settings>
3 <IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
4 </Settings>
5</ProjectConfiguration> \ No newline at end of file
diff --git a/src/ext/Sql/wixlib/sql.wixproj b/src/ext/Sql/wixlib/sql.wixproj
new file mode 100644
index 00000000..ac994e6b
--- /dev/null
+++ b/src/ext/Sql/wixlib/sql.wixproj
@@ -0,0 +1,24 @@
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<Project Sdk="WixToolset.Sdk">
3
4 <PropertyGroup>
5 <OutputType>Library</OutputType>
6 <BindFiles>true</BindFiles>
7 </PropertyGroup>
8
9 <ItemGroup>
10 <BindInputPaths Include="$(OutputPath)x86" BindName='x86' />
11 <BindInputPaths Include="$(OutputPath)x64" BindName='x64' />
12 <BindInputPaths Include="$(OutputPath)arm64" BindName='arm64' />
13 </ItemGroup>
14
15 <ItemGroup>
16 <ProjectReference Include="..\ca\sqlca.vcxproj" Properties="Platform=ARM64" ReferenceOutputAssembly="false" />
17 <ProjectReference Include="..\ca\sqlca.vcxproj" Properties="Platform=x86" ReferenceOutputAssembly="false" />
18 <ProjectReference Include="..\ca\sqlca.vcxproj" Properties="Platform=x64" ReferenceOutputAssembly="false" />
19 </ItemGroup>
20
21 <ItemGroup>
22 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="All" />
23 </ItemGroup>
24</Project>