├── .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
--------------------------------------------------------------------------------