├── .gitattributes ├── .gitignore ├── PartitionManagement.sln ├── PartitionManagement ├── CommandLineArguments.cs ├── ManagePartition.cs ├── PartitionManagement.cs ├── PartitionManagement2014.csproj ├── Properties │ ├── AssemblyInfo.cs │ └── app.manifest ├── Utility.cs └── app.config ├── PartitionManagement2012 ├── CommandLineArguments.cs ├── ManagePartition.cs ├── PartitionManagement.cs ├── PartitionManagement2012.csproj ├── Properties │ ├── AssemblyInfo.cs │ └── app.manifest ├── Utility.cs └── app.config ├── PartitionMgmtTest_2005.sql ├── PartitionMgmtTest_2008.sql ├── PartitionMgmtTest_2012.sql ├── readme.htm ├── readme.md └── readme_files ├── colorschememapping.xml ├── filelist.xml └── themedata.thmx /.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 | -------------------------------------------------------------------------------- /.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 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml -------------------------------------------------------------------------------- /PartitionManagement.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartitionManagement2014", "PartitionManagement\PartitionManagement2014.csproj", "{1BE0E539-3459-4C57-AB49-F3FD5750212A}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartitionManagement2012", "PartitionManagement2012\PartitionManagement2012.csproj", "{8F71C899-5374-477D-A307-FBC7C20EF62A}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {1BE0E539-3459-4C57-AB49-F3FD5750212A}.Debug|Any CPU.ActiveCfg = Release|Any CPU 17 | {1BE0E539-3459-4C57-AB49-F3FD5750212A}.Debug|Any CPU.Build.0 = Release|Any CPU 18 | {1BE0E539-3459-4C57-AB49-F3FD5750212A}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {1BE0E539-3459-4C57-AB49-F3FD5750212A}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {8F71C899-5374-477D-A307-FBC7C20EF62A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {8F71C899-5374-477D-A307-FBC7C20EF62A}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {8F71C899-5374-477D-A307-FBC7C20EF62A}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {8F71C899-5374-477D-A307-FBC7C20EF62A}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /PartitionManagement/CommandLineArguments.cs: -------------------------------------------------------------------------------- 1 | namespace Utilities 2 | { 3 | using System; 4 | using System.Diagnostics; 5 | using System.Reflection; 6 | using System.Collections; 7 | using System.IO; 8 | using System.Text; 9 | 10 | /// 11 | /// Used to control parsing of command line arguments. 12 | /// 13 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1714:FlagsEnumsShouldHavePluralNames"), Flags] 14 | public enum CommandLineArgumentType 15 | { 16 | /// 17 | /// Indicates that this field is required. An error will be displayed 18 | /// if it is not present when parsing arguments. 19 | /// 20 | Required = 0x01, 21 | /// 22 | /// Only valid in conjunction with Multiple. 23 | /// Duplicate values will result in an error. 24 | /// 25 | Unique = 0x02, 26 | /// 27 | /// Inidicates that the argument may be specified more than once. 28 | /// Only valid if the argument is a collection 29 | /// 30 | Multiple = 0x04, 31 | 32 | /// 33 | /// The default type for non-collection arguments. 34 | /// The argument is not required, but an error will be reported if it is specified more than once. 35 | /// 36 | AtMostOnce = 0x00, 37 | 38 | /// 39 | /// For non-collection arguments, when the argument is specified more than 40 | /// once no error is reported and the value of the argument is the last 41 | /// value which occurs in the argument list. 42 | /// 43 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Occurence")] 44 | LastOccurenceWins = Multiple, 45 | 46 | /// 47 | /// The default type for collection arguments. 48 | /// The argument is permitted to occur multiple times, but duplicate 49 | /// values will cause an error to be reported. 50 | /// 51 | MultipleUnique = Multiple | Unique, 52 | } 53 | 54 | /// 55 | /// Allows control of command line parsing. 56 | /// Attach this attribute to instance fields of types used 57 | /// as the destination of command line argument parsing. 58 | /// 59 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes"), AttributeUsage(AttributeTargets.Field)] 60 | public class CommandLineArgumentAttribute : Attribute 61 | { 62 | /// 63 | /// Allows control of command line parsing. 64 | /// 65 | /// Specifies the error checking to be done on the argument. 66 | public CommandLineArgumentAttribute(CommandLineArgumentType type) 67 | { 68 | this.type = type; 69 | } 70 | 71 | /// 72 | /// The error checking to be done on the argument. 73 | /// 74 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] 75 | public CommandLineArgumentType Type 76 | { 77 | get { return this.type; } 78 | } 79 | /// 80 | /// Returns true if the argument did not have an explicit short name specified. 81 | /// 82 | public bool DefaultShortName { get { return null == this.shortName; } } 83 | 84 | /// 85 | /// The short name of the argument. 86 | /// 87 | public string ShortName 88 | { 89 | get { return this.shortName; } 90 | set { this.shortName = value; } 91 | } 92 | 93 | /// 94 | /// Returns true if the argument did not have an explicit long name specified. 95 | /// 96 | public bool DefaultLongName { get { return null == this.longName; } } 97 | 98 | /// 99 | /// The long name of the argument. 100 | /// 101 | public string LongName 102 | { 103 | get { Debug.Assert(!this.DefaultLongName); return this.longName; } 104 | set { this.longName = value; } 105 | } 106 | 107 | private string shortName; 108 | private string longName; 109 | private CommandLineArgumentType type; 110 | } 111 | 112 | /// 113 | /// Indicates that this argument is the default argument. 114 | /// '/' or '-' prefix only the argument value is specified. 115 | /// 116 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes"), AttributeUsage(AttributeTargets.Field)] 117 | public class DefaultCommandLineArgumentAttribute : CommandLineArgumentAttribute 118 | { 119 | /// 120 | /// Indicates that this argument is the default argument. 121 | /// 122 | /// Specifies the error checking to be done on the argument. 123 | public DefaultCommandLineArgumentAttribute(CommandLineArgumentType type) 124 | : base(type) 125 | { 126 | } 127 | } 128 | 129 | /// 130 | /// Parser for command line arguments. 131 | /// 132 | /// The parser specification is infered from the instance fields of the object 133 | /// specified as the destination of the parse. 134 | /// Valid argument types are: int, uint, string, bool, enums 135 | /// Also argument types of Array of the above types are also valid. 136 | /// 137 | /// Error checking options can be controlled by adding a CommandLineArgumentAttribute 138 | /// to the instance fields of the destination object. 139 | /// 140 | /// At most one field may be marked with the DefaultCommandLineArgumentAttribute 141 | /// indicating that arguments without a '-' or '/' prefix will be parsed as that argument. 142 | /// 143 | /// If not specified then the parser will infer default options for parsing each 144 | /// instance field. The default long name of the argument is the field name. The 145 | /// default short name is the first character of the long name. Long names and explicitly 146 | /// specified short names must be unique. Default short names will be used provided that 147 | /// the default short name does not conflict with a long name or an explicitly 148 | /// specified short name. 149 | /// 150 | /// Arguments which are array types are collection arguments. Collection 151 | /// arguments can be specified multiple times. 152 | /// 153 | public class CommandLineArgumentParser 154 | { 155 | /// 156 | /// Creates a new command line argument parser. 157 | /// 158 | /// The type of object to parse. 159 | /// The destination for parse errors. 160 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] 161 | public CommandLineArgumentParser(Type argumentSpecification, ErrorReporter reporter) 162 | { 163 | this.reporter = reporter; 164 | this.arguments = new ArrayList(); 165 | this.argumentMap = new Hashtable(); 166 | 167 | foreach (FieldInfo field in argumentSpecification.GetFields()) 168 | { 169 | if (!field.IsStatic && !field.IsInitOnly && !field.IsLiteral) 170 | { 171 | CommandLineArgumentAttribute attribute = GetAttribute(field); 172 | if (attribute is DefaultCommandLineArgumentAttribute) 173 | { 174 | Debug.Assert(this.defaultArgument == null); 175 | this.defaultArgument = new Argument(attribute, field, reporter); 176 | } 177 | else 178 | { 179 | this.arguments.Add(new Argument(attribute, field, reporter)); 180 | } 181 | } 182 | } 183 | 184 | // add explicit names to map 185 | foreach (Argument argument in this.arguments) 186 | { 187 | Debug.Assert(!argumentMap.ContainsKey(argument.LongName)); 188 | this.argumentMap[argument.LongName] = argument; 189 | if (argument.ExplicitShortName && argument.ShortName != null && argument.ShortName.Length > 0) 190 | { 191 | Debug.Assert(!argumentMap.ContainsKey(argument.ShortName)); 192 | this.argumentMap[argument.ShortName] = argument; 193 | } 194 | } 195 | 196 | // add implicit names which don't collide to map 197 | foreach (Argument argument in this.arguments) 198 | { 199 | if (!argument.ExplicitShortName && argument.ShortName != null && argument.ShortName.Length > 0) 200 | { 201 | if (!argumentMap.ContainsKey(argument.ShortName)) 202 | this.argumentMap[argument.ShortName] = argument; 203 | } 204 | } 205 | } 206 | 207 | private static CommandLineArgumentAttribute GetAttribute(FieldInfo field) 208 | { 209 | object[] attributes = field.GetCustomAttributes(typeof(CommandLineArgumentAttribute), false); 210 | if (attributes.Length == 1) 211 | return (CommandLineArgumentAttribute)attributes[0]; 212 | 213 | Debug.Assert(attributes.Length == 0); 214 | return null; 215 | } 216 | 217 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)")] 218 | private void ReportUnrecognizedArgument(string argument) 219 | { 220 | this.reporter(string.Format("Unrecognized command line argument '{0}'", argument)); 221 | } 222 | 223 | /// 224 | /// Parses an argument list into an object 225 | /// 226 | /// 227 | /// 228 | /// true if an error occurred 229 | private bool ParseArgumentList(string[] args, object destination) 230 | { 231 | bool hadError = false; 232 | if (args != null) 233 | { 234 | foreach (string argument in args) 235 | { 236 | if (argument.Length > 0) 237 | { 238 | switch (argument[0]) 239 | { 240 | case '-': 241 | case '/': 242 | int endIndex = argument.IndexOfAny(new char[] { ':', '+', '-' }, 1); 243 | string option = argument.Substring(1, endIndex == -1 ? argument.Length - 1 : endIndex - 1); 244 | string optionArgument; 245 | if (option.Length + 1 == argument.Length) 246 | { 247 | optionArgument = null; 248 | } 249 | else if (argument.Length > 1 + option.Length && argument[1 + option.Length] == ':') 250 | { 251 | optionArgument = argument.Substring(option.Length + 2); 252 | } 253 | else 254 | { 255 | optionArgument = argument.Substring(option.Length + 1); 256 | } 257 | 258 | Argument arg = (Argument)this.argumentMap[option]; 259 | if (arg == null) 260 | { 261 | ReportUnrecognizedArgument(argument); 262 | hadError = true; 263 | } 264 | else 265 | { 266 | hadError |= !arg.SetValue(optionArgument, destination); 267 | } 268 | break; 269 | case '@': 270 | string[] nestedArguments; 271 | hadError |= LexFileArguments(argument.Substring(1), out nestedArguments); 272 | hadError |= ParseArgumentList(nestedArguments, destination); 273 | break; 274 | default: 275 | if (this.defaultArgument != null) 276 | { 277 | hadError |= !this.defaultArgument.SetValue(argument, destination); 278 | } 279 | else 280 | { 281 | ReportUnrecognizedArgument(argument); 282 | hadError = true; 283 | } 284 | break; 285 | } 286 | } 287 | } 288 | } 289 | 290 | return hadError; 291 | } 292 | 293 | /// 294 | /// Parses an argument list. 295 | /// 296 | /// The arguments to parse. 297 | /// The destination of the parsed arguments. 298 | /// true if no parse errors were encountered. 299 | public bool Parse(string[] args, object destination) 300 | { 301 | bool hadError = ParseArgumentList(args, destination); 302 | 303 | // check for missing required arguments 304 | foreach (Argument arg in this.arguments) 305 | { 306 | hadError |= arg.Finish(destination); 307 | } 308 | if (this.defaultArgument != null) 309 | { 310 | hadError |= this.defaultArgument.Finish(destination); 311 | } 312 | 313 | return !hadError; 314 | } 315 | 316 | 317 | /// 318 | /// A user firendly usage string describing the command line argument syntax. 319 | /// 320 | public string Usage 321 | { 322 | get 323 | { 324 | StringBuilder builder = new StringBuilder(); 325 | 326 | int oldLength; 327 | foreach (Argument arg in this.arguments) 328 | { 329 | oldLength = builder.Length; 330 | 331 | builder.Append(" /"); 332 | builder.Append(arg.LongName); 333 | Type valueType = arg.ValueType; 334 | if (valueType == typeof(int)) 335 | { 336 | builder.Append(":"); 337 | } 338 | else if (valueType == typeof(uint)) 339 | { 340 | builder.Append(":"); 341 | } 342 | else if (valueType == typeof(bool)) 343 | { 344 | builder.Append("[+|-]"); 345 | } 346 | else if (valueType == typeof(string)) 347 | { 348 | builder.Append(":"); 349 | } 350 | else 351 | { 352 | Debug.Assert(valueType.IsEnum); 353 | 354 | builder.Append(":{"); 355 | bool first = true; 356 | foreach (FieldInfo field in valueType.GetFields()) 357 | { 358 | if (field.IsStatic) 359 | { 360 | if (first) 361 | first = false; 362 | else 363 | builder.Append('|'); 364 | builder.Append(field.Name); 365 | } 366 | } 367 | builder.Append('}'); 368 | } 369 | 370 | if (arg.ShortName != arg.LongName && this.argumentMap[arg.ShortName] == arg) 371 | { 372 | builder.Append(' ', IndentLength(builder.Length - oldLength)); 373 | builder.Append("short form /"); 374 | builder.Append(arg.ShortName); 375 | } 376 | 377 | builder.Append(Utility.NewLine); 378 | } 379 | 380 | oldLength = builder.Length; 381 | builder.Append(" @"); 382 | builder.Append(' ', IndentLength(builder.Length - oldLength)); 383 | builder.Append("Read response file for more options"); 384 | builder.Append(Utility.NewLine); 385 | 386 | if (this.defaultArgument != null) 387 | { 388 | oldLength = builder.Length; 389 | builder.Append(" <"); 390 | builder.Append(this.defaultArgument.LongName); 391 | builder.Append(">"); 392 | builder.Append(Utility.NewLine); 393 | } 394 | 395 | return builder.ToString(); 396 | } 397 | } 398 | 399 | private static int IndentLength(int lineLength) 400 | { 401 | return Math.Max(4, 40 - lineLength); 402 | } 403 | 404 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "arguments")] 405 | private bool LexFileArguments(string fileName, out string[] arguments) 406 | { 407 | string args = null; 408 | 409 | try 410 | { 411 | using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read)) 412 | { 413 | args = (new StreamReader(file)).ReadToEnd(); 414 | } 415 | } 416 | catch (Exception e) 417 | { 418 | this.reporter(string.Format("Error: Can't open command line argument file '{0}' : '{1}'", fileName, e.Message)); 419 | arguments = null; 420 | return false; 421 | } 422 | 423 | bool hadError = false; 424 | ArrayList argArray = new ArrayList(); 425 | StringBuilder currentArg = new StringBuilder(); 426 | bool inQuotes = false; 427 | int index = 0; 428 | 429 | // while (index < args.Length) 430 | try 431 | { 432 | while (true) 433 | { 434 | // skip whitespace 435 | while (char.IsWhiteSpace(args[index])) 436 | { 437 | index += 1; 438 | } 439 | 440 | // # - comment to end of line 441 | if (args[index] == '#') 442 | { 443 | index += 1; 444 | while (args[index] != '\n') 445 | { 446 | index += 1; 447 | } 448 | continue; 449 | } 450 | 451 | // do one argument 452 | do 453 | { 454 | if (args[index] == '\\') 455 | { 456 | int cSlashes = 1; 457 | index += 1; 458 | while (index == args.Length && args[index] == '\\') 459 | { 460 | cSlashes += 1; 461 | } 462 | 463 | if (index == args.Length || args[index] != '"') 464 | { 465 | currentArg.Append('\\', cSlashes); 466 | } 467 | else 468 | { 469 | currentArg.Append('\\', (cSlashes >> 1)); 470 | if (0 != (cSlashes & 1)) 471 | { 472 | currentArg.Append('"'); 473 | } 474 | else 475 | { 476 | inQuotes = !inQuotes; 477 | } 478 | } 479 | } 480 | else if (args[index] == '"') 481 | { 482 | inQuotes = !inQuotes; 483 | index += 1; 484 | } 485 | else 486 | { 487 | currentArg.Append(args[index]); 488 | index += 1; 489 | } 490 | } while (!char.IsWhiteSpace(args[index]) || inQuotes); 491 | argArray.Add(currentArg.ToString()); 492 | currentArg.Length = 0; 493 | } 494 | } 495 | catch (System.IndexOutOfRangeException) 496 | { 497 | // got EOF 498 | if (inQuotes) 499 | { 500 | this.reporter(string.Format("Error: Unbalanced '\"' in command line argument file '{0}'", fileName)); 501 | hadError = true; 502 | } 503 | else if (currentArg.Length > 0) 504 | { 505 | // valid argument can be terminated by EOF 506 | argArray.Add(currentArg.ToString()); 507 | } 508 | } 509 | 510 | arguments = (string[])argArray.ToArray(typeof(string)); 511 | return hadError; 512 | } 513 | 514 | private static string LongName(CommandLineArgumentAttribute attribute, FieldInfo field) 515 | { 516 | return (attribute == null || attribute.DefaultLongName) ? field.Name : attribute.LongName; 517 | } 518 | 519 | private static string ShortName(CommandLineArgumentAttribute attribute, FieldInfo field) 520 | { 521 | return !ExplicitShortName(attribute) ? LongName(attribute, field).Substring(0, 1) : attribute.ShortName; 522 | } 523 | 524 | private static bool ExplicitShortName(CommandLineArgumentAttribute attribute) 525 | { 526 | return (attribute != null && !attribute.DefaultShortName); 527 | } 528 | 529 | private static Type ElementType(FieldInfo field) 530 | { 531 | if (IsCollectionType(field.FieldType)) 532 | return field.FieldType.GetElementType(); 533 | else 534 | return null; 535 | } 536 | 537 | private static CommandLineArgumentType Flags(CommandLineArgumentAttribute attribute, FieldInfo field) 538 | { 539 | if (attribute != null) 540 | return attribute.Type; 541 | else if (IsCollectionType(field.FieldType)) 542 | return CommandLineArgumentType.MultipleUnique; 543 | else 544 | return CommandLineArgumentType.AtMostOnce; 545 | } 546 | 547 | private static bool IsCollectionType(Type type) 548 | { 549 | return type.IsArray; 550 | } 551 | 552 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 553 | private static bool IsValidElementType(Type type) 554 | { 555 | return type != null && ( 556 | type == typeof(int) || 557 | type == typeof(uint) || 558 | type == typeof(string) || 559 | type == typeof(bool) || 560 | type.IsEnum); 561 | } 562 | 563 | private class Argument 564 | { 565 | public Argument(CommandLineArgumentAttribute attribute, FieldInfo field, ErrorReporter reporter) 566 | { 567 | this.longName = CommandLineArgumentParser.LongName(attribute, field); 568 | this.explicitShortName = CommandLineArgumentParser.ExplicitShortName(attribute); 569 | this.shortName = CommandLineArgumentParser.ShortName(attribute, field); 570 | this.elementType = ElementType(field); 571 | this.flags = Flags(attribute, field); 572 | this.field = field; 573 | this.seenValue = false; 574 | this.reporter = reporter; 575 | this.isDefault = attribute != null && attribute is DefaultCommandLineArgumentAttribute; 576 | 577 | if (IsCollection) 578 | { 579 | this.collectionValues = new ArrayList(); 580 | } 581 | 582 | Debug.Assert(this.longName != null && this.longName.Length > 0); 583 | Debug.Assert(!IsCollection || AllowMultiple, "Collection arguments must have allow multiple"); 584 | Debug.Assert(!Unique || IsCollection, "Unique only applicable to collection arguments"); 585 | Debug.Assert(IsValidElementType(Type) || 586 | IsCollectionType(Type)); 587 | Debug.Assert((IsCollection && IsValidElementType(elementType)) || 588 | (!IsCollection && elementType == null)); 589 | } 590 | 591 | public bool Finish(object destination) 592 | { 593 | if (this.IsCollection) 594 | { 595 | this.field.SetValue(destination, this.collectionValues.ToArray(this.elementType)); 596 | } 597 | 598 | return ReportMissingRequiredArgument(); 599 | } 600 | 601 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)")] 602 | private bool ReportMissingRequiredArgument() 603 | { 604 | if (this.IsRequired && !this.SeenValue) 605 | { 606 | if (this.IsDefault) 607 | reporter(string.Format("Missing required argument '<{0}>'.", this.LongName)); 608 | else 609 | reporter(string.Format("Missing required argument '/{0}'.", this.LongName)); 610 | return true; 611 | } 612 | return false; 613 | } 614 | 615 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)")] 616 | private void ReportDuplicateArgumentValue(string value) 617 | { 618 | this.reporter(string.Format("Duplicate '{0}' argument '{1}'", this.LongName, value)); 619 | } 620 | 621 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)")] 622 | public bool SetValue(string value, object destination) 623 | { 624 | if (SeenValue && !AllowMultiple) 625 | { 626 | this.reporter(string.Format("Duplicate '{0}' argument", this.LongName)); 627 | return false; 628 | } 629 | this.seenValue = true; 630 | 631 | object newValue; 632 | if (!ParseValue(this.ValueType, value, out newValue)) 633 | return false; 634 | if (this.IsCollection) 635 | { 636 | if (this.Unique && this.collectionValues.Contains(newValue)) 637 | { 638 | ReportDuplicateArgumentValue(value); 639 | return false; 640 | } 641 | else 642 | { 643 | this.collectionValues.Add(newValue); 644 | } 645 | } 646 | else 647 | { 648 | this.field.SetValue(destination, newValue); 649 | } 650 | 651 | return true; 652 | } 653 | 654 | public Type ValueType 655 | { 656 | get { return this.IsCollection ? this.elementType : this.Type; } 657 | } 658 | 659 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)")] 660 | private void ReportBadArgumentValue(string value) 661 | { 662 | this.reporter(string.Format("'{0}' is not a valid value for the '{1}' command line option", value, this.LongName)); 663 | } 664 | 665 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.Parse(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 666 | private bool ParseValue(Type type, string stringData, out object value) 667 | { 668 | // null is only valid for bool variables 669 | // empty string is never valid 670 | if ((stringData != null || type == typeof(bool)) && (stringData == null || stringData.Length > 0)) 671 | { 672 | try 673 | { 674 | if (type == typeof(string)) 675 | { 676 | value = stringData; 677 | return true; 678 | } 679 | else if (type == typeof(bool)) 680 | { 681 | if (stringData == null || stringData == "+") 682 | { 683 | value = true; 684 | return true; 685 | } 686 | else if (stringData == "-") 687 | { 688 | value = false; 689 | return true; 690 | } 691 | } 692 | else if (type == typeof(int)) 693 | { 694 | value = int.Parse(stringData); 695 | return true; 696 | } 697 | else if (type == typeof(uint)) 698 | { 699 | value = int.Parse(stringData); 700 | return true; 701 | } 702 | else 703 | { 704 | Debug.Assert(type.IsEnum); 705 | value = Enum.Parse(type, stringData, true); 706 | return true; 707 | } 708 | } 709 | catch 710 | { 711 | // catch parse errors 712 | } 713 | } 714 | 715 | ReportBadArgumentValue(stringData); 716 | value = null; 717 | return false; 718 | } 719 | 720 | public string LongName 721 | { 722 | get { return this.longName; } 723 | } 724 | 725 | public bool ExplicitShortName 726 | { 727 | get { return this.explicitShortName; } 728 | } 729 | 730 | public string ShortName 731 | { 732 | get { return this.shortName; } 733 | } 734 | 735 | public bool IsRequired 736 | { 737 | get { return 0 != (this.flags & CommandLineArgumentType.Required); } 738 | } 739 | 740 | public bool SeenValue 741 | { 742 | get { return this.seenValue; } 743 | } 744 | 745 | public bool AllowMultiple 746 | { 747 | get { return 0 != (this.flags & CommandLineArgumentType.Multiple); } 748 | } 749 | 750 | public bool Unique 751 | { 752 | get { return 0 != (this.flags & CommandLineArgumentType.Unique); } 753 | } 754 | 755 | public Type Type 756 | { 757 | get { return field.FieldType; } 758 | } 759 | 760 | public bool IsCollection 761 | { 762 | get { return IsCollectionType(Type); } 763 | } 764 | 765 | public bool IsDefault 766 | { 767 | get { return this.isDefault; } 768 | } 769 | 770 | private string longName; 771 | private string shortName; 772 | private bool explicitShortName; 773 | private bool seenValue; 774 | private FieldInfo field; 775 | private Type elementType; 776 | private CommandLineArgumentType flags; 777 | private ArrayList collectionValues; 778 | private ErrorReporter reporter; 779 | private bool isDefault; 780 | } 781 | 782 | private ArrayList arguments; 783 | private Hashtable argumentMap; 784 | private Argument defaultArgument; 785 | private ErrorReporter reporter; 786 | } 787 | } 788 | 789 | -------------------------------------------------------------------------------- /PartitionManagement/ManagePartition.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucazav/SqlServerPartitionManagementUtility/653e05fc86ea37a48d8145fa99e2a3f08cbb010a/PartitionManagement/ManagePartition.cs -------------------------------------------------------------------------------- /PartitionManagement/PartitionManagement.cs: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // PartitionManagement.cs 4 | // 5 | // Version 3.1 6 | // Forked to Github: https://github.com/lucazav/sqlserverpartitionmanager 7 | // 8 | // Version 3.0 9 | // Stuart Ozer 10 | // Microsoft Corporation 11 | // December 2012 12 | // 13 | // Class library to create a table that can be populated to load data for a partition SWITCH operation, 14 | // or used as a destination to empty rows from a partition SWITCH. Table structure and filegroup 15 | // location are based on the definition of the Partition Table and the Partition Number being used. 16 | // 17 | // Library supports creating the table fully, or deferring creation of the indexes until table has 18 | // been populated by a fast load. 19 | // 20 | // Version History 21 | // V 3.1 -- November 2015 22 | // Requires SQL2012 version of SMO 23 | // Added support for SQL Server 2014 in a different project 24 | // Fixed the deadlock issue when occurring when one instance of the exe was trying read from sys.tables 25 | // and the other one was trying to alter the schema with an Alter table command. 26 | // Fixed the missing throw issue in the catch block of the Run method 27 | // 28 | // V 3.0 -- December 2012 29 | // Requires SQL2012 version of SMO 30 | // Added support for Columnstore Indexes 31 | // Added support to script generated TSQL commands 32 | // Added global locale support for date formats 33 | // Fixed partitioning columns requiring quoted names 34 | // Added support for binary partitioning column types 35 | // Fixed problem with tables containing long text or long binary tyoes 36 | // 37 | // V 2.0 -- February 2009 38 | // Requires SQL2008 version of SMO 39 | // Added support for SQL2008 data types 40 | // Added support for nullable partition columns 41 | // Added support for filtered indexes and sparse columns 42 | // Added support for table and index compression 43 | // Added support for default constraints to assist when populating staging tables 44 | // Added support for partition-aligned indexed views 45 | // Added backward compatibility for SQL2005 46 | // 47 | // NOTE: Filestream columns are not supported because SWITCH has limited value in filestream environments 48 | // 49 | // V 1.0 -- May 2006 50 | // 51 | // Provided as-is, with no warranties expressed or implied 52 | // 53 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 54 | using System; 55 | using System.Collections.Generic; 56 | using Microsoft.SqlServer.Management.Common; 57 | using Microsoft.SqlServer.Management.Smo; 58 | using Microsoft.SqlServer.Management.Sdk.Sfc; 59 | using System.Data.SqlClient; 60 | using System.Text; 61 | using System.Text.RegularExpressions; 62 | using System.IO; 63 | 64 | namespace PartitionManagement 65 | { 66 | class PartitionManager 67 | { 68 | private Database db; 69 | private Table partitionTable; 70 | private PartitionFunction pf; 71 | private Table stgTable; 72 | private ServerConnection conn; 73 | private Server srv; 74 | private int partitionNumber; 75 | private StreamWriter scriptWriter; 76 | bool executeCommands; 77 | private List scriptChunks; 78 | 79 | // This version of the constructor relies on an explicit partition number to be provided 80 | public PartitionManager(ServerConnection conn, String dbName, String schName, 81 | String partitionTblName, String stgTblName, int partitionNumber, StreamWriter scriptWriter, 82 | bool executeCommands) 83 | { 84 | // Create all objects 85 | this.conn = conn; 86 | this.partitionNumber = partitionNumber; 87 | this.executeCommands = executeCommands; 88 | this.scriptWriter = scriptWriter; 89 | 90 | srv = new Server(conn); 91 | 92 | db = srv.Databases[dbName]; 93 | 94 | scriptChunks = new List(); 95 | 96 | // validate table 97 | if ((partitionTable = db.Tables[partitionTblName, schName]) == null) 98 | { 99 | throw new System.ArgumentException("Table [" + schName + "].[" + partitionTblName + "] not found in database [" + dbName + "]"); 100 | } 101 | // validate it is partitioned 102 | if (String.IsNullOrEmpty(partitionTable.PartitionScheme)) 103 | { 104 | throw new System.ArgumentException("Table [" + schName + "].[" + partitionTblName + "] is not partitioned"); 105 | } 106 | else 107 | { 108 | pf = db.PartitionFunctions[db.PartitionSchemes[partitionTable.PartitionScheme].PartitionFunction]; 109 | } 110 | // validate the partition number 111 | if ((pf.NumberOfPartitions < partitionNumber) || (partitionNumber <= 0)) 112 | { 113 | throw new System.ArgumentException("Invalid Partition Number"); 114 | } 115 | // check for presence of staging table with the same name 116 | if (db.Tables.Contains(stgTblName, schName)) 117 | { 118 | stgTable = db.Tables[stgTblName,schName]; 119 | } 120 | else 121 | { 122 | stgTable = new Table(db, stgTblName, schName); 123 | } 124 | } 125 | 126 | // Alternate version of constructor computes the partition number given an 127 | // input string representing the range value of the partitioning column 128 | public PartitionManager(ServerConnection conn, String dbName, String schName, 129 | String partitionTblName, String stgTblName, String partitionRangeValue, StreamWriter scriptWriter, 130 | bool executeCommands) 131 | : this(conn, dbName, schName, partitionTblName, stgTblName, 1, scriptWriter, executeCommands) 132 | { 133 | //Determine the correct partition number based on the range value 134 | this.partitionNumber = getPartitionNumber(partitionRangeValue); 135 | } 136 | 137 | public void SetTransactionIsolationLevelReaduncommitted() 138 | { 139 | System.Collections.Specialized.StringCollection sc = new System.Collections.Specialized.StringCollection(); 140 | 141 | string readUncomm = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"; 142 | sc.Add(readUncomm); 143 | 144 | scriptChunks.Add(sc); 145 | if (executeCommands) conn.ExecuteScalar(readUncomm); 146 | } 147 | 148 | public void CreateStgTable() 149 | { 150 | // Create the new table in the appropriate filegroup for the SWITCH 151 | foreach (Column c in partitionTable.Columns) 152 | { 153 | // Populate the table with each column and associated properties from the partition table 154 | Column stgCol = new Column(stgTable, c.Name, c.DataType); 155 | stgCol.Collation = c.Collation; 156 | stgCol.Nullable = c.Nullable; 157 | stgCol.Computed = c.Computed; 158 | stgCol.ComputedText = c.ComputedText; 159 | stgCol.Default = c.Default; 160 | // Apply default constraint value, if present, as a default value 161 | if (c.DefaultConstraint != null) 162 | { 163 | stgCol.AddDefaultConstraint(stgTable.Name + "_" + c.DefaultConstraint.Name); 164 | stgCol.DefaultConstraint.Text = c.DefaultConstraint.Text; 165 | } 166 | stgCol.IsPersisted = c.IsPersisted; 167 | stgCol.DefaultSchema = c.DefaultSchema; 168 | stgCol.RowGuidCol = c.RowGuidCol; 169 | if (srv.VersionMajor >= 10) 170 | { 171 | stgCol.IsFileStream = c.IsFileStream; 172 | stgCol.IsSparse = c.IsSparse; 173 | stgCol.IsColumnSet = c.IsColumnSet; 174 | } 175 | stgTable.Columns.Add(stgCol); 176 | } 177 | // Match other new table attributes to the partition table; required for SWITCH compatibility 178 | stgTable.AnsiNullsStatus = partitionTable.AnsiNullsStatus; 179 | stgTable.QuotedIdentifierStatus = partitionTable.QuotedIdentifierStatus; 180 | // Calculate the filegroup associated with the partition nunber to switch; create temp table in that filegroup 181 | stgTable.FileGroup = db.PartitionSchemes[partitionTable.PartitionScheme].FileGroups[partitionNumber - 1]; 182 | stgTable.TextFileGroup = db.PartitionSchemes[partitionTable.PartitionScheme].FileGroups[partitionNumber - 1]; 183 | 184 | if (srv.VersionMajor >= 10) 185 | { 186 | // Define compression property to match by creating a Physical Partition object 187 | PhysicalPartition stgPartition = new PhysicalPartition(stgTable, 1, partitionTable.PhysicalPartitions[partitionNumber - 1].DataCompression); 188 | stgTable.PhysicalPartitions.Add(stgPartition); 189 | } 190 | scriptChunks.Add(stgTable.Script()); 191 | if (executeCommands) stgTable.Create(); 192 | } 193 | /* 194 | public void CreateStgIndexes() 195 | { 196 | CreateStgIndexes(true); 197 | } 198 | */ 199 | public void CreateStgIndexes(bool createNonClusteredIndexes) 200 | { 201 | // start with Clustered 202 | createStgClusteredIndex(); 203 | // then create non-clustered indexes, along with indexed views, if requested 204 | if (createNonClusteredIndexes) 205 | { 206 | createStgNonclusteredIndexes(); 207 | createStgIndexedViews(); 208 | } 209 | } 210 | public void CreateStgFkeys() 211 | { 212 | // Apply any Foreign Key constraints on the new table that are present on the Partition Table 213 | foreach (ForeignKey fKey in partitionTable.ForeignKeys) 214 | { 215 | ForeignKey newFKey = new ForeignKey(stgTable, stgTable.Name + "_" + fKey.Name); 216 | newFKey.DeleteAction = fKey.DeleteAction; 217 | newFKey.IsChecked = fKey.IsChecked; 218 | newFKey.IsEnabled = fKey.IsEnabled; 219 | newFKey.ReferencedTable = fKey.ReferencedTable; 220 | newFKey.ReferencedTableSchema = fKey.ReferencedTableSchema; 221 | newFKey.UpdateAction = fKey.UpdateAction; 222 | foreach (ForeignKeyColumn col in fKey.Columns) 223 | { 224 | ForeignKeyColumn newCol = new ForeignKeyColumn(newFKey, col.Name, col.ReferencedColumn); 225 | newFKey.Columns.Add(newCol); 226 | } 227 | scriptChunks.Add(newFKey.Script()); 228 | if (executeCommands) newFKey.Create(); 229 | } 230 | } 231 | public void CreateStgChecks() 232 | { 233 | // Apply any Check constraints to the new table that are present on the Partition Table 234 | foreach (Check chkConstr in partitionTable.Checks) 235 | { 236 | Check newCheck = new Check(stgTable, stgTable.Name + "_" + chkConstr.Name); 237 | newCheck.IsChecked = chkConstr.IsChecked; 238 | newCheck.IsEnabled = chkConstr.IsEnabled; 239 | newCheck.Text = chkConstr.Text; 240 | scriptChunks.Add(newCheck.Script()); 241 | if (executeCommands) newCheck.Create(); 242 | } 243 | } 244 | public void CreateStgPartitionCheck() 245 | { 246 | // Now construct appropriate CHECK CONSTRAINT based on partition boundaries 247 | // We need to distinguish between dates, unicode vs. nonunicode strings, and numeric 248 | // values embedded in the partition boundarty collection. We do this by evaluating the 249 | // data type of the partition column, and then construct the Check Constraint string 250 | // appropriately quoted 251 | Check partitionCheckConstraint = new Check(stgTable, "chk_" + stgTable.Name + "_partition_" + partitionNumber.ToString(System.Globalization.CultureInfo.InvariantCulture)); 252 | String leftBoundary = ""; 253 | String rightBoundary = ""; 254 | String partitionColumnName = partitionTable.PartitionSchemeParameters[0].Name; 255 | String partitionColumnQuotedName = "[" + partitionColumnName + "]"; 256 | SqlDataType partitionColumnType = partitionTable.Columns[partitionColumnName].DataType.SqlDataType; 257 | 258 | 259 | // Construct the minimum value predicate string in the check constraint definition 260 | if (partitionNumber > 1) 261 | { 262 | leftBoundary = partitionColumnQuotedName + ((pf.RangeType == RangeType.Right) ? ">=" : ">") + localeIndependentText(partitionColumnType, pf.RangeValues[partitionNumber - 2]); 263 | } 264 | // Construct the maximum value predicate string in the check constraint definition 265 | if (partitionNumber < pf.NumberOfPartitions) 266 | { 267 | rightBoundary = partitionColumnQuotedName + ((pf.RangeType == RangeType.Right) ? "<" : "<=") + localeIndependentText(partitionColumnType, pf.RangeValues[partitionNumber - 1]); 268 | } 269 | // Assemble the full Check Constraint string 270 | // If the partitioning column is nullable 271 | // If the partition is the leftmost, allow NULLs in the check constraint, otherwise add NOT NULL check constraint 272 | String constraintText = 273 | ((partitionTable.Columns[partitionColumnName].Nullable) ? partitionColumnQuotedName + 274 | ((partitionNumber == 1) ? " IS NULL OR " : " IS NOT NULL AND ") 275 | : "" 276 | ) 277 | + "(" + leftBoundary + 278 | (((partitionNumber > 1) && (partitionNumber < pf.NumberOfPartitions)) ? " AND " : "") + 279 | rightBoundary + ")"; 280 | partitionCheckConstraint.IsEnabled = true; 281 | partitionCheckConstraint.Text = constraintText; 282 | // Create the Check Constraint 283 | scriptChunks.Add(partitionCheckConstraint.Script()); 284 | if (executeCommands) partitionCheckConstraint.Create(); 285 | } 286 | /* 287 | public void ClearPartition() 288 | { 289 | String s = ClearPartition(false); 290 | } 291 | */ 292 | public string ClearPartition(bool keepTable) 293 | { 294 | string cmd = "ALTER TABLE [" + partitionTable.Schema + "].[" + partitionTable.Name + "] SWITCH PARTITION " + 295 | partitionNumber.ToString() + " TO [" + stgTable.Schema + "].[" + stgTable.Name + "];"; 296 | System.Collections.Specialized.StringCollection sc = new System.Collections.Specialized.StringCollection(); 297 | sc.Add(cmd); 298 | if (executeCommands) partitionTable.SwitchPartition(partitionNumber, stgTable); 299 | 300 | if (!keepTable) 301 | { 302 | string dropCmd = "DROP TABLE [" + stgTable.Schema + "].[" + stgTable.Name + "];"; 303 | sc.Add(dropCmd); 304 | if (executeCommands) stgTable.Drop(); 305 | } 306 | scriptChunks.Add(sc); 307 | return keepTable ? stgTable.Name : null; 308 | } 309 | 310 | private void createStgClusteredIndex() 311 | { 312 | // Ignore if clustered index already exists, or if we are scripting only 313 | if ((!executeCommands) || (!stgTable.HasClusteredIndex)) 314 | { 315 | foreach (Index i in partitionTable.Indexes) 316 | { 317 | if (i.IsClustered && !i.IsDisabled) 318 | { 319 | createStgIndex(i, stgTable); 320 | break; 321 | } 322 | } 323 | } 324 | } 325 | private void createStgIndexedViews() 326 | { 327 | // Create a list of existing Indexed Views on the partition table 328 | List indexedViews = new List(); 329 | // Examine each view in the database 330 | foreach (View v in db.Views) 331 | { 332 | if (v.HasIndex) 333 | { 334 | // If it has an index, check if parent table is the partitioned table of interest 335 | string fullName = (string)conn.ExecuteScalar("SELECT DISTINCT Referenced_Schema_Name+'.'+Referenced_Entity_Name FROM sys.dm_sql_referenced_entities ('" + v.Schema + "." + v.Name + "', 'OBJECT')"); 336 | string sch = fullName.Substring(0, fullName.IndexOf('.')); 337 | string tab = fullName.Substring(fullName.IndexOf('.') + 1, fullName.Length - (fullName.IndexOf('.')+1)); 338 | if (sch == partitionTable.Schema && tab == partitionTable.Name) 339 | { 340 | indexedViews.Add(v); 341 | } 342 | } 343 | } 344 | foreach (View v in indexedViews) 345 | { 346 | createIndexedView(v); 347 | } 348 | } 349 | private void createIndexedView(View sourceView) 350 | { 351 | View stgView = new View(db, stgTable.Name + "_" + sourceView.Name, stgTable.Schema); 352 | stgView.TextHeader = "CREATE VIEW " + stgTable.Schema + "." + stgView.Name + " WITH SCHEMABINDING AS "; 353 | // Replace name of Partitioned Table in the view definition with the Staging Table name, wherever it occurs 354 | stgView.TextBody = Regex.Replace 355 | (sourceView.TextBody, @"([\W\s])" + partitionTable.Name + @"([\W\s])", @"$1" + stgTable.Name + @"$2",RegexOptions.IgnoreCase); 356 | // Create the view 357 | scriptChunks.Add(stgView.Script()); 358 | if (executeCommands) stgView.Create(); 359 | 360 | // Create the view's clustered index first 361 | foreach (Index i in sourceView.Indexes) 362 | { 363 | if (i.IsClustered) 364 | { 365 | createStgIndex(i, stgView); 366 | break; 367 | } 368 | } 369 | // Create any nonclustered indexes 370 | foreach (Index i in sourceView.Indexes) 371 | { 372 | if (!i.IsClustered) 373 | { 374 | createStgIndex(i, stgView); 375 | } 376 | } 377 | 378 | } 379 | private void createStgNonclusteredIndexes() 380 | { 381 | foreach (Index i in partitionTable.Indexes) 382 | { 383 | if (!i.IsClustered && !i.IsXmlIndex && !i.IsDisabled) 384 | { 385 | createStgIndex(i, stgTable); 386 | } 387 | } 388 | } 389 | private void createStgIndex(Index i, TableViewBase parent) 390 | { 391 | if (i.PartitionScheme == "") 392 | throw (new System.NotSupportedException( 393 | String.Format("The index '{0}' is not aligned to a Partition Scheme", i.Name))); 394 | 395 | // todo: differentiate between Base Table as source, and View as source 396 | 397 | // LZAV: Index stgIndex = new Index(parent, parent.Name + "_" + i.Name); 398 | String indexName = parent.Name + "_" + i.Name; // LZAV 399 | if (indexName.Length > 128) // LZAV 400 | indexName = "IX_CL_" + parent.Name; // LZAV 401 | 402 | Index stgIndex = new Index(parent, indexName); // LZAV 403 | 404 | foreach (IndexedColumn iCol in i.IndexedColumns) 405 | { 406 | IndexedColumn stgICol = new IndexedColumn(stgIndex, iCol.Name, iCol.Descending); 407 | stgICol.IsIncluded = iCol.IsIncluded; 408 | stgIndex.IndexedColumns.Add(stgICol); 409 | } 410 | stgIndex.IndexType = i.IndexType; 411 | stgIndex.IndexKeyType = i.IndexKeyType; 412 | stgIndex.IsClustered = i.IsClustered; 413 | stgIndex.IsUnique = i.IsUnique; 414 | stgIndex.CompactLargeObjects = i.CompactLargeObjects; 415 | stgIndex.IgnoreDuplicateKeys = i.IgnoreDuplicateKeys; 416 | stgIndex.IsFullTextKey = i.IsFullTextKey; 417 | stgIndex.PadIndex = i.PadIndex; 418 | stgIndex.FileGroup = db.PartitionSchemes[i.PartitionScheme].FileGroups[partitionNumber - 1]; 419 | 420 | // add the partitioning column to the index if it is not already there 421 | String partitionKeyName = i.PartitionSchemeParameters[0].Name; 422 | if (stgIndex.IndexedColumns[partitionKeyName] == null) 423 | { 424 | IndexedColumn stgICol = new IndexedColumn(stgIndex, partitionKeyName); 425 | // It is added as a Key to the Clustered index and as an Include column to a Nonclustered 426 | stgICol.IsIncluded = !stgIndex.IsClustered; 427 | stgIndex.IndexedColumns.Add(stgICol); 428 | } 429 | 430 | if (srv.VersionMajor >= 10) 431 | { 432 | // Define compression property to match by creating a Physical Partition object (not applicable to Colstore) 433 | { 434 | PhysicalPartition stgPartition = new PhysicalPartition(stgIndex, 1); 435 | if (i.IndexType != IndexType.NonClusteredColumnStoreIndex) 436 | { 437 | stgPartition.DataCompression = i.PhysicalPartitions[partitionNumber - 1].DataCompression; 438 | } 439 | stgIndex.PhysicalPartitions.Add(stgPartition); 440 | } 441 | // Handle Filtered Index 442 | if (i.HasFilter) 443 | { 444 | stgIndex.FilterDefinition = i.FilterDefinition; 445 | } 446 | } 447 | scriptChunks.Add(stgIndex.Script()); 448 | if (executeCommands) stgIndex.Create(); 449 | } 450 | // Compute the partition number corresponding to a range value of this instance's partition function 451 | // Done by executing the query: 452 | // Select .$partition.() 453 | // and relying on implicit conversion from string to the appropriate data type of the partitioning column 454 | private int getPartitionNumber(String rangeValue) 455 | { 456 | SqlConnection c = conn.SqlConnectionObject; 457 | String sqlText = "Select "+db.Name+".$partition."+pf.Name+"(@rangeValue)"; 458 | using (SqlCommand cmd = new SqlCommand(sqlText, c)) 459 | { 460 | cmd.Parameters.Add(new SqlParameter("@rangeValue", rangeValue)); 461 | return (int)cmd.ExecuteScalar(); 462 | } 463 | } 464 | 465 | // Create a string representation of a partition boundary value appropriate for use in CHECK CONSTRAINT 466 | // expressions, taking a SQL Data Type and Range Value object as inputs. 467 | // In particular ensure that date strings are represented in locale-independent formats appropriate for global 468 | // use. And unpack binary datatypes to deliver "0x..." string representation. 469 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] 470 | private static string localeIndependentText(SqlDataType sqlType, object rangeValue) 471 | { 472 | string hexString = ""; 473 | switch (sqlType) 474 | { 475 | case SqlDataType.Date: 476 | return "'" + ((DateTime)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss", System.Globalization.CultureInfo.InvariantCulture) + "'"; 477 | case SqlDataType.SmallDateTime: 478 | return "'" + ((DateTime)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss", System.Globalization.CultureInfo.InvariantCulture) + "'"; 479 | case SqlDataType.DateTime: 480 | return "'" + ((DateTime)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture) + "'"; 481 | case SqlDataType.DateTime2: 482 | return "'" + ((DateTime)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss.fffffff", System.Globalization.CultureInfo.InvariantCulture) + "'"; 483 | case SqlDataType.DateTimeOffset: 484 | return "'" + ((DateTimeOffset)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss.fffffffK", System.Globalization.CultureInfo.InvariantCulture) + "'"; 485 | case SqlDataType.Time: 486 | return "'" + ((TimeSpan)rangeValue).ToString() + "'"; 487 | case SqlDataType.Char: 488 | return "'" + (String)rangeValue + "'"; 489 | case SqlDataType.VarChar: 490 | return "'" + (String)rangeValue + "'"; 491 | case SqlDataType.NChar: 492 | return "N'" + (String)rangeValue + "'"; 493 | case SqlDataType.NVarChar: 494 | return "N'" + (String)rangeValue + "'"; 495 | case SqlDataType.Binary: 496 | foreach (Byte b in (Byte[])rangeValue) 497 | { 498 | hexString += b.ToString("x2", System.Globalization.CultureInfo.InvariantCulture); 499 | } 500 | return "0x" + hexString; 501 | case SqlDataType.VarBinary: 502 | foreach (Byte b in (Byte[])rangeValue) 503 | { 504 | hexString += b.ToString("x2", System.Globalization.CultureInfo.InvariantCulture); 505 | } 506 | return "0x" + hexString; 507 | case SqlDataType.Bit: 508 | return (((Boolean)rangeValue) ? "1" : "0"); 509 | case SqlDataType.Int: 510 | return rangeValue.ToString(); 511 | case SqlDataType.BigInt: 512 | return rangeValue.ToString(); 513 | case SqlDataType.SmallInt: 514 | return rangeValue.ToString(); 515 | case SqlDataType.TinyInt: 516 | return rangeValue.ToString(); 517 | 518 | // Note -- SQL Server partition boundary values for FLOATs are precise only to 14 digits, so ensure the 519 | // Check Constraint value matches that precision 520 | case SqlDataType.Float: 521 | return ((Double)rangeValue).ToString("E14", System.Globalization.CultureInfo.InvariantCulture); 522 | 523 | // Note -- SQL2012 RTM incorrectly handles REAL / (Float(24)) metadata in Check Constraints, 524 | // use Float (53) instead to support partition switching. Bug has been filed. 525 | case SqlDataType.Real: 526 | return ((Single)rangeValue).ToString("E6", System.Globalization.CultureInfo.InvariantCulture); 527 | 528 | case SqlDataType.Numeric: 529 | return rangeValue.ToString(); 530 | case SqlDataType.Decimal: 531 | return rangeValue.ToString(); 532 | case SqlDataType.Money: 533 | return rangeValue.ToString(); 534 | case SqlDataType.SmallMoney: 535 | return rangeValue.ToString(); 536 | default: 537 | throw (new System.NotSupportedException("Unsupported Data Type found as Partition Key")); 538 | } 539 | } 540 | 541 | public void outputScript() 542 | { 543 | foreach (System.Collections.Specialized.StringCollection sc in scriptChunks) 544 | { 545 | foreach (string s in sc) 546 | { 547 | if (scriptWriter == null) 548 | { 549 | Console.WriteLine(s); 550 | } 551 | else 552 | { 553 | scriptWriter.WriteLine(s); 554 | } 555 | } 556 | } 557 | } 558 | } 559 | } 560 | -------------------------------------------------------------------------------- /PartitionManagement/PartitionManagement2014.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {1BE0E539-3459-4C57-AB49-F3FD5750212A} 9 | Exe 10 | Properties 11 | PartitionManagement 12 | ManagePartition 13 | true 14 | 15 | 16 | 17 | 18 | 3.5 19 | v3.5 20 | 21 | http://localhost/ManagePartition/ 22 | true 23 | Web 24 | true 25 | Foreground 26 | 7 27 | Days 28 | false 29 | false 30 | true 31 | 0 32 | 3.1.0.%2a 33 | false 34 | true 35 | false 36 | 37 | 38 | true 39 | full 40 | false 41 | bin\Debug\ 42 | DEBUG;TRACE 43 | prompt 44 | 4 45 | AllRules.ruleset 46 | 47 | 48 | pdbonly 49 | true 50 | bin\Release\ 51 | TRACE 52 | prompt 53 | 4 54 | AllRules.ruleset 55 | true 56 | 57 | 58 | 930EEE92AB704AE7EE8DF063217AFBAD6C00E2DA 59 | 60 | 61 | PartitionManagement_TemporaryKey.pfx 62 | 63 | 64 | false 65 | 66 | 67 | LocalIntranet 68 | 69 | 70 | Properties\app.manifest 71 | 72 | 73 | false 74 | 75 | 76 | 77 | False 78 | ..\..\..\..\..\..\..\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll 79 | 80 | 81 | False 82 | ..\..\..\..\..\..\..\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Management.Sdk.Sfc.dll 83 | 84 | 85 | False 86 | ..\..\..\..\..\..\..\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Smo.dll 87 | 88 | 89 | False 90 | ..\..\..\..\..\..\..\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.SqlEnum.dll 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | False 107 | .NET Framework 3.5 SP1 Client Profile 108 | false 109 | 110 | 111 | False 112 | .NET Framework 2.0 %28x86%29 113 | false 114 | 115 | 116 | False 117 | .NET Framework 3.0 %28x86%29 118 | false 119 | 120 | 121 | False 122 | .NET Framework 3.5 123 | false 124 | 125 | 126 | False 127 | .NET Framework 3.5 SP1 128 | true 129 | 130 | 131 | False 132 | Microsoft® System CLR Types for SQL Server® 2012 %28x64%29 133 | true 134 | 135 | 136 | False 137 | Microsoft® System CLR Types for SQL Server® 2012 %28x86%29 138 | true 139 | 140 | 141 | False 142 | Windows Installer 4.5 143 | true 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 159 | -------------------------------------------------------------------------------- /PartitionManagement/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("PartitionManagement")] 9 | [assembly: AssemblyDescription("Patch by Luca Zavarella to avoid the deadlocks")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("PartitionManagement")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2012")] 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("5ac6f10f-bb89-43d7-8f86-d6843f662068")] 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 | [assembly: AssemblyVersion("3.1.0.0")] 33 | [assembly: AssemblyFileVersion("3.1.0.0")] 34 | -------------------------------------------------------------------------------- /PartitionManagement/Properties/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 52 | -------------------------------------------------------------------------------- /PartitionManagement/Utility.cs: -------------------------------------------------------------------------------- 1 | namespace Utilities 2 | { 3 | using System; 4 | 5 | /// 6 | /// A delegate used in error reporting. 7 | /// 8 | public delegate void ErrorReporter(string message); 9 | 10 | /// 11 | /// Useful Stuff. 12 | /// 13 | public sealed class Utility 14 | { 15 | /// 16 | /// The System Defined new line string. 17 | /// 18 | public const string NewLine = "\r\n"; 19 | 20 | /// 21 | /// Don't ever call this. 22 | /// 23 | private Utility() { } 24 | 25 | /// 26 | /// Parses Command Line Arguments. 27 | /// Errors are output on Console.Error. 28 | /// Use CommandLineArgumentAttributes to control parsing behaviour. 29 | /// 30 | /// The actual arguments. 31 | /// The resulting parsed arguments. 32 | /// true if no errors were detected. 33 | public static bool ParseCommandLineArguments(string[] arguments, object destination) 34 | { 35 | return ParseCommandLineArguments(arguments, destination, new ErrorReporter(Console.Error.WriteLine)); 36 | } 37 | 38 | /// 39 | /// Parses Command Line Arguments. 40 | /// Use CommandLineArgumentAttributes to control parsing behaviour. 41 | /// 42 | /// The actual arguments. 43 | /// The resulting parsed arguments. 44 | /// The destination for parse errors. 45 | /// true if no errors were detected. 46 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1")] 47 | public static bool ParseCommandLineArguments(string[] arguments, object destination, ErrorReporter reporter) 48 | { 49 | CommandLineArgumentParser parser = new CommandLineArgumentParser(destination.GetType(), reporter); 50 | return parser.Parse(arguments, destination); 51 | } 52 | /// 53 | /// Returns a Usage string for command line argument parsing. 54 | /// Use CommandLineArgumentAttributes to control parsing behaviour. 55 | /// 56 | /// The type of the arguments to display usage for. 57 | /// Printable string containing a user friendly description of command line arguments. 58 | public static string CommandLineArgumentsUsage(Type argumentType) 59 | { 60 | return (new CommandLineArgumentParser(argumentType, null)).Usage; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /PartitionManagement/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /PartitionManagement2012/CommandLineArguments.cs: -------------------------------------------------------------------------------- 1 | namespace Utilities 2 | { 3 | using System; 4 | using System.Diagnostics; 5 | using System.Reflection; 6 | using System.Collections; 7 | using System.IO; 8 | using System.Text; 9 | 10 | /// 11 | /// Used to control parsing of command line arguments. 12 | /// 13 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1714:FlagsEnumsShouldHavePluralNames"), Flags] 14 | public enum CommandLineArgumentType 15 | { 16 | /// 17 | /// Indicates that this field is required. An error will be displayed 18 | /// if it is not present when parsing arguments. 19 | /// 20 | Required = 0x01, 21 | /// 22 | /// Only valid in conjunction with Multiple. 23 | /// Duplicate values will result in an error. 24 | /// 25 | Unique = 0x02, 26 | /// 27 | /// Inidicates that the argument may be specified more than once. 28 | /// Only valid if the argument is a collection 29 | /// 30 | Multiple = 0x04, 31 | 32 | /// 33 | /// The default type for non-collection arguments. 34 | /// The argument is not required, but an error will be reported if it is specified more than once. 35 | /// 36 | AtMostOnce = 0x00, 37 | 38 | /// 39 | /// For non-collection arguments, when the argument is specified more than 40 | /// once no error is reported and the value of the argument is the last 41 | /// value which occurs in the argument list. 42 | /// 43 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Occurence")] 44 | LastOccurenceWins = Multiple, 45 | 46 | /// 47 | /// The default type for collection arguments. 48 | /// The argument is permitted to occur multiple times, but duplicate 49 | /// values will cause an error to be reported. 50 | /// 51 | MultipleUnique = Multiple | Unique, 52 | } 53 | 54 | /// 55 | /// Allows control of command line parsing. 56 | /// Attach this attribute to instance fields of types used 57 | /// as the destination of command line argument parsing. 58 | /// 59 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes"), AttributeUsage(AttributeTargets.Field)] 60 | public class CommandLineArgumentAttribute : Attribute 61 | { 62 | /// 63 | /// Allows control of command line parsing. 64 | /// 65 | /// Specifies the error checking to be done on the argument. 66 | public CommandLineArgumentAttribute(CommandLineArgumentType type) 67 | { 68 | this.type = type; 69 | } 70 | 71 | /// 72 | /// The error checking to be done on the argument. 73 | /// 74 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] 75 | public CommandLineArgumentType Type 76 | { 77 | get { return this.type; } 78 | } 79 | /// 80 | /// Returns true if the argument did not have an explicit short name specified. 81 | /// 82 | public bool DefaultShortName { get { return null == this.shortName; } } 83 | 84 | /// 85 | /// The short name of the argument. 86 | /// 87 | public string ShortName 88 | { 89 | get { return this.shortName; } 90 | set { this.shortName = value; } 91 | } 92 | 93 | /// 94 | /// Returns true if the argument did not have an explicit long name specified. 95 | /// 96 | public bool DefaultLongName { get { return null == this.longName; } } 97 | 98 | /// 99 | /// The long name of the argument. 100 | /// 101 | public string LongName 102 | { 103 | get { Debug.Assert(!this.DefaultLongName); return this.longName; } 104 | set { this.longName = value; } 105 | } 106 | 107 | private string shortName; 108 | private string longName; 109 | private CommandLineArgumentType type; 110 | } 111 | 112 | /// 113 | /// Indicates that this argument is the default argument. 114 | /// '/' or '-' prefix only the argument value is specified. 115 | /// 116 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes"), AttributeUsage(AttributeTargets.Field)] 117 | public class DefaultCommandLineArgumentAttribute : CommandLineArgumentAttribute 118 | { 119 | /// 120 | /// Indicates that this argument is the default argument. 121 | /// 122 | /// Specifies the error checking to be done on the argument. 123 | public DefaultCommandLineArgumentAttribute(CommandLineArgumentType type) 124 | : base(type) 125 | { 126 | } 127 | } 128 | 129 | /// 130 | /// Parser for command line arguments. 131 | /// 132 | /// The parser specification is infered from the instance fields of the object 133 | /// specified as the destination of the parse. 134 | /// Valid argument types are: int, uint, string, bool, enums 135 | /// Also argument types of Array of the above types are also valid. 136 | /// 137 | /// Error checking options can be controlled by adding a CommandLineArgumentAttribute 138 | /// to the instance fields of the destination object. 139 | /// 140 | /// At most one field may be marked with the DefaultCommandLineArgumentAttribute 141 | /// indicating that arguments without a '-' or '/' prefix will be parsed as that argument. 142 | /// 143 | /// If not specified then the parser will infer default options for parsing each 144 | /// instance field. The default long name of the argument is the field name. The 145 | /// default short name is the first character of the long name. Long names and explicitly 146 | /// specified short names must be unique. Default short names will be used provided that 147 | /// the default short name does not conflict with a long name or an explicitly 148 | /// specified short name. 149 | /// 150 | /// Arguments which are array types are collection arguments. Collection 151 | /// arguments can be specified multiple times. 152 | /// 153 | public class CommandLineArgumentParser 154 | { 155 | /// 156 | /// Creates a new command line argument parser. 157 | /// 158 | /// The type of object to parse. 159 | /// The destination for parse errors. 160 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] 161 | public CommandLineArgumentParser(Type argumentSpecification, ErrorReporter reporter) 162 | { 163 | this.reporter = reporter; 164 | this.arguments = new ArrayList(); 165 | this.argumentMap = new Hashtable(); 166 | 167 | foreach (FieldInfo field in argumentSpecification.GetFields()) 168 | { 169 | if (!field.IsStatic && !field.IsInitOnly && !field.IsLiteral) 170 | { 171 | CommandLineArgumentAttribute attribute = GetAttribute(field); 172 | if (attribute is DefaultCommandLineArgumentAttribute) 173 | { 174 | Debug.Assert(this.defaultArgument == null); 175 | this.defaultArgument = new Argument(attribute, field, reporter); 176 | } 177 | else 178 | { 179 | this.arguments.Add(new Argument(attribute, field, reporter)); 180 | } 181 | } 182 | } 183 | 184 | // add explicit names to map 185 | foreach (Argument argument in this.arguments) 186 | { 187 | Debug.Assert(!argumentMap.ContainsKey(argument.LongName)); 188 | this.argumentMap[argument.LongName] = argument; 189 | if (argument.ExplicitShortName && argument.ShortName != null && argument.ShortName.Length > 0) 190 | { 191 | Debug.Assert(!argumentMap.ContainsKey(argument.ShortName)); 192 | this.argumentMap[argument.ShortName] = argument; 193 | } 194 | } 195 | 196 | // add implicit names which don't collide to map 197 | foreach (Argument argument in this.arguments) 198 | { 199 | if (!argument.ExplicitShortName && argument.ShortName != null && argument.ShortName.Length > 0) 200 | { 201 | if (!argumentMap.ContainsKey(argument.ShortName)) 202 | this.argumentMap[argument.ShortName] = argument; 203 | } 204 | } 205 | } 206 | 207 | private static CommandLineArgumentAttribute GetAttribute(FieldInfo field) 208 | { 209 | object[] attributes = field.GetCustomAttributes(typeof(CommandLineArgumentAttribute), false); 210 | if (attributes.Length == 1) 211 | return (CommandLineArgumentAttribute)attributes[0]; 212 | 213 | Debug.Assert(attributes.Length == 0); 214 | return null; 215 | } 216 | 217 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)")] 218 | private void ReportUnrecognizedArgument(string argument) 219 | { 220 | this.reporter(string.Format("Unrecognized command line argument '{0}'", argument)); 221 | } 222 | 223 | /// 224 | /// Parses an argument list into an object 225 | /// 226 | /// 227 | /// 228 | /// true if an error occurred 229 | private bool ParseArgumentList(string[] args, object destination) 230 | { 231 | bool hadError = false; 232 | if (args != null) 233 | { 234 | foreach (string argument in args) 235 | { 236 | if (argument.Length > 0) 237 | { 238 | switch (argument[0]) 239 | { 240 | case '-': 241 | case '/': 242 | int endIndex = argument.IndexOfAny(new char[] { ':', '+', '-' }, 1); 243 | string option = argument.Substring(1, endIndex == -1 ? argument.Length - 1 : endIndex - 1); 244 | string optionArgument; 245 | if (option.Length + 1 == argument.Length) 246 | { 247 | optionArgument = null; 248 | } 249 | else if (argument.Length > 1 + option.Length && argument[1 + option.Length] == ':') 250 | { 251 | optionArgument = argument.Substring(option.Length + 2); 252 | } 253 | else 254 | { 255 | optionArgument = argument.Substring(option.Length + 1); 256 | } 257 | 258 | Argument arg = (Argument)this.argumentMap[option]; 259 | if (arg == null) 260 | { 261 | ReportUnrecognizedArgument(argument); 262 | hadError = true; 263 | } 264 | else 265 | { 266 | hadError |= !arg.SetValue(optionArgument, destination); 267 | } 268 | break; 269 | case '@': 270 | string[] nestedArguments; 271 | hadError |= LexFileArguments(argument.Substring(1), out nestedArguments); 272 | hadError |= ParseArgumentList(nestedArguments, destination); 273 | break; 274 | default: 275 | if (this.defaultArgument != null) 276 | { 277 | hadError |= !this.defaultArgument.SetValue(argument, destination); 278 | } 279 | else 280 | { 281 | ReportUnrecognizedArgument(argument); 282 | hadError = true; 283 | } 284 | break; 285 | } 286 | } 287 | } 288 | } 289 | 290 | return hadError; 291 | } 292 | 293 | /// 294 | /// Parses an argument list. 295 | /// 296 | /// The arguments to parse. 297 | /// The destination of the parsed arguments. 298 | /// true if no parse errors were encountered. 299 | public bool Parse(string[] args, object destination) 300 | { 301 | bool hadError = ParseArgumentList(args, destination); 302 | 303 | // check for missing required arguments 304 | foreach (Argument arg in this.arguments) 305 | { 306 | hadError |= arg.Finish(destination); 307 | } 308 | if (this.defaultArgument != null) 309 | { 310 | hadError |= this.defaultArgument.Finish(destination); 311 | } 312 | 313 | return !hadError; 314 | } 315 | 316 | 317 | /// 318 | /// A user firendly usage string describing the command line argument syntax. 319 | /// 320 | public string Usage 321 | { 322 | get 323 | { 324 | StringBuilder builder = new StringBuilder(); 325 | 326 | int oldLength; 327 | foreach (Argument arg in this.arguments) 328 | { 329 | oldLength = builder.Length; 330 | 331 | builder.Append(" /"); 332 | builder.Append(arg.LongName); 333 | Type valueType = arg.ValueType; 334 | if (valueType == typeof(int)) 335 | { 336 | builder.Append(":"); 337 | } 338 | else if (valueType == typeof(uint)) 339 | { 340 | builder.Append(":"); 341 | } 342 | else if (valueType == typeof(bool)) 343 | { 344 | builder.Append("[+|-]"); 345 | } 346 | else if (valueType == typeof(string)) 347 | { 348 | builder.Append(":"); 349 | } 350 | else 351 | { 352 | Debug.Assert(valueType.IsEnum); 353 | 354 | builder.Append(":{"); 355 | bool first = true; 356 | foreach (FieldInfo field in valueType.GetFields()) 357 | { 358 | if (field.IsStatic) 359 | { 360 | if (first) 361 | first = false; 362 | else 363 | builder.Append('|'); 364 | builder.Append(field.Name); 365 | } 366 | } 367 | builder.Append('}'); 368 | } 369 | 370 | if (arg.ShortName != arg.LongName && this.argumentMap[arg.ShortName] == arg) 371 | { 372 | builder.Append(' ', IndentLength(builder.Length - oldLength)); 373 | builder.Append("short form /"); 374 | builder.Append(arg.ShortName); 375 | } 376 | 377 | builder.Append(Utility.NewLine); 378 | } 379 | 380 | oldLength = builder.Length; 381 | builder.Append(" @"); 382 | builder.Append(' ', IndentLength(builder.Length - oldLength)); 383 | builder.Append("Read response file for more options"); 384 | builder.Append(Utility.NewLine); 385 | 386 | if (this.defaultArgument != null) 387 | { 388 | oldLength = builder.Length; 389 | builder.Append(" <"); 390 | builder.Append(this.defaultArgument.LongName); 391 | builder.Append(">"); 392 | builder.Append(Utility.NewLine); 393 | } 394 | 395 | return builder.ToString(); 396 | } 397 | } 398 | 399 | private static int IndentLength(int lineLength) 400 | { 401 | return Math.Max(4, 40 - lineLength); 402 | } 403 | 404 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "arguments")] 405 | private bool LexFileArguments(string fileName, out string[] arguments) 406 | { 407 | string args = null; 408 | 409 | try 410 | { 411 | using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read)) 412 | { 413 | args = (new StreamReader(file)).ReadToEnd(); 414 | } 415 | } 416 | catch (Exception e) 417 | { 418 | this.reporter(string.Format("Error: Can't open command line argument file '{0}' : '{1}'", fileName, e.Message)); 419 | arguments = null; 420 | return false; 421 | } 422 | 423 | bool hadError = false; 424 | ArrayList argArray = new ArrayList(); 425 | StringBuilder currentArg = new StringBuilder(); 426 | bool inQuotes = false; 427 | int index = 0; 428 | 429 | // while (index < args.Length) 430 | try 431 | { 432 | while (true) 433 | { 434 | // skip whitespace 435 | while (char.IsWhiteSpace(args[index])) 436 | { 437 | index += 1; 438 | } 439 | 440 | // # - comment to end of line 441 | if (args[index] == '#') 442 | { 443 | index += 1; 444 | while (args[index] != '\n') 445 | { 446 | index += 1; 447 | } 448 | continue; 449 | } 450 | 451 | // do one argument 452 | do 453 | { 454 | if (args[index] == '\\') 455 | { 456 | int cSlashes = 1; 457 | index += 1; 458 | while (index == args.Length && args[index] == '\\') 459 | { 460 | cSlashes += 1; 461 | } 462 | 463 | if (index == args.Length || args[index] != '"') 464 | { 465 | currentArg.Append('\\', cSlashes); 466 | } 467 | else 468 | { 469 | currentArg.Append('\\', (cSlashes >> 1)); 470 | if (0 != (cSlashes & 1)) 471 | { 472 | currentArg.Append('"'); 473 | } 474 | else 475 | { 476 | inQuotes = !inQuotes; 477 | } 478 | } 479 | } 480 | else if (args[index] == '"') 481 | { 482 | inQuotes = !inQuotes; 483 | index += 1; 484 | } 485 | else 486 | { 487 | currentArg.Append(args[index]); 488 | index += 1; 489 | } 490 | } while (!char.IsWhiteSpace(args[index]) || inQuotes); 491 | argArray.Add(currentArg.ToString()); 492 | currentArg.Length = 0; 493 | } 494 | } 495 | catch (System.IndexOutOfRangeException) 496 | { 497 | // got EOF 498 | if (inQuotes) 499 | { 500 | this.reporter(string.Format("Error: Unbalanced '\"' in command line argument file '{0}'", fileName)); 501 | hadError = true; 502 | } 503 | else if (currentArg.Length > 0) 504 | { 505 | // valid argument can be terminated by EOF 506 | argArray.Add(currentArg.ToString()); 507 | } 508 | } 509 | 510 | arguments = (string[])argArray.ToArray(typeof(string)); 511 | return hadError; 512 | } 513 | 514 | private static string LongName(CommandLineArgumentAttribute attribute, FieldInfo field) 515 | { 516 | return (attribute == null || attribute.DefaultLongName) ? field.Name : attribute.LongName; 517 | } 518 | 519 | private static string ShortName(CommandLineArgumentAttribute attribute, FieldInfo field) 520 | { 521 | return !ExplicitShortName(attribute) ? LongName(attribute, field).Substring(0, 1) : attribute.ShortName; 522 | } 523 | 524 | private static bool ExplicitShortName(CommandLineArgumentAttribute attribute) 525 | { 526 | return (attribute != null && !attribute.DefaultShortName); 527 | } 528 | 529 | private static Type ElementType(FieldInfo field) 530 | { 531 | if (IsCollectionType(field.FieldType)) 532 | return field.FieldType.GetElementType(); 533 | else 534 | return null; 535 | } 536 | 537 | private static CommandLineArgumentType Flags(CommandLineArgumentAttribute attribute, FieldInfo field) 538 | { 539 | if (attribute != null) 540 | return attribute.Type; 541 | else if (IsCollectionType(field.FieldType)) 542 | return CommandLineArgumentType.MultipleUnique; 543 | else 544 | return CommandLineArgumentType.AtMostOnce; 545 | } 546 | 547 | private static bool IsCollectionType(Type type) 548 | { 549 | return type.IsArray; 550 | } 551 | 552 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 553 | private static bool IsValidElementType(Type type) 554 | { 555 | return type != null && ( 556 | type == typeof(int) || 557 | type == typeof(uint) || 558 | type == typeof(string) || 559 | type == typeof(bool) || 560 | type.IsEnum); 561 | } 562 | 563 | private class Argument 564 | { 565 | public Argument(CommandLineArgumentAttribute attribute, FieldInfo field, ErrorReporter reporter) 566 | { 567 | this.longName = CommandLineArgumentParser.LongName(attribute, field); 568 | this.explicitShortName = CommandLineArgumentParser.ExplicitShortName(attribute); 569 | this.shortName = CommandLineArgumentParser.ShortName(attribute, field); 570 | this.elementType = ElementType(field); 571 | this.flags = Flags(attribute, field); 572 | this.field = field; 573 | this.seenValue = false; 574 | this.reporter = reporter; 575 | this.isDefault = attribute != null && attribute is DefaultCommandLineArgumentAttribute; 576 | 577 | if (IsCollection) 578 | { 579 | this.collectionValues = new ArrayList(); 580 | } 581 | 582 | Debug.Assert(this.longName != null && this.longName.Length > 0); 583 | Debug.Assert(!IsCollection || AllowMultiple, "Collection arguments must have allow multiple"); 584 | Debug.Assert(!Unique || IsCollection, "Unique only applicable to collection arguments"); 585 | Debug.Assert(IsValidElementType(Type) || 586 | IsCollectionType(Type)); 587 | Debug.Assert((IsCollection && IsValidElementType(elementType)) || 588 | (!IsCollection && elementType == null)); 589 | } 590 | 591 | public bool Finish(object destination) 592 | { 593 | if (this.IsCollection) 594 | { 595 | this.field.SetValue(destination, this.collectionValues.ToArray(this.elementType)); 596 | } 597 | 598 | return ReportMissingRequiredArgument(); 599 | } 600 | 601 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)")] 602 | private bool ReportMissingRequiredArgument() 603 | { 604 | if (this.IsRequired && !this.SeenValue) 605 | { 606 | if (this.IsDefault) 607 | reporter(string.Format("Missing required argument '<{0}>'.", this.LongName)); 608 | else 609 | reporter(string.Format("Missing required argument '/{0}'.", this.LongName)); 610 | return true; 611 | } 612 | return false; 613 | } 614 | 615 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)")] 616 | private void ReportDuplicateArgumentValue(string value) 617 | { 618 | this.reporter(string.Format("Duplicate '{0}' argument '{1}'", this.LongName, value)); 619 | } 620 | 621 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)")] 622 | public bool SetValue(string value, object destination) 623 | { 624 | if (SeenValue && !AllowMultiple) 625 | { 626 | this.reporter(string.Format("Duplicate '{0}' argument", this.LongName)); 627 | return false; 628 | } 629 | this.seenValue = true; 630 | 631 | object newValue; 632 | if (!ParseValue(this.ValueType, value, out newValue)) 633 | return false; 634 | if (this.IsCollection) 635 | { 636 | if (this.Unique && this.collectionValues.Contains(newValue)) 637 | { 638 | ReportDuplicateArgumentValue(value); 639 | return false; 640 | } 641 | else 642 | { 643 | this.collectionValues.Add(newValue); 644 | } 645 | } 646 | else 647 | { 648 | this.field.SetValue(destination, newValue); 649 | } 650 | 651 | return true; 652 | } 653 | 654 | public Type ValueType 655 | { 656 | get { return this.IsCollection ? this.elementType : this.Type; } 657 | } 658 | 659 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Utilities.ErrorReporter.Invoke(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)")] 660 | private void ReportBadArgumentValue(string value) 661 | { 662 | this.reporter(string.Format("'{0}' is not a valid value for the '{1}' command line option", value, this.LongName)); 663 | } 664 | 665 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.Parse(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 666 | private bool ParseValue(Type type, string stringData, out object value) 667 | { 668 | // null is only valid for bool variables 669 | // empty string is never valid 670 | if ((stringData != null || type == typeof(bool)) && (stringData == null || stringData.Length > 0)) 671 | { 672 | try 673 | { 674 | if (type == typeof(string)) 675 | { 676 | value = stringData; 677 | return true; 678 | } 679 | else if (type == typeof(bool)) 680 | { 681 | if (stringData == null || stringData == "+") 682 | { 683 | value = true; 684 | return true; 685 | } 686 | else if (stringData == "-") 687 | { 688 | value = false; 689 | return true; 690 | } 691 | } 692 | else if (type == typeof(int)) 693 | { 694 | value = int.Parse(stringData); 695 | return true; 696 | } 697 | else if (type == typeof(uint)) 698 | { 699 | value = int.Parse(stringData); 700 | return true; 701 | } 702 | else 703 | { 704 | Debug.Assert(type.IsEnum); 705 | value = Enum.Parse(type, stringData, true); 706 | return true; 707 | } 708 | } 709 | catch 710 | { 711 | // catch parse errors 712 | } 713 | } 714 | 715 | ReportBadArgumentValue(stringData); 716 | value = null; 717 | return false; 718 | } 719 | 720 | public string LongName 721 | { 722 | get { return this.longName; } 723 | } 724 | 725 | public bool ExplicitShortName 726 | { 727 | get { return this.explicitShortName; } 728 | } 729 | 730 | public string ShortName 731 | { 732 | get { return this.shortName; } 733 | } 734 | 735 | public bool IsRequired 736 | { 737 | get { return 0 != (this.flags & CommandLineArgumentType.Required); } 738 | } 739 | 740 | public bool SeenValue 741 | { 742 | get { return this.seenValue; } 743 | } 744 | 745 | public bool AllowMultiple 746 | { 747 | get { return 0 != (this.flags & CommandLineArgumentType.Multiple); } 748 | } 749 | 750 | public bool Unique 751 | { 752 | get { return 0 != (this.flags & CommandLineArgumentType.Unique); } 753 | } 754 | 755 | public Type Type 756 | { 757 | get { return field.FieldType; } 758 | } 759 | 760 | public bool IsCollection 761 | { 762 | get { return IsCollectionType(Type); } 763 | } 764 | 765 | public bool IsDefault 766 | { 767 | get { return this.isDefault; } 768 | } 769 | 770 | private string longName; 771 | private string shortName; 772 | private bool explicitShortName; 773 | private bool seenValue; 774 | private FieldInfo field; 775 | private Type elementType; 776 | private CommandLineArgumentType flags; 777 | private ArrayList collectionValues; 778 | private ErrorReporter reporter; 779 | private bool isDefault; 780 | } 781 | 782 | private ArrayList arguments; 783 | private Hashtable argumentMap; 784 | private Argument defaultArgument; 785 | private ErrorReporter reporter; 786 | } 787 | } 788 | 789 | -------------------------------------------------------------------------------- /PartitionManagement2012/ManagePartition.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucazav/SqlServerPartitionManagementUtility/653e05fc86ea37a48d8145fa99e2a3f08cbb010a/PartitionManagement2012/ManagePartition.cs -------------------------------------------------------------------------------- /PartitionManagement2012/PartitionManagement.cs: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // PartitionManagement.cs 4 | // 5 | // Version 3.1 6 | // Forked to Github: https://github.com/lucazav/sqlserverpartitionmanager 7 | // 8 | // Version 3.0 9 | // Stuart Ozer 10 | // Microsoft Corporation 11 | // December 2012 12 | // 13 | // Class library to create a table that can be populated to load data for a partition SWITCH operation, 14 | // or used as a destination to empty rows from a partition SWITCH. Table structure and filegroup 15 | // location are based on the definition of the Partition Table and the Partition Number being used. 16 | // 17 | // Library supports creating the table fully, or deferring creation of the indexes until table has 18 | // been populated by a fast load. 19 | // 20 | // Version History 21 | // V 3.1 -- November 2015 22 | // Requires SQL2012 version of SMO 23 | // Added support for SQL Server 2014 in a different project 24 | // Fixed the deadlock issue when occurring when one instance of the exe was trying read from sys.tables 25 | // and the other one was trying to alter the schema with an Alter table command. 26 | // Fixed the missing throw issue in the catch block of the Run method 27 | // V 3.0 -- December 2012 28 | // Requires SQL2012 version of SMO 29 | // Added support for Columnstore Indexes 30 | // Added support to script generated TSQL commands 31 | // Added global locale support for date formats 32 | // Fixed partitioning columns requiring quoted names 33 | // Added support for binary partitioning column types 34 | // Fixed problem with tables containing long text or long binary tyoes 35 | // 36 | // V 2.0 -- February 2009 37 | // Requires SQL2008 version of SMO 38 | // Added support for SQL2008 data types 39 | // Added support for nullable partition columns 40 | // Added support for filtered indexes and sparse columns 41 | // Added support for table and index compression 42 | // Added support for default constraints to assist when populating staging tables 43 | // Added support for partition-aligned indexed views 44 | // Added backward compatibility for SQL2005 45 | // 46 | // NOTE: Filestream columns are not supported because SWITCH has limited value in filestream environments 47 | // 48 | // V 1.0 -- May 2006 49 | // 50 | // Provided as-is, with no warranties expressed or implied 51 | // 52 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 53 | using System; 54 | using System.Collections.Generic; 55 | using Microsoft.SqlServer.Management.Common; 56 | using Microsoft.SqlServer.Management.Smo; 57 | using Microsoft.SqlServer.Management.Sdk.Sfc; 58 | using System.Data.SqlClient; 59 | using System.Text; 60 | using System.Text.RegularExpressions; 61 | using System.IO; 62 | 63 | namespace PartitionManagement 64 | { 65 | class PartitionManager 66 | { 67 | private Database db; 68 | private Table partitionTable; 69 | private PartitionFunction pf; 70 | private Table stgTable; 71 | private ServerConnection conn; 72 | private Server srv; 73 | private int partitionNumber; 74 | private StreamWriter scriptWriter; 75 | bool executeCommands; 76 | private List scriptChunks; 77 | 78 | // This version of the constructor relies on an explicit partition number to be provided 79 | public PartitionManager(ServerConnection conn, String dbName, String schName, 80 | String partitionTblName, String stgTblName, int partitionNumber, StreamWriter scriptWriter, 81 | bool executeCommands) 82 | { 83 | // Create all objects 84 | this.conn = conn; 85 | this.partitionNumber = partitionNumber; 86 | this.executeCommands = executeCommands; 87 | this.scriptWriter = scriptWriter; 88 | 89 | srv = new Server(conn); 90 | 91 | db = srv.Databases[dbName]; 92 | 93 | scriptChunks = new List(); 94 | 95 | // validate table 96 | if ((partitionTable = db.Tables[partitionTblName, schName]) == null) 97 | { 98 | throw new System.ArgumentException("Table [" + schName + "].[" + partitionTblName + "] not found in database [" + dbName + "]"); 99 | } 100 | // validate it is partitioned 101 | if (String.IsNullOrEmpty(partitionTable.PartitionScheme)) 102 | { 103 | throw new System.ArgumentException("Table [" + schName + "].[" + partitionTblName + "] is not partitioned"); 104 | } 105 | else 106 | { 107 | pf = db.PartitionFunctions[db.PartitionSchemes[partitionTable.PartitionScheme].PartitionFunction]; 108 | } 109 | // validate the partition number 110 | if ((pf.NumberOfPartitions < partitionNumber) || (partitionNumber <= 0)) 111 | { 112 | throw new System.ArgumentException("Invalid Partition Number"); 113 | } 114 | // check for presence of staging table with the same name 115 | if (db.Tables.Contains(stgTblName, schName)) 116 | { 117 | stgTable = db.Tables[stgTblName,schName]; 118 | } 119 | else 120 | { 121 | stgTable = new Table(db, stgTblName, schName); 122 | } 123 | } 124 | 125 | // Alternate version of constructor computes the partition number given an 126 | // input string representing the range value of the partitioning column 127 | public PartitionManager(ServerConnection conn, String dbName, String schName, 128 | String partitionTblName, String stgTblName, String partitionRangeValue, StreamWriter scriptWriter, 129 | bool executeCommands) 130 | : this(conn, dbName, schName, partitionTblName, stgTblName, 1, scriptWriter, executeCommands) 131 | { 132 | //Determine the correct partition number based on the range value 133 | this.partitionNumber = getPartitionNumber(partitionRangeValue); 134 | } 135 | 136 | public void SetTransactionIsolationLevelReaduncommitted() 137 | { 138 | System.Collections.Specialized.StringCollection sc = new System.Collections.Specialized.StringCollection(); 139 | 140 | string readUncomm = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"; 141 | sc.Add(readUncomm); 142 | 143 | scriptChunks.Add(sc); 144 | if (executeCommands) conn.ExecuteScalar(readUncomm); 145 | } 146 | 147 | public void CreateStgTable() 148 | { 149 | // Create the new table in the appropriate filegroup for the SWITCH 150 | foreach (Column c in partitionTable.Columns) 151 | { 152 | // Populate the table with each column and associated properties from the partition table 153 | Column stgCol = new Column(stgTable, c.Name, c.DataType); 154 | stgCol.Collation = c.Collation; 155 | stgCol.Nullable = c.Nullable; 156 | stgCol.Computed = c.Computed; 157 | stgCol.ComputedText = c.ComputedText; 158 | stgCol.Default = c.Default; 159 | // Apply default constraint value, if present, as a default value 160 | if (c.DefaultConstraint != null) 161 | { 162 | stgCol.AddDefaultConstraint(stgTable.Name + "_" + c.DefaultConstraint.Name); 163 | stgCol.DefaultConstraint.Text = c.DefaultConstraint.Text; 164 | } 165 | stgCol.IsPersisted = c.IsPersisted; 166 | stgCol.DefaultSchema = c.DefaultSchema; 167 | stgCol.RowGuidCol = c.RowGuidCol; 168 | if (srv.VersionMajor >= 10) 169 | { 170 | stgCol.IsFileStream = c.IsFileStream; 171 | stgCol.IsSparse = c.IsSparse; 172 | stgCol.IsColumnSet = c.IsColumnSet; 173 | } 174 | stgTable.Columns.Add(stgCol); 175 | } 176 | // Match other new table attributes to the partition table; required for SWITCH compatibility 177 | stgTable.AnsiNullsStatus = partitionTable.AnsiNullsStatus; 178 | stgTable.QuotedIdentifierStatus = partitionTable.QuotedIdentifierStatus; 179 | // Calculate the filegroup associated with the partition nunber to switch; create temp table in that filegroup 180 | stgTable.FileGroup = db.PartitionSchemes[partitionTable.PartitionScheme].FileGroups[partitionNumber - 1]; 181 | stgTable.TextFileGroup = db.PartitionSchemes[partitionTable.PartitionScheme].FileGroups[partitionNumber - 1]; 182 | 183 | if (srv.VersionMajor >= 10) 184 | { 185 | // Define compression property to match by creating a Physical Partition object 186 | PhysicalPartition stgPartition = new PhysicalPartition(stgTable, 1, partitionTable.PhysicalPartitions[partitionNumber - 1].DataCompression); 187 | stgTable.PhysicalPartitions.Add(stgPartition); 188 | } 189 | scriptChunks.Add(stgTable.Script()); 190 | if (executeCommands) stgTable.Create(); 191 | } 192 | /* 193 | public void CreateStgIndexes() 194 | { 195 | CreateStgIndexes(true); 196 | } 197 | */ 198 | public void CreateStgIndexes(bool createNonClusteredIndexes) 199 | { 200 | // start with Clustered 201 | createStgClusteredIndex(); 202 | // then create non-clustered indexes, along with indexed views, if requested 203 | if (createNonClusteredIndexes) 204 | { 205 | createStgNonclusteredIndexes(); 206 | createStgIndexedViews(); 207 | } 208 | } 209 | public void CreateStgFkeys() 210 | { 211 | // Apply any Foreign Key constraints on the new table that are present on the Partition Table 212 | foreach (ForeignKey fKey in partitionTable.ForeignKeys) 213 | { 214 | ForeignKey newFKey = new ForeignKey(stgTable, stgTable.Name + "_" + fKey.Name); 215 | newFKey.DeleteAction = fKey.DeleteAction; 216 | newFKey.IsChecked = fKey.IsChecked; 217 | newFKey.IsEnabled = fKey.IsEnabled; 218 | newFKey.ReferencedTable = fKey.ReferencedTable; 219 | newFKey.ReferencedTableSchema = fKey.ReferencedTableSchema; 220 | newFKey.UpdateAction = fKey.UpdateAction; 221 | foreach (ForeignKeyColumn col in fKey.Columns) 222 | { 223 | ForeignKeyColumn newCol = new ForeignKeyColumn(newFKey, col.Name, col.ReferencedColumn); 224 | newFKey.Columns.Add(newCol); 225 | } 226 | scriptChunks.Add(newFKey.Script()); 227 | if (executeCommands) newFKey.Create(); 228 | } 229 | } 230 | public void CreateStgChecks() 231 | { 232 | // Apply any Check constraints to the new table that are present on the Partition Table 233 | foreach (Check chkConstr in partitionTable.Checks) 234 | { 235 | Check newCheck = new Check(stgTable, stgTable.Name + "_" + chkConstr.Name); 236 | newCheck.IsChecked = chkConstr.IsChecked; 237 | newCheck.IsEnabled = chkConstr.IsEnabled; 238 | newCheck.Text = chkConstr.Text; 239 | scriptChunks.Add(newCheck.Script()); 240 | if (executeCommands) newCheck.Create(); 241 | } 242 | } 243 | public void CreateStgPartitionCheck() 244 | { 245 | // Now construct appropriate CHECK CONSTRAINT based on partition boundaries 246 | // We need to distinguish between dates, unicode vs. nonunicode strings, and numeric 247 | // values embedded in the partition boundarty collection. We do this by evaluating the 248 | // data type of the partition column, and then construct the Check Constraint string 249 | // appropriately quoted 250 | Check partitionCheckConstraint = new Check(stgTable, "chk_" + stgTable.Name + "_partition_" + partitionNumber.ToString(System.Globalization.CultureInfo.InvariantCulture)); 251 | String leftBoundary = ""; 252 | String rightBoundary = ""; 253 | String partitionColumnName = partitionTable.PartitionSchemeParameters[0].Name; 254 | String partitionColumnQuotedName = "[" + partitionColumnName + "]"; 255 | SqlDataType partitionColumnType = partitionTable.Columns[partitionColumnName].DataType.SqlDataType; 256 | 257 | 258 | // Construct the minimum value predicate string in the check constraint definition 259 | if (partitionNumber > 1) 260 | { 261 | leftBoundary = partitionColumnQuotedName + ((pf.RangeType == RangeType.Right) ? ">=" : ">") + localeIndependentText(partitionColumnType, pf.RangeValues[partitionNumber - 2]); 262 | } 263 | // Construct the maximum value predicate string in the check constraint definition 264 | if (partitionNumber < pf.NumberOfPartitions) 265 | { 266 | rightBoundary = partitionColumnQuotedName + ((pf.RangeType == RangeType.Right) ? "<" : "<=") + localeIndependentText(partitionColumnType, pf.RangeValues[partitionNumber - 1]); 267 | } 268 | // Assemble the full Check Constraint string 269 | // If the partitioning column is nullable 270 | // If the partition is the leftmost, allow NULLs in the check constraint, otherwise add NOT NULL check constraint 271 | String constraintText = 272 | ((partitionTable.Columns[partitionColumnName].Nullable) ? partitionColumnQuotedName + 273 | ((partitionNumber == 1) ? " IS NULL OR " : " IS NOT NULL AND ") 274 | : "" 275 | ) 276 | + "(" + leftBoundary + 277 | (((partitionNumber > 1) && (partitionNumber < pf.NumberOfPartitions)) ? " AND " : "") + 278 | rightBoundary + ")"; 279 | partitionCheckConstraint.IsEnabled = true; 280 | partitionCheckConstraint.Text = constraintText; 281 | // Create the Check Constraint 282 | scriptChunks.Add(partitionCheckConstraint.Script()); 283 | if (executeCommands) partitionCheckConstraint.Create(); 284 | } 285 | /* 286 | public void ClearPartition() 287 | { 288 | String s = ClearPartition(false); 289 | } 290 | */ 291 | public string ClearPartition(bool keepTable) 292 | { 293 | string cmd = "ALTER TABLE [" + partitionTable.Schema + "].[" + partitionTable.Name + "] SWITCH PARTITION " + 294 | partitionNumber.ToString() + " TO [" + stgTable.Schema + "].[" + stgTable.Name + "];"; 295 | System.Collections.Specialized.StringCollection sc = new System.Collections.Specialized.StringCollection(); 296 | sc.Add(cmd); 297 | if (executeCommands) partitionTable.SwitchPartition(partitionNumber, stgTable); 298 | 299 | if (!keepTable) 300 | { 301 | string dropCmd = "DROP TABLE [" + stgTable.Schema + "].[" + stgTable.Name + "];"; 302 | sc.Add(dropCmd); 303 | if (executeCommands) stgTable.Drop(); 304 | } 305 | scriptChunks.Add(sc); 306 | return keepTable ? stgTable.Name : null; 307 | } 308 | 309 | private void createStgClusteredIndex() 310 | { 311 | // Ignore if clustered index already exists, or if we are scripting only 312 | if ((!executeCommands) || (!stgTable.HasClusteredIndex)) 313 | { 314 | foreach (Index i in partitionTable.Indexes) 315 | { 316 | if (i.IsClustered && !i.IsDisabled) 317 | { 318 | createStgIndex(i, stgTable); 319 | break; 320 | } 321 | } 322 | } 323 | } 324 | private void createStgIndexedViews() 325 | { 326 | // Create a list of existing Indexed Views on the partition table 327 | List indexedViews = new List(); 328 | // Examine each view in the database 329 | foreach (View v in db.Views) 330 | { 331 | if (v.HasIndex) 332 | { 333 | // If it has an index, check if parent table is the partitioned table of interest 334 | string fullName = (string)conn.ExecuteScalar("SELECT DISTINCT Referenced_Schema_Name+'.'+Referenced_Entity_Name FROM sys.dm_sql_referenced_entities ('" + v.Schema + "." + v.Name + "', 'OBJECT')"); 335 | string sch = fullName.Substring(0, fullName.IndexOf('.')); 336 | string tab = fullName.Substring(fullName.IndexOf('.') + 1, fullName.Length - (fullName.IndexOf('.')+1)); 337 | if (sch == partitionTable.Schema && tab == partitionTable.Name) 338 | { 339 | indexedViews.Add(v); 340 | } 341 | } 342 | } 343 | foreach (View v in indexedViews) 344 | { 345 | createIndexedView(v); 346 | } 347 | } 348 | private void createIndexedView(View sourceView) 349 | { 350 | View stgView = new View(db, stgTable.Name + "_" + sourceView.Name, stgTable.Schema); 351 | stgView.TextHeader = "CREATE VIEW " + stgTable.Schema + "." + stgView.Name + " WITH SCHEMABINDING AS "; 352 | // Replace name of Partitioned Table in the view definition with the Staging Table name, wherever it occurs 353 | stgView.TextBody = Regex.Replace 354 | (sourceView.TextBody, @"([\W\s])" + partitionTable.Name + @"([\W\s])", @"$1" + stgTable.Name + @"$2",RegexOptions.IgnoreCase); 355 | // Create the view 356 | scriptChunks.Add(stgView.Script()); 357 | if (executeCommands) stgView.Create(); 358 | 359 | // Create the view's clustered index first 360 | foreach (Index i in sourceView.Indexes) 361 | { 362 | if (i.IsClustered) 363 | { 364 | createStgIndex(i, stgView); 365 | break; 366 | } 367 | } 368 | // Create any nonclustered indexes 369 | foreach (Index i in sourceView.Indexes) 370 | { 371 | if (!i.IsClustered) 372 | { 373 | createStgIndex(i, stgView); 374 | } 375 | } 376 | 377 | } 378 | private void createStgNonclusteredIndexes() 379 | { 380 | foreach (Index i in partitionTable.Indexes) 381 | { 382 | if (!i.IsClustered && !i.IsXmlIndex && !i.IsDisabled) 383 | { 384 | createStgIndex(i, stgTable); 385 | } 386 | } 387 | } 388 | private void createStgIndex(Index i, TableViewBase parent) 389 | { 390 | if (i.PartitionScheme == "") 391 | throw (new System.NotSupportedException( 392 | String.Format("The index '{0}' is not aligned to a Partition Scheme", i.Name))); 393 | 394 | // todo: differentiate between Base Table as source, and View as source 395 | 396 | // LZAV: Index stgIndex = new Index(parent, parent.Name + "_" + i.Name); 397 | String indexName = parent.Name + "_" + i.Name; // LZAV 398 | if (indexName.Length > 128) // LZAV 399 | indexName = "IX_CL_" + parent.Name; // LZAV 400 | 401 | Index stgIndex = new Index(parent, indexName); // LZAV 402 | 403 | foreach (IndexedColumn iCol in i.IndexedColumns) 404 | { 405 | IndexedColumn stgICol = new IndexedColumn(stgIndex, iCol.Name, iCol.Descending); 406 | stgICol.IsIncluded = iCol.IsIncluded; 407 | stgIndex.IndexedColumns.Add(stgICol); 408 | } 409 | stgIndex.IndexType = i.IndexType; 410 | stgIndex.IndexKeyType = i.IndexKeyType; 411 | stgIndex.IsClustered = i.IsClustered; 412 | stgIndex.IsUnique = i.IsUnique; 413 | stgIndex.CompactLargeObjects = i.CompactLargeObjects; 414 | stgIndex.IgnoreDuplicateKeys = i.IgnoreDuplicateKeys; 415 | stgIndex.IsFullTextKey = i.IsFullTextKey; 416 | stgIndex.PadIndex = i.PadIndex; 417 | stgIndex.FileGroup = db.PartitionSchemes[i.PartitionScheme].FileGroups[partitionNumber - 1]; 418 | 419 | // add the partitioning column to the index if it is not already there 420 | String partitionKeyName = i.PartitionSchemeParameters[0].Name; 421 | if (stgIndex.IndexedColumns[partitionKeyName] == null) 422 | { 423 | IndexedColumn stgICol = new IndexedColumn(stgIndex, partitionKeyName); 424 | // It is added as a Key to the Clustered index and as an Include column to a Nonclustered 425 | stgICol.IsIncluded = !stgIndex.IsClustered; 426 | stgIndex.IndexedColumns.Add(stgICol); 427 | } 428 | 429 | if (srv.VersionMajor >= 10) 430 | { 431 | // Define compression property to match by creating a Physical Partition object (not applicable to Colstore) 432 | { 433 | PhysicalPartition stgPartition = new PhysicalPartition(stgIndex, 1); 434 | if (i.IndexType != IndexType.NonClusteredColumnStoreIndex) 435 | { 436 | stgPartition.DataCompression = i.PhysicalPartitions[partitionNumber - 1].DataCompression; 437 | } 438 | stgIndex.PhysicalPartitions.Add(stgPartition); 439 | } 440 | // Handle Filtered Index 441 | if (i.HasFilter) 442 | { 443 | stgIndex.FilterDefinition = i.FilterDefinition; 444 | } 445 | } 446 | scriptChunks.Add(stgIndex.Script()); 447 | if (executeCommands) stgIndex.Create(); 448 | } 449 | // Compute the partition number corresponding to a range value of this instance's partition function 450 | // Done by executing the query: 451 | // Select .$partition.() 452 | // and relying on implicit conversion from string to the appropriate data type of the partitioning column 453 | private int getPartitionNumber(String rangeValue) 454 | { 455 | SqlConnection c = conn.SqlConnectionObject; 456 | String sqlText = "Select "+db.Name+".$partition."+pf.Name+"(@rangeValue)"; 457 | using (SqlCommand cmd = new SqlCommand(sqlText, c)) 458 | { 459 | cmd.Parameters.Add(new SqlParameter("@rangeValue", rangeValue)); 460 | return (int)cmd.ExecuteScalar(); 461 | } 462 | } 463 | 464 | // Create a string representation of a partition boundary value appropriate for use in CHECK CONSTRAINT 465 | // expressions, taking a SQL Data Type and Range Value object as inputs. 466 | // In particular ensure that date strings are represented in locale-independent formats appropriate for global 467 | // use. And unpack binary datatypes to deliver "0x..." string representation. 468 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] 469 | private static string localeIndependentText(SqlDataType sqlType, object rangeValue) 470 | { 471 | string hexString = ""; 472 | switch (sqlType) 473 | { 474 | case SqlDataType.Date: 475 | return "'" + ((DateTime)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss", System.Globalization.CultureInfo.InvariantCulture) + "'"; 476 | case SqlDataType.SmallDateTime: 477 | return "'" + ((DateTime)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss", System.Globalization.CultureInfo.InvariantCulture) + "'"; 478 | case SqlDataType.DateTime: 479 | return "'" + ((DateTime)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture) + "'"; 480 | case SqlDataType.DateTime2: 481 | return "'" + ((DateTime)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss.fffffff", System.Globalization.CultureInfo.InvariantCulture) + "'"; 482 | case SqlDataType.DateTimeOffset: 483 | return "'" + ((DateTimeOffset)rangeValue).ToString("yyyy-MM-ddTHH:mm:ss.fffffffK", System.Globalization.CultureInfo.InvariantCulture) + "'"; 484 | case SqlDataType.Time: 485 | return "'" + ((TimeSpan)rangeValue).ToString() + "'"; 486 | case SqlDataType.Char: 487 | return "'" + (String)rangeValue + "'"; 488 | case SqlDataType.VarChar: 489 | return "'" + (String)rangeValue + "'"; 490 | case SqlDataType.NChar: 491 | return "N'" + (String)rangeValue + "'"; 492 | case SqlDataType.NVarChar: 493 | return "N'" + (String)rangeValue + "'"; 494 | case SqlDataType.Binary: 495 | foreach (Byte b in (Byte[])rangeValue) 496 | { 497 | hexString += b.ToString("x2", System.Globalization.CultureInfo.InvariantCulture); 498 | } 499 | return "0x" + hexString; 500 | case SqlDataType.VarBinary: 501 | foreach (Byte b in (Byte[])rangeValue) 502 | { 503 | hexString += b.ToString("x2", System.Globalization.CultureInfo.InvariantCulture); 504 | } 505 | return "0x" + hexString; 506 | case SqlDataType.Bit: 507 | return (((Boolean)rangeValue) ? "1" : "0"); 508 | case SqlDataType.Int: 509 | return rangeValue.ToString(); 510 | case SqlDataType.BigInt: 511 | return rangeValue.ToString(); 512 | case SqlDataType.SmallInt: 513 | return rangeValue.ToString(); 514 | case SqlDataType.TinyInt: 515 | return rangeValue.ToString(); 516 | 517 | // Note -- SQL Server partition boundary values for FLOATs are precise only to 14 digits, so ensure the 518 | // Check Constraint value matches that precision 519 | case SqlDataType.Float: 520 | return ((Double)rangeValue).ToString("E14", System.Globalization.CultureInfo.InvariantCulture); 521 | 522 | // Note -- SQL2012 RTM incorrectly handles REAL / (Float(24)) metadata in Check Constraints, 523 | // use Float (53) instead to support partition switching. Bug has been filed. 524 | case SqlDataType.Real: 525 | return ((Single)rangeValue).ToString("E6", System.Globalization.CultureInfo.InvariantCulture); 526 | 527 | case SqlDataType.Numeric: 528 | return rangeValue.ToString(); 529 | case SqlDataType.Decimal: 530 | return rangeValue.ToString(); 531 | case SqlDataType.Money: 532 | return rangeValue.ToString(); 533 | case SqlDataType.SmallMoney: 534 | return rangeValue.ToString(); 535 | default: 536 | throw (new System.NotSupportedException("Unsupported Data Type found as Partition Key")); 537 | } 538 | } 539 | 540 | public void outputScript() 541 | { 542 | foreach (System.Collections.Specialized.StringCollection sc in scriptChunks) 543 | { 544 | foreach (string s in sc) 545 | { 546 | if (scriptWriter == null) 547 | { 548 | Console.WriteLine(s); 549 | } 550 | else 551 | { 552 | scriptWriter.WriteLine(s); 553 | } 554 | } 555 | } 556 | } 557 | } 558 | } 559 | -------------------------------------------------------------------------------- /PartitionManagement2012/PartitionManagement2012.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {8F71C899-5374-477D-A307-FBC7C20EF62A} 9 | Exe 10 | Properties 11 | PartitionManagement 12 | ManagePartition 13 | true 14 | 15 | 16 | 17 | 18 | 3.5 19 | v3.5 20 | 21 | http://localhost/ManagePartition/ 22 | true 23 | Web 24 | true 25 | Foreground 26 | 7 27 | Days 28 | false 29 | false 30 | true 31 | 0 32 | 3.1.0.%2a 33 | false 34 | true 35 | false 36 | 37 | 38 | true 39 | full 40 | false 41 | bin\Debug\ 42 | DEBUG;TRACE 43 | prompt 44 | 4 45 | AllRules.ruleset 46 | 47 | 48 | pdbonly 49 | true 50 | bin\Release\ 51 | TRACE 52 | prompt 53 | 4 54 | AllRules.ruleset 55 | true 56 | 57 | 58 | 930EEE92AB704AE7EE8DF063217AFBAD6C00E2DA 59 | 60 | 61 | PartitionManagement_TemporaryKey.pfx 62 | 63 | 64 | false 65 | 66 | 67 | LocalIntranet 68 | 69 | 70 | Properties\app.manifest 71 | 72 | 73 | false 74 | 75 | 76 | 77 | False 78 | C:\Program Files (x86)\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll 79 | 80 | 81 | False 82 | C:\Program Files (x86)\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Management.Sdk.Sfc.dll 83 | 84 | 85 | False 86 | C:\Program Files (x86)\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Smo.dll 87 | 88 | 89 | False 90 | C:\Program Files (x86)\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.SqlEnum.dll 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | False 107 | .NET Framework 3.5 SP1 Client Profile 108 | false 109 | 110 | 111 | False 112 | .NET Framework 2.0 %28x86%29 113 | false 114 | 115 | 116 | False 117 | .NET Framework 3.0 %28x86%29 118 | false 119 | 120 | 121 | False 122 | .NET Framework 3.5 123 | false 124 | 125 | 126 | False 127 | .NET Framework 3.5 SP1 128 | true 129 | 130 | 131 | False 132 | Microsoft® System CLR Types for SQL Server® 2012 %28x64%29 133 | true 134 | 135 | 136 | False 137 | Microsoft® System CLR Types for SQL Server® 2012 %28x86%29 138 | true 139 | 140 | 141 | False 142 | Windows Installer 4.5 143 | true 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 159 | -------------------------------------------------------------------------------- /PartitionManagement2012/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("PartitionManagement")] 9 | [assembly: AssemblyDescription("Patch by Luca Zavarella to avoid the deadlocks")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("PartitionManagement")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2012")] 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("5ac6f10f-bb89-43d7-8f86-d6843f662068")] 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 | [assembly: AssemblyVersion("3.1.0.0")] 33 | [assembly: AssemblyFileVersion("3.1.0.0")] 34 | -------------------------------------------------------------------------------- /PartitionManagement2012/Properties/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 52 | -------------------------------------------------------------------------------- /PartitionManagement2012/Utility.cs: -------------------------------------------------------------------------------- 1 | namespace Utilities 2 | { 3 | using System; 4 | 5 | /// 6 | /// A delegate used in error reporting. 7 | /// 8 | public delegate void ErrorReporter(string message); 9 | 10 | /// 11 | /// Useful Stuff. 12 | /// 13 | public sealed class Utility 14 | { 15 | /// 16 | /// The System Defined new line string. 17 | /// 18 | public const string NewLine = "\r\n"; 19 | 20 | /// 21 | /// Don't ever call this. 22 | /// 23 | private Utility() { } 24 | 25 | /// 26 | /// Parses Command Line Arguments. 27 | /// Errors are output on Console.Error. 28 | /// Use CommandLineArgumentAttributes to control parsing behaviour. 29 | /// 30 | /// The actual arguments. 31 | /// The resulting parsed arguments. 32 | /// true if no errors were detected. 33 | public static bool ParseCommandLineArguments(string[] arguments, object destination) 34 | { 35 | return ParseCommandLineArguments(arguments, destination, new ErrorReporter(Console.Error.WriteLine)); 36 | } 37 | 38 | /// 39 | /// Parses Command Line Arguments. 40 | /// Use CommandLineArgumentAttributes to control parsing behaviour. 41 | /// 42 | /// The actual arguments. 43 | /// The resulting parsed arguments. 44 | /// The destination for parse errors. 45 | /// true if no errors were detected. 46 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1")] 47 | public static bool ParseCommandLineArguments(string[] arguments, object destination, ErrorReporter reporter) 48 | { 49 | CommandLineArgumentParser parser = new CommandLineArgumentParser(destination.GetType(), reporter); 50 | return parser.Parse(arguments, destination); 51 | } 52 | /// 53 | /// Returns a Usage string for command line argument parsing. 54 | /// Use CommandLineArgumentAttributes to control parsing behaviour. 55 | /// 56 | /// The type of the arguments to display usage for. 57 | /// Printable string containing a user friendly description of command line arguments. 58 | public static string CommandLineArgumentsUsage(Type argumentType) 59 | { 60 | return (new CommandLineArgumentParser(argumentType, null)).Usage; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /PartitionManagement2012/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /PartitionMgmtTest_2005.sql: -------------------------------------------------------------------------------- 1 | -- Testing scenarios for ManagePartition 2.0 on SQL2005 2 | -- 3 | -- Stuart Ozer 4 | -- February 2008 5 | --- 6 | -- Relies on Adventureworks2008 database installed on the test instance 7 | -- 8 | -- NOTE: Commented lines invoking ManagePartition.exe must be executed 9 | -- from the command line in the bin/release directory of the tool 10 | 11 | -- Create the DB 12 | 13 | USE [master] 14 | GO 15 | 16 | DROP DATABASE PartitionTest 17 | go 18 | 19 | CREATE DATABASE [PartitionTest] ON PRIMARY 20 | ( NAME = N'PartitionTest', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\PartitionTest.mdf' , SIZE = 21504KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ), 21 | FILEGROUP [FG1] 22 | ( NAME = N'FG1_1', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\FG1_1.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ), 23 | FILEGROUP [FG2] 24 | ( NAME = N'FG2_1', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\FG2_1.ndf' , SIZE = 6144KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ), 25 | FILEGROUP [FG3] 26 | ( NAME = N'FG3_1', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\FG3_1.ndf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) 27 | LOG ON 28 | ( NAME = N'PartitionTest_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\PartitionTest_log.ldf' , SIZE = 39296KB , MAXSIZE = 2048GB , FILEGROWTH = 10%) 29 | GO 30 | 31 | ALTER DATABASE [PartitionTest] SET ANSI_NULL_DEFAULT OFF 32 | GO 33 | 34 | ALTER DATABASE [PartitionTest] SET ANSI_NULLS OFF 35 | GO 36 | 37 | ALTER DATABASE [PartitionTest] SET ANSI_PADDING OFF 38 | GO 39 | 40 | ALTER DATABASE [PartitionTest] SET ANSI_WARNINGS OFF 41 | GO 42 | 43 | ALTER DATABASE [PartitionTest] SET ARITHABORT OFF 44 | GO 45 | 46 | ALTER DATABASE [PartitionTest] SET AUTO_CLOSE OFF 47 | GO 48 | 49 | ALTER DATABASE [PartitionTest] SET AUTO_CREATE_STATISTICS ON 50 | GO 51 | 52 | ALTER DATABASE [PartitionTest] SET AUTO_SHRINK OFF 53 | GO 54 | 55 | ALTER DATABASE [PartitionTest] SET AUTO_UPDATE_STATISTICS ON 56 | GO 57 | 58 | ALTER DATABASE [PartitionTest] SET CURSOR_CLOSE_ON_COMMIT OFF 59 | GO 60 | 61 | ALTER DATABASE [PartitionTest] SET CURSOR_DEFAULT GLOBAL 62 | GO 63 | 64 | ALTER DATABASE [PartitionTest] SET CONCAT_NULL_YIELDS_NULL OFF 65 | GO 66 | 67 | ALTER DATABASE [PartitionTest] SET NUMERIC_ROUNDABORT OFF 68 | GO 69 | 70 | ALTER DATABASE [PartitionTest] SET QUOTED_IDENTIFIER OFF 71 | GO 72 | 73 | ALTER DATABASE [PartitionTest] SET RECURSIVE_TRIGGERS OFF 74 | GO 75 | 76 | ALTER DATABASE [PartitionTest] SET DISABLE_BROKER 77 | GO 78 | 79 | ALTER DATABASE [PartitionTest] SET AUTO_UPDATE_STATISTICS_ASYNC OFF 80 | GO 81 | 82 | ALTER DATABASE [PartitionTest] SET DATE_CORRELATION_OPTIMIZATION OFF 83 | GO 84 | 85 | ALTER DATABASE [PartitionTest] SET TRUSTWORTHY OFF 86 | GO 87 | 88 | ALTER DATABASE [PartitionTest] SET ALLOW_SNAPSHOT_ISOLATION OFF 89 | GO 90 | 91 | ALTER DATABASE [PartitionTest] SET PARAMETERIZATION SIMPLE 92 | GO 93 | 94 | ALTER DATABASE [PartitionTest] SET READ_COMMITTED_SNAPSHOT OFF 95 | GO 96 | 97 | ALTER DATABASE [PartitionTest] SET READ_WRITE 98 | GO 99 | 100 | ALTER DATABASE [PartitionTest] SET RECOVERY FULL 101 | GO 102 | 103 | ALTER DATABASE [PartitionTest] SET MULTI_USER 104 | GO 105 | 106 | ALTER DATABASE [PartitionTest] SET PAGE_VERIFY CHECKSUM 107 | GO 108 | 109 | ALTER DATABASE [PartitionTest] SET DB_CHAINING OFF 110 | GO 111 | 112 | ------------------------------------------------------------ 113 | -- Copy some reference tables 114 | 115 | USE [AdventureWorks] 116 | 117 | -- select distinct DATEPART(year,OrderDate) from Sales.SalesOrderHeader 118 | -- select distinct salespersonid from Sales.SalesOrderHeader order by 1 119 | -- select distinct status from Sales.SalesOrderHeader order by 1 120 | 121 | Select * into PartitionTest.dbo.Address from Person.Address; 122 | 123 | Select * into PartitionTest.dbo.CurrencyRate from Sales.CurrencyRate; 124 | 125 | ------------------------------------------------------ 126 | -- Create the partitioned table and indexes 127 | 128 | USE [PartitionTest] 129 | GO 130 | 131 | ALTER TABLE [Address] ADD CONSTRAINT [PK_Address_AddressID] PRIMARY KEY CLUSTERED 132 | ( 133 | [AddressID] ASC 134 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 135 | 136 | 137 | ALTER TABLE [CurrencyRate] ADD CONSTRAINT [PK_CurrencyRate_CurrencyRateID] PRIMARY KEY CLUSTERED 138 | ( 139 | [CurrencyRateID] ASC 140 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 141 | GO 142 | 143 | Create Partition Function pf_l_date (datetime) as RANGE LEFT for values 144 | ('01/01/2001', '01/01/2002', '01/01/2003', '01/01/2004', '01/01/2005'); 145 | 146 | Create Partition Scheme ps_l_date as partition pf_l_date to (fg1, fg2, fg3, fg1, fg2, fg3); 147 | 148 | Create Partition Function pf_r_date (datetime) as RANGE RIGHT for values 149 | ('01/01/2001', '01/01/2002', '01/01/2003', '01/01/2004', '01/01/2005'); 150 | Create Partition Scheme ps_r_date as partition pf_r_date to (fg1, fg2, fg3, fg1, fg2, fg3); 151 | 152 | Create Partition Function pf_l_salespers (int) as RANGE LEFT for values 153 | (275, 280, 285, 290); 154 | Create Partition Scheme ps_l_salespers as partition pf_l_salespers to (fg1, fg2, fg3, fg1, fg2); 155 | 156 | Create Partition Function pf_r_salespers (int) as RANGE RIGHT for values 157 | (275, 280, 285, 290); 158 | Create Partition Scheme ps_r_salespers as partition pf_r_salespers all to ([PRIMARY]); 159 | 160 | CREATE TYPE [dbo].[Flag] FROM [bit] NOT NULL 161 | GO 162 | CREATE TYPE [dbo].[OrderNumber] FROM [nvarchar](25) NULL 163 | GO 164 | CREATE TYPE [dbo].[AccountNumber] FROM [nvarchar](15) NULL 165 | GO 166 | 167 | ------------------------------- 168 | -- Range Left date (quotable) Key 169 | DROP VIEW v_SOH_CC_SHIP; 170 | go 171 | drop view [v_SOH_SALESP_TOTALS] 172 | go 173 | DROP VIEW t1_v_SOH_CC_SHIP 174 | go 175 | DROP VIEW t2_v_SOH_CC_SHIP 176 | go 177 | DROP VIEW t3_v_SOH_CC_SHIP 178 | go 179 | DROP VIEW t1_v_SOH_SALESP_TOTALS 180 | go 181 | DROP VIEW t2_v_SOH_SALESP_TOTALS 182 | go 183 | DROP VIEW t3_v_SOH_SALESP_TOTALS 184 | go 185 | DROP TABLE SalesOrderHeader; 186 | go 187 | drop table t1; 188 | go 189 | drop table t2; 190 | go 191 | drop table t3; 192 | go 193 | 194 | CREATE TABLE [SalesOrderHeader]( 195 | [SalesOrderID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, 196 | [RevisionNumber] [tinyint] NOT NULL, 197 | [OrderDate] [datetime] NOT NULL, 198 | [DueDate] [datetime] NOT NULL, 199 | [ShipDate] [datetime] NULL, 200 | [Status] [tinyint] NOT NULL, 201 | [OnlineOrderFlag] [dbo].[Flag] NOT NULL, 202 | [SalesOrderNumber] AS (isnull(N'SO'+CONVERT([nvarchar](23),[SalesOrderID],0),N'*** ERROR ***')), 203 | [PurchaseOrderNumber] [dbo].[OrderNumber] NULL, 204 | [AccountNumber] [dbo].[AccountNumber] NULL, 205 | [CustomerID] [int] NOT NULL, 206 | [SalesPersonID] [int] NULL, 207 | [TerritoryID] [int] NULL, 208 | [BillToAddressID] [int] NOT NULL, 209 | [ShipToAddressID] [int] NOT NULL, 210 | [ShipMethodID] [int] NOT NULL, 211 | [CreditCardID] [int] NULL, 212 | [CreditCardApprovalCode] [varchar](15) NULL, 213 | [CurrencyRateID] [int] NULL, 214 | [SubTotal] [money] NOT NULL, 215 | [TaxAmt] [money] NOT NULL, 216 | [Freight] [money] NOT NULL, 217 | [TotalDue] AS (isnull(([SubTotal]+[TaxAmt])+[Freight],(0))) PERSISTED, 218 | [Comment] [nvarchar](128) NULL, 219 | [rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL, 220 | [ModifiedDate] [datetime] NOT NULL, 221 | CONSTRAINT [PK_SalesOrderHeader_SalesOrderID] PRIMARY KEY CLUSTERED 222 | ( 223 | [SalesOrderID] ASC, [OrderDate] ASC 224 | )WITH (PAD_INDEX = OFF, 225 | STATISTICS_NORECOMPUTE = OFF, 226 | IGNORE_DUP_KEY = OFF, 227 | ALLOW_ROW_LOCKS = ON, 228 | ALLOW_PAGE_LOCKS = ON) ON ps_l_date(OrderDate) 229 | ) ON ps_l_date(OrderDate) 230 | go 231 | 232 | Create nonclustered index NC_SOH_CUST on SalesOrderHeader(CustomerID) 233 | on ps_l_date(OrderDate) 234 | go 235 | 236 | Create nonclustered index NC_SOH_ACCT on SalesOrderHeader(AccountNumber) 237 | on ps_l_date(OrderDate) 238 | go 239 | 240 | Create nonclustered index NC_SOH_SONBR on SalesOrderHeader(SalesOrderNumber) 241 | on ps_l_date(OrderDate) 242 | go 243 | 244 | Create nonclustered index NC_SOH_TERR on SalesOrderHeader(TerritoryID, AccountNumber) 245 | INCLUDE(ShipDate, DueDate) 246 | on ps_l_date(OrderDate) 247 | go 248 | 249 | Create unique nonclustered index NC_SOH_SOID on SalesOrderHeader([SalesOrderID], [OrderDate]) 250 | on ps_l_date(OrderDate) 251 | go 252 | 253 | set identity_insert SalesOrderHeader ON 254 | 255 | insert into SalesOrderHeader with (TABLOCK) 256 | ( [SalesOrderID] 257 | ,[RevisionNumber] 258 | ,[OrderDate] 259 | ,[DueDate] 260 | ,[ShipDate] 261 | ,[Status] 262 | ,[OnlineOrderFlag] 263 | -- ,[SalesOrderNumber] 264 | ,[PurchaseOrderNumber] 265 | ,[AccountNumber] 266 | ,[CustomerID] 267 | ,[SalesPersonID] 268 | ,[TerritoryID] 269 | ,[BillToAddressID] 270 | ,[ShipToAddressID] 271 | ,[ShipMethodID] 272 | ,[CreditCardID] 273 | ,[CreditCardApprovalCode] 274 | ,[CurrencyRateID] 275 | ,[SubTotal] 276 | ,[TaxAmt] 277 | ,[Freight] 278 | -- ,[TotalDue] 279 | ,[Comment] 280 | ,[rowguid] 281 | ,[ModifiedDate]) 282 | SELECT [SalesOrderID] 283 | ,[RevisionNumber] 284 | ,[OrderDate] 285 | ,[DueDate] 286 | ,[ShipDate] 287 | ,[Status] 288 | ,[OnlineOrderFlag] 289 | -- ,[SalesOrderNumber] 290 | ,[PurchaseOrderNumber] 291 | ,[AccountNumber] 292 | ,[CustomerID] 293 | ,[SalesPersonID] 294 | ,[TerritoryID] 295 | ,[BillToAddressID] 296 | ,[ShipToAddressID] 297 | ,[ShipMethodID] 298 | ,[CreditCardID] 299 | ,[CreditCardApprovalCode] 300 | ,[CurrencyRateID] 301 | ,[SubTotal] 302 | ,[TaxAmt] 303 | ,[Freight] 304 | -- ,[TotalDue] 305 | ,[Comment] 306 | ,[rowguid] 307 | ,[ModifiedDate] 308 | from AdventureWorks.Sales.SalesOrderHeader; 309 | 310 | SET ANSI_PADDING ON 311 | GO 312 | 313 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_Address_BillToAddressID] FOREIGN KEY([BillToAddressID]) 314 | REFERENCES [Address] ([AddressID]) 315 | GO 316 | 317 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_Address_BillToAddressID] 318 | GO 319 | 320 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_Address_ShipToAddressID] FOREIGN KEY([ShipToAddressID]) 321 | REFERENCES [Address] ([AddressID]) 322 | GO 323 | 324 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_Address_ShipToAddressID] 325 | GO 326 | 327 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_CurrencyRate_CurrencyRateID] FOREIGN KEY([CurrencyRateID]) 328 | REFERENCES [CurrencyRate] ([CurrencyRateID]) 329 | GO 330 | 331 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_CurrencyRate_CurrencyRateID] 332 | GO 333 | 334 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_DueDate] CHECK (([DueDate]>=[OrderDate])) 335 | GO 336 | 337 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_DueDate] 338 | GO 339 | 340 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_Freight] CHECK (([Freight]>=(0.00))) 341 | GO 342 | 343 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_Freight] 344 | GO 345 | 346 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_ShipDate] CHECK (([ShipDate]>=[OrderDate] OR [ShipDate] IS NULL)) 347 | GO 348 | 349 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_ShipDate] 350 | GO 351 | 352 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_Status] CHECK (([Status]>=(0) AND [Status]<=(8))) 353 | GO 354 | 355 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_Status] 356 | GO 357 | 358 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_SubTotal] CHECK (([SubTotal]>=(0.00))) 359 | GO 360 | 361 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_SubTotal] 362 | GO 363 | 364 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_TaxAmt] CHECK (([TaxAmt]>=(0.00))) 365 | GO 366 | 367 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_TaxAmt] 368 | GO 369 | 370 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_RevisionNumber] DEFAULT ((0)) FOR [RevisionNumber] 371 | GO 372 | 373 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_OrderDate] DEFAULT (getdate()) FOR [OrderDate] 374 | GO 375 | 376 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_Status] DEFAULT ((1)) FOR [Status] 377 | GO 378 | 379 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_OnlineOrderFlag] DEFAULT ((1)) FOR [OnlineOrderFlag] 380 | GO 381 | 382 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_SubTotal] DEFAULT ((0.00)) FOR [SubTotal] 383 | GO 384 | 385 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_TaxAmt] DEFAULT ((0.00)) FOR [TaxAmt] 386 | GO 387 | 388 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_Freight] DEFAULT ((0.00)) FOR [Freight] 389 | GO 390 | 391 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_rowguid] DEFAULT (newid()) FOR [rowguid] 392 | GO 393 | 394 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_ModifiedDate] DEFAULT (getdate()) FOR [ModifiedDate] 395 | GO 396 | 397 | ALTER INDEX NC_SOH_SONBR on SalesOrderHeader DISABLE 398 | go 399 | 400 | ---------------------------------------------------- 401 | 402 | /* ManagePartition tests: 403 | 404 | ManagePartition /C:CreateStagingFull /PartitionRangeValue:2002-01-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t1 405 | 406 | ManagePartition /C:CreateStagingClusteredIndex /PartitionRangeValue:2003-01-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t2 407 | 408 | ManagePartition /C:CreateStagingNoIndex /PartitionRangeValue:2001-01-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t3 409 | 410 | Errs: 411 | Object reference not set to an instance of an object: Invalid Table Name 412 | NOTE: Switch out works even when non-clustered index is not available! 413 | */ 414 | ------------------------------------------------------- 415 | 416 | Alter table [SalesOrderHeader] switch partition 2 to t1; 417 | go 418 | Alter table t1 switch to [SalesOrderHeader] partition 2; 419 | go 420 | 421 | -- ManagePartition /C:IndexStaging /PartitionRangeValue:2003-01-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t2 422 | 423 | Alter table [SalesOrderHeader] switch partition 3 to t2; 424 | go 425 | Alter table t2 switch to [SalesOrderHeader] partition 3; 426 | go 427 | -- ManagePartition /C:IndexStaging /PartitionRangeValue:2001-01-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t3 428 | 429 | Alter table [SalesOrderHeader] switch partition 1 to t3; 430 | go 431 | Alter table t3 switch to [SalesOrderHeader] partition 1; 432 | go 433 | --------------------------------------- 434 | 435 | -- Range Right date (quotable) Key 436 | 437 | DROP TABLE SalesOrderHeader; 438 | go 439 | drop table t1; 440 | go 441 | drop table t2; 442 | go 443 | drop table t3; 444 | go 445 | 446 | CREATE TABLE [SalesOrderHeader]( 447 | [SalesOrderID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, 448 | [RevisionNumber] [tinyint] NOT NULL, 449 | [OrderDate] [datetime] NOT NULL, 450 | [DueDate] [datetime] NOT NULL, 451 | [ShipDate] [datetime] NULL, 452 | [Status] [tinyint] NOT NULL, 453 | [OnlineOrderFlag] [dbo].[Flag] NOT NULL, 454 | [SalesOrderNumber] AS (isnull(N'SO'+CONVERT([nvarchar](23),[SalesOrderID],0),N'*** ERROR ***')), 455 | [PurchaseOrderNumber] [dbo].[OrderNumber] NULL, 456 | [AccountNumber] [dbo].[AccountNumber] NULL, 457 | [CustomerID] [int] NOT NULL, 458 | [SalesPersonID] [int] NULL, 459 | [TerritoryID] [int] NULL, 460 | [BillToAddressID] [int] NOT NULL, 461 | [ShipToAddressID] [int] NOT NULL, 462 | [ShipMethodID] [int] NOT NULL, 463 | [CreditCardID] [int] NULL, 464 | [CreditCardApprovalCode] [varchar](15) NULL, 465 | [CurrencyRateID] [int] NULL, 466 | [SubTotal] [money] NOT NULL, 467 | [TaxAmt] [money] NOT NULL, 468 | [Freight] [money] NOT NULL, 469 | [TotalDue] AS (isnull(([SubTotal]+[TaxAmt])+[Freight],(0))) PERSISTED, 470 | [Comment] [nvarchar](128) NULL, 471 | [rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL, 472 | [ModifiedDate] [datetime] NOT NULL, 473 | CONSTRAINT [PK_SalesOrderHeader_SalesOrderID] PRIMARY KEY CLUSTERED 474 | ( 475 | [SalesOrderID] ASC, [OrderDate] ASC 476 | )WITH (PAD_INDEX = OFF, 477 | STATISTICS_NORECOMPUTE = OFF, 478 | IGNORE_DUP_KEY = OFF, 479 | ALLOW_ROW_LOCKS = ON, 480 | ALLOW_PAGE_LOCKS = ON) ON ps_r_date(OrderDate) 481 | ) ON ps_r_date(OrderDate) 482 | go 483 | 484 | Create nonclustered index NC_SOH_CUST on SalesOrderHeader(CustomerID) 485 | on ps_r_date(OrderDate) 486 | go 487 | 488 | Create nonclustered index NC_SOH_ACCT on SalesOrderHeader(AccountNumber) 489 | on ps_r_date(OrderDate) 490 | go 491 | 492 | Create nonclustered index NC_SOH_SONBR on SalesOrderHeader(SalesOrderNumber) 493 | on ps_r_date(OrderDate) 494 | go 495 | 496 | Create nonclustered index NC_SOH_TERR on SalesOrderHeader(TerritoryID, AccountNumber) 497 | INCLUDE(ShipDate, DueDate) 498 | on ps_r_date(OrderDate) 499 | go 500 | 501 | Create unique nonclustered index NC_SOH_SOID on SalesOrderHeader([SalesOrderID], [OrderDate]) 502 | on ps_r_date(OrderDate) 503 | go 504 | 505 | set identity_insert SalesOrderHeader ON 506 | 507 | insert into SalesOrderHeader with (TABLOCK) 508 | ( [SalesOrderID] 509 | ,[RevisionNumber] 510 | ,[OrderDate] 511 | ,[DueDate] 512 | ,[ShipDate] 513 | ,[Status] 514 | ,[OnlineOrderFlag] 515 | -- ,[SalesOrderNumber] 516 | ,[PurchaseOrderNumber] 517 | ,[AccountNumber] 518 | ,[CustomerID] 519 | ,[SalesPersonID] 520 | ,[TerritoryID] 521 | ,[BillToAddressID] 522 | ,[ShipToAddressID] 523 | ,[ShipMethodID] 524 | ,[CreditCardID] 525 | ,[CreditCardApprovalCode] 526 | ,[CurrencyRateID] 527 | ,[SubTotal] 528 | ,[TaxAmt] 529 | ,[Freight] 530 | -- ,[TotalDue] 531 | ,[Comment] 532 | ,[rowguid] 533 | ,[ModifiedDate]) 534 | SELECT [SalesOrderID] 535 | ,[RevisionNumber] 536 | ,[OrderDate] 537 | ,[DueDate] 538 | ,[ShipDate] 539 | ,[Status] 540 | ,[OnlineOrderFlag] 541 | -- ,[SalesOrderNumber] 542 | ,[PurchaseOrderNumber] 543 | ,[AccountNumber] 544 | ,[CustomerID] 545 | ,[SalesPersonID] 546 | ,[TerritoryID] 547 | ,[BillToAddressID] 548 | ,[ShipToAddressID] 549 | ,[ShipMethodID] 550 | ,[CreditCardID] 551 | ,[CreditCardApprovalCode] 552 | ,[CurrencyRateID] 553 | ,[SubTotal] 554 | ,[TaxAmt] 555 | ,[Freight] 556 | -- ,[TotalDue] 557 | ,[Comment] 558 | ,[rowguid] 559 | ,[ModifiedDate] 560 | from AdventureWorks.Sales.SalesOrderHeader; 561 | 562 | SET ANSI_PADDING ON 563 | GO 564 | 565 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_Address_BillToAddressID] FOREIGN KEY([BillToAddressID]) 566 | REFERENCES [Address] ([AddressID]) 567 | GO 568 | 569 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_Address_BillToAddressID] 570 | GO 571 | 572 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_Address_ShipToAddressID] FOREIGN KEY([ShipToAddressID]) 573 | REFERENCES [Address] ([AddressID]) 574 | GO 575 | 576 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_Address_ShipToAddressID] 577 | GO 578 | 579 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_CurrencyRate_CurrencyRateID] FOREIGN KEY([CurrencyRateID]) 580 | REFERENCES [CurrencyRate] ([CurrencyRateID]) 581 | GO 582 | 583 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_CurrencyRate_CurrencyRateID] 584 | GO 585 | 586 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_DueDate] CHECK (([DueDate]>=[OrderDate])) 587 | GO 588 | 589 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_DueDate] 590 | GO 591 | 592 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_Freight] CHECK (([Freight]>=(0.00))) 593 | GO 594 | 595 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_Freight] 596 | GO 597 | 598 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_ShipDate] CHECK (([ShipDate]>=[OrderDate] OR [ShipDate] IS NULL)) 599 | GO 600 | 601 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_ShipDate] 602 | GO 603 | 604 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_Status] CHECK (([Status]>=(0) AND [Status]<=(8))) 605 | GO 606 | 607 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_Status] 608 | GO 609 | 610 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_SubTotal] CHECK (([SubTotal]>=(0.00))) 611 | GO 612 | 613 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_SubTotal] 614 | GO 615 | 616 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_TaxAmt] CHECK (([TaxAmt]>=(0.00))) 617 | GO 618 | 619 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_TaxAmt] 620 | GO 621 | 622 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_RevisionNumber] DEFAULT ((0)) FOR [RevisionNumber] 623 | GO 624 | 625 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_OrderDate] DEFAULT (getdate()) FOR [OrderDate] 626 | GO 627 | 628 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_Status] DEFAULT ((1)) FOR [Status] 629 | GO 630 | 631 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_OnlineOrderFlag] DEFAULT ((1)) FOR [OnlineOrderFlag] 632 | GO 633 | 634 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_SubTotal] DEFAULT ((0.00)) FOR [SubTotal] 635 | GO 636 | 637 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_TaxAmt] DEFAULT ((0.00)) FOR [TaxAmt] 638 | GO 639 | 640 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_Freight] DEFAULT ((0.00)) FOR [Freight] 641 | GO 642 | 643 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_rowguid] DEFAULT (newid()) FOR [rowguid] 644 | GO 645 | 646 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_ModifiedDate] DEFAULT (getdate()) FOR [ModifiedDate] 647 | GO 648 | 649 | ALTER INDEX NC_SOH_SONBR on SalesOrderHeader DISABLE 650 | go 651 | 652 | ---------------------------------------------------- 653 | 654 | /* ManagePartition tests: 655 | 656 | ManagePartition /C:CreateStagingFull /PartitionRangeValue:2002-01-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t1 657 | 658 | ManagePartition /C:CreateStagingClusteredIndex /PartitionRangeValue:2003-01-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t2 659 | 660 | ManagePartition /C:CreateStagingNoIndex /PartitionRangeValue:2000-12-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t3 661 | 662 | */ 663 | ------------------------------------------------------- 664 | 665 | Alter table [SalesOrderHeader] switch partition 3 to t1; 666 | go 667 | Alter table t1 switch to [SalesOrderHeader] partition 3; 668 | go 669 | 670 | -- ManagePartition /C:IndexStaging /PartitionRangeValue:2003-01-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t2 671 | 672 | Alter table [SalesOrderHeader] switch partition 4 to t2; 673 | go 674 | Alter table t2 switch to [SalesOrderHeader] partition 4; 675 | go 676 | -- ManagePartition /C:IndexStaging /PartitionRangeValue:2000-12-01 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t3 677 | 678 | Alter table [SalesOrderHeader] switch partition 1 to t3; 679 | go 680 | Alter table t3 switch to [SalesOrderHeader] partition 1; 681 | go 682 | 683 | ------------------------------------------------- 684 | 685 | -- Range left nullable int Key; 686 | DROP TABLE SalesOrderHeader; 687 | go 688 | drop table t1; 689 | go 690 | drop table t2; 691 | go 692 | drop table t3; 693 | go 694 | 695 | CREATE TABLE [SalesOrderHeader]( 696 | [SalesOrderID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, 697 | [RevisionNumber] [tinyint] NOT NULL, 698 | [OrderDate] [datetime] NOT NULL, 699 | [DueDate] [datetime] NOT NULL, 700 | [ShipDate] [datetime] NULL, 701 | [Status] [tinyint] NOT NULL, 702 | [OnlineOrderFlag] [dbo].[Flag] NOT NULL, 703 | [SalesOrderNumber] AS (isnull(N'SO'+CONVERT([nvarchar](23),[SalesOrderID],0),N'*** ERROR ***')), 704 | [PurchaseOrderNumber] [dbo].[OrderNumber] NULL, 705 | [AccountNumber] [dbo].[AccountNumber] NULL, 706 | [CustomerID] [int] NOT NULL, 707 | [SalesPersonID] [int] NULL, 708 | [TerritoryID] [int] NULL, 709 | [BillToAddressID] [int] NOT NULL, 710 | [ShipToAddressID] [int] NOT NULL, 711 | [ShipMethodID] [int] NOT NULL, 712 | [CreditCardID] [int] NULL, 713 | [CreditCardApprovalCode] [varchar](15) NULL, 714 | [CurrencyRateID] [int] NULL, 715 | [SubTotal] [money] NOT NULL, 716 | [TaxAmt] [money] NOT NULL, 717 | [Freight] [money] NOT NULL, 718 | [TotalDue] AS (isnull(([SubTotal]+[TaxAmt])+[Freight],(0))) PERSISTED, 719 | [Comment] [nvarchar](128) NULL, 720 | [rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL, 721 | [ModifiedDate] [datetime] NOT NULL 722 | ) 723 | ON ps_l_salespers(SalesPersonID) 724 | go 725 | 726 | Create Clustered Index CI_SOH_Spers on SalesOrderHeader (SalesPersonID, TerritoryID) 727 | ON ps_l_salespers(SalesPersonID) 728 | 729 | 730 | Create nonclustered index NC_SOH_CUST on SalesOrderHeader(CustomerID) 731 | on ps_l_salespers(SalesPersonID) 732 | go 733 | 734 | Create nonclustered index NC_SOH_ACCT on SalesOrderHeader(AccountNumber) 735 | on ps_l_salespers(SalesPersonID) 736 | go 737 | 738 | Create nonclustered index NC_SOH_SONBR on SalesOrderHeader(SalesOrderNumber) 739 | on ps_l_salespers(SalesPersonID) 740 | go 741 | 742 | Create nonclustered index NC_SOH_TERR on SalesOrderHeader(TerritoryID, AccountNumber) 743 | INCLUDE(ShipDate, DueDate) 744 | on ps_l_salespers(SalesPersonID) 745 | go 746 | 747 | Create unique nonclustered index NC_SOH_SOID on SalesOrderHeader([SalesOrderID], [OrderDate], [SalesPersonID]) 748 | on ps_l_salespers(SalesPersonID) 749 | go 750 | 751 | set identity_insert SalesOrderHeader ON 752 | 753 | insert into SalesOrderHeader with (TABLOCK) 754 | ( [SalesOrderID] 755 | ,[RevisionNumber] 756 | ,[OrderDate] 757 | ,[DueDate] 758 | ,[ShipDate] 759 | ,[Status] 760 | ,[OnlineOrderFlag] 761 | -- ,[SalesOrderNumber] 762 | ,[PurchaseOrderNumber] 763 | ,[AccountNumber] 764 | ,[CustomerID] 765 | ,[SalesPersonID] 766 | ,[TerritoryID] 767 | ,[BillToAddressID] 768 | ,[ShipToAddressID] 769 | ,[ShipMethodID] 770 | ,[CreditCardID] 771 | ,[CreditCardApprovalCode] 772 | ,[CurrencyRateID] 773 | ,[SubTotal] 774 | ,[TaxAmt] 775 | ,[Freight] 776 | -- ,[TotalDue] 777 | ,[Comment] 778 | ,[rowguid] 779 | ,[ModifiedDate]) 780 | SELECT [SalesOrderID] 781 | ,[RevisionNumber] 782 | ,[OrderDate] 783 | ,[DueDate] 784 | ,[ShipDate] 785 | ,[Status] 786 | ,[OnlineOrderFlag] 787 | -- ,[SalesOrderNumber] 788 | ,[PurchaseOrderNumber] 789 | ,[AccountNumber] 790 | ,[CustomerID] 791 | ,[SalesPersonID] 792 | ,[TerritoryID] 793 | ,[BillToAddressID] 794 | ,[ShipToAddressID] 795 | ,[ShipMethodID] 796 | ,[CreditCardID] 797 | ,[CreditCardApprovalCode] 798 | ,[CurrencyRateID] 799 | ,[SubTotal] 800 | ,[TaxAmt] 801 | ,[Freight] 802 | -- ,[TotalDue] 803 | ,[Comment] 804 | ,[rowguid] 805 | ,[ModifiedDate] 806 | from AdventureWorks.Sales.SalesOrderHeader; 807 | 808 | SET ANSI_PADDING ON 809 | GO 810 | 811 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_Address_BillToAddressID] FOREIGN KEY([BillToAddressID]) 812 | REFERENCES [Address] ([AddressID]) 813 | GO 814 | 815 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_Address_BillToAddressID] 816 | GO 817 | 818 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_Address_ShipToAddressID] FOREIGN KEY([ShipToAddressID]) 819 | REFERENCES [Address] ([AddressID]) 820 | GO 821 | 822 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_Address_ShipToAddressID] 823 | GO 824 | 825 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_CurrencyRate_CurrencyRateID] FOREIGN KEY([CurrencyRateID]) 826 | REFERENCES [CurrencyRate] ([CurrencyRateID]) 827 | GO 828 | 829 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_CurrencyRate_CurrencyRateID] 830 | GO 831 | 832 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_DueDate] CHECK (([DueDate]>=[OrderDate])) 833 | GO 834 | 835 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_DueDate] 836 | GO 837 | 838 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_Freight] CHECK (([Freight]>=(0.00))) 839 | GO 840 | 841 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_Freight] 842 | GO 843 | 844 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_ShipDate] CHECK (([ShipDate]>=[OrderDate] OR [ShipDate] IS NULL)) 845 | GO 846 | 847 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_ShipDate] 848 | GO 849 | 850 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_Status] CHECK (([Status]>=(0) AND [Status]<=(8))) 851 | GO 852 | 853 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_Status] 854 | GO 855 | 856 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_SubTotal] CHECK (([SubTotal]>=(0.00))) 857 | GO 858 | 859 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_SubTotal] 860 | GO 861 | 862 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_TaxAmt] CHECK (([TaxAmt]>=(0.00))) 863 | GO 864 | 865 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_TaxAmt] 866 | GO 867 | 868 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_RevisionNumber] DEFAULT ((0)) FOR [RevisionNumber] 869 | GO 870 | 871 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_OrderDate] DEFAULT (getdate()) FOR [OrderDate] 872 | GO 873 | 874 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_Status] DEFAULT ((1)) FOR [Status] 875 | GO 876 | 877 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_OnlineOrderFlag] DEFAULT ((1)) FOR [OnlineOrderFlag] 878 | GO 879 | 880 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_SubTotal] DEFAULT ((0.00)) FOR [SubTotal] 881 | GO 882 | 883 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_TaxAmt] DEFAULT ((0.00)) FOR [TaxAmt] 884 | GO 885 | 886 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_Freight] DEFAULT ((0.00)) FOR [Freight] 887 | GO 888 | 889 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_rowguid] DEFAULT (newid()) FOR [rowguid] 890 | GO 891 | 892 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_ModifiedDate] DEFAULT (getdate()) FOR [ModifiedDate] 893 | GO 894 | 895 | ALTER INDEX NC_SOH_SONBR on SalesOrderHeader DISABLE 896 | go 897 | 898 | ------------------------------------------------------- 899 | /* ManagePartition tests: 900 | 901 | ManagePartition /C:CreateStagingFull /PartitionRangeValue:280 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t1 902 | 903 | ManagePartition /C:CreateStagingClusteredIndex /PartitionRangeValue:290 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t2 904 | 905 | ManagePartition /C:CreateStagingNoIndex /PartitionRangeValue:270 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t3 906 | 907 | */ 908 | ------------------------------------------------------- 909 | Alter table [SalesOrderHeader] switch partition 2 to t1; 910 | go 911 | Alter table t1 switch to [SalesOrderHeader] partition 2; 912 | go 913 | 914 | -- ManagePartition /C:IndexStaging /PartitionRangeValue:290 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t2 915 | 916 | Alter table [SalesOrderHeader] switch partition 4 to t2; 917 | go 918 | Alter table t2 switch to [SalesOrderHeader] partition 4; 919 | go 920 | -- ManagePartition /C:IndexStaging /PartitionRangeValue:270 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t3 921 | 922 | Alter table [SalesOrderHeader] switch partition 1 to t3; 923 | go 924 | Alter table t3 switch to [SalesOrderHeader] partition 1; 925 | go 926 | 927 | --------------------------------------------------------- 928 | 929 | -- Range right nullable int Key 930 | 931 | DROP TABLE SalesOrderHeader; 932 | go 933 | drop table t1; 934 | go 935 | drop table t2; 936 | go 937 | drop table t3; 938 | go 939 | CREATE TABLE [SalesOrderHeader]( 940 | [SalesOrderID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, 941 | [RevisionNumber] [tinyint] NOT NULL, 942 | [OrderDate] [datetime] NOT NULL, 943 | [DueDate] [datetime] NOT NULL, 944 | [ShipDate] [datetime] NULL, 945 | [Status] [tinyint] NOT NULL, 946 | [OnlineOrderFlag] [dbo].[Flag] NOT NULL, 947 | [SalesOrderNumber] AS (isnull(N'SO'+CONVERT([nvarchar](23),[SalesOrderID],0),N'*** ERROR ***')), 948 | [PurchaseOrderNumber] [dbo].[OrderNumber] NULL, 949 | [AccountNumber] [dbo].[AccountNumber] NULL, 950 | [CustomerID] [int] NOT NULL, 951 | [SalesPersonID] [int] NULL, 952 | [TerritoryID] [int] NULL, 953 | [BillToAddressID] [int] NOT NULL, 954 | [ShipToAddressID] [int] NOT NULL, 955 | [ShipMethodID] [int] NOT NULL, 956 | [CreditCardID] [int] NULL, 957 | [CreditCardApprovalCode] [varchar](15) NULL, 958 | [CurrencyRateID] [int] NULL, 959 | [SubTotal] [money] NOT NULL, 960 | [TaxAmt] [money] NOT NULL, 961 | [Freight] [money] NOT NULL, 962 | [TotalDue] AS (isnull(([SubTotal]+[TaxAmt])+[Freight],(0))) PERSISTED, 963 | [Comment] [nvarchar](128) NULL, 964 | [rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL, 965 | [ModifiedDate] [datetime] NOT NULL 966 | ) 967 | ON ps_r_salespers(SalesPersonID) 968 | go 969 | 970 | Create Clustered Index CI_SOH_Spers on SalesOrderHeader (SalesPersonID, TerritoryID) 971 | ON ps_r_salespers(SalesPersonID) 972 | 973 | 974 | Create nonclustered index NC_SOH_CUST on SalesOrderHeader(CustomerID) 975 | on ps_r_salespers(SalesPersonID) 976 | go 977 | 978 | Create nonclustered index NC_SOH_ACCT on SalesOrderHeader(AccountNumber) 979 | on ps_r_salespers(SalesPersonID) 980 | go 981 | 982 | Create nonclustered index NC_SOH_SONBR on SalesOrderHeader(SalesOrderNumber) 983 | on ps_r_salespers(SalesPersonID) 984 | go 985 | 986 | Create nonclustered index NC_SOH_TERR on SalesOrderHeader(TerritoryID, AccountNumber) 987 | INCLUDE(ShipDate, DueDate) 988 | on ps_r_salespers(SalesPersonID) 989 | go 990 | 991 | Create unique nonclustered index NC_SOH_SOID on SalesOrderHeader([SalesOrderID], [OrderDate], [SalesPersonID]) 992 | on ps_r_salespers(SalesPersonID) 993 | go 994 | 995 | set identity_insert SalesOrderHeader ON 996 | 997 | insert into SalesOrderHeader with (TABLOCK) 998 | ( [SalesOrderID] 999 | ,[RevisionNumber] 1000 | ,[OrderDate] 1001 | ,[DueDate] 1002 | ,[ShipDate] 1003 | ,[Status] 1004 | ,[OnlineOrderFlag] 1005 | -- ,[SalesOrderNumber] 1006 | ,[PurchaseOrderNumber] 1007 | ,[AccountNumber] 1008 | ,[CustomerID] 1009 | ,[SalesPersonID] 1010 | ,[TerritoryID] 1011 | ,[BillToAddressID] 1012 | ,[ShipToAddressID] 1013 | ,[ShipMethodID] 1014 | ,[CreditCardID] 1015 | ,[CreditCardApprovalCode] 1016 | ,[CurrencyRateID] 1017 | ,[SubTotal] 1018 | ,[TaxAmt] 1019 | ,[Freight] 1020 | -- ,[TotalDue] 1021 | ,[Comment] 1022 | ,[rowguid] 1023 | ,[ModifiedDate]) 1024 | SELECT [SalesOrderID] 1025 | ,[RevisionNumber] 1026 | ,[OrderDate] 1027 | ,[DueDate] 1028 | ,[ShipDate] 1029 | ,[Status] 1030 | ,[OnlineOrderFlag] 1031 | -- ,[SalesOrderNumber] 1032 | ,[PurchaseOrderNumber] 1033 | ,[AccountNumber] 1034 | ,[CustomerID] 1035 | ,[SalesPersonID] 1036 | ,[TerritoryID] 1037 | ,[BillToAddressID] 1038 | ,[ShipToAddressID] 1039 | ,[ShipMethodID] 1040 | ,[CreditCardID] 1041 | ,[CreditCardApprovalCode] 1042 | ,[CurrencyRateID] 1043 | ,[SubTotal] 1044 | ,[TaxAmt] 1045 | ,[Freight] 1046 | -- ,[TotalDue] 1047 | ,[Comment] 1048 | ,[rowguid] 1049 | ,[ModifiedDate] 1050 | from AdventureWorks.Sales.SalesOrderHeader; 1051 | 1052 | SET ANSI_PADDING ON 1053 | GO 1054 | 1055 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_Address_BillToAddressID] FOREIGN KEY([BillToAddressID]) 1056 | REFERENCES [Address] ([AddressID]) 1057 | GO 1058 | 1059 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_Address_BillToAddressID] 1060 | GO 1061 | 1062 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_Address_ShipToAddressID] FOREIGN KEY([ShipToAddressID]) 1063 | REFERENCES [Address] ([AddressID]) 1064 | GO 1065 | 1066 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_Address_ShipToAddressID] 1067 | GO 1068 | 1069 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [FK_SalesOrderHeader_CurrencyRate_CurrencyRateID] FOREIGN KEY([CurrencyRateID]) 1070 | REFERENCES [CurrencyRate] ([CurrencyRateID]) 1071 | GO 1072 | 1073 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [FK_SalesOrderHeader_CurrencyRate_CurrencyRateID] 1074 | GO 1075 | 1076 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_DueDate] CHECK (([DueDate]>=[OrderDate])) 1077 | GO 1078 | 1079 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_DueDate] 1080 | GO 1081 | 1082 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_Freight] CHECK (([Freight]>=(0.00))) 1083 | GO 1084 | 1085 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_Freight] 1086 | GO 1087 | 1088 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_ShipDate] CHECK (([ShipDate]>=[OrderDate] OR [ShipDate] IS NULL)) 1089 | GO 1090 | 1091 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_ShipDate] 1092 | GO 1093 | 1094 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_Status] CHECK (([Status]>=(0) AND [Status]<=(8))) 1095 | GO 1096 | 1097 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_Status] 1098 | GO 1099 | 1100 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_SubTotal] CHECK (([SubTotal]>=(0.00))) 1101 | GO 1102 | 1103 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_SubTotal] 1104 | GO 1105 | 1106 | ALTER TABLE [SalesOrderHeader] WITH CHECK ADD CONSTRAINT [CK_SalesOrderHeader_TaxAmt] CHECK (([TaxAmt]>=(0.00))) 1107 | GO 1108 | 1109 | ALTER TABLE [SalesOrderHeader] CHECK CONSTRAINT [CK_SalesOrderHeader_TaxAmt] 1110 | GO 1111 | 1112 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_RevisionNumber] DEFAULT ((0)) FOR [RevisionNumber] 1113 | GO 1114 | 1115 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_OrderDate] DEFAULT (getdate()) FOR [OrderDate] 1116 | GO 1117 | 1118 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_Status] DEFAULT ((1)) FOR [Status] 1119 | GO 1120 | 1121 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_OnlineOrderFlag] DEFAULT ((1)) FOR [OnlineOrderFlag] 1122 | GO 1123 | 1124 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_SubTotal] DEFAULT ((0.00)) FOR [SubTotal] 1125 | GO 1126 | 1127 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_TaxAmt] DEFAULT ((0.00)) FOR [TaxAmt] 1128 | GO 1129 | 1130 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_Freight] DEFAULT ((0.00)) FOR [Freight] 1131 | GO 1132 | 1133 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_rowguid] DEFAULT (newid()) FOR [rowguid] 1134 | GO 1135 | 1136 | ALTER TABLE [SalesOrderHeader] ADD CONSTRAINT [DF_SalesOrderHeader_ModifiedDate] DEFAULT (getdate()) FOR [ModifiedDate] 1137 | GO 1138 | 1139 | ALTER INDEX NC_SOH_SONBR on SalesOrderHeader DISABLE 1140 | go 1141 | 1142 | 1143 | ---------------------------------------------------- 1144 | 1145 | /* ManagePartition tests: 1146 | 1147 | ManagePartition /C:CreateStagingFull /PartitionRangeValue:280 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t1 1148 | 1149 | ManagePartition /C:CreateStagingClusteredIndex /PartitionRangeValue:295 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t2 1150 | 1151 | ManagePartition /C:CreateStagingNoIndex /PartitionRangeValue:270 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t3 1152 | 1153 | */ 1154 | ------------------------------------------------------- 1155 | Alter table [SalesOrderHeader] switch partition 3 to t1; 1156 | go 1157 | Alter table t1 switch to [SalesOrderHeader] partition 3; 1158 | go 1159 | 1160 | -- ManagePartition /C:IndexStaging /PartitionRangeValue:290 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t2 1161 | 1162 | Alter table [SalesOrderHeader] switch partition 5 to t2; 1163 | go 1164 | Alter table t2 switch to [SalesOrderHeader] partition 5; 1165 | go 1166 | -- ManagePartition /C:IndexStaging /PartitionRangeValue:270 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t3 1167 | 1168 | Alter table [SalesOrderHeader] switch partition 1 to t3; 1169 | go 1170 | Alter table t3 switch to [SalesOrderHeader] partition 1; 1171 | go 1172 | 1173 | ------------------ 1174 | -- ClearPartition tests 1175 | 1176 | drop table t1; 1177 | go 1178 | drop table t2; 1179 | go 1180 | drop table t3; 1181 | go 1182 | 1183 | --------------------------------------------------------- 1184 | /* 1185 | 1186 | ManagePartition /C:ClearPartition /PartitionRangeValue:285 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /K+ 1187 | 1188 | ManagePartition /C:ClearPartition /PartitionRangeValue:280 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t2 /K+ 1189 | 1190 | ManagePartition /C:ClearPartition /PartitionRangeValue:290 /S:localhost /E /d:PartitionTest /s:dbo /t:SalesOrderHeader /A:t3 /K- 1191 | 1192 | */ 1193 | --------------------------------------------------------- 1194 | 1195 | -- Should be empty: 1196 | 1197 | select * from SalesOrderHeader where SalesPersonID between 280 and 290; -------------------------------------------------------------------------------- /readme.htm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucazav/SqlServerPartitionManagementUtility/653e05fc86ea37a48d8145fa99e2a3f08cbb010a/readme.htm -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ### Welcome! 2 | This is a fork of the most used tool provided by the SQL CAT team to manage partitions in SQL Server ([https://sqlpartitionmgmt.codeplex.com/](https://sqlpartitionmgmt.codeplex.com/)). 3 | 4 | It provides a set of commands (at the Command Line or via Powershell) to create a staging table on-demand (including all appropriate indexes and constraints) based on a specific partitioned table and a particular partition of interest. 5 | By calling this executable, with parameters, from maintenance scripts or SSIS packages, DBAs can avoid having to "hard code" table and index definition scripts for staging tables. This solves the problem of keeping staging table scripts in synch when a permanent partitioned table evolves to contain new boundary values or column attributes. It also provides a fast, single-command shortcut for the operation of quickly deleting all data from a partition. 6 | 7 | I decided to fork the project because it seems that the owner of the project Stuart Ozer abandoned it (the last update was on November 28, 2012). New feature are added and some issues are fixed as you can see in the [Releases Page](https://github.com/lucazav/sqlserverpartitionmanager/releases), where you can find the executables too. 8 | 9 | If you want to collaborate, you're welcome! :) Just let me know and I'll add you as a contributor. 10 | 11 | ### Authors and Contributors 12 | The original project creator is [Stuart Ozer](https://social.msdn.microsoft.com/Profile/stuart%20ozer%20msft) 13 | -------------------------------------------------------------------------------- /readme_files/colorschememapping.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /readme_files/filelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /readme_files/themedata.thmx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucazav/SqlServerPartitionManagementUtility/653e05fc86ea37a48d8145fa99e2a3f08cbb010a/readme_files/themedata.thmx --------------------------------------------------------------------------------