├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ └── default.md ├── .gitignore ├── DacFxStronglyTypedModel ├── DacFxStronglyTypedModel.csproj ├── ISqlModelElement.cs ├── ISqlModelElementReference.cs ├── Interfaces.cs ├── Interfaces.tt ├── MarkerInterfaces.cs ├── ModelExtensions.cs ├── ModelMessages.Designer.cs ├── ModelMessages.resx ├── ModelUtilityMethods.cs ├── ModelUtilityMethods.tt ├── Properties │ └── AssemblyInfo.cs ├── TSqlModelElement.cs ├── TSqlModelElementReference.cs ├── TSqlTypedModel.cs ├── UnresolvedElementException.cs ├── Utils.cs ├── Utils.tt ├── VersionSpecificImplementations.cs ├── VersionSpecificImplementations.tt ├── model.cs ├── model.tt ├── modelmetadata.xml └── packages.config ├── DacPublicSamples.sln ├── LICENSE ├── README.md ├── RuleSamples ├── AvoidWaitForDelayRule.cs ├── CapitalizedNamesRule.cs ├── InMemoryTableBin2CollationRule.cs ├── LocalizedExportCodeAnalysisRuleAttribute.cs ├── Properties │ └── AssemblyInfo.cs ├── RuleConstants.cs ├── RuleResources.Designer.cs ├── RuleResources.resx ├── RuleSamples.csproj ├── RuleUtils.cs ├── TSqlScriptDomUtils.cs ├── TableNameEndingInViewRule.cs ├── ViewsOnMemoryOptimizedTableRule.cs ├── WaitForDelayVisitor.cs └── packages.config ├── RuleTests ├── BaselinedRuleTest.cs ├── Properties │ └── AssemblyInfo.cs ├── RuleTest.cs ├── RuleTestCases.cs ├── RuleTestUtils.cs ├── RuleTests.csproj ├── TestScripts │ ├── AvoidWaitForDelayRule │ │ ├── AvoidWaitForDelayRule-Baseline.txt │ │ ├── DatabaseScalarFunction1.sql │ │ ├── InlineFunction.sql │ │ ├── ProcWithWaitForDelay.sql │ │ ├── ProcWithWaitForTime.sql │ │ ├── ServerTrigger1.sql │ │ ├── Table1.sql │ │ └── TableValuedFunctionWithWaitForDelay.sql │ ├── README.txt │ ├── TestBin2CollationOnProjectRule │ │ ├── Filegroup.sql │ │ ├── TableWithBin2Collation.sql │ │ ├── TableWithSpecificNonBin2Collation.sql │ │ ├── TableWithoutBin2Collation.sql │ │ ├── TestBin2CollationOnProjectRule-Baseline.txt │ │ └── UddtTests.sql │ ├── TestCapitalizedNamesRule │ │ ├── TestCapitalizedNamesRule-Baseline.txt │ │ └── TestScript.sql │ ├── TestNonBin2CollationOnProjectRule │ │ ├── Filegroup.sql │ │ ├── TableWithBin2Collation.sql │ │ ├── TableWithSpecificNonBin2Collation.sql │ │ ├── TableWithoutBin2Collation.sql │ │ ├── TestNonBin2CollationOnProjectRule-Baseline.txt │ │ └── UddtTests.sql │ └── TestViewOnMemoryOptimizedTableRule │ │ ├── Filegroup.sql │ │ ├── Table1.sql │ │ ├── Table2.sql │ │ ├── TestViewOnMemoryOptimizedTableRule-Baseline.txt │ │ └── View1Tests.sql └── packages.config ├── SECURITY.md ├── SampleConsoleApp ├── App.config ├── ModelEndToEnd.cs ├── ModelFilterExample.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── RunCodeAnalysisExample.cs ├── RunValidateQuerySemanticallyExample.cs ├── SampleConsoleApp.csproj └── packages.config ├── SampleTests ├── Properties │ └── AssemblyInfo.cs ├── SampleTests.csproj ├── StronglyTypedUnitTests.cs ├── TestCreateIndexOperationalPropsModifier.cs ├── TestDbLocationModifiers.cs ├── TestDeploymentStoppingContributor.cs ├── TestFiltering.cs └── packages.config ├── Samples ├── CompositeFilter.cs ├── Contributors │ ├── AlterTableAlterColumnOnlineModifier.cs │ ├── CreateIndexOperationalPropsModifier.cs │ ├── DbCreateDatabaseModifier.cs │ ├── DbLocationModifier.cs │ ├── DefaultConstraintNameModifier.cs │ └── DeploymentStoppingContributor.cs ├── DisposableList.cs ├── Filter.cs ├── ModelFilterer.cs ├── PlanFilterer.cs ├── Properties │ └── AssemblyInfo.cs ├── Samples.csproj ├── SchemaBasedFilter.cs ├── TSqlModelExtensions.cs ├── Utils.cs └── packages.config ├── Scripts └── RemoveMasterKey.ps1 └── TestUtils ├── CommonConstants.cs ├── ExceptionText.cs ├── InstanceInfo.cs ├── Properties └── AssemblyInfo.cs ├── SqlTestDb.cs ├── TestUtils.cs ├── TestUtils.csproj └── packages.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Default 3 | about: Default issue template 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 19 | !packages/*/build/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | 98 | # NuGet Packages Directory 99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 100 | packages/ 101 | 102 | # Windows Azure Build Output 103 | csx 104 | *.build.csdef 105 | 106 | # Windows Store app package directory 107 | AppPackages/ 108 | 109 | # Others 110 | sql/ 111 | *.Cache 112 | ClientBin/ 113 | [Ss]tyle[Cc]op.* 114 | ~$* 115 | *~ 116 | *.dbmdl 117 | *.[Pp]ublish.xml 118 | *.pfx 119 | *.publishsettings 120 | 121 | # RIA/Silverlight projects 122 | Generated_Code/ 123 | 124 | # Backup & report files from converting an old project file to a newer 125 | # Visual Studio version. Backup files are not needed, because we have git ;-) 126 | _UpgradeReport_Files/ 127 | Backup*/ 128 | UpgradeLog*.XML 129 | UpgradeLog*.htm 130 | 131 | # SQL Server files 132 | App_Data/*.mdf 133 | App_Data/*.ldf 134 | 135 | 136 | #LightSwitch generated files 137 | GeneratedArtifacts/ 138 | _Pvt_Extensions/ 139 | ModelManifest.xml 140 | 141 | # ========================= 142 | # Windows detritus 143 | # ========================= 144 | 145 | # Windows image file caches 146 | Thumbs.db 147 | ehthumbs.db 148 | 149 | # Folder config file 150 | Desktop.ini 151 | 152 | # Recycle Bin used on file shares 153 | $RECYCLE.BIN/ 154 | 155 | # Mac desktop service store files 156 | .DS_Store 157 | /DacFxStronglyTypedModel.zip 158 | /.vs 159 | -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/ISqlModelElement.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | namespace Microsoft.SqlServer.Dac.Extensions.Prototype 28 | { 29 | using System; 30 | using Microsoft.SqlServer.TransactSql.ScriptDom; 31 | using Microsoft.SqlServer.Dac.Model; 32 | using System.Collections.Generic; 33 | public interface ISqlModelElement 34 | { 35 | ObjectIdentifier Name { get; } 36 | TSqlObject Element { get; } 37 | TSqlScript GetAst(); 38 | IEnumerable GetChildren(); 39 | IEnumerable GetChildren(DacQueryScopes queryScopes); 40 | object GetMetadata(ModelMetadataClass metadata); 41 | T GetMetadata(ModelMetadataClass metadata); 42 | TSqlObject GetParent(); 43 | TSqlObject GetParent(DacQueryScopes queryScopes); 44 | object GetProperty(ModelPropertyClass property); 45 | T GetProperty(ModelPropertyClass property); 46 | IEnumerable GetReferenced(); 47 | IEnumerable GetReferenced(DacQueryScopes queryScopes); 48 | IEnumerable GetReferenced(ModelRelationshipClass relationshipType); 49 | IEnumerable GetReferenced(ModelRelationshipClass relationshipType, DacQueryScopes queryScopes); 50 | IEnumerable GetReferencedRelationshipInstances(); 51 | IEnumerable GetReferencedRelationshipInstances(DacExternalQueryScopes queryScopes); 52 | IEnumerable GetReferencedRelationshipInstances(DacQueryScopes queryScopes); 53 | IEnumerable GetReferencedRelationshipInstances(ModelRelationshipClass relationshipType); 54 | IEnumerable GetReferencedRelationshipInstances(ModelRelationshipClass relationshipType, DacExternalQueryScopes queryScopes); 55 | IEnumerable GetReferencedRelationshipInstances(ModelRelationshipClass relationshipType, DacQueryScopes queryScopes); 56 | IEnumerable GetReferencing(); 57 | IEnumerable GetReferencing(DacQueryScopes queryScopes); 58 | IEnumerable GetReferencing(ModelRelationshipClass relationshipType); 59 | IEnumerable GetReferencing(ModelRelationshipClass relationshipType, DacQueryScopes queryScopes); 60 | IEnumerable GetReferencingRelationshipInstances(); 61 | IEnumerable GetReferencingRelationshipInstances(DacQueryScopes queryScopes); 62 | IEnumerable GetReferencingRelationshipInstances(ModelRelationshipClass relationshipType); 63 | IEnumerable GetReferencingRelationshipInstances(ModelRelationshipClass relationshipType, DacQueryScopes queryScopes); 64 | string GetScript(); 65 | SourceInformation GetSourceInformation(); 66 | ModelTypeClass ObjectType { get; } 67 | object this[ModelPropertyClass property] { get; } 68 | bool TryGetAst(out TSqlScript objectAst); 69 | bool TryGetScript(out string objectScript); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/ISqlModelElementReference.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using Microsoft.SqlServer.Dac.Model; 28 | namespace Microsoft.SqlServer.Dac.Extensions.Prototype 29 | { 30 | 31 | public interface ISqlModelElementReference : ISqlModelElement 32 | { 33 | T GetMetadataProperty(ModelPropertyClass property); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/Interfaces.tt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | <#@ template debug="false" hostspecific="true" language="C#" #> 28 | <#@ assembly name="System.Core" #> 29 | <#@ assembly name="System.Xml" #> 30 | <#@ import namespace="System.Linq" #> 31 | <#@ import namespace="System.Text" #> 32 | <#@ import namespace="System" #> 33 | <#@ import namespace="System.Xml" #> 34 | <#@ import namespace="System.Collections.Generic" #> 35 | <#@ assembly name="$(DacFxExternals)\Microsoft.SqlServer.Dac.Extensions.dll" #> 36 | <#@ import namespace="Microsoft.SqlServer.Dac.Model"#> 37 | <#@ output extension=".cs" #> 38 | <#@ include file="Utils.tt" #> 39 | namespace <#=NamespaceName#> 40 | { 41 | using System; 42 | using System.Linq; 43 | using Microsoft.SqlServer.Server; 44 | using Microsoft.SqlServer.Dac.Model; 45 | using System.Collections.Generic; 46 | <# 47 | var overrides = LoadOverrides(this.Host.TemplateFile); 48 | string interfacePrefix; 49 | 50 | foreach(SqlServerVersion currentSQLVersion in GetSqlServerVersionValues()) 51 | { 52 | interfacePrefix = GetInterfacePrefix(currentSQLVersion); 53 | foreach(var type in ModelSchema.SchemaInstance.AllTypes) 54 | { 55 | string className = interfacePrefix+ ClassNamePrefix +type.Name; 56 | ModelEntry modelEntry; 57 | overrides.TryGetValue(type.Name, out modelEntry); 58 | 59 | #> 60 | public interface <#= className #>Reference : <#= className #> 61 | { 62 | } 63 | public interface <#= className #> : ISqlModelElement 64 | { 65 | <# 66 | foreach (var property in type.Properties.OrderBy(p => p.Name)) 67 | { 68 | if(!SupportsVersion(property.SupportedPlatforms, currentSQLVersion)) 69 | { 70 | continue; 71 | } 72 | bool useGenericGetter; 73 | string typeName = GetPropertyTypeName(property.DataType, out useGenericGetter); 74 | string propertyName = GetPropertyName(property, modelEntry); 75 | #> 76 | <#= typeName #> <#= propertyName #> 77 | { 78 | get; 79 | } 80 | <# 81 | }// end property loop 82 | 83 | 84 | // begin relationship loop 85 | foreach (var relationship in type.Relationships.OrderBy( r => r.Name)) 86 | { 87 | if (!SupportsVersion(relationship.SupportedPlatforms, currentSQLVersion)) 88 | { 89 | // skip unsupported properties 90 | continue; 91 | } 92 | string returnType = DefaultReturnType; 93 | if(modelEntry != null) 94 | { 95 | RelationshipOverride localoverride; 96 | if(modelEntry.RelationshipOverrides.TryGetValue(relationship.Name, out localoverride)) 97 | { 98 | if(localoverride.Specialize) 99 | { 100 | // specialize the return type to match the sql version interface name 101 | returnType = string.Format("{0}.{1}{2}", localoverride.ReturnTypeNamespace,interfacePrefix, localoverride.ReturnType); 102 | } 103 | else 104 | { 105 | // return type is not specialized for each sql version interface. 106 | returnType = string.Format("{0}.{1}", localoverride.ReturnTypeNamespace, localoverride.ReturnType); 107 | } 108 | } 109 | } 110 | #> 111 | //<#=relationship.Type#> 112 | IEnumerable<<#=returnType#>> <#=relationship.Name #> 113 | { 114 | get; 115 | } 116 | <# 117 | } //end foreach relationship 118 | #> 119 | } 120 | <# 121 | } 122 | } 123 | #> 124 | } -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/MarkerInterfaces.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SqlServer.Dac.Model; 2 | //------------------------------------------------------------------------------ 3 | // 4 | // 5 | // The MIT License (MIT) 6 | // 7 | // Copyright (c) 2015 Microsoft 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in all 17 | // copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | // SOFTWARE. 26 | // 27 | //------------------------------------------------------------------------------ 28 | using System; 29 | using System.Collections.Generic; 30 | using System.Linq; 31 | using System.Text; 32 | 33 | namespace Microsoft.SqlServer.Dac.Extensions.Prototype 34 | { 35 | 36 | public interface ISqlSecurityPrincipal : ISqlModelElement { } 37 | 38 | public interface IServerSecurityPrincipal : ISqlSecurityPrincipal { } 39 | 40 | public interface ISqlDatabaseSecurityPrincipal : ISqlSecurityPrincipal, ISqlObjectAuthorizer{ } 41 | 42 | public sealed class UnresolvedISqlDatabaseSecurityPrincipalElement : TSqlModelElementReference, ISqlDatabaseSecurityPrincipal 43 | { 44 | public UnresolvedISqlDatabaseSecurityPrincipalElement(Model.ModelRelationshipInstance relationshipReference) : base(relationshipReference) 45 | { 46 | 47 | } 48 | } 49 | public interface ISqlSecurable : ISqlModelElement { } 50 | 51 | public sealed class UnresolvedISqlSecurableElement : TSqlModelElementReference, ISqlSecurable 52 | { 53 | public UnresolvedISqlSecurableElement(Model.ModelRelationshipInstance relationshipReference):base(relationshipReference) 54 | { } 55 | } 56 | 57 | public interface ISpecifiesIndex : ISqlModelElement 58 | { 59 | IEnumerable Indexes { get; } 60 | } 61 | 62 | public sealed class UnresolvedISpecifiesIndexElement: TSqlModelElementReference, ISpecifiesIndex 63 | { 64 | public UnresolvedISpecifiesIndexElement(Model.ModelRelationshipInstance instance) 65 | : base(instance) 66 | { 67 | } 68 | 69 | public IEnumerable Indexes 70 | { 71 | get { throw new UnresolvedElementException(ModelMessages.UnresolvedObject); } 72 | } 73 | } 74 | 75 | public interface ISpecifiesDmlTrigger : ISqlModelElement 76 | { 77 | IEnumerable Triggers { get; } 78 | } 79 | 80 | public interface ISqlColumnSource : ISqlModelElement 81 | { 82 | IEnumerable Columns { get; } 83 | } 84 | public interface ISqlPromotedNodePath : ISqlModelElement { } 85 | 86 | public sealed class UnresolvedISqlPromotedNodePathElement : TSqlModelElementReference, ISqlPromotedNodePath 87 | { 88 | public UnresolvedISqlPromotedNodePathElement(Model.ModelRelationshipInstance relationshipReference) 89 | : base(relationshipReference) 90 | { } 91 | } 92 | 93 | public interface ISqlIndex : ISqlModelElement { } 94 | public interface ITableTypeConstraint : ISqlModelElement { } 95 | public interface IProtocolSpecifier : ISqlModelElement { } 96 | public interface IEndpointLanguageSpecifier : ISqlModelElement { } 97 | 98 | 99 | #region IExtendedProprtyHost 100 | public interface IExtendedPropertyHost : ISqlModelElement { } 101 | 102 | //TODO: Collect all extended property hosts. Some added but lots missing 103 | #endregion 104 | 105 | #region ISqlObjectAuthorizer 106 | public interface ISqlObjectAuthorizer : ISqlModelElement { } 107 | 108 | public sealed class UnresolvedISqlObjectAuthorizerElement : TSqlModelElementReference, ISqlObjectAuthorizer 109 | { 110 | public UnresolvedISqlObjectAuthorizerElement(Model.ModelRelationshipInstance relationshipReference) : base(relationshipReference) 111 | { 112 | 113 | } 114 | } 115 | 116 | // TODO: Collect all Authorizers 117 | #endregion 118 | 119 | public interface ISpecifiesStorage : ISqlModelElement 120 | { 121 | IEnumerable DataCompressionOptions { get; } 122 | 123 | } 124 | 125 | public interface ISqlDataType: ISqlModelElement 126 | { 127 | } 128 | 129 | public sealed class UnresolvedISqlDataTypeElement : TSqlModelElementReference, ISqlDataType 130 | { 131 | public UnresolvedISqlDataTypeElement(Model.ModelRelationshipInstance relationshipReference) 132 | : base(relationshipReference) 133 | { } 134 | } 135 | } 136 | 137 | -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/ModelMessages.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.34209 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Microsoft.SqlServer.Dac.Extensions.Prototype { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class ModelMessages { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal ModelMessages() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.SqlServer.Dac.Extensions.Prototype.ModelMessages", typeof(ModelMessages).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Model Type Class {0} does not match the TSqlObject ObjectType {1}. 65 | /// 66 | internal static string InvalidObjectType { 67 | get { 68 | return ResourceManager.GetString("InvalidObjectType", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Underlying object {0} is unresolved.. 74 | /// 75 | internal static string UnresolvedObject { 76 | get { 77 | return ResourceManager.GetString("UnresolvedObject", resourceCulture); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/ModelMessages.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Model Type Class {0} does not match the TSqlObject ObjectType {1} 122 | 123 | 124 | Underlying object {0} is unresolved. 125 | 126 | -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DacFxStronglyTypedModel")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DacFxStronglyTypedModel")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("42196f12-dcd8-451f-8b2b-cc63ed40f9a2")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/TSqlModelElementReference.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using Microsoft.SqlServer.Dac.Model; 29 | using System; 30 | using System.Collections.Generic; 31 | using System.Globalization; 32 | 33 | namespace Microsoft.SqlServer.Dac.Extensions.Prototype 34 | { 35 | public class TSqlModelElementReference : TSqlModelElement, ISqlModelElementReference 36 | { 37 | private ModelRelationshipInstance relationshipInstance; 38 | private ModelTypeClass predefinedTypeClass; 39 | 40 | 41 | public TSqlModelElementReference(ModelRelationshipInstance relationshipReference) : 42 | base() 43 | { 44 | relationshipInstance = relationshipReference; 45 | } 46 | public TSqlModelElementReference(ModelRelationshipInstance relationshipReference, ModelTypeClass typeClass) : 47 | this(relationshipReference) 48 | { 49 | 50 | if (relationshipInstance.Object != null && relationshipInstance.Object.ObjectType != typeClass) 51 | { 52 | throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, 53 | ModelMessages.InvalidObjectType, relationshipInstance.Object.ObjectType.Name, typeClass.Name), 54 | "typeClass"); 55 | } 56 | 57 | predefinedTypeClass = typeClass; 58 | } 59 | 60 | public override ObjectIdentifier Name 61 | { 62 | get 63 | { 64 | return relationshipInstance.ObjectName; 65 | } 66 | } 67 | 68 | public override ModelTypeClass ObjectType 69 | { 70 | get 71 | { 72 | if (IsResolved()) 73 | { 74 | return base.ObjectType; 75 | } 76 | else 77 | { 78 | // when object is unresolved default to the predefined ModelTypClass 79 | return predefinedTypeClass; 80 | } 81 | } 82 | } 83 | public bool IsResolved() 84 | { 85 | return relationshipInstance.Object != null; 86 | } 87 | 88 | public override TSqlObject Element 89 | { 90 | get 91 | { 92 | // Verify the Element is resolved. 93 | if (!IsResolved()) 94 | { 95 | throw new UnresolvedElementException( 96 | string.Format(CultureInfo.CurrentUICulture, 97 | ModelMessages.UnresolvedObject, 98 | relationshipInstance.ObjectName)); 99 | } 100 | return relationshipInstance.Object; 101 | } 102 | 103 | } 104 | 105 | public T GetMetadataProperty(ModelPropertyClass property) 106 | { 107 | return relationshipInstance.GetProperty(property); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/UnresolvedElementException.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Linq; 30 | using System.Runtime.Serialization; 31 | using System.Text; 32 | using System.Threading.Tasks; 33 | 34 | namespace Microsoft.SqlServer.Dac.Extensions.Prototype 35 | { 36 | /// 37 | /// Thrown when a the referenced element is not resolvable. This happens when there 0 or more than 1 candidate elements 38 | /// that the reference can resolve to. 39 | /// 40 | public sealed class UnresolvedElementException : Exception 41 | { 42 | public UnresolvedElementException() { } 43 | public UnresolvedElementException(string message) : base(message) { } 44 | public UnresolvedElementException(string message, Exception innerException) : base(message, innerException) { } 45 | public UnresolvedElementException(SerializationInfo info, StreamingContext context) : base(info, context) { } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/Utils.cs: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/VersionSpecificImplementations.tt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | <#@ template debug="false" hostspecific="true" language="C#" #> 28 | <#@ assembly name="System.Core" #> 29 | <#@ assembly name="System.Xml" #> 30 | <#@ import namespace="System.Linq" #> 31 | <#@ import namespace="System.Text" #> 32 | <#@ import namespace="System.Xml" #> 33 | <#@ import namespace="System.Collections.Generic" #> 34 | <#@ assembly name="$(DacFxExternals)\Microsoft.SqlServer.Dac.Extensions.dll" #> 35 | <#@ import namespace="Microsoft.SqlServer.Dac.Model"#> 36 | <#@ output extension=".cs" #> 37 | <#@ include file="Utils.tt" #> 38 | namespace <#=NamespaceName#> 39 | { 40 | using System; 41 | using System.Linq; 42 | using Microsoft.SqlServer.Server; 43 | using Microsoft.SqlServer.Dac.Model; 44 | using System.Collections.Generic; 45 | <# 46 | var overrides = LoadOverrides(this.Host.TemplateFile); 47 | string typePrefix; 48 | foreach(SqlServerVersion currentSQLVersion in GetSqlServerVersionValues()) 49 | { 50 | typePrefix = GetInterfacePrefix(currentSQLVersion); 51 | foreach(var type in ModelSchema.SchemaInstance.AllTypes) 52 | { 53 | if(!SupportsVersion(type.SupportedPlatforms, currentSQLVersion)) 54 | { 55 | // skipping type as it does not support the platform 56 | continue; 57 | } 58 | string interfaceName = typePrefix + ClassNamePrefix + type.Name; 59 | ModelEntry modelEntry; 60 | if(!overrides.TryGetValue(type.Name, out modelEntry)) 61 | { 62 | modelEntry = null; 63 | } 64 | #> 65 | /// 66 | /// Explicit implementation of . 67 | /// 68 | public partial class <#= ClassNamePrefix + type.Name#> : <#=interfaceName#> 69 | { 70 | <# 71 | foreach (var property in type.Properties.OrderBy(p => p.Name)) 72 | { 73 | if(!SupportsVersion(property.SupportedPlatforms, currentSQLVersion)) 74 | { 75 | continue; 76 | } 77 | bool useGenericGetter; 78 | string typeName = GetPropertyTypeName(property.DataType, out useGenericGetter); 79 | string propertyName = GetPropertyName(property, modelEntry); 80 | #> 81 | <#= typeName #> <#=interfaceName#>.<#= propertyName #> 82 | { 83 | get { return this.<#=propertyName#>;} 84 | } 85 | <# 86 | }// end property loop 87 | 88 | // begin relationship loop 89 | foreach (var relationship in type.Relationships.OrderBy( r => r.Name)) 90 | { 91 | if (!SupportsVersion(relationship.SupportedPlatforms, currentSQLVersion)) 92 | { 93 | // skip unsupported properties 94 | continue; 95 | } 96 | string returnType = DefaultReturnType; 97 | string castExpression = ""; 98 | if(modelEntry != null) 99 | { RelationshipOverride localoverride; 100 | if(modelEntry.RelationshipOverrides.TryGetValue(relationship.Name, out localoverride)) 101 | { 102 | if(localoverride.Specialize) 103 | { 104 | // specialize the return type for the sql server version 105 | returnType = string.Format("{0}.{1}{2}", localoverride.ReturnTypeNamespace, typePrefix, localoverride.ReturnType); 106 | castExpression = string.Format(".Cast<{0}>()", returnType); 107 | } 108 | else 109 | { 110 | // do not specialize the return type for the sql server version 111 | returnType = string.Format("{0}.{1}", localoverride.ReturnTypeNamespace, localoverride.ReturnType); 112 | } 113 | } 114 | } 115 | #> 116 | 117 | // <#=relationship.Type#> relationship 118 | IEnumerable<<#=returnType#>> <#=interfaceName#>.<#=relationship.Name #> 119 | { 120 | get 121 | { 122 | return this.<#=relationship.Name + castExpression#>; 123 | } 124 | } 125 | <# 126 | } //end foreach relationship 127 | #> 128 | } 129 | <# 130 | } 131 | } 132 | #> 133 | } -------------------------------------------------------------------------------- /DacFxStronglyTypedModel/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /DacPublicSamples.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.22823.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleConsoleApp", "SampleConsoleApp\SampleConsoleApp.csproj", "{7855389B-A1F0-4A7C-A83A-38EEF5B73F9A}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples", "Samples\Samples.csproj", "{C1C2B521-22B6-4124-AAEC-A5E1FCAB0DFA}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleTests", "SampleTests\SampleTests.csproj", "{E8F7142C-412D-40A8-AC5E-C90339A8C559}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RuleSamples", "RuleSamples\RuleSamples.csproj", "{18E096E9-6A3D-4124-B908-9C39A425F7BE}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RuleTests", "RuleTests\RuleTests.csproj", "{DF142FCD-E8E0-4841-BDB9-C9974F09068D}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DacFxStronglyTypedModel", "DacFxStronglyTypedModel\DacFxStronglyTypedModel.csproj", "{832ECF86-C071-4628-A8B7-2529D8A7BDBC}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtils", "TestUtils\TestUtils.csproj", "{EDF01D79-66D0-496C-82D2-431831564817}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {7855389B-A1F0-4A7C-A83A-38EEF5B73F9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {7855389B-A1F0-4A7C-A83A-38EEF5B73F9A}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {7855389B-A1F0-4A7C-A83A-38EEF5B73F9A}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {7855389B-A1F0-4A7C-A83A-38EEF5B73F9A}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {C1C2B521-22B6-4124-AAEC-A5E1FCAB0DFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {C1C2B521-22B6-4124-AAEC-A5E1FCAB0DFA}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {C1C2B521-22B6-4124-AAEC-A5E1FCAB0DFA}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {C1C2B521-22B6-4124-AAEC-A5E1FCAB0DFA}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {E8F7142C-412D-40A8-AC5E-C90339A8C559}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {E8F7142C-412D-40A8-AC5E-C90339A8C559}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {E8F7142C-412D-40A8-AC5E-C90339A8C559}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {E8F7142C-412D-40A8-AC5E-C90339A8C559}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {18E096E9-6A3D-4124-B908-9C39A425F7BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {18E096E9-6A3D-4124-B908-9C39A425F7BE}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {18E096E9-6A3D-4124-B908-9C39A425F7BE}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {18E096E9-6A3D-4124-B908-9C39A425F7BE}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {DF142FCD-E8E0-4841-BDB9-C9974F09068D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {DF142FCD-E8E0-4841-BDB9-C9974F09068D}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {DF142FCD-E8E0-4841-BDB9-C9974F09068D}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {DF142FCD-E8E0-4841-BDB9-C9974F09068D}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {832ECF86-C071-4628-A8B7-2529D8A7BDBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {832ECF86-C071-4628-A8B7-2529D8A7BDBC}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {832ECF86-C071-4628-A8B7-2529D8A7BDBC}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {832ECF86-C071-4628-A8B7-2529D8A7BDBC}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {EDF01D79-66D0-496C-82D2-431831564817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {EDF01D79-66D0-496C-82D2-431831564817}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {EDF01D79-66D0-496C-82D2-431831564817}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {EDF01D79-66D0-496C-82D2-431831564817}.Release|Any CPU.Build.0 = Release|Any CPU 54 | EndGlobalSection 55 | GlobalSection(SolutionProperties) = preSolution 56 | HideSolutionNode = FALSE 57 | EndGlobalSection 58 | EndGlobal 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Microsoft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DACExtensions 2 | 3 | 4 | > [!IMPORTANT] 5 | > This repository has been archived and the samples are no longer maintained. The development of DacFx and SQL projects is active, including the areas of extensibility and code analysis as seen in this repository. We welcome your feedback and issue reports over at https://github.com/microsoft/dacfx. 6 | 7 | ## Project Description 8 | DACExtensions contains API extensions and samples using the [DacFx API](https://msdn.microsoft.com/en-us/library/dn645454.aspx) to develop Data-Tier Applications. 9 | 10 | These extensions and samples include an improved object model, deployment contributors and static code analysis rules that can be used with Visual Studio or directly with the DacFx public API. 11 | 12 | ## Background Information 13 | SQL Server Data Tools is built into Visual Studio 2013. For other versions of visual studio you can download SQL Server Data Tools from the [Data Developer Center](https://msdn.microsoft.com/en-us/data/hh297027) 14 | 15 | SQL Server Data Tools provides an integrated environment for database developers to carry out all of their database design work for any SQL Server Platform. 16 | 17 | DacFx is the core technology the SQL Server Data Tools leverages for incremental database deployments, modelling and validation of database schemas and other key functionality. DacFx provides a DacServices API that supports programmatic deployment of Dacpac files. 18 | DacFx has a number of public extensibility points that customers can implement. Some possible functionality includes: 19 | 20 | * Programmatic examinations of database schemas (as represented in a Visual Studio database project, a Dacpac and even a target database when used during deployment) 21 | * Modification of the deployment plans used to incrementally deploy schema updates from a Dacpac to a database 22 | * Static Code Analysis rules provide build-time support for analyzing the database schema and warning users of potential issues. 23 | 24 | These samples are primarily intended to show users how to create their own extensions, test them and use them in deployment. They include solutions to real customer problems and can be used as-is if you have the same issue. Ideally you will take this project, extend it and create your own solutions. 25 | 26 | ## Prerequisites 27 | An installation of SQL Server Data Tools or DacFx is required to run these samples. The sample projects include references to DLLs in a Visual Studio installation with the most recent release of SQL Server Data Tools. 28 | 29 | * For Visual Studio 2013 the install directory will is "%ProgramFiles(x86)%\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\120". 30 | * This is set as the current hint path in all sample projects 31 | * For Visual Studio 2012 the install directory is "%ProgramFiles(x86)%\Microsoft Visual Studio 11.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\120". 32 | * The hint path in all sample projects must be updated if you want to target Visual Studio 2012 DLLs. 33 | * For DacFx the install directory is "%ProgramFiles(x86)%\Microsoft Server Server \Common7\IDE\Extensions\Microsoft\SQLDB\DAC\120". 34 | * The hint path in all sample projects must be updated if you want to target the DacFx DLLs. 35 | 36 | This project uses Git for source code control. Visual Studio 2013 has Git support built in, and for Visual Studio 2012 please download the Visual Studio Tools for Git plugin. 37 | 38 | ## Usage 39 | The samples in this project are provided as-is. To run the samples, we recommend you download the source code and attach a debugger while running the sample console application and unit test code. 40 | 41 | The full tutorial explaining how to use the public APIs can be found [here][dacfxturorial]. 42 | 43 | ## Samples Installation 44 | 45 | These samples assume the latest SQL Server Data Tools updates for Visual Studio 2013 are installed. 46 | To develop using Visual Studio 2012 please modify the .csproj files to change 47 | "C:\Program Files (x86)\Microsoft Visual Studio 12.0" to "C:\Program Files (x86)\Microsoft Visual Studio 11.0", and ensure the latest version of SQL Server Data Tools is installed for Visual Studio 2012. 48 | 49 | These samples are intended to work in tandem with the walkthroughs at 50 | [http://msdn.microsoft.com/en-us/library/dn268597(v=vs.103).aspx][msdn] and with the standard 51 | SQL Server Data Tools help documentation. They show how to bootstrap an extensions library for Static 52 | Code Analysis rules and contributors and test them without installing anything into 53 | Visual Studio. 54 | 55 | If you wish to install any samples DLL into visual studio you need to sign the DLLs per 56 | the walkthrough instructions: 57 | 58 | To sign and build the assembly 59 | 60 | * On the Project menu, click Properties . 61 | * Click the Signing tab. 62 | * Click Sign the assembly. 63 | * In Choose a strong name key file , click . 64 | * In the Create Strong Name Key dialog box, in Key file name , type MyRefKey. 65 | * (optional) You can specify a password for your strong name key file. 66 | * Click OK. 67 | * On the File menu, click Save All. 68 | * On the Build menu, click Build Solution. 69 | 70 | 71 | Then copy them to the extension installation directory: 72 | 73 | * VS 2013: %ProgramFiles(x86)%\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\120\Extensions 74 | * VS 2012: %ProgramFiles(x86)%\Microsoft Visual Studio 11.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\120\Extensions 75 | 76 | ## Code of Conduct 77 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 78 | 79 | [msdn]:http://msdn.microsoft.com/en-us/library/dn268597(v=vs.103).aspx 80 | [dacfxturorial]:http://blogs.msdn.com/b/ssdt/archive/2013/12/23/dacfx-public-model-tutorial.aspx 81 | -------------------------------------------------------------------------------- /RuleSamples/LocalizedExportCodeAnalysisRuleAttribute.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using Microsoft.SqlServer.Dac.CodeAnalysis; 29 | using System; 30 | using System.Globalization; 31 | using System.Reflection; 32 | using System.Resources; 33 | 34 | namespace Public.Dac.Samples.Rules 35 | { 36 | /// 37 | /// This is an example of a localized export attribute. These can be very useful in the case where 38 | /// you need localized resource strings for things like the display name and description of a rule. 39 | /// 40 | /// All of the export attributes provided by the DAC API can be localized, and internally a very 41 | /// similar structure is used. If you do not need to perform localization of any resources it's easier to use the 42 | /// directly. 43 | /// 44 | /// 45 | internal class LocalizedExportCodeAnalysisRuleAttribute : ExportCodeAnalysisRuleAttribute 46 | { 47 | private readonly string _resourceBaseName; 48 | private readonly string _displayNameResourceId; 49 | private readonly string _descriptionResourceId; 50 | 51 | private ResourceManager _resourceManager; 52 | private string _displayName; 53 | private string _descriptionValue; 54 | 55 | /// 56 | /// Creates the attribute, with the specified rule ID, the fully qualified 57 | /// name of the resource file that will be used for looking up display name 58 | /// and description, and the Ids of those resources inside the resource file. 59 | /// 60 | public LocalizedExportCodeAnalysisRuleAttribute( 61 | string id, 62 | string resourceBaseName, 63 | string displayNameResourceId, 64 | string descriptionResourceId) 65 | : base(id, null) 66 | { 67 | _resourceBaseName = resourceBaseName; 68 | _displayNameResourceId = displayNameResourceId; 69 | _descriptionResourceId = descriptionResourceId; 70 | } 71 | 72 | /// 73 | /// Rules in a different assembly would need to overwrite this 74 | /// 75 | /// 76 | protected virtual Assembly GetAssembly() 77 | { 78 | return GetType().Assembly; 79 | } 80 | 81 | private void EnsureResourceManagerInitialized() 82 | { 83 | var resourceAssembly = GetAssembly(); 84 | 85 | try 86 | { 87 | _resourceManager = new ResourceManager(_resourceBaseName, resourceAssembly); 88 | } 89 | catch (Exception ex) 90 | { 91 | var msg = String.Format(CultureInfo.CurrentCulture, RuleResources.CannotCreateResourceManager, _resourceBaseName, resourceAssembly); 92 | throw new RuleException(msg, ex); 93 | } 94 | } 95 | 96 | private string GetResourceString(string resourceId) 97 | { 98 | if (string.IsNullOrWhiteSpace(resourceId)) 99 | { 100 | return string.Empty; 101 | } 102 | EnsureResourceManagerInitialized(); 103 | return _resourceManager.GetString(resourceId, CultureInfo.CurrentUICulture); 104 | } 105 | 106 | /// 107 | /// Overrides the standard DisplayName and looks up its value inside a resources file 108 | /// 109 | public override string DisplayName 110 | { 111 | get 112 | { 113 | if (_displayName == null) 114 | { 115 | _displayName = GetResourceString(_displayNameResourceId); 116 | } 117 | return _displayName; 118 | } 119 | } 120 | 121 | /// 122 | /// Overrides the standard Description and looks up its value inside a resources file 123 | /// 124 | public override string Description 125 | { 126 | get 127 | { 128 | if (_descriptionValue == null) 129 | { 130 | // Using the descriptionResourceId as the key for looking up the description in the resources file. 131 | _descriptionValue = GetResourceString(_descriptionResourceId); 132 | } 133 | return _descriptionValue; 134 | } 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /RuleSamples/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RuleSamples")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("RuleSamples")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6936afeb-f7c1-4cd8-8cdd-71d9de761ba3")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /RuleSamples/RuleConstants.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using Microsoft.SqlServer.Dac.Extensibility; 29 | 30 | namespace Public.Dac.Samples.Rules 31 | { 32 | internal static class RuleConstants 33 | { 34 | /// 35 | /// The name of the resources file to use when looking up rule resources 36 | /// 37 | public const string ResourceBaseName = "Public.Dac.Samples.Rules.RuleResources"; 38 | 39 | /// 40 | /// Lookup name inside the resources file for the rule name 41 | /// 42 | public const string AvoidWaitForDelay_RuleName = "AvoidWaitForDelay_RuleName"; 43 | /// 44 | /// Lookup ID inside the resources file for the description 45 | /// 46 | public const string AvoidWaitForDelay_ProblemDescription = "AvoidWaitForDelay_ProblemDescription"; 47 | 48 | /// 49 | /// Lookup name inside the resources file for the rule name 50 | /// 51 | public const string InMemoryBinCollection_RuleName = "InMemoryBinCollection_RuleName"; 52 | /// 53 | /// Lookup ID inside the resources file for the description 54 | /// 55 | public const string InMemoryBinCollection_ProblemDescription = "InMemoryBinCollection_ProblemDescription"; 56 | 57 | /// 58 | /// Lookup name inside the resources file for the rule name 59 | /// 60 | public const string ViewsOnMemoryOptimizedTable_RuleName = "ViewsOnMemoryOptimizedTable_RuleName"; 61 | 62 | public const string CapitalizedNames_RuleName = "CapitalizedNames_RuleName"; 63 | 64 | public const string CapitalizedNames_ProblemDescription = "CapitalizedNames_ProblemDescription"; 65 | 66 | /// 67 | /// The design category (should not be localized) 68 | /// 69 | public const string CategoryDesign = "Design"; 70 | 71 | public const string CategoryPerformance = "Performance"; 72 | 73 | public const string CategoryNaming = "Naming"; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /RuleSamples/RuleSamples.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {18E096E9-6A3D-4124-B908-9C39A425F7BE} 8 | Library 9 | Properties 10 | Public.Dac.Samples.Rules 11 | Public.Dac.Samples.Rules 12 | v4.6 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.Data.Tools.Schema.Sql.dll 36 | 37 | 38 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.Data.Tools.Utilities.dll 39 | 40 | 41 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Dac.dll 42 | 43 | 44 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Dac.Extensions.dll 45 | 46 | 47 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.TransactSql.ScriptDom.dll 48 | 49 | 50 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Types.dll 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | True 71 | True 72 | RuleResources.resx 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | ResXFileCodeGenerator 82 | RuleResources.Designer.cs 83 | 84 | 85 | 86 | 87 | 88 | 89 | 96 | -------------------------------------------------------------------------------- /RuleSamples/RuleUtils.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using Microsoft.SqlServer.Dac.CodeAnalysis; 29 | using Microsoft.SqlServer.Dac.Model; 30 | 31 | namespace Public.Dac.Samples.Rules 32 | { 33 | internal static class RuleUtils 34 | { 35 | /// 36 | /// Gets a formatted element name with the default style 37 | /// 38 | public static string GetElementName(SqlRuleExecutionContext ruleExecutionContext, TSqlObject modelElement) 39 | { 40 | return GetElementName(modelElement, ruleExecutionContext, ElementNameStyle.EscapedFullyQualifiedName); 41 | } 42 | 43 | /// 44 | /// Gets a formatted element name 45 | /// 46 | public static string GetElementName(TSqlObject modelElement, SqlRuleExecutionContext ruleExecutionContext, ElementNameStyle style) 47 | { 48 | // Get the element name using the built in DisplayServices. This provides a number of useful formatting options to 49 | // make a name user-readable 50 | var displayServices = ruleExecutionContext.SchemaModel.DisplayServices; 51 | string elementName = displayServices.GetElementName(modelElement, style); 52 | return elementName; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /RuleSamples/TableNameEndingInViewRule.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using Microsoft.SqlServer.Dac.CodeAnalysis; 29 | using Microsoft.SqlServer.Dac.Model; 30 | using System; 31 | using System.Collections.Generic; 32 | using System.Linq; 33 | 34 | namespace Public.Dac.Samples.Rules 35 | { 36 | /// 37 | /// This is probably the simplest possible example of a rule that uses the public model API to analyze properties of elements. 38 | /// In this case any table whose name ends in "View" is treated as a problem. 39 | /// 40 | /// This does not use a localized export attribute, unlike the and other rules. It is 41 | /// not recommended that you use this code in a real world scenario 42 | /// 43 | [ExportCodeAnalysisRule(TableNameEndingInViewRule.RuleId, 44 | TableNameEndingInViewRule.RuleDisplayName, 45 | Description = "Table names should not end in 'View'", 46 | Category = "Naming", 47 | RuleScope = SqlRuleScope.Element)] 48 | public sealed class TableNameEndingInViewRule : SqlCodeAnalysisRule 49 | { 50 | public const string RuleId = "Public.Dac.Samples.Rules.TableNameEndingInViewRule"; 51 | public const string RuleDisplayName = "SqlSampleRule001"; 52 | public const string NameEndingInViewMsgFormat = "Table name {0} ends in View. This can cause confusion and should be avoided"; 53 | 54 | /// 55 | /// For Element-scoped rules the SupportedElementTypes must be defined, ideally inside the constructor. 56 | /// Only objects that match one of these types will be passed to the method, so this 57 | /// helps avoid the need to iterate over the model and select the object to be processed. 58 | /// 59 | /// This rule only operates on regular Tables. 60 | /// 61 | public TableNameEndingInViewRule() 62 | { 63 | SupportedElementTypes = new[] { Table.TypeClass }; 64 | } 65 | 66 | /// 67 | /// Analysis is quite simple - the table's name is examined and if it ends with "View" then a problem 68 | /// is created 69 | /// 70 | /// 71 | /// 72 | public override IList Analyze(SqlRuleExecutionContext ruleExecutionContext) 73 | { 74 | List problems = new List(); 75 | TSqlObject table = ruleExecutionContext.ModelElement; 76 | if (table != null) 77 | { 78 | if (NameEndsInView(table.Name)) 79 | { 80 | // DisplayServices is a useful helper service for formatting names 81 | DisplayServices displayServices = ruleExecutionContext.SchemaModel.DisplayServices; 82 | string formattedName = displayServices.GetElementName(table, ElementNameStyle.FullyQualifiedName); 83 | 84 | string problemDescription = string.Format(NameEndingInViewMsgFormat, 85 | formattedName); 86 | SqlRuleProblem problem = new SqlRuleProblem(problemDescription, table); 87 | problems.Add(problem); 88 | } 89 | } 90 | 91 | return problems; 92 | } 93 | 94 | private bool NameEndsInView(ObjectIdentifier id) 95 | { 96 | return id.HasName && id.Parts.Last().EndsWith("View", StringComparison.OrdinalIgnoreCase); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /RuleSamples/WaitForDelayVisitor.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using System.Collections.Generic; 29 | using Microsoft.SqlServer.TransactSql.ScriptDom; 30 | 31 | namespace Public.Dac.Samples.Rules 32 | { 33 | /// 34 | /// A TSqlConcreteFragmentVisitor allows us to examine an AST (abstract syntax tree) representation of a 35 | /// TSql object such as a Function, Procedure or Trigger. The implementation uses a visitor pattern, which traverses 36 | /// the logical tree structure of the object. For any type in the tree, the default unless you override it is to 37 | /// do nothing except examine its children. If you override one of the Visit methods it'll just let you examine 38 | /// objects of the type passes in as a parameter, and the visitor class will still automatically examine any children 39 | /// for that object. The ExplicitVisit methods control whether children are also visited so if you want to stop that from 40 | /// happening, you should override that method instead. 41 | /// 42 | /// Using a visitor can sometimes be much simpler than querying the object model, especially in the case where the concept 43 | /// you are trying to find isn't specifically related to a property or relationship in the model. That is true 44 | /// in this case, since we are looking to find any "WAITFOR" clause inside a Procedure, Function or Trigger and 45 | /// this isn't something you could query the Model API to find. As such it's a perfect example of when to examine the 46 | /// underlying structure of the object, rather than its basic set of properties and relationships. 47 | /// 48 | /// Side Note: 49 | /// Also note that the "WAITFOR" statement will be found inside the body script of a procedure/function/trigger. 50 | /// The body script is something of a special case in the model API since it's not queryable directly from the public model, 51 | /// and it can contain "dynamic" objects that aren't a part of the full model. What this means is that you can define temporary 52 | /// variables and objects in a procedure body, but these won't be queryable using the public model. If you wanted to identify problems 53 | /// with these dynamic objects you'd again have to check for them using a TSqlFragmentVisitor / TSqlConcreteFragmentVisitor since there's 54 | /// no way to find them using the Model APIs. However for objects that are defined elsewhere in the model you could check the 55 | /// Procedure.BodyDependencies relationship to see what the procedure's body references, and run some analysis based on this. 56 | /// 57 | /// 58 | internal class WaitForDelayVisitor : TSqlConcreteFragmentVisitor 59 | { 60 | public IList WaitForDelayStatements { get; private set; } 61 | 62 | public WaitForDelayVisitor() 63 | { 64 | WaitForDelayStatements = new List(); 65 | } 66 | 67 | public override void ExplicitVisit(WaitForStatement node) 68 | { 69 | // We are only interested in WAITFOR DELAY occurrences 70 | if (node.WaitForOption == WaitForOption.Delay) 71 | { 72 | WaitForDelayStatements.Add(node); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /RuleSamples/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /RuleTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RuleTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("RuleTests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a914137f-f6f7-40a9-b41e-1975102348dd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /RuleTests/RuleTestUtils.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using System.IO; 29 | 30 | namespace Public.Dac.Samples.Rules.Tests 31 | { 32 | internal sealed class RuleTestUtils 33 | { 34 | 35 | public static void SaveStringToFile(string contents, string filename) 36 | { 37 | FileStream fileStream = null; 38 | StreamWriter streamWriter = null; 39 | try 40 | { 41 | string directory = Path.GetDirectoryName(filename); 42 | if (!Directory.Exists(directory)) 43 | { 44 | Directory.CreateDirectory(directory); 45 | } 46 | 47 | fileStream = new FileStream(filename, FileMode.Create); 48 | streamWriter = new StreamWriter(fileStream); 49 | streamWriter.Write(contents); 50 | } 51 | finally 52 | { 53 | if (streamWriter != null) 54 | { 55 | streamWriter.Close(); 56 | } 57 | if (fileStream != null) 58 | { 59 | fileStream.Close(); 60 | } 61 | } 62 | } 63 | 64 | public static string ReadFileToString(string filePath) 65 | { 66 | using (StreamReader reader = new StreamReader(filePath)) 67 | { 68 | return reader.ReadToEnd(); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/AvoidWaitForDelayRule/AvoidWaitForDelayRule-Baseline.txt: -------------------------------------------------------------------------------- 1 | Problem description: WAITFOR DELAY statement was found in [dbo].[DatabaseScalarFunction1] 2 | FullID: Public.Dac.Samples.SR1004 3 | Severity: Warning 4 | Model element: dbo.DatabaseScalarFunction1 5 | Script file: DatabaseScalarFunction1.sql 6 | Start line: 9 7 | Start column: 5 8 | ========end of problem======== 9 | 10 | Problem description: WAITFOR DELAY statement was found in [dbo].[ProcWithWaitForDelay] 11 | FullID: Public.Dac.Samples.SR1004 12 | Severity: Warning 13 | Model element: dbo.ProcWithWaitForDelay 14 | Script file: ProcWithWaitForDelay.sql 15 | Start line: 5 16 | Start column: 3 17 | ========end of problem======== 18 | 19 | Problem description: WAITFOR DELAY statement was found in [ServerTrigger1] 20 | FullID: Public.Dac.Samples.SR1004 21 | Severity: Warning 22 | Model element: ServerTrigger1 23 | Script file: ServerTrigger1.sql 24 | Start line: 6 25 | Start column: 3 26 | ========end of problem======== 27 | 28 | Problem description: WAITFOR DELAY statement was found in [dbo].[TableValuedFunctionWithWaitForDelay] 29 | FullID: Public.Dac.Samples.SR1004 30 | Severity: Warning 31 | Model element: dbo.TableValuedFunctionWithWaitForDelay 32 | Script file: TableValuedFunctionWithWaitForDelay.sql 33 | Start line: 13 34 | Start column: 5 35 | ========end of problem======== 36 | 37 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/AvoidWaitForDelayRule/DatabaseScalarFunction1.sql: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION [dbo].[DatabaseScalarFunction1] 2 | ( 3 | @param1 int, 4 | @param2 int 5 | ) 6 | RETURNS INT 7 | AS 8 | BEGIN 9 | WAITFOR DELAY '00:00:05'; -- This should be flagged as a problem 10 | RETURN @param1 + @param2 11 | END 12 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/AvoidWaitForDelayRule/InlineFunction.sql: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION [dbo].[InlineFunction] -- Won't even be examined since it's an inlined function 2 | ( 3 | @param1 int, 4 | @param2 char(5) 5 | ) 6 | RETURNS TABLE AS RETURN 7 | ( 8 | SELECT @param1 AS c1, 9 | @param2 AS c2 10 | ) 11 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/AvoidWaitForDelayRule/ProcWithWaitForDelay.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE ProcWithWaitForDelay 3 | AS 4 | BEGIN 5 | WAITFOR DELAY '00:00:15'; -- Waits 15 seconds before executing. This should be flagged as a problem 6 | RETURN SELECT * FROM dbo.Table1 7 | 8 | END -------------------------------------------------------------------------------- /RuleTests/TestScripts/AvoidWaitForDelayRule/ProcWithWaitForTime.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE ProcWithWaitForTime 3 | AS 4 | BEGIN 5 | WAITFOR TIME '00:00:15'; -- Executes at 15seconds after midnight. This shouldn't cause a problem 6 | RETURN SELECT * FROM dbo.Table1 7 | 8 | END -------------------------------------------------------------------------------- /RuleTests/TestScripts/AvoidWaitForDelayRule/ServerTrigger1.sql: -------------------------------------------------------------------------------- 1 | CREATE TRIGGER [ServerTrigger1] 2 | ON ALL SERVER 3 | FOR LOGON 4 | AS 5 | BEGIN 6 | WAITFOR DELAY '00:00:05'; -- This should be flagged as a problem 7 | SET NOCOUNT ON 8 | END 9 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/AvoidWaitForDelayRule/Table1.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [dbo].[Table1] ( 2 | [C1] INT NOT NULL 3 | ); 4 | 5 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/AvoidWaitForDelayRule/TableValuedFunctionWithWaitForDelay.sql: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION [dbo].[TableValuedFunctionWithWaitForDelay] 2 | ( 3 | @param1 int, 4 | @param2 char(5) 5 | ) 6 | RETURNS @returntable TABLE 7 | ( 8 | c1 int, 9 | c2 char(5) 10 | ) 11 | AS 12 | BEGIN 13 | WAITFOR DELAY '00:00:05'; -- This should be flagged as a problem 14 | INSERT @returntable 15 | SELECT @param1, @param2 16 | RETURN 17 | END 18 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/README.txt: -------------------------------------------------------------------------------- 1 | When adding new test scripts (source files and baselines), you must ensure that you set the "Copy to Output Directory" 2 | property to "Copy Always". Otherwise they won't be found in the expected location when running our tests. 3 | To set this property, right-click on the file in Solution Explorer and choose "Properties". The options for the file will be 4 | visible in the Properties window once you do this. -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestBin2CollationOnProjectRule/Filegroup.sql: -------------------------------------------------------------------------------- 1 |  2 | 3 | /* 4 | Do not change the database path or name variables. 5 | Any sqlcmd variables will be properly substituted during 6 | build and deployment. 7 | */ 8 | 9 | ALTER DATABASE [$(DatabaseName)] 10 | ADD FILEGROUP [Table1_FG] CONTAINS MEMORY_OPTIMIZED_DATA -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestBin2CollationOnProjectRule/TableWithBin2Collation.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Given indexes on a column with specific Bin2 collation, no problem should be found 3 | */ 4 | 5 | CREATE TABLE [dbo].[TableWithBin2Collation] 6 | ( 7 | [Id] INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 8 | [c2] nvarchar(30) COLLATE SQL_Latin1_General_CP850_BIN2 NOT NULL , 9 | INDEX [IX_TableWithoutBin2Collation_Column] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072) 10 | ) WITH (MEMORY_OPTIMIZED = ON) 11 | 12 | GO 13 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestBin2CollationOnProjectRule/TableWithSpecificNonBin2Collation.sql: -------------------------------------------------------------------------------- 1 | /* 2 | If column has specific non-BIN2 collation a problem should be detected 3 | */ 4 | CREATE TABLE [dbo].[TableWithSpecificNonBin2Collation] 5 | ( 6 | [Id] INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 7 | [c2] nvarchar(30) COLLATE SQL_Latin1_General_CP1250_CS_AS NOT NULL , 8 | INDEX [IX_TableWithSpecificNonBin2Collation_Column] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072) 9 | ) WITH (MEMORY_OPTIMIZED = ON) 10 | 11 | GO 12 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestBin2CollationOnProjectRule/TableWithoutBin2Collation.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Given the overall project has BIN2 collation, even character columns without a specific collation 3 | should be fine - no problems will be detected. 4 | */ 5 | 6 | CREATE TABLE [dbo].[TableWithoutBin2Collation] 7 | ( 8 | [Id] INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 9 | [c2] nvarchar(30) NOT NULL, 10 | [c3] varchar(30) NOT NULL, 11 | [c4] char(30) NOT NULL, 12 | [c5] nchar(30) NOT NULL, 13 | [cWithCollation] nchar(30) COLLATE SQL_Latin1_General_CP850_BIN2 NOT NULL, 14 | [int5] int NOT NULL, 15 | INDEX [IX_T1_C2] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072), 16 | INDEX [IX_T1_MultipleIndexes] NONCLUSTERED HASH (c3, c4) WITH (BUCKET_COUNT = 131072), 17 | INDEX [IX_T1_c5] NONCLUSTERED HASH (c5) WITH (BUCKET_COUNT = 131072), 18 | INDEX [IX_T1_int5] NONCLUSTERED HASH (int5) WITH (BUCKET_COUNT = 131072), 19 | INDEX [IX_T1_MultipleIndexesOneWithBin2] NONCLUSTERED HASH (c3, cWithCollation) WITH (BUCKET_COUNT = 131072), 20 | INDEX [IX_T1_MultipleIndexesAllValid] NONCLUSTERED HASH (cWithCollation, int5) WITH (BUCKET_COUNT = 131072) 21 | ) WITH (MEMORY_OPTIMIZED = ON) 22 | 23 | GO -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestBin2CollationOnProjectRule/TestBin2CollationOnProjectRule-Baseline.txt: -------------------------------------------------------------------------------- 1 | Problem description: Index [dbo].[TableWithSpecificNonBin2Collation].[IX_TableWithSpecificNonBin2Collation_Column] is on a character column [dbo].[TableWithSpecificNonBin2Collation].[c2] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1250_CS_AS' for the database or for the specified column should be changed 2 | FullID: Public.Dac.Samples.SR1101 3 | Severity: Warning 4 | Model element: dbo.TableWithSpecificNonBin2Collation.IX_TableWithSpecificNonBin2Collation_Column 5 | Script file: TableWithSpecificNonBin2Collation.sql 6 | Start line: 8 7 | Start column: 5 8 | ========end of problem======== 9 | 10 | Problem description: Index [dbo].[TableWithUddts].[IX_TableWithUddts_C2] is on a character column [dbo].[TableWithUddts].[c2] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1250_CS_AS' for the database or for the specified column should be changed 11 | FullID: Public.Dac.Samples.SR1101 12 | Severity: Warning 13 | Model element: dbo.TableWithUddts.IX_TableWithUddts_C2 14 | Script file: UddtTests.sql 15 | Start line: 23 16 | Start column: 5 17 | ========end of problem======== 18 | 19 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestBin2CollationOnProjectRule/UddtTests.sql: -------------------------------------------------------------------------------- 1 | CREATE TYPE [dbo].[CharDataType1] 2 | FROM varchar(11) NOT NULL 3 | 4 | GO 5 | 6 | CREATE TYPE [dbo].[CharDataType2] 7 | FROM nvarchar(25) NOT NULL 8 | GO 9 | 10 | CREATE TYPE [dbo].[IntDataType2] 11 | FROM int NOT NULL 12 | 13 | GO 14 | 15 | 16 | CREATE TABLE [dbo].[TableWithUddts] 17 | ( 18 | [Id] IntDataType2 NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 19 | [c1] CharDataType1 NOT NULL, 20 | [c2] CharDataType2 COLLATE SQL_Latin1_General_CP1250_CS_AS NOT NULL, 21 | INDEX [IX_TableWithUddts_Id] NONCLUSTERED HASH (Id) WITH (BUCKET_COUNT = 222272), 22 | INDEX [IX_TableWithUddts_C1] NONCLUSTERED HASH (c1) WITH (BUCKET_COUNT = 131072), 23 | INDEX [IX_TableWithUddts_C2] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072), 24 | ) WITH (MEMORY_OPTIMIZED = ON) -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestCapitalizedNamesRule/TestCapitalizedNamesRule-Baseline.txt: -------------------------------------------------------------------------------- 1 | Problem description: '[dbo].[lowercasetable]' does not start with a capital letter. Lowercase names are not recommended 2 | FullID: Public.Dac.Samples.SR1103 3 | Severity: Warning 4 | Model element: dbo.lowercasetable 5 | Script file: TestScript.sql 6 | Start line: 6 7 | Start column: 14 8 | ========end of problem======== 9 | 10 | Problem description: '[dbo].[lowercasetable].[c2]' does not start with a capital letter. Lowercase names are not recommended 11 | FullID: Public.Dac.Samples.SR1103 12 | Severity: Warning 13 | Model element: dbo.lowercasetable.c2 14 | Script file: TestScript.sql 15 | Start line: 11 16 | Start column: 5 17 | ========end of problem======== 18 | 19 | Problem description: '[dbo].[lowercaseView]' does not start with a capital letter. Lowercase names are not recommended 20 | FullID: Public.Dac.Samples.SR1103 21 | Severity: Warning 22 | Model element: dbo.lowercaseView 23 | Script file: TestScript.sql 24 | Start line: 19 25 | Start column: 13 26 | ========end of problem======== 27 | 28 | Problem description: '[dbo].[lowercaseView].[c2]' does not start with a capital letter. Lowercase names are not recommended 29 | FullID: Public.Dac.Samples.SR1103 30 | Severity: Warning 31 | Model element: dbo.lowercaseView.c2 32 | Script file: TestScript.sql 33 | Start line: 22 34 | Start column: 12 35 | ========end of problem======== 36 | 37 | Problem description: '[dbo].[lowercaseView].[id]' does not start with a capital letter. Lowercase names are not recommended 38 | FullID: Public.Dac.Samples.SR1103 39 | Severity: Warning 40 | Model element: dbo.lowercaseView.id 41 | Script file: TestScript.sql 42 | Start line: 22 43 | Start column: 26 44 | ========end of problem======== 45 | 46 | Problem description: '[dbo].[lowercaseProcedure]' does not start with a capital letter. Lowercase names are not recommended 47 | FullID: Public.Dac.Samples.SR1103 48 | Severity: Warning 49 | Model element: dbo.lowercaseProcedure 50 | Script file: TestScript.sql 51 | Start line: 26 52 | Start column: 18 53 | ========end of problem======== 54 | 55 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestCapitalizedNamesRule/TestScript.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Given lowercase named objects expect problems to be detected. 3 | Note that since dbo is not user-defined it won't be flagged 4 | */ 5 | 6 | CREATE TABLE [dbo].[lowercasetable] 7 | ( 8 | -- Id capitalized: no problem even though table is not capitalized 9 | [Id] INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 10 | -- c2 lowercase: expect problem 11 | [c2] nvarchar(30) COLLATE SQL_Latin1_General_CP850_BIN2 NOT NULL, 12 | 13 | INDEX [IX_UPPERCASE] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072), 14 | ) WITH (MEMORY_OPTIMIZED = ON) 15 | 16 | GO 17 | 18 | -- v2, c2, id all should be flagged 19 | CREATE VIEW lowercaseView 20 | WITH SCHEMABINDING 21 | AS 22 | SELECT c2, c2 AS C3, Id as id FROM dbo.lowercasetable 23 | GO 24 | 25 | -- Procedure is flagged 26 | CREATE PROCEDURE [dbo].[lowercaseProcedure] 27 | -- Parameters will be not be flagged as they do not start with a letter or digit. 28 | @param1 int = 0, 29 | @param2 int 30 | AS 31 | SELECT @param1, @param2 32 | RETURN 0 33 | 34 | GO 35 | /* 36 | 37 | */ 38 | /* 39 | Given capitalized or uppercase named expect no problems 40 | */ 41 | CREATE TABLE [dbo].[CapitalizedTable] 42 | ( 43 | [Id] INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 44 | [C2] nvarchar(30) COLLATE SQL_Latin1_General_CP850_BIN2 NOT NULL, 45 | 46 | INDEX [IX_UPPERCASE] NONCLUSTERED HASH (C2) WITH (BUCKET_COUNT = 131072), 47 | ) WITH (MEMORY_OPTIMIZED = ON) 48 | 49 | GO 50 | 51 | CREATE VIEW UPPERCASEVIEW AS 52 | SELECT C2, C2 AS C3 FROM [dbo].[CapitalizedTable] 53 | 54 | GO 55 | 56 | CREATE PROCEDURE [dbo].[CapitalizedProc] 57 | @Param1 int = 0, 58 | @Param2 int 59 | AS 60 | SELECT @Param1, @Param2 61 | RETURN 0 62 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestNonBin2CollationOnProjectRule/Filegroup.sql: -------------------------------------------------------------------------------- 1 |  2 | 3 | /* 4 | Do not change the database path or name variables. 5 | Any sqlcmd variables will be properly substituted during 6 | build and deployment. 7 | */ 8 | 9 | ALTER DATABASE [$(DatabaseName)] 10 | ADD FILEGROUP [Table1_FG] CONTAINS MEMORY_OPTIMIZED_DATA -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestNonBin2CollationOnProjectRule/TableWithBin2Collation.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Given indexes on a column with specific Bin2 collation, no problem should be found 3 | */ 4 | 5 | CREATE TABLE [dbo].[TableWithBin2Collation] 6 | ( 7 | [Id] INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 8 | [c2] nvarchar(30) COLLATE SQL_Latin1_General_CP850_BIN2 NOT NULL , 9 | INDEX [IX_TableWithoutBin2Collation_Column] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072) 10 | ) WITH (MEMORY_OPTIMIZED = ON) 11 | 12 | GO 13 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestNonBin2CollationOnProjectRule/TableWithSpecificNonBin2Collation.sql: -------------------------------------------------------------------------------- 1 | /* 2 | If column has specific non-BIN2 collation a problem should be detected 3 | */ 4 | CREATE TABLE [dbo].[TableWithSpecificNonBin2Collation] 5 | ( 6 | [Id] INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 7 | [c2] nvarchar(30) COLLATE SQL_Latin1_General_CP1250_CS_AS NOT NULL , 8 | INDEX [IX_TableWithSpecificNonBin2Collation_Column] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072) 9 | ) WITH (MEMORY_OPTIMIZED = ON) 10 | 11 | GO 12 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestNonBin2CollationOnProjectRule/TableWithoutBin2Collation.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Given the project has a non-BIN2 collation, any indexes on character columns without a specific, BIN2 collation 3 | should cause errors to be raised 4 | */ 5 | 6 | CREATE TABLE [dbo].[TableWithoutBin2Collation] 7 | ( 8 | [Id] INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 9 | [c2] nvarchar(30) NOT NULL, 10 | [c3] varchar(30) NOT NULL, 11 | [c4] char(30) NOT NULL, 12 | [c5] nchar(30) NOT NULL, 13 | [cWithCollation] nchar(30) COLLATE SQL_Latin1_General_CP850_BIN2 NOT NULL, 14 | [int5] int NOT NULL, 15 | INDEX [IX_T1_C2] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072), 16 | INDEX [IX_T1_MultipleIndexes] NONCLUSTERED HASH (c3, c4) WITH (BUCKET_COUNT = 131072), 17 | INDEX [IX_T1_c5] NONCLUSTERED HASH (c5) WITH (BUCKET_COUNT = 131072), 18 | INDEX [IX_T1_int5] NONCLUSTERED HASH (int5) WITH (BUCKET_COUNT = 131072), 19 | INDEX [IX_T1_MultipleIndexesOneWithBin2] NONCLUSTERED HASH (c3, cWithCollation) WITH (BUCKET_COUNT = 131072), 20 | INDEX [IX_T1_MultipleIndexesAllValid] NONCLUSTERED HASH (cWithCollation, int5) WITH (BUCKET_COUNT = 131072) 21 | ) WITH (MEMORY_OPTIMIZED = ON) 22 | 23 | GO -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestNonBin2CollationOnProjectRule/TestNonBin2CollationOnProjectRule-Baseline.txt: -------------------------------------------------------------------------------- 1 | Problem description: Index [dbo].[TableWithoutBin2Collation].[IX_T1_C2] is on a character column [dbo].[TableWithoutBin2Collation].[c2] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1_CI_AS' for the database or for the specified column should be changed 2 | FullID: Public.Dac.Samples.SR1101 3 | Severity: Warning 4 | Model element: dbo.TableWithoutBin2Collation.IX_T1_C2 5 | Script file: TableWithoutBin2Collation.sql 6 | Start line: 15 7 | Start column: 5 8 | ========end of problem======== 9 | 10 | Problem description: Index [dbo].[TableWithoutBin2Collation].[IX_T1_MultipleIndexes] is on a character column [dbo].[TableWithoutBin2Collation].[c3] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1_CI_AS' for the database or for the specified column should be changed 11 | FullID: Public.Dac.Samples.SR1101 12 | Severity: Warning 13 | Model element: dbo.TableWithoutBin2Collation.IX_T1_MultipleIndexes 14 | Script file: TableWithoutBin2Collation.sql 15 | Start line: 16 16 | Start column: 5 17 | ========end of problem======== 18 | 19 | Problem description: Index [dbo].[TableWithoutBin2Collation].[IX_T1_MultipleIndexes] is on a character column [dbo].[TableWithoutBin2Collation].[c4] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1_CI_AS' for the database or for the specified column should be changed 20 | FullID: Public.Dac.Samples.SR1101 21 | Severity: Warning 22 | Model element: dbo.TableWithoutBin2Collation.IX_T1_MultipleIndexes 23 | Script file: TableWithoutBin2Collation.sql 24 | Start line: 16 25 | Start column: 5 26 | ========end of problem======== 27 | 28 | Problem description: Index [dbo].[TableWithoutBin2Collation].[IX_T1_c5] is on a character column [dbo].[TableWithoutBin2Collation].[c5] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1_CI_AS' for the database or for the specified column should be changed 29 | FullID: Public.Dac.Samples.SR1101 30 | Severity: Warning 31 | Model element: dbo.TableWithoutBin2Collation.IX_T1_c5 32 | Script file: TableWithoutBin2Collation.sql 33 | Start line: 17 34 | Start column: 5 35 | ========end of problem======== 36 | 37 | Problem description: Index [dbo].[TableWithoutBin2Collation].[IX_T1_MultipleIndexesOneWithBin2] is on a character column [dbo].[TableWithoutBin2Collation].[c3] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1_CI_AS' for the database or for the specified column should be changed 38 | FullID: Public.Dac.Samples.SR1101 39 | Severity: Warning 40 | Model element: dbo.TableWithoutBin2Collation.IX_T1_MultipleIndexesOneWithBin2 41 | Script file: TableWithoutBin2Collation.sql 42 | Start line: 19 43 | Start column: 5 44 | ========end of problem======== 45 | 46 | Problem description: Index [dbo].[TableWithSpecificNonBin2Collation].[IX_TableWithSpecificNonBin2Collation_Column] is on a character column [dbo].[TableWithSpecificNonBin2Collation].[c2] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1250_CS_AS' for the database or for the specified column should be changed 47 | FullID: Public.Dac.Samples.SR1101 48 | Severity: Warning 49 | Model element: dbo.TableWithSpecificNonBin2Collation.IX_TableWithSpecificNonBin2Collation_Column 50 | Script file: TableWithSpecificNonBin2Collation.sql 51 | Start line: 8 52 | Start column: 5 53 | ========end of problem======== 54 | 55 | Problem description: Index [dbo].[TableWithUddts].[IX_TableWithUddts_C1] is on a character column [dbo].[TableWithUddts].[c1] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1_CI_AS' for the database or for the specified column should be changed 56 | FullID: Public.Dac.Samples.SR1101 57 | Severity: Warning 58 | Model element: dbo.TableWithUddts.IX_TableWithUddts_C1 59 | Script file: UddtTests.sql 60 | Start line: 22 61 | Start column: 5 62 | ========end of problem======== 63 | 64 | Problem description: Index [dbo].[TableWithUddts].[IX_TableWithUddts_C2] is on a character column [dbo].[TableWithUddts].[c2] that does not use a *_BIN2 collation. This is not supported for indexes on memory optimized tables. The collation 'SQL_Latin1_General_CP1250_CS_AS' for the database or for the specified column should be changed 65 | FullID: Public.Dac.Samples.SR1101 66 | Severity: Warning 67 | Model element: dbo.TableWithUddts.IX_TableWithUddts_C2 68 | Script file: UddtTests.sql 69 | Start line: 23 70 | Start column: 5 71 | ========end of problem======== 72 | 73 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestNonBin2CollationOnProjectRule/UddtTests.sql: -------------------------------------------------------------------------------- 1 | CREATE TYPE [dbo].[CharDataType1] 2 | FROM varchar(11) NOT NULL 3 | 4 | GO 5 | 6 | CREATE TYPE [dbo].[CharDataType2] 7 | FROM nvarchar(25) NOT NULL 8 | GO 9 | 10 | CREATE TYPE [dbo].[IntDataType2] 11 | FROM int NOT NULL 12 | 13 | GO 14 | 15 | 16 | CREATE TABLE [dbo].[TableWithUddts] 17 | ( 18 | [Id] IntDataType2 NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 19 | [c1] CharDataType1 NOT NULL, 20 | [c2] CharDataType2 COLLATE SQL_Latin1_General_CP1250_CS_AS NOT NULL, 21 | INDEX [IX_TableWithUddts_Id] NONCLUSTERED HASH (Id) WITH (BUCKET_COUNT = 222272), 22 | INDEX [IX_TableWithUddts_C1] NONCLUSTERED HASH (c1) WITH (BUCKET_COUNT = 131072), 23 | INDEX [IX_TableWithUddts_C2] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072), 24 | ) WITH (MEMORY_OPTIMIZED = ON) -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestViewOnMemoryOptimizedTableRule/Filegroup.sql: -------------------------------------------------------------------------------- 1 |  2 | 3 | /* 4 | Do not change the database path or name variables. 5 | Any sqlcmd variables will be properly substituted during 6 | build and deployment. 7 | */ 8 | 9 | ALTER DATABASE [$(DatabaseName)] 10 | ADD FILEGROUP [Table1_FG] CONTAINS MEMORY_OPTIMIZED_DATA -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestViewOnMemoryOptimizedTableRule/Table1.sql: -------------------------------------------------------------------------------- 1 | -- Memory optimized table 2 | CREATE TABLE [dbo].[Table1] 3 | ( 4 | [Id] INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072), 5 | [c2] nvarchar(30) NOT NULL, 6 | INDEX [IX_Table1_Column] NONCLUSTERED HASH (c2) WITH (BUCKET_COUNT = 131072) 7 | ) WITH (MEMORY_OPTIMIZED = ON) 8 | 9 | GO -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestViewOnMemoryOptimizedTableRule/Table2.sql: -------------------------------------------------------------------------------- 1 | -- standard table 2 | CREATE TABLE [dbo].[Table2] ( 3 | [Id] INT NOT NULL, 4 | PRIMARY KEY CLUSTERED ([Id] ASC), 5 | CONSTRAINT [CK_Table_Column2] CHECK ((2)=(2)) 6 | ); 7 | 8 | GO 9 | ALTER TABLE [dbo].[Table2] ADD CONSTRAINT [CK_Table_Column] CHECK ((1)=(1)) 10 | 11 | GO 12 | CREATE NONCLUSTERED INDEX [IX_Table_Column] 13 | ON [dbo].[Table2]([Id] ASC); 14 | 15 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestViewOnMemoryOptimizedTableRule/TestViewOnMemoryOptimizedTableRule-Baseline.txt: -------------------------------------------------------------------------------- 1 | Problem description: View [dbo].[View1] must specify the 'WITH SCHEMABINDING' view attribute as it references a memory optimized table [dbo].[Table1] 2 | FullID: Public.Dac.Samples.SR1102 3 | Severity: Warning 4 | Model element: dbo.View1 5 | Script file: View1Tests.sql 6 | Start line: 1 7 | Start column: 13 8 | ========end of problem======== 9 | 10 | Problem description: The index [dbo].[View1].[IX_View1_myCol] on view [dbo].[View1] is not allowed, as the view references a memory optimized table [dbo].[Table1] 11 | FullID: Public.Dac.Samples.SR1102 12 | Severity: Warning 13 | Model element: dbo.View1.IX_View1_myCol 14 | Script file: View1Tests.sql 15 | Start line: 7 16 | Start column: 31 17 | ========end of problem======== 18 | 19 | Problem description: The index [dbo].[View1].[IX_View1_c2] on view [dbo].[View1] is not allowed, as the view references a memory optimized table [dbo].[Table1] 20 | FullID: Public.Dac.Samples.SR1102 21 | Severity: Warning 22 | Model element: dbo.View1.IX_View1_c2 23 | Script file: View1Tests.sql 24 | Start line: 10 25 | Start column: 14 26 | ========end of problem======== 27 | 28 | -------------------------------------------------------------------------------- /RuleTests/TestScripts/TestViewOnMemoryOptimizedTableRule/View1Tests.sql: -------------------------------------------------------------------------------- 1 | CREATE VIEW [dbo].[View1] 2 | -- missing WITH SCHEMABINDING attribute 3 | AS SELECT T1.c2, T2.Id as myCol FROM [dbo].[Table1] as T1, [dbo].[Table2] as T2 4 | GO 5 | 6 | -- Indexes aren't allowed on this table 7 | CREATE UNIQUE CLUSTERED INDEX [IX_View1_myCol] on [dbo].[View1] (myCol) 8 | GO 9 | 10 | CREATE INDEX [IX_View1_c2] on [dbo].[View1] (c2) 11 | GO 12 | 13 | -- Valid View: Creating a view on Table1 should be OK if it specified schema binding 14 | CREATE VIEW [dbo].[View2] 15 | WITH SCHEMABINDING 16 | AS SELECT T1.c2, T2.Id as myCol FROM [dbo].[Table1] as T1, [dbo].Table2 as T2 17 | GO 18 | 19 | -- Valid Indexes: Creating indexes on views that don't reference memory optimized tables is acceptable 20 | CREATE VIEW [dbo].[View3] 21 | WITH SCHEMABINDING 22 | AS SELECT T2.Id as myCol FROM [dbo].Table2 as T2 23 | GO 24 | CREATE UNIQUE CLUSTERED INDEX [IX_View3_myCol] on [dbo].[View3] (myCol) 25 | GO 26 | -------------------------------------------------------------------------------- /RuleTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SampleConsoleApp/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SampleConsoleApp/ModelEndToEnd.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using Microsoft.SqlServer.Dac; 28 | using Microsoft.SqlServer.Dac.Model; 29 | using Microsoft.SqlServer.TransactSql.ScriptDom; 30 | using System; 31 | using System.IO; 32 | using System.Linq; 33 | using ColumnType = Microsoft.SqlServer.Dac.Model.ColumnType; 34 | 35 | namespace Public.Dac.Samples.App 36 | { 37 | /// 38 | /// Basic demo class showing end to end usage of the model 39 | /// 40 | internal class ModelEndToEnd 41 | { 42 | public static void Run() 43 | { 44 | string dacpacPath = "relativePath.dacpac"; 45 | 46 | // Note that you could read scripts from a file or use TSqlScript objects that are taken from other models. 47 | // Hand-crafting TSqlScript is quite awkard but could be done programmatically (we do it internally). 48 | // If you need examples for this let us know and we can look into that too. 49 | string[] scripts = new[] 50 | { 51 | "CREATE TABLE t1 (c1 NVARCHAR(30) NOT NULL)", 52 | "CREATE TABLE t2 (c2 INT NOT NULL)", 53 | "CREATE TABLE t3 (c3 INT NOT NULL)", 54 | "CREATE TABLE t4 (c4 INT NOT NULL)", 55 | }; 56 | using (TSqlModel model = new TSqlModel(SqlServerVersion.Sql110, new TSqlModelOptions { })) 57 | { 58 | // Adding objects to the model. 59 | foreach (string script in scripts) 60 | { 61 | model.AddObjects(script); 62 | } 63 | 64 | ReadTheModel(model); 65 | 66 | CopyFromTheModel(model); 67 | 68 | // save the model to a new .dacpac 69 | // Note that the PackageOptions can be used to specify RefactorLog and contributors to include 70 | DacPackageExtensions.BuildPackage( 71 | dacpacPath, 72 | model, 73 | new PackageMetadata { Name = "MyPackageName", Description = "This is usually ignored", Version = "1.0" }, 74 | new PackageOptions() 75 | ); 76 | } 77 | 78 | // Load from a dacpac 79 | using (TSqlModel modelFromDacpac = new TSqlModel(dacpacPath)) 80 | { 81 | // Show that all the elements were saved successfully 82 | ReadTheModel(modelFromDacpac); 83 | 84 | // You can update the model in the dacpac. Other parts of a dacpac can't be updated yet (pre/post deployment scripts) 85 | modelFromDacpac.AddObjects("CREATE VIEW V1 AS SELECT * FROM T1"); 86 | 87 | using (DacPackage dacPackage = DacPackage.Load(dacpacPath, 88 | DacSchemaModelStorageType.Memory, 89 | FileAccess.ReadWrite)) 90 | { 91 | DacPackageExtensions.UpdateModel(dacPackage, modelFromDacpac, null); 92 | } 93 | } 94 | 95 | Console.WriteLine("Press any key to finish"); 96 | Console.ReadKey(); 97 | } 98 | 99 | private static void ReadTheModel(TSqlModel model) 100 | { 101 | // This will get all tables. 102 | var tables = model.GetObjects(DacQueryScopes.Default, Table.TypeClass).ToList(); 103 | 104 | // Look up a specific table by ID. Note that if no schema is defined when creating an element, the default "dbo" schema is used 105 | var t1 = model.GetObjects(Table.TypeClass, new ObjectIdentifier("dbo", "t1"), DacQueryScopes.UserDefined).FirstOrDefault(); 106 | 107 | // Get a the column referenced by this table, and query its length 108 | TSqlObject column = t1.GetReferenced(Table.Columns).First(col => col.Name.Parts[2].Equals("c1")); 109 | int columnLength = column.GetProperty(Column.Length); 110 | Console.WriteLine("Column c1 has length {0}", columnLength); 111 | 112 | // Verify the ColumnType of this column. This can help indicate which properties will return meaningful values. 113 | // For instance since Column.Collation is only available on a simple column, and Column.Persisted is only on computed columns 114 | ColumnType columnType = column.GetMetadata(Column.ColumnType); 115 | Console.WriteLine("Column c1 is of type '{0}'", columnType); 116 | } 117 | 118 | private static void CopyFromTheModel(TSqlModel model) 119 | { 120 | // Copy all tables from 1 model to another - could be useful for filtering, say when you load from 1 model 121 | // And copy to another 122 | using (TSqlModel copiedModel = new TSqlModel(SqlServerVersion.Sql110, null)) 123 | { 124 | foreach (var table in model.GetObjects(DacQueryScopes.Default, Table.TypeClass)) 125 | { 126 | TSqlScript script; 127 | if (table.TryGetAst(out script)) 128 | { 129 | copiedModel.AddObjects(script); 130 | } 131 | } 132 | } 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /SampleConsoleApp/Program.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using System; 28 | 29 | namespace Public.Dac.Samples.App 30 | { 31 | class Program 32 | { 33 | internal enum Behavior 34 | { 35 | Usage, 36 | RunEndToEnd, 37 | FilterModel, 38 | RunCodeAnalysis, 39 | ValidateQuerySemantically 40 | } 41 | 42 | static void Main(string[] args) 43 | { 44 | 45 | switch (GetBehavior(args)) 46 | { 47 | case Behavior.Usage: 48 | Console.WriteLine(@"Specify the action you wish to perform, for example 'ModelBuilderApp.exe RunEndToEnd' 49 | Current actions: 50 | [RunEndToEnd] - Runs the end to end demo that creates a model, copies to another model, and saves the model to a dacpac 51 | [FilterModel] - Runs a demo that creates a model then creates a filtered copy with some schemas removed. 52 | [RunCodeAnalysis] - Runs a demo of running Static Code Analysis from your code. 53 | [Usage] - Print this usage message 54 | "); 55 | break; 56 | case Behavior.RunEndToEnd: 57 | ModelEndToEnd.Run(); 58 | break; 59 | case Behavior.FilterModel: 60 | ModelFilterExample.RunFilteringExample(); 61 | break; 62 | case Behavior.RunCodeAnalysis: 63 | RunCodeAnalysisExample.RunAnalysisExample(); 64 | break; 65 | case Behavior.ValidateQuerySemantically: 66 | RunValidateQuerySemanticallyExample.Run(); 67 | break; 68 | // To test deployment plan-based filtering see the TestFiltering.TestFilterPlanWhenPublishing() unit test 69 | } 70 | 71 | Console.WriteLine("Press any key to finish"); 72 | Console.ReadKey(); 73 | } 74 | 75 | private static Behavior GetBehavior(string[] args) 76 | { 77 | Behavior behavior = Behavior.Usage; 78 | if (args.Length > 0) 79 | { 80 | if (MatchesBehavior(args[0], Behavior.RunEndToEnd)) 81 | { 82 | behavior = Behavior.RunEndToEnd; 83 | } 84 | if (MatchesBehavior(args[0], Behavior.FilterModel)) 85 | { 86 | behavior = Behavior.FilterModel; 87 | } 88 | if (MatchesBehavior(args[0], Behavior.RunCodeAnalysis)) 89 | { 90 | behavior = Behavior.RunCodeAnalysis; 91 | } 92 | if (MatchesBehavior(args[0], Behavior.ValidateQuerySemantically)) 93 | { 94 | behavior = Behavior.ValidateQuerySemantically; 95 | } 96 | } 97 | return behavior; 98 | } 99 | 100 | private static bool MatchesBehavior(string name, Behavior behavior) 101 | { 102 | return string.Compare(name, behavior.ToString(), StringComparison.OrdinalIgnoreCase) == 0; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /SampleConsoleApp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using System.Reflection; 28 | using System.Runtime.CompilerServices; 29 | using System.Runtime.InteropServices; 30 | 31 | // General Information about an assembly is controlled through the following 32 | // set of attributes. Change these attribute values to modify the information 33 | // associated with an assembly. 34 | [assembly: AssemblyTitle("ModelBuilderApp")] 35 | [assembly: AssemblyDescription("")] 36 | [assembly: AssemblyConfiguration("")] 37 | [assembly: AssemblyCompany("")] 38 | [assembly: AssemblyProduct("ModelBuilderApp")] 39 | [assembly: AssemblyCopyright("Copyright © 2013")] 40 | [assembly: AssemblyTrademark("")] 41 | [assembly: AssemblyCulture("")] 42 | 43 | // Setting ComVisible to false makes the types in this assembly not visible 44 | // to COM components. If you need to access a type in this assembly from 45 | // COM, set the ComVisible attribute to true on that type. 46 | [assembly: ComVisible(false)] 47 | 48 | // The following GUID is for the ID of the typelib if this project is exposed to COM 49 | [assembly: Guid("33997024-206a-4456-81ba-3bb0f1564126")] 50 | 51 | // Version information for an assembly consists of the following four values: 52 | // 53 | // Major Version 54 | // Minor Version 55 | // Build Number 56 | // Revision 57 | // 58 | // You can specify all the values or you can default the Build and Revision Numbers 59 | // by using the '*' as shown below: 60 | // [assembly: AssemblyVersion("1.0.*")] 61 | [assembly: AssemblyVersion("1.0.0.0")] 62 | [assembly: AssemblyFileVersion("1.0.0.0")] 63 | -------------------------------------------------------------------------------- /SampleConsoleApp/RunValidateQuerySemanticallyExample.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Globalization; 30 | using System.Linq; 31 | using Microsoft.SqlServer.Dac; 32 | using Microsoft.SqlServer.Dac.Model; 33 | using Public.Dac.Samples.TestUtilities; 34 | 35 | namespace Public.Dac.Samples.App 36 | { 37 | public class RunValidateQuerySemanticallyExample 38 | { 39 | 40 | private static readonly string[] SampleScripts = new string[] 41 | { 42 | "CREATE TABLE T1 (c1 int)", 43 | @"CREATE VIEW [dbo].[View1] AS SELECT * FROM [dbo].[T1]", 44 | }; 45 | 46 | /// 47 | /// DacFx is smart enough to realize there's a column c1 projected through View1 from T1 48 | /// 49 | private const string GoodQuery = "SELECT c1 from View1"; 50 | /// 51 | /// DacFx will complain since the relevant column does not exist 52 | /// 53 | private const string BadQuery = @"SELECT c2 from View1"; 54 | 55 | private const string ProcTemplate = @"CREATE PROCEDURE [NameThatNeverExistsInDb] AS BEGIN {0} END"; 56 | public static void Run() 57 | { 58 | Console.WriteLine("Publishing scripts to DB"); 59 | using (SqlTestDB db = TestUtils.CreateTestDatabase(TestUtils.DefaultInstanceInfo, "MyQueryExample")) 60 | { 61 | // set up the database with your scripts 62 | TestUtils.ExecuteNonQuery(db, SampleScripts); 63 | 64 | ValidateQuery(BadQuery, db, false); 65 | 66 | // BUG: Normally AddOrUpdateObjects will replace the contents of a file so we could just update the contents of our "Query File" 67 | // and re-run validation. This simulates live validation of a query in SSMS/SSDT. 68 | // Somehow when loading model directly from Database this isn't working. We will resolve this issue in a future DacFx update. 69 | // For now we create a new model for each query which is inefficient but relatively effective. 70 | ValidateQuery(GoodQuery, db, true); 71 | } 72 | } 73 | 74 | public static void ValidateQuery(string query, SqlTestDB db, bool expectQueryToPass) 75 | { 76 | Console.WriteLine("Testing query '{0}'", query); 77 | Console.WriteLine("Loading model from DB"); 78 | using (TSqlModel model = TSqlModel.LoadFromDatabase(db.BuildConnectionString())) 79 | { 80 | // Currently we just give a message but no source information. Will work around this for now by ensuring the model is fully valid before proceeding 81 | bool modelInitiallyValid = PrintModelState(model, true); 82 | if (!modelInitiallyValid) 83 | { 84 | Console.WriteLine("Quitting due to invalid model"); 85 | return; 86 | } 87 | AssertModelHasNProcedures(model, 0); 88 | 89 | string myFileName = "QueryFile.sql"; 90 | 91 | // validate bad query fails validation 92 | model.AddOrUpdateObjects(CreateQueryAsProc(query), myFileName, null); 93 | PrintModelState(model, expectQueryToPass); 94 | 95 | AssertModelHasNProcedures(model, 1); 96 | } 97 | } 98 | 99 | 100 | private static void AssertModelHasNProcedures(TSqlModel model, int numProcs) 101 | { 102 | IEnumerable procs = model.GetObjects(DacQueryScopes.UserDefined, ModelSchema.Procedure); 103 | if(numProcs != procs.Count()) 104 | { 105 | throw new Exception("Incorrect number of elements. Expected " + numProcs + " proc(s)"); 106 | } 107 | } 108 | 109 | 110 | private static string CreateQueryAsProc(string query) 111 | { 112 | return string.Format(CultureInfo.CurrentCulture, ProcTemplate, query); 113 | } 114 | 115 | private static bool PrintModelState(TSqlModel model, bool expectQueryToPass) 116 | { 117 | 118 | string errorMessage = expectQueryToPass ? "Fail: Expected no issues but got the following:" : "Pass: expected issues found during validation:"; 119 | string passMessage = expectQueryToPass ? "Pass: No problems found during validation" : "Fail: expected issues but none were found"; 120 | bool breakingIssuesFound = false; 121 | var validationMessages = model.Validate(); 122 | if (validationMessages.Count > 0) 123 | { 124 | Console.WriteLine(errorMessage); 125 | foreach (var message in validationMessages) 126 | { 127 | Console.WriteLine("\t" + message.Message); 128 | breakingIssuesFound = breakingIssuesFound || message.MessageType == DacMessageType.Error; 129 | } 130 | return false; 131 | } 132 | else 133 | { 134 | Console.WriteLine(passMessage); 135 | return true; 136 | } 137 | 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /SampleConsoleApp/SampleConsoleApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7855389B-A1F0-4A7C-A83A-38EEF5B73F9A} 8 | Exe 9 | Properties 10 | Public.Dac.Samples.App 11 | SampleConsoleApp 12 | v4.6 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.Data.Tools.Schema.Sql.dll 38 | 39 | 40 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.Data.Tools.Utilities.dll 41 | 42 | 43 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Dac.dll 44 | 45 | 46 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Dac.Extensions.dll 47 | 48 | 49 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.TransactSql.ScriptDom.dll 50 | 51 | 52 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Types.dll 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | {c1c2b521-22b6-4124-aaec-a5e1fcab0dfa} 77 | Samples 78 | 79 | 80 | {edf01d79-66d0-496c-82d2-431831564817} 81 | TestUtils 82 | 83 | 84 | 85 | 92 | -------------------------------------------------------------------------------- /SampleConsoleApp/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /SampleTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using System.Reflection; 28 | using System.Runtime.CompilerServices; 29 | using System.Runtime.InteropServices; 30 | 31 | // General Information about an assembly is controlled through the following 32 | // set of attributes. Change these attribute values to modify the information 33 | // associated with an assembly. 34 | [assembly: AssemblyTitle("SampleTests")] 35 | [assembly: AssemblyDescription("")] 36 | [assembly: AssemblyConfiguration("")] 37 | [assembly: AssemblyCompany("")] 38 | [assembly: AssemblyProduct("SampleTests")] 39 | [assembly: AssemblyCopyright("Copyright © 2013")] 40 | [assembly: AssemblyTrademark("")] 41 | [assembly: AssemblyCulture("")] 42 | 43 | // Setting ComVisible to false makes the types in this assembly not visible 44 | // to COM components. If you need to access a type in this assembly from 45 | // COM, set the ComVisible attribute to true on that type. 46 | [assembly: ComVisible(false)] 47 | 48 | // The following GUID is for the ID of the typelib if this project is exposed to COM 49 | [assembly: Guid("8c5b9dfc-8136-43b2-9626-7277d5a3fd9b")] 50 | 51 | // Version information for an assembly consists of the following four values: 52 | // 53 | // Major Version 54 | // Minor Version 55 | // Build Number 56 | // Revision 57 | // 58 | // You can specify all the values or you can default the Build and Revision Numbers 59 | // by using the '*' as shown below: 60 | // [assembly: AssemblyVersion("1.0.*")] 61 | [assembly: AssemblyVersion("1.0.0.0")] 62 | [assembly: AssemblyFileVersion("1.0.0.0")] 63 | -------------------------------------------------------------------------------- /SampleTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Samples/CompositeFilter.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using System.Collections.Generic; 28 | using Microsoft.SqlServer.Dac.Model; 29 | 30 | namespace Public.Dac.Samples 31 | { 32 | /// 33 | /// Combines a bunch of filters together. 34 | /// 35 | public class CompositeFilter : IFilter 36 | { 37 | private readonly IList _filters; 38 | 39 | public CompositeFilter(IList filters) 40 | { 41 | _filters = filters; 42 | } 43 | 44 | public IEnumerable Filter(IEnumerable tSqlObjects) 45 | { 46 | foreach (IFilter filter in _filters) 47 | { 48 | tSqlObjects = filter.Filter(tSqlObjects); 49 | } 50 | 51 | return tSqlObjects; 52 | } 53 | 54 | public void Initialize(Dictionary filterArguments) 55 | { 56 | // Do nothing 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Samples/Contributors/AlterTableAlterColumnOnlineModifier.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using Microsoft.SqlServer.Dac.Deployment; 29 | using Microsoft.SqlServer.Dac.Model; 30 | using Microsoft.SqlServer.TransactSql.ScriptDom; 31 | using System; 32 | using System.Collections; 33 | using System.Collections.Generic; 34 | 35 | namespace Public.Dac.Samples.Contributors 36 | { 37 | /// 38 | /// This deployment contributor allows ALTER TABLE...ALTER COLUMN operations to be done online (this is a new feature supported in SQL 2016 and in Azure SQL DB) 39 | /// 40 | /// 41 | /// This sample was created based on an actual customer scenario where deployments happen when the workload is still active. In those cases, any ALTER TABLE...ALTER COLUMN 42 | /// operations took the table 'offline' and caused blocking. Using this deployment contributor leverages the new online alter column functionality and minimizes such blocking. 43 | /// 44 | [ExportDeploymentPlanModifier(ContributorId, "1.0.0.0")] 45 | public class AlterTableAlterColumnOnlineModifier : DeploymentPlanModifier 46 | { 47 | public const string ContributorId = "Public.Dac.Samples.Contributors.AlterTableAlterColumnOnlineModifier"; 48 | 49 | protected override void OnExecute(DeploymentPlanContributorContext context) 50 | { 51 | this.FindAndMakeAlterColumnsOnline(context); 52 | } 53 | 54 | private void FindAndMakeAlterColumnsOnline(DeploymentPlanContributorContext context) 55 | { 56 | DeploymentStep nextStep = context.PlanHandle.Head; 57 | 58 | // Loop through all steps in the deployment plan 59 | bool foundMainSection = false; 60 | while (nextStep != null) 61 | { 62 | DeploymentStep currentStep = nextStep; 63 | nextStep = currentStep.Next; 64 | 65 | // We only want to analyze the main part of the deployment script - we'll skip 66 | // any steps until we pass the end of the predeployment section, and stop once 67 | // we hit the start of the postdeployment section 68 | if (currentStep is EndPreDeploymentScriptStep) 69 | { 70 | foundMainSection = true; 71 | continue; 72 | } 73 | 74 | if (!foundMainSection) 75 | { 76 | // Haven't gotten past predeployment yet 77 | continue; 78 | } 79 | 80 | if (currentStep is BeginPostDeploymentScriptStep) 81 | { 82 | break; 83 | } 84 | 85 | // We need to care about AlterElementSteps. 86 | DeploymentScriptDomStep domStep = currentStep as DeploymentScriptDomStep; 87 | TSqlObject elementObject = null; 88 | 89 | if (domStep is AlterElementStep) 90 | { 91 | elementObject = ((AlterElementStep)domStep).SourceElement; 92 | } 93 | 94 | if (elementObject != null) 95 | { 96 | TSqlFragment fragment = domStep.Script; 97 | 98 | // call the visitor, which in turn will auto-name these constraints 99 | var visitor = new AlterTableAlterColumnVisitor(); 100 | fragment.Accept(visitor); 101 | } 102 | } 103 | } 104 | 105 | private class AlterTableAlterColumnVisitor : TSqlConcreteFragmentVisitor 106 | { 107 | /// 108 | /// This visitor looks for ALTER TABLE...ALTER COLUMN statements and overrides by adding ONLINE = ON attribute 109 | /// 110 | public override void ExplicitVisit(AlterTableAlterColumnStatement node) 111 | { 112 | bool isAlreadyOnline = false; 113 | 114 | // check if the statement already has ONLINE = ON 115 | foreach(var option in node.Options) 116 | { 117 | if (option is OnlineIndexOption) 118 | { 119 | isAlreadyOnline = true; 120 | } 121 | } 122 | 123 | if (!isAlreadyOnline) 124 | { 125 | node.Options.Add(new OnlineIndexOption() 126 | { 127 | OptionKind = IndexOptionKind.Online, 128 | OptionState = OptionState.On 129 | }); 130 | } 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Samples/Contributors/DefaultConstraintNameModifier.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using Microsoft.SqlServer.Dac.Deployment; 29 | using Microsoft.SqlServer.Dac.Model; 30 | using Microsoft.SqlServer.TransactSql.ScriptDom; 31 | using System; 32 | using System.Collections; 33 | using System.Collections.Generic; 34 | 35 | namespace Public.Dac.Samples.Contributors 36 | { 37 | /// 38 | /// This deployment contributor explicitly names unnamed default constraints with a auto-generated GUID name. 39 | /// 40 | /// 41 | /// This sample was created based on an actual customer scenario where there was a mixture of 'named' and un-named default constraints 42 | /// The reason 'named' is in quotes is that in that scenario the name was actually a previously auto-generated default constraint name 43 | /// (for example the 'named' constraint was named DF__Contoso_A__IsOld__3BEC4C22). 44 | /// 45 | /// Due to a non-deterministic order in which these constraints get deployed by DacFX, if the unnamed constraint was deployed first, and then 46 | /// an named constraint deployed afterwards, in some rare cases the deployment due to a name clash. 47 | /// 48 | /// This sample aims to fix the issue by explicitly naming all unnamed default constraints. 49 | /// 50 | [ExportDeploymentPlanModifier(ContributorId, "1.0.0.0")] 51 | public class DefaultConstraintNameModifier : DeploymentPlanModifier 52 | { 53 | public const string ContributorId = "Public.Dac.Samples.Contributors.DefaultConstraintNameModifier"; 54 | 55 | protected override void OnExecute(DeploymentPlanContributorContext context) 56 | { 57 | this.FindAndRenameUnnamedDefaultConstraints(context); 58 | } 59 | 60 | private void FindAndRenameUnnamedDefaultConstraints(DeploymentPlanContributorContext context) 61 | { 62 | DeploymentStep nextStep = context.PlanHandle.Head; 63 | 64 | // Loop through all steps in the deployment plan 65 | bool foundMainSection = false; 66 | while (nextStep != null) 67 | { 68 | DeploymentStep currentStep = nextStep; 69 | nextStep = currentStep.Next; 70 | 71 | // We only want to analyze the main part of the deployment script - we'll skip 72 | // any steps until we pass the end of the predeployment section, and stop once 73 | // we hit the start of the postdeployment section 74 | if (currentStep is EndPreDeploymentScriptStep) 75 | { 76 | foundMainSection = true; 77 | continue; 78 | } 79 | 80 | if (!foundMainSection) 81 | { 82 | // Haven't gotten past predeployment yet 83 | continue; 84 | } 85 | 86 | if (currentStep is BeginPostDeploymentScriptStep) 87 | { 88 | break; 89 | } 90 | 91 | // We need to care about CreateElementSteps and AlterElementSteps for default constraints. 92 | DeploymentScriptDomStep domStep = currentStep as DeploymentScriptDomStep; 93 | TSqlObject elementObject = null; 94 | 95 | // most of the default constraints in the deployment plan seem to be deployed as Alter Table statements, but 96 | // just in case the default constraint was deployed as part of a Create Table (don't see how it is possible, but just being safe) 97 | if (domStep is CreateElementStep) 98 | { 99 | elementObject = ((CreateElementStep)domStep).SourceElement; 100 | 101 | } 102 | else if (domStep is AlterElementStep) 103 | { 104 | elementObject = ((AlterElementStep)domStep).SourceElement; 105 | } 106 | 107 | if (elementObject != null) 108 | { 109 | TSqlFragment fragment = domStep.Script; 110 | 111 | // call the visitor, which in turn will auto-name these constraints 112 | var visitor = new DefaultConstraintDefinitionVisitor(); 113 | fragment.Accept(visitor); 114 | } 115 | } 116 | } 117 | 118 | private class DefaultConstraintDefinitionVisitor : TSqlConcreteFragmentVisitor 119 | { 120 | /// 121 | /// This visitor looks for default constraints without any identifier (name) and for those explicitly names them. 122 | /// In the cases where the constraint is unnamed, the ConstraintIdentifier field is null. 123 | /// 124 | public override void ExplicitVisit(DefaultConstraintDefinition node) 125 | { 126 | if (node.ConstraintIdentifier == null) 127 | { 128 | node.ConstraintIdentifier = new Identifier() 129 | { 130 | Value = string.Format("DF_autonamed_{0}", Guid.NewGuid().ToString("N")) 131 | }; 132 | } 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Samples/Contributors/DeploymentStoppingContributor.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using Microsoft.SqlServer.Dac.Deployment; 28 | using Microsoft.SqlServer.Dac.Extensibility; 29 | 30 | namespace Public.Dac.Samples.Contributors 31 | { 32 | /// 33 | /// This is a sample contributor that blocks deployment. Clearly this isn't something that would be 34 | /// used in a real environment, but it shows how you go about blocking deployment from happening. 35 | /// A realistic use of this it to check for certain preconditions and block deployment if these are 36 | /// not met. 37 | /// 38 | [ExportDeploymentPlanModifier(ContributorId, "1.0.0.0")] 39 | public class DeploymentStoppingContributor : DeploymentPlanModifier 40 | { 41 | public const string ContributorId = "Public.Dac.Samples.Contributors.DeploymentStoppingContributor"; 42 | public const string ErrorViaPublishMessage = "Data Motion Detected!"; 43 | public const string ErrorViaThrownException = "Data Motion Detected!"; 44 | 45 | /// 46 | /// Iterates over the deployment plan to find the definition for 47 | /// 48 | /// 49 | protected override void OnExecute(DeploymentPlanContributorContext context) 50 | { 51 | var planStep = context.PlanHandle.Head; 52 | while (planStep != null) 53 | { 54 | if (planStep is SqlTableMigrationStep) 55 | { 56 | // Publishing Severity.Error message blocks deployment 57 | base.PublishMessage(new ExtensibilityError(ErrorViaPublishMessage, Severity.Error)); 58 | 59 | // Alternatively throwing an exception will also block deployment 60 | throw new DeploymentFailedException(ErrorViaThrownException); 61 | } 62 | planStep = planStep.Next; 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Samples/DisposableList.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using System; 28 | using System.Collections.Generic; 29 | 30 | namespace Public.Dac.Samples 31 | { 32 | /// 33 | /// Utility class for tracking and disposing of objects that implement IDisposable. 34 | /// 35 | public sealed class DisposableList : List, IDisposable 36 | { 37 | /// 38 | /// Disposes of all elements of list. 39 | /// 40 | public void Dispose() 41 | { 42 | Dispose(true); 43 | } 44 | 45 | /// 46 | /// Internal implementation of Dispose logic. 47 | /// 48 | private void Dispose(bool isDisposing) 49 | { 50 | foreach (IDisposable disposable in this) 51 | { 52 | disposable.Dispose(); 53 | } 54 | } 55 | 56 | /// 57 | /// Add an item to the list. 58 | /// 59 | public T Add(T item) where T : IDisposable 60 | { 61 | base.Add(item); 62 | 63 | return item; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Samples/Filter.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using Microsoft.SqlServer.Dac.Model; 28 | using System.Collections.Generic; 29 | 30 | namespace Public.Dac.Samples 31 | { 32 | /// 33 | /// A Filter should take in a set of TSqlObjects, filter them based on some criteria, 34 | /// and return a (smaller) set of objects. 35 | /// 36 | public interface IFilter 37 | { 38 | /// 39 | /// Filter a stream of TSqlObjects based on some criteria 40 | /// 41 | /// the objects to filter 42 | /// some filtered set of objects 43 | IEnumerable Filter(IEnumerable tSqlObjects); 44 | 45 | /// 46 | /// Provides a chance to initialize the filter based on some set of key-value pairs. 47 | /// Note that this kind of method would be better in an abstract parent class than in an interface 48 | /// since only some filters would need this. This would be something to improve on if using this in a real application 49 | /// 50 | /// set of key value pairs that can be used to initialize the filter 51 | void Initialize(Dictionary filterArguments); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Samples/PlanFilterer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using Microsoft.SqlServer.Dac.Deployment; 28 | using Microsoft.SqlServer.Dac.Model; 29 | using System; 30 | using System.Collections.Generic; 31 | using System.Linq; 32 | using System.Text; 33 | 34 | namespace Public.Dac.Samples 35 | { 36 | /// 37 | /// A Deployment plan modifier that filters "Create Element" steps from a deployment plan. 38 | /// This stops elements from being created. This is a simple example. A more advanced 39 | /// version of this would probably check any SqlRenameSteps in the plan, but for this 40 | /// sample we're assuming that this isn't something the developer would have done. 41 | /// 42 | [ExportDeploymentPlanModifier(PlanFilterer.PlanFiltererContributorId, "1.0.0.0")] 43 | public class PlanFilterer : DeploymentPlanModifier 44 | { 45 | public const string PlanFiltererContributorId = "Public.Dac.Samples.PlanFilterer"; 46 | public const string FilterNameArg = "FilterName"; 47 | 48 | private static Dictionary> _filterMap = new Dictionary>() 49 | { 50 | {"SchemaBasedFilter", new Lazy(() => new SchemaBasedFilter())} 51 | }; 52 | 53 | private IFilter _filter; 54 | 55 | protected override void OnExecute(DeploymentPlanContributorContext context) 56 | { 57 | InitializeFilter(context.Arguments); 58 | DeploymentStep next = context.PlanHandle.Head; 59 | while (next != null) 60 | { 61 | DeploymentStep current = next; 62 | next = current.Next; 63 | 64 | CreateElementStep createStep = current as CreateElementStep; 65 | if (createStep != null && ShouldFilter(createStep)) 66 | { 67 | base.Remove(context.PlanHandle, createStep); 68 | } 69 | } 70 | } 71 | 72 | /// 73 | /// We should filter the step if the source element for the step 74 | /// doesn't pass the filter 75 | /// 76 | private bool ShouldFilter(CreateElementStep createStep) 77 | { 78 | TSqlObject createdObject = createStep.SourceElement; 79 | return !_filter.Filter(new[] {createdObject}).Any(); 80 | } 81 | 82 | private void InitializeFilter(Dictionary arguments) 83 | { 84 | string filterName; 85 | if (arguments.TryGetValue(FilterNameArg, out filterName) 86 | && _filterMap.ContainsKey(filterName)) 87 | { 88 | // Note: could use MEF or some other lookup technique to find a specific filter. If you 89 | // just have a few known filters, a map like this might be a good idea 90 | _filter = _filterMap[filterName].Value; 91 | _filter.Initialize(arguments); 92 | } 93 | } 94 | 95 | /// 96 | /// Builds the arguments string to be passed to the DacServices API when running the contributor 97 | /// 98 | public static string BuildPlanFiltererArgumentString(string filterName, 99 | Dictionary filterArguments) 100 | { 101 | filterArguments[FilterNameArg] = filterName; 102 | return Utils.BuildContributorArguments(filterArguments); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Samples/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using System.Reflection; 28 | using System.Runtime.CompilerServices; 29 | using System.Runtime.InteropServices; 30 | 31 | // General Information about an assembly is controlled through the following 32 | // set of attributes. Change these attribute values to modify the information 33 | // associated with an assembly. 34 | [assembly: AssemblyTitle("Samples")] 35 | [assembly: AssemblyDescription("")] 36 | [assembly: AssemblyConfiguration("")] 37 | [assembly: AssemblyCompany("")] 38 | [assembly: AssemblyProduct("Samples")] 39 | [assembly: AssemblyCopyright("Copyright © 2013")] 40 | [assembly: AssemblyTrademark("")] 41 | [assembly: AssemblyCulture("")] 42 | 43 | // Setting ComVisible to false makes the types in this assembly not visible 44 | // to COM components. If you need to access a type in this assembly from 45 | // COM, set the ComVisible attribute to true on that type. 46 | [assembly: ComVisible(false)] 47 | 48 | // The following GUID is for the ID of the typelib if this project is exposed to COM 49 | [assembly: Guid("32be1e6f-b4e1-4a2d-9685-ee37872fd011")] 50 | 51 | // Version information for an assembly consists of the following four values: 52 | // 53 | // Major Version 54 | // Minor Version 55 | // Build Number 56 | // Revision 57 | // 58 | // You can specify all the values or you can default the Build and Revision Numbers 59 | // by using the '*' as shown below: 60 | // [assembly: AssemblyVersion("1.0.*")] 61 | [assembly: AssemblyVersion("1.0.0.0")] 62 | [assembly: AssemblyFileVersion("1.0.0.0")] 63 | -------------------------------------------------------------------------------- /Samples/Samples.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C1C2B521-22B6-4124-AAEC-A5E1FCAB0DFA} 8 | Library 9 | Properties 10 | Public.Dac.Samples 11 | Public.Dac.Samples 12 | v4.6 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.Data.Tools.Schema.Sql.dll 36 | 37 | 38 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.Data.Tools.Utilities.dll 39 | 40 | 41 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Dac.dll 42 | 43 | 44 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Dac.Extensions.dll 45 | 46 | 47 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.TransactSql.ScriptDom.dll 48 | 49 | 50 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Types.dll 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 89 | -------------------------------------------------------------------------------- /Samples/SchemaBasedFilter.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using Microsoft.SqlServer.Dac.Model; 28 | using System; 29 | using System.Collections.Generic; 30 | using System.Linq; 31 | 32 | namespace Public.Dac.Samples 33 | { 34 | /// 35 | /// Simple filter that compares to schema name. Note that this does not use the model 36 | /// collation - for a more robust filter an would be 37 | /// used that checked the collation. 38 | /// 39 | public class SchemaBasedFilter : IFilter 40 | { 41 | public const string SchemaNameArg = "Schema"; 42 | 43 | public enum FilterType 44 | { 45 | /// 46 | /// Default 47 | /// 48 | Exclude, 49 | Include 50 | } 51 | 52 | private HashSet _schemaNames; 53 | 54 | /// 55 | /// Creates a filter for the specified , with the 56 | /// default filtering behavior to remove objects with the given schema names. 57 | /// 58 | /// 59 | public SchemaBasedFilter(params string[] schemaNames) 60 | : this((IList) schemaNames) 61 | { 62 | } 63 | 64 | /// 65 | /// Creates a filter for the specified , with the 66 | /// default filtering behavior to remove objects with the given schema names. 67 | /// 68 | /// 69 | public SchemaBasedFilter(IList schemaNames) 70 | { 71 | _schemaNames = new HashSet(schemaNames); 72 | Filtering = FilterType.Exclude; 73 | } 74 | 75 | /// 76 | /// This would be called by a deployment contributor to initialize the filter. The 77 | /// assumption is that in the code that runs the deployment, a number of arguments 78 | /// "Schema1=dev;Schema2=test" would be passed into the contributor arguments 79 | /// 80 | public void Initialize(Dictionary filterArguments) 81 | { 82 | var schemaNames = filterArguments 83 | .Where(pair => pair.Key.StartsWith(SchemaNameArg)) 84 | .Select(pair => pair.Value); 85 | 86 | _schemaNames = new HashSet(schemaNames); 87 | 88 | // Currently there is no "FilterType" argument that would allow us to 89 | // specify the filter's behavior. For now, will always by in "Exclude" mode 90 | } 91 | 92 | /// 93 | /// What type of filtering to use. Defaults to 94 | /// 95 | public FilterType Filtering 96 | { 97 | get; 98 | set; 99 | } 100 | 101 | public IEnumerable Filter(IEnumerable tSqlObjects) 102 | { 103 | return tSqlObjects.Where(o => ShouldInclude(o)); 104 | } 105 | 106 | 107 | private bool ShouldInclude(TSqlObject tsqlObject) 108 | { 109 | // almost all top-level TSqlObjects are expected to have a name. 110 | // The ObjectIdentifier 111 | bool found = false; 112 | ObjectIdentifier id = tsqlObject.Name; 113 | if (id.HasName && id.Parts.Count >= 1) 114 | { 115 | // Assuming schema name is always the first part. 116 | string schemaName = id.Parts[0]; 117 | found = _schemaNames.Contains(schemaName, StringComparer.OrdinalIgnoreCase); 118 | } 119 | 120 | if (Filtering == FilterType.Exclude) 121 | { 122 | // exclude any objects whose schema was in the filter list 123 | return !found; 124 | } 125 | return found; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Samples/Utils.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | using Microsoft.SqlServer.Dac; 28 | using System.Collections.Generic; 29 | using System.Text; 30 | 31 | namespace Public.Dac.Samples 32 | { 33 | /// 34 | /// Useful utility methods that the samples can use 35 | /// 36 | public static class Utils 37 | { 38 | 39 | /// 40 | /// Builds the arguments string to be used when running contributors. This should be 41 | /// set as the when 42 | /// running deployment via the API. 43 | /// 44 | public static string BuildContributorArguments(Dictionary arguments) 45 | { 46 | StringBuilder args = new StringBuilder(); 47 | 48 | foreach (var entry in arguments) 49 | { 50 | AddArgument(args, entry.Key, entry.Value); 51 | } 52 | return args.ToString(); 53 | } 54 | 55 | /// 56 | /// Adds an argument into the string. Args are name-value pairs separated by the "=" sign, with 57 | /// each argument in the list semicolon delimited. Hence and arg string might look like 58 | /// "FilterName=SchemaBasedFilter;Schema1=dev;Schema2=test" 59 | /// 60 | private static void AddArgument(StringBuilder args, string key, string value) 61 | { 62 | if (args.Length > 0) 63 | { 64 | args.Append(";"); 65 | } 66 | args.Append(key).Append("=").Append(value); 67 | } 68 | 69 | /// 70 | /// Builds the string describing the contributors to be run - this should be 71 | /// set as the when 72 | /// running deployment via the API. 73 | /// 74 | /// Names of the contributors to be run 75 | /// semi-colon delimited string describing the contributors to be run 76 | public static string BuildContributorsList(IList contributors) 77 | { 78 | StringBuilder args = new StringBuilder(); 79 | 80 | foreach (var contributor in contributors) 81 | { 82 | AddContributor(args, contributor); 83 | } 84 | return args.ToString(); 85 | } 86 | 87 | private static void AddContributor(StringBuilder args, string contributor) 88 | { 89 | if (args.Length > 0) 90 | { 91 | args.Append(";"); 92 | } 93 | args.Append(contributor); 94 | } 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Samples/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Scripts/RemoveMasterKey.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Given a new [file].bacpac, creates a new [file]-patched.bacpac with master key information removed from the model.xml and origin.xml. 4 | .DESCRIPTION 5 | When exporting a .bacpac from Azure SQLDB with auditing enabled, the .bacpac will contain a master key without a password in the model.xml. A 6 | master key without a password is an Azure SQLDB only feature, so it's presence prevents being able to import the .bacpac into an on-premise 7 | SQL Server database. This script works around this limitation by extracting the model.xml and origin.xml from the .bacpac, removing the references 8 | to the master key, and creating a new .bacpac with the updated model.xml and origin.xml. The resulting .bacpac can then be imported to an on-premise 9 | database. 10 | .EXAMPLE 11 | C:\PS> .\RemoveMasterKey.ps1 -bacpacPath "C:\BacPacs\Test.bacpac" # Generates a Test-patched.bacpac file 12 | .PARAMETER bacpacPath 13 | Specifies the path the .bacpac to patch. 14 | #> 15 | param( 16 | [Parameter(Mandatory=$true, HelpMessage="Specifies the path the .bacpac. This file will not be modified.")] 17 | [string]$bacpacPath 18 | ) 19 | 20 | 21 | if ($PSVersionTable.PSVersion.Major -lt 4) { 22 | Write-Host "Unsupported powershell version. This script requires powershell version 4.0 or later" 23 | return 24 | } 25 | 26 | 27 | Add-Type -Assembly System.IO.Compression.FileSystem 28 | 29 | 30 | $targetBacpacPath = [System.IO.Path]::Combine( 31 | [System.IO.Path]::GetDirectoryName($bacpacPath), 32 | [System.IO.Path]::GetFileNameWithoutExtension($bacpacPath) + "-patched" + [System.IO.Path]::GetExtension($bacpacPath)) 33 | $originXmlFile = [System.IO.Path]::Combine([System.IO.Path]::GetDirectoryName($targetBacpacPath), "Origin.xml") 34 | $modelXmlFile = [System.IO.Path]::Combine([System.IO.Path]::GetDirectoryName($targetBacpacPath), "model.xml") 35 | 36 | 37 | if ([System.IO.File]::Exists($targetBacpacPath)) { 38 | [System.IO.File]::Delete($targetBacpacPath) 39 | } 40 | 41 | 42 | # 43 | # Extract the model.xml and Origin.xml from the .bacpac 44 | # 45 | $zip = [System.IO.Compression.ZipFile]::OpenRead($bacpacPath) 46 | foreach ($entry in $zip.Entries) { 47 | if ([string]::Compare($entry.Name, "model.xml", $True) -eq 0) { 48 | [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $modelXmlFile, $true) 49 | break 50 | } 51 | } 52 | foreach ($entry in $zip.Entries) { 53 | if ([string]::Compare($entry.Name, "Origin.xml", $True) -eq 0) { 54 | [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $originXmlFile, $true) 55 | break 56 | } 57 | } 58 | $zip.Dispose() 59 | 60 | 61 | if(![System.IO.File]::Exists($modelXmlFile)) { 62 | Write-Host "Could not extract the model.xml from file " + $bacpacPath 63 | return 64 | } 65 | if(![System.IO.File]::Exists($originXmlFile)) { 66 | Write-Host "Could not extract the Origin.xml from file " + $bacpacPath 67 | return 68 | } 69 | 70 | 71 | # 72 | # Modify the model.xml 73 | # 74 | [xml]$modelXml = Get-Content $modelXmlFile 75 | $ns = New-Object System.Xml.XmlNamespaceManager($modelXml.NameTable) 76 | $ns.AddNamespace("x", $modelXml.DocumentElement.NamespaceURI) 77 | 78 | 79 | $masterKeyNodes = $modelXml.SelectNodes("//x:DataSchemaModel/x:Model/x:Element[@Type='SqlMasterKey']", $ns) 80 | foreach ($masterKeyNode in $masterKeyNodes) { 81 | $masterKeyNode.ParentNode.RemoveChild($masterKeyNode) 82 | } 83 | 84 | 85 | $sqlDatabaseCredentialNodes = $modelXml.SelectNodes("//x:DataSchemaModel/x:Model/x:Element[@Type='SqlDatabaseCredential']", $ns) 86 | foreach ($sqlDatabaseCredentialNode in $sqlDatabaseCredentialNodes) { 87 | if ($sqlDatabaseCredentialNode.Property.Name -eq "Identity" -and $sqlDatabaseCredentialNode.Property.Value -eq "SHARED ACCESS SIGNATURE") 88 | { 89 | $sqlDatabaseCredentialNode.ParentNode.RemoveChild($sqlDatabaseCredentialNode) 90 | } 91 | } 92 | 93 | 94 | $modelXml.Save($modelXmlFile) 95 | 96 | 97 | # 98 | # Modify the Origin.xml 99 | # 100 | [xml]$originXml = Get-Content $originXmlFile 101 | $ns = New-Object System.Xml.XmlNamespaceManager($originXml.NameTable) 102 | $ns.AddNamespace("x", $originXml.DocumentElement.NamespaceURI) 103 | 104 | 105 | $databaseCredentialNode = $originXml.SelectSingleNode("//x:DacOrigin/x:Server/x:ObjectCounts/x:DatabaseCredential", $ns) 106 | if ($databaseCredentialNode) { 107 | if ($databaseCredentialNode.InnerText -eq "1") { 108 | $databaseCredentialNode.ParentNode.RemoveChild($databaseCredentialNode) 109 | } else { 110 | $databaseCredentialNode.InnerText = $databaseCredentialNode.Value - 1 111 | } 112 | } 113 | 114 | 115 | $masterKeyNode = $originXml.SelectSingleNode("//x:DacOrigin/x:Server/x:ObjectCounts/x:MasterKey", $ns) 116 | if ($masterKeyNode) { 117 | $masterKeyNode.ParentNode.RemoveChild($masterKeyNode) 118 | } 119 | 120 | 121 | $modelXmlHash = (Get-FileHash $modelXmlFile -Algorithm SHA256).Hash 122 | $checksumNode = $originXml.SelectSingleNode("//x:DacOrigin/x:Checksums/x:Checksum", $ns) 123 | if ($checksumNode) { 124 | $checksumNode.InnerText = $modelXmlHash 125 | } 126 | 127 | 128 | $originXml.Save($originXmlFile) 129 | 130 | 131 | # 132 | # Create the new .bacpac using the patched model.xml and Origin.xml 133 | # 134 | $zipSource = [System.IO.Compression.ZipFile]::OpenRead($bacpacPath) 135 | $zipTarget = [System.IO.Compression.ZipFile]::Open($targetBacpacPath, "Create") 136 | foreach ($entry in $zipSource.Entries) { 137 | if ([string]::Compare($entry.Name, "Origin.xml", $True) -eq 0) { 138 | [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zipTarget, $originXmlFile, $entry.FullName) 139 | } elseif ([string]::Compare($entry.Name, "model.xml", $True) -eq 0) { 140 | [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zipTarget, $modelXmlFile, $entry.FullName) 141 | } else { 142 | $targetEntry = $zipTarget.CreateEntry($entry.FullName) 143 | $sourceStream = $null 144 | $targetStream = $null 145 | try { 146 | $sourceStream = [System.IO.Stream]$entry.Open() 147 | $targetStream = [System.IO.Stream]$targetEntry.Open() 148 | $sourceStream.CopyTo($targetStream) 149 | } 150 | finally { 151 | if ($targetStream -ne $null) { 152 | $targetStream.Dispose() 153 | } 154 | if ($sourceStream -ne $null) { 155 | $sourceStream.Dispose() 156 | } 157 | } 158 | } 159 | } 160 | $zipSource.Dispose() 161 | $zipTarget.Dispose() 162 | 163 | 164 | [System.IO.File]::Delete($modelXmlFile) 165 | [System.IO.File]::Delete($originXmlFile) 166 | 167 | 168 | Write-Host "Completed update to the model.xml and Origin.xml in file"([System.IO.Path]::GetFullPath($targetBacpacPath)) -------------------------------------------------------------------------------- /TestUtils/CommonConstants.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | namespace Public.Dac.Samples.TestUtilities 29 | { 30 | internal class CommonConstants 31 | { 32 | public const string MasterDatabaseName = "master"; 33 | 34 | public const int DefaultSqlQueryTimeoutInSeconds = 60; 35 | 36 | public const int DefaultCommandTimeout = 30; 37 | } 38 | } -------------------------------------------------------------------------------- /TestUtils/ExceptionText.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using System; 29 | using System.Text; 30 | 31 | namespace Public.Dac.Samples.TestUtilities 32 | { 33 | 34 | public static class ExceptionText 35 | { 36 | public static string GetText(Exception ex, bool stackTrace = false) 37 | { 38 | StringBuilder sb = new StringBuilder(); 39 | int depth = 0; 40 | while (ex != null) 41 | { 42 | if (depth > 0) 43 | { 44 | sb.Append("Inner Exception: "); 45 | } 46 | sb.AppendLine(ex.Message); 47 | if (stackTrace) 48 | { 49 | sb.AppendLine(ex.StackTrace); 50 | } 51 | ex = ex.InnerException; 52 | ++depth; 53 | } 54 | return sb.ToString(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /TestUtils/InstanceInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using System; 29 | using System.Data.SqlClient; 30 | 31 | namespace Public.Dac.Samples.TestUtilities 32 | { 33 | 34 | public class InstanceInfo 35 | { 36 | 37 | public InstanceInfo(string dataSource) 38 | { 39 | DataSource = dataSource; 40 | } 41 | 42 | // Persisted data properties 43 | public string DataSource { get; set; } 44 | 45 | public string RemoteSharePath { get; set; } 46 | 47 | public int ConnectTimeout { get; set; } 48 | 49 | public string ConnectTimeoutAsString 50 | { 51 | get { return ConnectTimeout.ToString(); } 52 | set 53 | { 54 | int temp; 55 | if (int.TryParse(value, out temp)) 56 | { 57 | this.ConnectTimeout = temp; 58 | } 59 | else 60 | { 61 | this.ConnectTimeout = 15; 62 | } 63 | } 64 | } 65 | 66 | 67 | public string MachineName 68 | { 69 | get 70 | { 71 | string serverName = DataSource; 72 | int index = DataSource.IndexOf('\\'); 73 | if (index > 0) 74 | { 75 | serverName = DataSource.Substring(0, index); 76 | } 77 | if (StringComparer.OrdinalIgnoreCase.Compare("(local)", serverName) == 0 78 | || StringComparer.OrdinalIgnoreCase.Compare(".", serverName) == 0) 79 | { 80 | serverName = Environment.MachineName; 81 | } 82 | return serverName; 83 | } 84 | } 85 | public string InstanceName 86 | { 87 | get 88 | { 89 | string name = null; 90 | int index = DataSource.IndexOf('\\'); 91 | if (index > 0) 92 | { 93 | name = DataSource.Substring(index + 1); 94 | } 95 | return name; 96 | } 97 | } 98 | 99 | public string UserId { get; set; } 100 | 101 | public string Password { get; set; } 102 | 103 | /// 104 | /// Connection string to this instance with the master database as the default. 105 | /// Integrated security is used 106 | /// 107 | /// 108 | public string BuildConnectionString() 109 | { 110 | return CreateBuilder().ConnectionString; 111 | } 112 | 113 | public SqlConnectionStringBuilder CreateBuilder() 114 | { 115 | return CreateBuilder(CommonConstants.MasterDatabaseName); 116 | } 117 | 118 | public string BuildConnectionString(string dbName) 119 | { 120 | return CreateBuilder(dbName).ConnectionString; 121 | } 122 | 123 | public SqlConnectionStringBuilder CreateBuilder(string dbName) 124 | { 125 | return CreateBuilder(UserId, Password, dbName); 126 | } 127 | 128 | /// 129 | /// Build a connection string for this instance using the specified 130 | /// username/password for security and specifying the dbName as the 131 | /// initial catalog 132 | /// 133 | public string BuildConnectionString(string userId, string password, string dbName) 134 | { 135 | SqlConnectionStringBuilder scsb = CreateBuilder(userId, password, dbName); 136 | return scsb.ConnectionString; 137 | } 138 | public SqlConnectionStringBuilder CreateBuilder(string userId, string password, string dbName) 139 | { 140 | SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder(); 141 | scsb.DataSource = DataSource; 142 | scsb.InitialCatalog = dbName; 143 | scsb.Pooling = false; 144 | scsb.MultipleActiveResultSets = false; 145 | if (ConnectTimeout != 15) 146 | { 147 | scsb.ConnectTimeout = this.ConnectTimeout; 148 | } 149 | 150 | if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(password)) 151 | { 152 | scsb.IntegratedSecurity = true; 153 | } 154 | else 155 | { 156 | scsb.IntegratedSecurity = false; 157 | scsb.UserID = userId; 158 | scsb.Password = password; 159 | } 160 | 161 | return scsb; 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /TestUtils/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2015 Microsoft 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | //------------------------------------------------------------------------------ 27 | 28 | using System.Reflection; 29 | using System.Runtime.CompilerServices; 30 | using System.Runtime.InteropServices; 31 | 32 | // General Information about an assembly is controlled through the following 33 | // set of attributes. Change these attribute values to modify the information 34 | // associated with an assembly. 35 | [assembly: AssemblyTitle("Public.Dac.Samples.TestUtilitiess")] 36 | [assembly: AssemblyDescription("")] 37 | [assembly: AssemblyConfiguration("")] 38 | [assembly: AssemblyCompany("")] 39 | [assembly: AssemblyProduct("TestUtils")] 40 | [assembly: AssemblyCopyright("Copyright © 2015")] 41 | [assembly: AssemblyTrademark("")] 42 | [assembly: AssemblyCulture("")] 43 | 44 | // Setting ComVisible to false makes the types in this assembly not visible 45 | // to COM components. If you need to access a type in this assembly from 46 | // COM, set the ComVisible attribute to true on that type. 47 | [assembly: ComVisible(false)] 48 | 49 | // The following GUID is for the ID of the typelib if this project is exposed to COM 50 | [assembly: Guid("edf01d79-66d0-496c-82d2-431831564817")] 51 | 52 | // Version information for an assembly consists of the following four values: 53 | // 54 | // Major Version 55 | // Minor Version 56 | // Build Number 57 | // Revision 58 | // 59 | // You can specify all the values or you can default the Build and Revision Numbers 60 | // by using the '*' as shown below: 61 | // [assembly: AssemblyVersion("1.0.*")] 62 | [assembly: AssemblyVersion("1.0.0.0")] 63 | [assembly: AssemblyFileVersion("1.0.0.0")] 64 | -------------------------------------------------------------------------------- /TestUtils/TestUtils.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EDF01D79-66D0-496C-82D2-431831564817} 8 | Library 9 | Properties 10 | Public.Dac.Samples.TestUtilities 11 | Public.Dac.Samples.TestUtilitiess 12 | v4.6 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.Data.Tools.Schema.Sql.dll 36 | 37 | 38 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.Data.Tools.Utilities.dll 39 | 40 | 41 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Dac.dll 42 | 43 | 44 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Dac.Extensions.dll 45 | 46 | 47 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.TransactSql.ScriptDom.dll 48 | 49 | 50 | ..\packages\Microsoft.SqlServer.DacFx.x64.150.4826.1\lib\net46\Microsoft.SqlServer.Types.dll 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 80 | -------------------------------------------------------------------------------- /TestUtils/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------