diff --git a/CHANGELOG.md b/CHANGELOG.md
index 39818cc1..29c79e0e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,11 @@
Update this document for externally visible changes. Put most recent changes first.
Once we push a new version to nuget.org add a double hash header for that version.
+# 172.64.0
+
+- Add DesignMode support to `QueryStoreOptions` class
+- Add Vector data type support
+
# 172.61.0
- Remove major version restriction on Microsoft.Data.SqlClient dependency Fixes [Issue 188](https://github.com/microsoft/sqlmanagementobjects/issues/188)
diff --git a/Packages.props b/Packages.props
deleted file mode 100644
index 9aabaf6d..00000000
--- a/Packages.props
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
- 6.0.0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/README.md b/docs/README.md
index 59ab5a45..106bf94b 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -31,6 +31,21 @@ Create a corresponding partial class in `%basedir%\src\Microsoft\SqlServer\Manag
7. Add a UrnSuffix: `public static string UrnSuffix => "";`
8. If the object is scriptable on its own, not directly included as part of the script for its parent, reference its UrnSuffix in the scriptableTypes HashSet in ScriptMaker.cs.
+### DesignMode
+
+`DesignMode` (or `Design Mode`) is the label for an instance of the object hierarchy whose root `Server` object is using a `ServerConnection` that's in `Offline` mode. Any object added to a child collection in a `DesignMode` hierarchy is automatically set to the `Existing` state.
+
+
+When the connection is offline, many code paths get short circuited and skip running queries, leaving the objects in whatever state the caller has set them. Correct support for DesignMode in your object will enable it to be used for offline unit tests. In `DesignMode`, certain methods like `Alter` are blocked completely, but unit tests can call the internal `ScriptAlter` method and validate that correct scripts are generated based on the set of properties the unit test set. Such a unit test can detect bugs that affect non-DesignMode operation, such as a failure to properly check if a property has been set on the object before trying to reference its value.
+
+If an object property is not explicitly set by a caller and that object doesn't have a `default` value set for it in [cfg.xml](/src/Codegen/cfg.xml), attempting to get the property value will result in an exception. Typically, readonly properties _should_ have a default value assigned. Default values for settable properties are optional, and may be limited to the properties that don't directly affect the `ScriptAlter` implementation of the object.
+
+To make an object available in `DesignMode`, add `is_design_mode="true"` attribute to its definition in `cfg.xml`. To mark a property explicitly as `DesignMode`-friendly, use `mode="design"` in its definition in the object XML file. Note that `mode="deploy"` no longer seems to have any effect and can be removed or changed to `mode="all"` if you want to make an existing property available for `DesignMode`.
+
+Adding an existing property to `DesignMode` is safe because it doesn't change its behavior at all in normal connected scenarios.
+
+It's not clear how decisions were made in the past to choose which objects and properties support DesignMode. Going forward, we recommend new code supports DesignMode and includes appropriate offline unit tests.
+
### Collections
If your new object is part of a collection under a parent object, create a corresponding .cs file for your new collection. This can be done by adding an entry to [collections_codegen.proj](/src/codegen/README.md#collections_codegen.proj) and building that project. Then add the appropriate `````` tag to [Microsoft.SqlServer.Smo.csproj](/src/Microsoft/SqlServer/Management/Smo/Microsoft.SqlServer.Smo.csproj).
diff --git a/global.json b/global.json
index 957d4ef8..ffa7d0b4 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.405",
+ "version": "8.0.406",
"rollForward": "latestMinor"
},
"msbuild-sdks": {
diff --git a/src/Codegen/README.md b/src/Codegen/README.md
index c2a458e2..6c2168bd 100644
--- a/src/Codegen/README.md
+++ b/src/Codegen/README.md
@@ -315,7 +315,9 @@ public void Deny(ObjectPermissionSet permission, System.String granteeName)
#### Parent_has_setter
-#### Is_design_mode
+#### is_design_mode
+
+Set this property to `true` to allow your object to participate in `DesignMode`. Such objects can be unit tested with an offline connection. Most objects should have this set.
#### Parent_mode
diff --git a/src/Codegen/SmoCodeGen.csproj b/src/Codegen/SmoCodeGen.csproj
index 5b31bfd6..e9e6b1ec 100644
--- a/src/Codegen/SmoCodeGen.csproj
+++ b/src/Codegen/SmoCodeGen.csproj
@@ -77,6 +77,7 @@
+
@@ -129,6 +130,9 @@
+
+
+
diff --git a/src/Codegen/cfg.xml b/src/Codegen/cfg.xml
index 6dc26127..b79bf081 100644
--- a/src/Codegen/cfg.xml
+++ b/src/Codegen/cfg.xml
@@ -46,7 +46,7 @@
-
+
@@ -2179,15 +2179,15 @@
-
+
-
+
-
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 49a67cf5..ce798220 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -84,7 +84,7 @@
- 172.1.1
+ 172.18.0
Microsoft.Data.SqlClient
5.1.6
diff --git a/src/FunctionalTest/Smo/ScriptingTests/Column_SmoTestSuite.cs b/src/FunctionalTest/Smo/ScriptingTests/Column_SmoTestSuite.cs
index 2434303f..1be4e15a 100644
--- a/src/FunctionalTest/Smo/ScriptingTests/Column_SmoTestSuite.cs
+++ b/src/FunctionalTest/Smo/ScriptingTests/Column_SmoTestSuite.cs
@@ -141,6 +141,11 @@ private static IEnumerable GetAllDataTypeColumns(_SMO.Database
{
yield return new ColumnProperties($"col{i++}", _SMO.DataType.Json);
}
+
+ if (database.Parent.ServerType != DatabaseEngineType.Standalone || database.Parent.VersionMajor > 17)
+ {
+ yield return new ColumnProperties($"col{i++}", _SMO.DataType.Vector(2));
+ }
}
[TestMethod]
diff --git a/src/FunctionalTest/Smo/ScriptingTests/SmoTestFramework/SmoTestBase.cs b/src/FunctionalTest/Smo/ScriptingTests/SmoTestFramework/SmoTestBase.cs
index f020cfdf..566a7101 100644
--- a/src/FunctionalTest/Smo/ScriptingTests/SmoTestFramework/SmoTestBase.cs
+++ b/src/FunctionalTest/Smo/ScriptingTests/SmoTestFramework/SmoTestBase.cs
@@ -106,6 +106,18 @@ public static IEnumerable> TestServerScriptingOp
OptimizerData = true,
Permissions = true
});
+ yield return new Tuple(
+ "Sqlv170",
+ new ScriptingOptions()
+ {
+ ExtendedProperties = true,
+ TargetDatabaseEngineType = DatabaseEngineType.Standalone,
+ TargetServerVersion = SqlServerVersion.Version170,
+ IncludeScriptingParametersHeader = true,
+ OptimizerData = true,
+ Permissions = true
+ });
+ // VBUMP : Add new server versions here
yield return new Tuple(
"AzureSterlingV12",
new ScriptingOptions()
diff --git a/src/FunctionalTest/Smo/ScriptingTests/Table_SmoTestSuite.cs b/src/FunctionalTest/Smo/ScriptingTests/Table_SmoTestSuite.cs
index 67f362fe..38852d92 100644
--- a/src/FunctionalTest/Smo/ScriptingTests/Table_SmoTestSuite.cs
+++ b/src/FunctionalTest/Smo/ScriptingTests/Table_SmoTestSuite.cs
@@ -4065,6 +4065,50 @@ public void ScriptingJsonColumnCrossVersionTest()
#endregion
+ #region Vector column tests
+ ///
+ /// This test verifies that JSON column is correctly scripted for insert statements.
+ ///
+ [TestMethod]
+ [SupportedServerVersionRange(DatabaseEngineType = DatabaseEngineType.SqlAzureDatabase)]
+ [SupportedServerVersionRange(DatabaseEngineType = DatabaseEngineType.Standalone, MinMajor = 17)]
+ [UnsupportedDatabaseEngineEdition(DatabaseEngineEdition.SqlDataWarehouse)]
+ public void ScriptingInsertTableWithVectorColumnTest()
+ {
+ ExecuteFromDbPool(
+ this.TestContext.FullyQualifiedTestClassName,
+ (database) =>
+ {
+ if (database.Parent.ServerType != DatabaseEngineType.Standalone || database.Parent.VersionMajor > 17)
+ {
+ string queryMatch = @"INSERT \[.*\]\.\[.*\] \(\[vectorColumn\]\) VALUES \(CAST\(N'\[0\.0000000e\+000,0\.0000000e\+000\]' AS Vector\(2\)\)\)";
+
+ var table = new Table(database, "vectorTable");
+ var vectorColumn = new Column(table, "vectorColumn", DataType.Vector(2));
+ table.Columns.Add(vectorColumn);
+ table.Create();
+
+ string insertQuery = $"INSERT INTO {table.Name.SqlBracketQuoteString()} values('[0,0]')";
+
+ database.ExecuteNonQuery(insertQuery);
+
+ var scripter = new Scripter(database.Parent);
+ scripter.Options.ScriptData = true;
+ scripter.Options.ScriptSchema = true;
+
+ IEnumerable scripts = scripter.EnumScript(new Urn[] { table.Urn });
+ Assert.That(scripts, Has.One.Matches(queryMatch).IgnoreCase, "Scripting of Vector tables is expected to generate a valid INSERT statement");
+
+ table.DropIfExists();
+ string tableCreateScript = (from string script in scripts where script.StartsWith("CREATE", StringComparison.InvariantCultureIgnoreCase) select script).First();
+ database.ExecuteNonQuery(tableCreateScript);
+ database.Tables.ClearAndInitialize(string.Empty, null);
+ Assert.That(database.Tables, Has.One.Items.Matches(i => i.Name == table.Name), "Table should be created successfully.");
+ }
+ });
+ }
+ #endregion // Vector column tests
+
#endregion // Scripting Tests
#region Sparse column tests
diff --git a/src/Microsoft/SqlServer/Management/RegisteredServers/RegisteredServer.cs b/src/Microsoft/SqlServer/Management/RegisteredServers/RegisteredServer.cs
index 56b6a89f..c1dbfe11 100644
--- a/src/Microsoft/SqlServer/Management/RegisteredServers/RegisteredServer.cs
+++ b/src/Microsoft/SqlServer/Management/RegisteredServers/RegisteredServer.cs
@@ -1,12 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-/*************************************************************
-* *
-* Copyright (C) Microsoft Corporation. All rights reserved.*
-* *
-*************************************************************/
-
using System;
using System.Collections.Generic;
using System.Text;
diff --git a/src/Microsoft/SqlServer/Management/Sdk/Sfc/Enumerator/Util.cs b/src/Microsoft/SqlServer/Management/Sdk/Sfc/Enumerator/Util.cs
index 79105689..f61aaab5 100644
--- a/src/Microsoft/SqlServer/Management/Sdk/Sfc/Enumerator/Util.cs
+++ b/src/Microsoft/SqlServer/Management/Sdk/Sfc/Enumerator/Util.cs
@@ -15,51 +15,52 @@ namespace Microsoft.SqlServer.Management.Sdk.Sfc
/// Contains common utility functions
///
public class Util
- {
- ///
- /// Convert a database type name to the equivalent CLS type
- ///
- ///
- ///
+ {
+ ///
+ /// Convert a database type name to the equivalent CLS type
+ ///
+ ///
+ ///
static public String DbTypeToClrType(String strDBType)
- {
- String strType;
- switch(strDBType)
- {
- case "xml":goto case "text";
- case "json": goto case "text";
- case "nvarchar":goto case "text";
- case "varchar":goto case "text";
- case "sysname":goto case "text";
- case "nchar":goto case "text";
- case "char":goto case "text";
- case "ntext":goto case "text";
- case "text":
- strType = "System.String";
- break;
- case "int":
- strType = "System.Int32";
- break;
- case "bigint":
- strType = "System.Int64";
- break;
- case "bit":
- strType = "System.Boolean";
- break;
- case "long":
- strType = "System.Int32";
- break;
- case "real":goto case "float";
- case "float":
- strType = "System.Double";
- break;
+ {
+ String strType;
+ switch(strDBType)
+ {
+ case "xml":
+ case "json":
+ case "vector":
+ case "nvarchar":
+ case "varchar":
+ case "sysname":
+ case "nchar":
+ case "char":
+ case "ntext":
+ case "text":
+ strType = "System.String";
+ break;
+ case "int":
+ strType = "System.Int32";
+ break;
+ case "bigint":
+ strType = "System.Int64";
+ break;
+ case "bit":
+ strType = "System.Boolean";
+ break;
+ case "long":
+ strType = "System.Int32";
+ break;
+ case "real":goto case "float";
+ case "float":
+ strType = "System.Double";
+ break;
case "datetime":
case "datetime2":
case "date":
// For "date" in particular, it is assumed the time portion is zeroed, so in effect merging it with a "time" (as a client-side TimeSpan) would merely
// add its ticks to the date to make a complete date+time for a DateTime object.
strType = "System.DateTime";
- break;
+ break;
case "datetimeoffset":
strType = "System.DateTimeOffset";
break;
@@ -71,32 +72,32 @@ static public String DbTypeToClrType(String strDBType)
// Alternatively, we could go with the convention of also accounting for fractional seconds instead of ticks presented as a T-SQL decimal value.
strType = "System.TimeSpan";
break;
- case "tinyint":
- strType = "System.Byte";
- break;
- case "smallint":
- strType = "System.Int16";
- break;
- case "uniqueidentifier":
- strType = "System.Guid";
- break;
- case "numeric":
- strType = "System.Decimal";
- break;
+ case "tinyint":
+ strType = "System.Byte";
+ break;
+ case "smallint":
+ strType = "System.Int16";
+ break;
+ case "uniqueidentifier":
+ strType = "System.Guid";
+ break;
+ case "numeric":
+ strType = "System.Decimal";
+ break;
case "decimal": goto case "numeric";
- case "binary":goto case "varbinary";
- case "image":goto case "varbinary";
- case "varbinary":
- strType = "System.Byte[]";
- break;
- case "sql_variant":
- strType = "System.Object";
- break;
- default:
- throw new InvalidConfigurationFileEnumeratorException(SfcStrings.UnknownType(strDBType));
- }
- return strType;
- }
+ case "binary":goto case "varbinary";
+ case "image":goto case "varbinary";
+ case "varbinary":
+ strType = "System.Byte[]";
+ break;
+ case "sql_variant":
+ strType = "System.Object";
+ break;
+ default:
+ throw new InvalidConfigurationFileEnumeratorException(SfcStrings.UnknownType(strDBType));
+ }
+ return strType;
+ }
///
/// Transform a dataset into the expected enumeration result type
@@ -104,9 +105,9 @@ static public String DbTypeToClrType(String strDBType)
///
///
///
- protected EnumResult TransformToRequest(DataSet ds, ResultType res)
- {
- if( ResultType.Default == res )
+ protected EnumResult TransformToRequest(DataSet ds, ResultType res)
+ {
+ if( ResultType.Default == res )
{
res = ResultType.DataSet;
}
@@ -118,9 +119,9 @@ protected EnumResult TransformToRequest(DataSet ds, ResultType res)
else
{
TraceHelper.Assert( ResultType.DataTable == res );
- return new EnumResult(ds.Tables[0], res);
+ return new EnumResult(ds.Tables[0], res);
}
- }
+ }
///
/// Escape a particular character in a string
@@ -128,69 +129,69 @@ protected EnumResult TransformToRequest(DataSet ds, ResultType res)
/// The string
/// The character to escape
/// The equivalent string with the character escaped
- public static String EscapeString(String value, char escapeCharacter)
- {
- StringBuilder sb = new StringBuilder();
- foreach(char c in value)
- {
- sb.Append(c);
- if( escapeCharacter == c )
+ public static String EscapeString(String value, char escapeCharacter)
+ {
+ StringBuilder sb = new StringBuilder();
+ foreach(char c in value)
+ {
+ sb.Append(c);
+ if( escapeCharacter == c )
{
sb.Append(c);
}
}
- return sb.ToString();
- }
+ return sb.ToString();
+ }
- static internal String MakeSqlString(String value)
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("N'");
- sb.Append(EscapeString(value, '\''));
- sb.Append("'");
- return sb.ToString();
- }
+ static internal String MakeSqlString(String value)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("N'");
+ sb.Append(EscapeString(value, '\''));
+ sb.Append("'");
+ return sb.ToString();
+ }
///
/// Load assembly replacing it's name.
///
- static public Assembly LoadAssembly(string assemblyName)
- {
- Assembly a = null;
- try
- {
+ static public Assembly LoadAssembly(string assemblyName)
+ {
+ Assembly a = null;
+ try
+ {
String fullName = SmoManagementUtil.GetExecutingAssembly().FullName;
fullName = fullName.Replace(SmoManagementUtil.GetExecutingAssembly().GetName().Name, assemblyName);
- a = SmoManagementUtil.LoadAssembly(fullName);
- }
- catch(Exception e)
- {
- throw new InternalEnumeratorException(SfcStrings.FailedToLoadAssembly(assemblyName) + "\n\n" + e.ToString());
- }
- if( null == a )
- {
- throw new InternalEnumeratorException(SfcStrings.FailedToLoadAssembly(assemblyName));
- }
- return a;
- }
+ a = SmoManagementUtil.LoadAssembly(fullName);
+ }
+ catch(Exception e)
+ {
+ throw new InternalEnumeratorException(SfcStrings.FailedToLoadAssembly(assemblyName) + "\n\n" + e.ToString());
+ }
+ if( null == a )
+ {
+ throw new InternalEnumeratorException(SfcStrings.FailedToLoadAssembly(assemblyName));
+ }
+ return a;
+ }
- static internal Object CreateObjectInstance(Assembly assembly, string objectType)
- {
- Object o = assembly.CreateInstance(objectType,
- false, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
- null, null, CultureInfo.InvariantCulture, null);
- if( null == o )
- {
- throw new InternalEnumeratorException(SfcStrings.CouldNotInstantiateObj(objectType));
- }
- return o;
- }
+ static internal Object CreateObjectInstance(Assembly assembly, string objectType)
+ {
+ Object o = assembly.CreateInstance(objectType,
+ false, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
+ null, null, CultureInfo.InvariantCulture, null);
+ if( null == o )
+ {
+ throw new InternalEnumeratorException(SfcStrings.CouldNotInstantiateObj(objectType));
+ }
+ return o;
+ }
- //stops when a name is completed
- internal static String UnEscapeString(String escapedValue, char startEscapeChar, char escapeChar, ref int index)
- {
+ //stops when a name is completed
+ internal static String UnEscapeString(String escapedValue, char startEscapeChar, char escapeChar, ref int index)
+ {
return UnEscapeString(escapedValue, startEscapeChar, escapeChar, '\0', ref index);
- }
+ }
//stops when a name is completed
internal static String UnEscapeString(string escapedValue, char startEscapeChar, char escapeChar, char partSeperator, ref int index)
@@ -227,10 +228,10 @@ internal static String UnEscapeString(string escapedValue, char startEscapeChar,
}
- internal static StringCollection SplitNames(string name)
- {
+ internal static StringCollection SplitNames(string name)
+ {
return SplitNames(name, '\0');
- }
+ }
internal static StringCollection SplitNames(string name, char partSeperator)
{
@@ -254,70 +255,70 @@ internal static StringCollection SplitNames(string name, char partSeperator)
}
- internal static string EscapeLikePattern(string pattern)
- {
- // The characters: %[]_ are special characters to the sql LIKE operator. To escape them,
- // enclose them in brackets so "ab[_]c" matches "ab_c" and "ab[[]c" matches ab[c
- // more information can be found at:
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_la-lz_115x.asp
+ internal static string EscapeLikePattern(string pattern)
+ {
+ // The characters: %[]_ are special characters to the sql LIKE operator. To escape them,
+ // enclose them in brackets so "ab[_]c" matches "ab_c" and "ab[[]c" matches ab[c
+ // more information can be found at:
+ // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_la-lz_115x.asp
- // defer stringbuilder creation until we know we need to escape
- StringBuilder sb = null;
+ // defer stringbuilder creation until we know we need to escape
+ StringBuilder sb = null;
- for (int i = 0; i < pattern.Length; i++)
- {
- bool escape = false;
+ for (int i = 0; i < pattern.Length; i++)
+ {
+ bool escape = false;
- switch(pattern[i])
- {
- case '%':
- case '[':
- case '_':
- escape = true;
- break;
-
- default:
- break;
- }
+ switch(pattern[i])
+ {
+ case '%':
+ case '[':
+ case '_':
+ escape = true;
+ break;
+
+ default:
+ break;
+ }
- if (escape && null == sb)
- {
- // Havent had to escape yet,
- // put the leading portion of the string into the stringbuilder
- // from now on, every char will go into the
- // the StringBuilder
- sb = new StringBuilder(pattern.Length * 3);
- sb.Append(pattern.Substring(0, i));
- }
+ if (escape && null == sb)
+ {
+ // Havent had to escape yet,
+ // put the leading portion of the string into the stringbuilder
+ // from now on, every char will go into the
+ // the StringBuilder
+ sb = new StringBuilder(pattern.Length * 3);
+ sb.Append(pattern.Substring(0, i));
+ }
- // if we are going to escape this character, then sb should not be null
- TraceHelper.Assert(!escape || sb != null);
+ // if we are going to escape this character, then sb should not be null
+ TraceHelper.Assert(!escape || sb != null);
-
- if (escape)
- {
- sb.Append("[");
- }
+
+ if (escape)
+ {
+ sb.Append("[");
+ }
- if (sb != null)
- {
- sb.Append(pattern[i]);
- }
+ if (sb != null)
+ {
+ sb.Append(pattern[i]);
+ }
- if (escape)
- {
- sb.Append("]");
- }
-
-
- }
+ if (escape)
+ {
+ sb.Append("]");
+ }
+
+
+ }
- // if we didnt do any escaping, just return the pattern, else return the StringBuilder sb
- return sb == null ? pattern : sb.ToString();
-
- }
+ // if we didnt do any escaping, just return the pattern, else return the StringBuilder sb
+ return sb == null ? pattern : sb.ToString();
+
+ }
- }
-
+ }
+
}
diff --git a/src/Microsoft/SqlServer/Management/Smo/DataEnumerator.cs b/src/Microsoft/SqlServer/Management/Smo/DataEnumerator.cs
index 90b60c29..0fe091c6 100644
--- a/src/Microsoft/SqlServer/Management/Smo/DataEnumerator.cs
+++ b/src/Microsoft/SqlServer/Management/Smo/DataEnumerator.cs
@@ -23,14 +23,49 @@ namespace Microsoft.SqlServer.Management.Smo
///
internal class DataEnumerator : IEnumerator, IDisposable
{
+ private class ColumnData
+ {
+ public ColumnData(SqlDataType dataType)
+ {
+ this.DataType = dataType;
+ }
+
+ public SqlDataType DataType { get; }
+
+ private int? numericPrecision = null;
+ public int NumericPrecision
+ {
+ get => numericPrecision ?? throw new InvalidOperationException("NumericPrecision not set");
+ set => numericPrecision = value;
+ }
+
+ private int? numericScale = null;
+ public int NumericScale
+ {
+ get => numericScale ?? throw new InvalidOperationException("NumericScale not set");
+ set => numericScale = value;
+ }
+
+ private string collation = null;
+ public string Collation
+ {
+ get => collation ?? throw new InvalidOperationException("Collation not set");
+ set => collation = value;
+ }
+
+ private int? maxLength = null;
+ public int MaxLength
+ {
+ get => maxLength ?? throw new InvalidOperationException("MaxLength not set");
+ set => maxLength = value;
+ }
+ }
+
#region Private Fields
private SqlDataReader reader;
private SqlConnection conn;
private Database database;
- private Dictionary columnDataType;
- private Dictionary columnNumericPrecision;
- private Dictionary columnNumericScale;
- private Dictionary columnCollation;
+ private Dictionary columnData;
private string tableName;
private string schemaQualifiedTableName;
private ScriptingPreferences options;
@@ -53,10 +88,7 @@ internal class DataEnumerator : IEnumerator, IDisposable
internal DataEnumerator(Table table, ScriptingPreferences options)
{
this.database = table.Parent;
- this.columnNumericScale = new Dictionary(this.database.StringComparer);
- this.columnNumericPrecision = new Dictionary(this.database.StringComparer);
- this.columnCollation = new Dictionary(this.database.StringComparer);
- this.columnDataType = new Dictionary(this.database.StringComparer);
+ this.columnData = new Dictionary(this.database.StringComparer);
this.options = options;
this.tableName = table.FormatFullNameForScripting(options);
@@ -271,9 +303,9 @@ public bool MoveNext()
userOptions = this.database.GetServerObject().UserOptions;
}
- if (this.hasPersisted &&
- userOptions != null &&
- userOptions.IsSupportedProperty("AnsiPadding") &&
+ if (this.hasPersisted &&
+ userOptions != null &&
+ userOptions.IsSupportedProperty("AnsiPadding") &&
!userOptions.AnsiPadding)
{
currentScriptString =
@@ -297,9 +329,9 @@ public bool MoveNext()
{
userOptions = this.database.GetServerObject().UserOptions;
}
- if (this.hasPersisted &&
+ if (this.hasPersisted &&
userOptions != null &&
- userOptions.IsSupportedProperty("AnsiPadding")
+ userOptions.IsSupportedProperty("AnsiPadding")
&& !userOptions.AnsiPadding)
{
//setting ANSI_PADDING OFF if it was off before set on by us
@@ -450,27 +482,33 @@ private void GetColumnNamesAndSelectSQL(out StringBuilder columnNameSQL, out Str
private void StoreDataTypeInformation(Column col)
{
//this stores information which later used while insert statement generation
- this.columnDataType.Add(col.Name, col.UnderlyingSqlDataType);
+ if (!this.columnData.TryGetValue(col.Name, out ColumnData columnData))
+ {
+ columnData = new ColumnData(col.UnderlyingSqlDataType);
+ this.columnData.Add(col.Name, columnData);
+ }
switch (col.UnderlyingSqlDataType)
{
case SqlDataType.Decimal:
case SqlDataType.Numeric:
- this.columnNumericPrecision.Add(col.Name, col.DataType.NumericPrecision);
- this.columnNumericScale.Add(col.Name, col.DataType.NumericScale);
+ columnData.NumericPrecision = col.DataType.NumericPrecision;
+ columnData.NumericScale = col.DataType.NumericScale;
break;
case SqlDataType.Char:
case SqlDataType.VarChar:
case SqlDataType.VarCharMax:
case SqlDataType.Text:
- this.columnCollation.Add(col.Name, col.Collation);
+ columnData.Collation = col.Collation;
+ break;
+ case SqlDataType.Vector:
+ columnData.MaxLength = col.DataType.MaximumLength;
break;
default:
break;
}
}
-
///
/// Returns the current INSERT statement string for the current row in the
/// SQLDataReader
@@ -516,7 +554,7 @@ private String GetNextInsertStatement()
}
else
{
- SqlDataType dataType = this.columnDataType[columnName];
+ SqlDataType dataType = this.columnData[columnName].DataType;
if (dataType == SqlDataType.Timestamp)
{
columnIndex++;
@@ -753,9 +791,9 @@ private string FormatValueByType(string columnName, int columnIndex)
{
string formattedValue = string.Empty;
- SqlDataType dataType = this.columnDataType[columnName]; ;
+ var columnData = this.columnData[columnName];
- switch (dataType)
+ switch (columnData.DataType)
{
case SqlDataType.UserDefinedType:
@@ -800,27 +838,20 @@ private string FormatValueByType(string columnName, int columnIndex)
case SqlDataType.Decimal:
// we have to manually format the string by ToStringing the value first, and then converting
// the potential (European formatted) comma to a period.
- formattedValue = String.Format(
- CultureInfo.InvariantCulture,
- "CAST({0} AS Decimal({1}, {2}))",
- String.Format(
+ var decimalValue = String.Format(
GetUsCultureInfo(),
"{0}",
- this.reader.GetProviderSpecificValue(columnIndex).ToString()),
- this.columnNumericPrecision[columnName],
- this.columnNumericScale[columnName]);
+ this.reader.GetProviderSpecificValue(columnIndex).ToString());
+ formattedValue = $"CAST({decimalValue} AS Decimal({columnData.NumericPrecision}, {columnData.NumericScale}))";
break;
-
case SqlDataType.Numeric:
- formattedValue = String.Format(
- CultureInfo.InvariantCulture,
- "CAST({0} AS Numeric({1}, {2}))",
- String.Format(
+ // we have to manually format the string by ToStringing the value first, and then converting
+ // the potential (European formatted) comma to a period.
+ var numericValue = String.Format(
GetUsCultureInfo(),
"{0}",
- this.reader.GetProviderSpecificValue(columnIndex).ToString()),
- this.columnNumericPrecision[columnName],
- this.columnNumericScale[columnName]);
+ this.reader.GetProviderSpecificValue(columnIndex).ToString());
+ formattedValue = $"CAST({numericValue} AS Numeric({columnData.NumericPrecision}, {columnData.NumericScale}))";
break;
case SqlDataType.DateTime:
@@ -880,10 +911,7 @@ private string FormatValueByType(string columnName, int columnIndex)
}
else
{
- formattedValue = string.Format(CultureInfo.InvariantCulture,
- "CONVERT(TEXT, {0} COLLATE {1})",
- SqlSmoObject.MakeSqlStringForInsert(providerValue),
- this.columnCollation[columnName]);
+ formattedValue = $"CONVERT(TEXT, {SqlSmoObject.MakeSqlStringForInsert(providerValue)} COLLATE {columnData.Collation})";
}
}
else
@@ -923,21 +951,31 @@ private string FormatValueByType(string columnName, int columnIndex)
formattedValue = String.Format(
CultureInfo.InvariantCulture,
"CAST({0} AS Json)", SqlSmoObject.MakeSqlString(this.reader.GetProviderSpecificValue(columnIndex).ToString()));
+ break;
+ case SqlDataType.Vector:
+ string sqlStringValue = SqlSmoObject.MakeSqlString(this.reader.GetProviderSpecificValue(columnIndex).ToString());
+ // Temporary workaround to convert the length of the column to the dimensions for vector types
+ // until sys.columns is updated to include the dimensions of the vector type.
+ // https://msdata.visualstudio.com/SQLToolsAndLibraries/_workitems/edit/3906463
+ // dimensions = (length - 8) / 4
+ // https://learn.microsoft.com/sql/t-sql/data-types/vector-data-type
+ int dimensions = (columnData.MaxLength - 8) / 4;
+ formattedValue = $"CAST({sqlStringValue} AS Vector({dimensions}))";
break;
default:
- // We are explictly handling all types that we support. We will not attempt
+ // We are explicitly handling all types that we support. We will not attempt
// to support types that we don't understand.
//
- Diagnostics.TraceHelper.Trace(SmoApplication.ModuleName, SmoApplication.trAlways, "ERROR: Attempting to script data for type " + dataType);
+ Diagnostics.TraceHelper.Trace(SmoApplication.ModuleName, SmoApplication.trAlways, $"ERROR: Attempting to script data for type {columnData.DataType}");
throw new InvalidSmoOperationException(
ExceptionTemplates.DataScriptingUnsupportedDataTypeException(
this.tableName,
columnName,
- dataType.ToString()));
+ columnData.DataType.ToString()));
}
@@ -1005,9 +1043,9 @@ private void CleanUp()
}
-#endregion
+ #endregion
-#region Enum
+ #region Enum
///
/// The enumeration for the different states of the Enumerator
///
@@ -1021,9 +1059,9 @@ private enum EnumeratorState
PersistedOFF,
Finished
}
-#endregion
+ #endregion
-#region Private Properties
+ #region Private Properties
private SqlConnection Connection
{
get
@@ -1046,7 +1084,7 @@ private SqlConnection Connection
return this.conn;
}
}
-#endregion
+ #endregion
}
}
diff --git a/src/Microsoft/SqlServer/Management/Smo/DataType.cs b/src/Microsoft/SqlServer/Management/Smo/DataType.cs
index 719e0b34..1498b208 100644
--- a/src/Microsoft/SqlServer/Management/Smo/DataType.cs
+++ b/src/Microsoft/SqlServer/Management/Smo/DataType.cs
@@ -54,7 +54,8 @@ public enum SqlDataType
HierarchyId = 41, //system clr type
Geometry = 42, // A datatype used for planar 2-dimensional geometries.
Geography = 43, // A geodetic datatype.
- Json = 44 // A json datatype.
+ Json = 44, // A json datatype.
+ Vector = 45, // A vector datatype.
// !!IMPORTANT!! If updating this with new types make sure to update IsDataTypeSupportedOnTargetVersion and/or IsSystemDataType with the new type!
// You should also update the AllSqlDataTypeValues_SupportedOnAllApplicableVersions unit test with the new type and minimum version
@@ -117,6 +118,12 @@ public DataType(SqlDataType sqlDataType)
this.sqlDataType = sqlDataType;
this.name = GetSqlName(sqlDataType);
break;
+ case SqlDataType.Vector:
+ this.sqlDataType = sqlDataType;
+ this.name = GetSqlName(sqlDataType);
+ // set a default of the max supported value for vector
+ this.MaximumLength = 1998;
+ break;
case SqlDataType.Numeric:
case SqlDataType.Decimal:
// set the default Precision and Scale values when not mentioned anything
@@ -164,6 +171,7 @@ public DataType(SqlDataType sqlDataType, Int32 precisionOrMaxLengthOrScale)
case SqlDataType.Image:
case SqlDataType.NText:
case SqlDataType.Text:
+ case SqlDataType.Vector:
this.sqlDataType = sqlDataType;
this.MaximumLength = precisionOrMaxLengthOrScale;
this.name = GetSqlName(sqlDataType);
@@ -809,6 +817,33 @@ public static DataType Json
get { return new DataType(SqlDataType.Json); }
}
+ ///
+ /// Maximum value of dimensions we can handle. Note that this isn't necessarily the max
+ /// dimensions allowed by the engine since that can change - instead we have this handle
+ /// the highest value allowed and then the engine will throw an error later if it's too high.
+ ///
+ private const int MaxVectorDimensions = (int.MaxValue - 8) / 4;
+
+ ///
+ /// Creates a DataType of type SqlDataType.Vector
+ ///
+ /// The number of dimensions for the vector
+ ///
+ public static DataType Vector(Int32 dimensions)
+ {
+ // Throw a clear error if the dimensions are out of range
+ if (dimensions < 1 || dimensions > MaxVectorDimensions)
+ {
+ throw new ArgumentOutOfRangeException(nameof(dimensions));
+ }
+ // Temporary workaround to convert the dimensions to maxlength for vector types
+ // until sys.columns is updated to include the dimensions of the vector type.
+ // https://msdata.visualstudio.com/SQLToolsAndLibraries/_workitems/edit/3906463
+ // dimensions = (length - 8) / 4
+ // https://learn.microsoft.com/sql/t-sql/data-types/vector-data-type
+ return new DataType(SqlDataType.Vector, (dimensions * 4) + 8);
+ }
+
#endregion
public override string ToString()
@@ -1178,8 +1213,12 @@ internal void ReadFromPropBag(SqlSmoObject sqlObject)
numericScale = (Int32)sqlObject.GetPropValueOptional("NumericScale", 0);
//get the enum for system data types
- //special case for sysname, although it is a UDDT we treat it as a SDT
- if (dt == st || "sysname" == dt)
+ // Special cases:
+ // sysname - although it is a UDDT we treat it as a SDT
+ // vector - underlying type is varbinary, so it is expected not to match
+ if (dt == st ||
+ "sysname" == dt ||
+ ("vector" == dt && "varbinary" == st))
{
name = dt;
// it's a system type
@@ -1203,7 +1242,7 @@ internal void ReadFromPropBag(SqlSmoObject sqlObject)
xmlDocumentConstraint = (XmlDocumentConstraint)sqlObject.GetPropValueOptional("XmlDocumentConstraint", XmlDocumentConstraint.Default);
}
}
- else if( st.Length > 0)
+ else if (st.Length > 0)
{
// UserDefinedDataType
sqlDataType = SqlDataType.UserDefinedDataType;
@@ -1311,6 +1350,8 @@ public string GetSqlName(SqlDataType sqldt)
return "datetime2";
case SqlDataType.Json:
return "json";
+ case SqlDataType.Vector:
+ return "vector";
}
return string.Empty;
@@ -1483,10 +1524,11 @@ public static SqlDataType SqlToEnum(string sqlTypeName)
case "json":
sqlDataType = SqlDataType.Json;
break;
+ case "vector":
+ sqlDataType = SqlDataType.Vector;
+ break;
default:
- /*Removing Strace as in case of computed columns , there might
- * be a case when we donot provide DataTypeName BUG 151436*/
break;
}
return sqlDataType;
@@ -1582,6 +1624,21 @@ private static bool IsSystemDataType160(SqlDataType dataType)
return false;
}
+ private static bool IsSystemDataType170(SqlDataType dataType)
+ {
+ if (IsSystemDataType160(dataType))
+ {
+ return true;
+ }
+
+ switch (dataType)
+ {
+ case SqlDataType.Vector:
+ return true;
+ }
+ return false;
+ }
+
///
/// This function verify whether given data type is system type or not for given version, engine type/edition.
///
@@ -1604,12 +1661,16 @@ internal static bool IsSystemDataType(SqlDataType dataType, SqlServerVersion tar
// Since both of them are supposed to support all system data types, we simply
// treat them as the latest SQL version.
//
- if (engineEdition == DatabaseEngineEdition.SqlManagedInstance || targetVersion >= SqlServerVersion.Version160)
+ if (engineEdition == DatabaseEngineEdition.SqlManagedInstance || targetVersion >= SqlServerVersion.Version170)
{
// If a new type is added later on then a new IsSystemDataType method should be added
// with those new types - and that one set as the default. Also update IsSystemDataTypeOnAzure
// with the new IsSystemDataType method because Azure uses the latest types.
//
+ return IsSystemDataType170(dataType);
+ }
+ else if (targetVersion >= SqlServerVersion.Version160)
+ {
return IsSystemDataType160(dataType);
}
else if (targetVersion <= SqlServerVersion.Version80)
@@ -1686,14 +1747,20 @@ internal static bool IsSystemDataTypeOnAzure(SqlDataType dataType, DatabaseEngin
// If the data type is supported, check if it is a system data type
//
- return isSupported ? IsSystemDataType160(dataType) : false;
+ return isSupported ? IsSystemDataType170(dataType) : false;
}
internal static bool IsDataTypeSupportedOnSqlDw(SqlDataType dataType)
{
- // JSON data type is not supported on SQL DW.
- //
- return dataType != SqlDataType.Json;
+ switch (dataType)
+ {
+ // Put any data types that are not supported on SQL DW here
+ case SqlDataType.Json:
+ case SqlDataType.Vector:
+ return false;
+ default:
+ return true;
+ }
}
internal static void CheckColumnTypeSupportability(string parentName, string columnName, SqlDataType dataType, ScriptingPreferences sp)
diff --git a/src/Microsoft/SqlServer/Management/Smo/Microsoft.SqlServer.Smo.csproj b/src/Microsoft/SqlServer/Management/Smo/Microsoft.SqlServer.Smo.csproj
index 180278b1..7c0bbf4f 100644
--- a/src/Microsoft/SqlServer/Management/Smo/Microsoft.SqlServer.Smo.csproj
+++ b/src/Microsoft/SqlServer/Management/Smo/Microsoft.SqlServer.Smo.csproj
@@ -506,6 +506,7 @@
+
diff --git a/src/Microsoft/SqlServer/Management/Smo/ParamBase.cs b/src/Microsoft/SqlServer/Management/Smo/ParamBase.cs
index 64def682..969f65ef 100644
--- a/src/Microsoft/SqlServer/Management/Smo/ParamBase.cs
+++ b/src/Microsoft/SqlServer/Management/Smo/ParamBase.cs
@@ -229,6 +229,7 @@ private string MakeSqlStringIfRequired(string defaultValue)
case SqlDataType.DateTimeOffset:
case SqlDataType.DateTime2:
case SqlDataType.Json:
+ case SqlDataType.Vector:
return MakeSqlString(defaultValue);
default:
return defaultValue;
diff --git a/src/Microsoft/SqlServer/Management/Smo/QueryStoreEnums.cs b/src/Microsoft/SqlServer/Management/Smo/QueryStoreEnums.cs
new file mode 100644
index 00000000..87d8bb58
--- /dev/null
+++ b/src/Microsoft/SqlServer/Management/Smo/QueryStoreEnums.cs
@@ -0,0 +1,158 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using System;
+using System.ComponentModel;
+
+//1591 is for verifying all public members have xml documentation. It's really heavy handed though - requiring
+//docs for things as specific as each enum value. Disabling since the documentation we have is enough.
+#pragma warning disable 1591
+
+namespace Microsoft.SqlServer.Management.Smo
+{
+ ///
+ /// type converter for QueryStoreOperationMode
+ ///
+ public class QueryStoreOperationModeConverter : EnumToDisplayNameConverter
+ {
+ public QueryStoreOperationModeConverter()
+ : base(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreOperationMode))
+ { }
+ }
+
+ ///
+ /// type converter for QueryStoreCaptureMode
+ ///
+ public class QueryStoreCaptureModeConverter : EnumToDisplayNameConverter
+ {
+ public QueryStoreCaptureModeConverter()
+ : base(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreCaptureMode))
+ { }
+ }
+
+ ///
+ /// type converter for QueryStoreSizeBasedCleanupMode
+ ///
+ public class QueryStoreSizeBasedCleanupModeConverter : EnumToDisplayNameConverter
+ {
+ public QueryStoreSizeBasedCleanupModeConverter()
+ : base(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreSizeBasedCleanupMode))
+ { }
+
+ ///
+ /// Converts the given value object to the specified destination type.
+ ///
+ /// An System.ComponentModel.ITypeDescriptorContext that provides a format context.
+ /// An optional System.Globalization.CultureInfo. If not supplied, the current culture is assumed.
+ /// The System.Object to convert.
+ /// The System.Type to convert the value to.
+ /// An System.Object that represents the converted value.
+ public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+ {
+ if (destinationType == typeof(string) && value == null)
+ {
+ return string.Empty;
+ }
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ ///
+ /// type converter for QueryStoreWaitStatsCaptureMode
+ ///
+ public class QueryStoreWaitStatsCaptureModeConverter : EnumToDisplayNameConverter
+ {
+ public QueryStoreWaitStatsCaptureModeConverter()
+ : base(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreWaitStatsCaptureMode))
+ { }
+
+ ///
+ /// Converts the given value object to the specified destination type.
+ ///
+ /// An System.ComponentModel.ITypeDescriptorContext that provides a format context.
+ /// An optional System.Globalization.CultureInfo. If not supplied, the current culture is assumed.
+ /// The System.Object to convert.
+ /// The System.Type to convert the value to.
+ /// An System.Object that represents the converted value.
+ public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+ {
+ if (destinationType == typeof(string) && value == null)
+ {
+ return string.Empty;
+ }
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ ///
+ /// Operation Mode values for Query Store
+ ///
+ [TypeConverter(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreOperationModeConverter))]
+ public enum QueryStoreOperationMode
+ {
+ [LocDisplayName("Off")]
+ [TsqlSyntaxString("OFF")]
+ Off = 0,
+ [LocDisplayName("ReadOnly")]
+ [TsqlSyntaxString("READ_ONLY")]
+ ReadOnly = 1,
+ [LocDisplayName("ReadWrite")]
+ [TsqlSyntaxString("READ_WRITE")]
+ ReadWrite = 2,
+ [LocDisplayName("Error")]
+ Error = 3,
+ }
+
+ ///
+ /// Capture Mode values for Query Store
+ ///
+ [TypeConverter(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreCaptureModeConverter))]
+ public enum QueryStoreCaptureMode
+ {
+ [LocDisplayName("All")]
+ [TsqlSyntaxString("ALL")]
+ All = 1,
+ [LocDisplayName("Auto")]
+ [TsqlSyntaxString("AUTO")]
+ Auto = 2,
+ [LocDisplayName("None")]
+ [TsqlSyntaxString("NONE")]
+ None = 3,
+ [LocDisplayName("Custom")]
+ [TsqlSyntaxString("CUSTOM")]
+ Custom = 4,
+ }
+
+ ///
+ /// Size Based Cleanup Mode values for Query Store
+ ///
+ [TypeConverter(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreSizeBasedCleanupModeConverter))]
+ public enum QueryStoreSizeBasedCleanupMode
+ {
+ [LocDisplayName("Off")]
+ [TsqlSyntaxString("OFF")]
+ Off = 0,
+ [LocDisplayName("Auto")]
+ [TsqlSyntaxString("AUTO")]
+ Auto = 1,
+ }
+
+ ///
+ /// Wait Statistics Capture Mode values for Query Store
+ ///
+ [TypeConverter(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreWaitStatsCaptureModeConverter))]
+ public enum QueryStoreWaitStatsCaptureMode
+ {
+ [LocDisplayName("Off")]
+ [TsqlSyntaxString("OFF")]
+ Off = 0,
+ [LocDisplayName("On")]
+ [TsqlSyntaxString("ON")]
+ On = 1,
+ }
+
+
+}
+
+
+#pragma warning restore 1591
\ No newline at end of file
diff --git a/src/Microsoft/SqlServer/Management/Smo/QueryStoreOptions.cs b/src/Microsoft/SqlServer/Management/Smo/QueryStoreOptions.cs
index a339911a..3cc37eb9 100644
--- a/src/Microsoft/SqlServer/Management/Smo/QueryStoreOptions.cs
+++ b/src/Microsoft/SqlServer/Management/Smo/QueryStoreOptions.cs
@@ -9,152 +9,9 @@
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Sdk.Sfc.Metadata;
-//1591 is for verifying all public members have xml documentation. It's really heavy handed though - requiring
-//docs for things as specific as each enum value. Disabling since the documentation we have is enough.
-#pragma warning disable 1591
namespace Microsoft.SqlServer.Management.Smo
{
- ///
- /// type converter for QueryStoreOperationMode
- ///
- public class QueryStoreOperationModeConverter : EnumToDisplayNameConverter
- {
- public QueryStoreOperationModeConverter()
- : base(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreOperationMode))
- { }
- }
-
- ///
- /// type converter for QueryStoreCaptureMode
- ///
- public class QueryStoreCaptureModeConverter : EnumToDisplayNameConverter
- {
- public QueryStoreCaptureModeConverter()
- : base(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreCaptureMode))
- { }
- }
-
- ///
- /// type converter for QueryStoreSizeBasedCleanupMode
- ///
- public class QueryStoreSizeBasedCleanupModeConverter : EnumToDisplayNameConverter
- {
- public QueryStoreSizeBasedCleanupModeConverter()
- : base(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreSizeBasedCleanupMode))
- { }
-
- ///
- /// Converts the given value object to the specified destination type.
- ///
- /// An System.ComponentModel.ITypeDescriptorContext that provides a format context.
- /// An optional System.Globalization.CultureInfo. If not supplied, the current culture is assumed.
- /// The System.Object to convert.
- /// The System.Type to convert the value to.
- /// An System.Object that represents the converted value.
- public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
- {
- if (destinationType == typeof(string) && value == null)
- {
- return string.Empty;
- }
- return base.ConvertTo(context, culture, value, destinationType);
- }
- }
-
- ///
- /// type converter for QueryStoreWaitStatsCaptureMode
- ///
- public class QueryStoreWaitStatsCaptureModeConverter : EnumToDisplayNameConverter
- {
- public QueryStoreWaitStatsCaptureModeConverter()
- : base(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreWaitStatsCaptureMode))
- { }
-
- ///
- /// Converts the given value object to the specified destination type.
- ///
- /// An System.ComponentModel.ITypeDescriptorContext that provides a format context.
- /// An optional System.Globalization.CultureInfo. If not supplied, the current culture is assumed.
- /// The System.Object to convert.
- /// The System.Type to convert the value to.
- /// An System.Object that represents the converted value.
- public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
- {
- if (destinationType == typeof(string) && value == null)
- {
- return string.Empty;
- }
- return base.ConvertTo(context, culture, value, destinationType);
- }
- }
-
- ///
- /// Operation Mode values for Query Store
- ///
- [TypeConverter(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreOperationModeConverter))]
- public enum QueryStoreOperationMode
- {
- [LocDisplayName("Off")]
- [TsqlSyntaxString("OFF")]
- Off = 0,
- [LocDisplayName("ReadOnly")]
- [TsqlSyntaxString("READ_ONLY")]
- ReadOnly = 1,
- [LocDisplayName("ReadWrite")]
- [TsqlSyntaxString("READ_WRITE")]
- ReadWrite = 2,
- [LocDisplayName("Error")]
- Error = 3,
- }
-
- ///
- /// Capture Mode values for Query Store
- ///
- [TypeConverter(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreCaptureModeConverter))]
- public enum QueryStoreCaptureMode
- {
- [LocDisplayName("All")]
- [TsqlSyntaxString("ALL")]
- All = 1,
- [LocDisplayName("Auto")]
- [TsqlSyntaxString("AUTO")]
- Auto = 2,
- [LocDisplayName("None")]
- [TsqlSyntaxString("NONE")]
- None = 3,
- [LocDisplayName("Custom")]
- [TsqlSyntaxString("CUSTOM")]
- Custom = 4,
- }
-
- ///
- /// Size Based Cleanup Mode values for Query Store
- ///
- [TypeConverter(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreSizeBasedCleanupModeConverter))]
- public enum QueryStoreSizeBasedCleanupMode
- {
- [LocDisplayName("Off")]
- [TsqlSyntaxString("OFF")]
- Off = 0,
- [LocDisplayName("Auto")]
- [TsqlSyntaxString("AUTO")]
- Auto = 1,
- }
-
- ///
- /// Wait Statistics Capture Mode values for Query Store
- ///
- [TypeConverter(typeof(Microsoft.SqlServer.Management.Smo.QueryStoreWaitStatsCaptureModeConverter))]
- public enum QueryStoreWaitStatsCaptureMode
- {
- [LocDisplayName("Off")]
- [TsqlSyntaxString("OFF")]
- Off = 0,
- [LocDisplayName("On")]
- [TsqlSyntaxString("ON")]
- On = 1,
- }
///
/// QueryStore Options Smo Object.
@@ -198,7 +55,7 @@ internal override void ScriptAlter(StringCollection query, ScriptingPreferences
{
// When doing an alter when database is in restoring state, we do not want to script query store options
// Querying for this options in a restoring database will cause a null reference exception
- if (this.Parent.Status == DatabaseStatus.Restoring)
+ if (!Parent.IsDesignMode && Parent.Status == DatabaseStatus.Restoring)
{
// Make sure none of the properties are dirty though because if the user changed a value that would indicate that
// they are intending to actually modify those values but we can't do that when it's restoring
@@ -370,19 +227,21 @@ private void ScriptQueryStoreOptions(StringCollection query, ScriptingPreference
(long) maxStorageSizeInMBProp.Value));
}
- QueryStoreCaptureMode newValue = (QueryStoreCaptureMode) queryCaptureModeProp.Value;
+ // In DesignMode, GetPropertyOptional doesn't get the default value so we check for null
+ QueryStoreCaptureMode? newValue = (QueryStoreCaptureMode?)queryCaptureModeProp.Value;
- if (newValue == QueryStoreCaptureMode.Custom && !IsSupportedProperty("CapturePolicyExecutionCount", sp))
+ if (newValue == QueryStoreCaptureMode.Custom && !IsSupportedProperty(nameof(CapturePolicyExecutionCount), sp))
{
newValue = QueryStoreCaptureMode.Auto;
}
+
if (scriptAll || queryCaptureModeProp.Dirty)
{
sb.Append(string.Format(SmoApplication.DefaultCulture, "QUERY_CAPTURE_MODE = {0}, ",
- queryStoreCaptureModeTypeConverter.ConvertToInvariantString(newValue)));
- }
+ queryStoreCaptureModeTypeConverter.ConvertToInvariantString(newValue.Value)));
+ }
if (newValue == QueryStoreCaptureMode.Custom)
{
StringBuilder capturePolicy = new StringBuilder();
@@ -391,25 +250,25 @@ private void ScriptQueryStoreOptions(StringCollection query, ScriptingPreference
{
capturePolicy.Append(string.Format(SmoApplication.DefaultCulture,
"STALE_CAPTURE_POLICY_THRESHOLD = {0} HOURS, ",
- (int) capturePolicyStaleThresholdInHrsProp.Value));
+ (int)capturePolicyStaleThresholdInHrsProp.Value));
}
if (scriptAll || capturePolicyExecutionCountProp.Dirty)
{
capturePolicy.Append(string.Format(SmoApplication.DefaultCulture, "EXECUTION_COUNT = {0}, ",
- (int) capturePolicyExecutionCountProp.Value));
+ (int)capturePolicyExecutionCountProp.Value));
}
if (scriptAll || capturePolicyTotalCompileCpuTimeInMSProp.Dirty)
{
capturePolicy.Append(string.Format(SmoApplication.DefaultCulture, "TOTAL_COMPILE_CPU_TIME_MS = {0}, ",
- (long) capturePolicyTotalCompileCpuTimeInMSProp.Value));
+ (long)capturePolicyTotalCompileCpuTimeInMSProp.Value));
}
if (scriptAll || capturePolicyTotalExecutionCpuTimeInMSProp.Dirty)
{
capturePolicy.Append(string.Format(SmoApplication.DefaultCulture, "TOTAL_EXECUTION_CPU_TIME_MS = {0}, ",
- (long) capturePolicyTotalExecutionCpuTimeInMSProp.Value));
+ (long)capturePolicyTotalExecutionCpuTimeInMSProp.Value));
}
if (capturePolicy.Length > 0)
@@ -534,6 +393,3 @@ internal static string[] GetScriptFields(Type parentType,
}
}
}
-
-
-#pragma warning restore 1591
\ No newline at end of file
diff --git a/src/Microsoft/SqlServer/Management/Smo/SqlSmoObject.cs b/src/Microsoft/SqlServer/Management/Smo/SqlSmoObject.cs
index 07fbbf57..48efde72 100644
--- a/src/Microsoft/SqlServer/Management/Smo/SqlSmoObject.cs
+++ b/src/Microsoft/SqlServer/Management/Smo/SqlSmoObject.cs
@@ -8294,6 +8294,10 @@ internal void WriteToPropBag(DataType dataType)
case SqlDataType.Json:
this.Properties.Get("DataType").Value = dataType.GetSqlName(SqlDataType.Json);
break;
+ case SqlDataType.Vector:
+ this.Properties.Get("DataType").Value = dataType.GetSqlName(SqlDataType.Vector);
+ this.Properties.Get("Length").Value = dataType.MaximumLength;
+ break;
}
}
#endregion
diff --git a/src/Microsoft/SqlServer/Management/Smo/uddtbase.cs b/src/Microsoft/SqlServer/Management/Smo/uddtbase.cs
index 7f23a3c5..ac0824e7 100644
--- a/src/Microsoft/SqlServer/Management/Smo/uddtbase.cs
+++ b/src/Microsoft/SqlServer/Management/Smo/uddtbase.cs
@@ -416,10 +416,17 @@ static private string GetTypeDefinitionScript(ScriptingPreferences sp, SqlSmoObj
{
throw new PropertyNotSetException("Length");
}
-
- if ((Int32)oLength != 0)
+ var length = (Int32)oLength;
+ if (sType == "vector")
+ {
+ // Temporary workaround to convert the length of the column to the dimensions for vector types
+ // until sys.columns is updated to include the dimensions of the vector type.
+ // https://learn.microsoft.com/sql/t-sql/data-types/vector-data-type
+ sb.AppendFormat(SmoApplication.DefaultCulture, "({0})", (length - 8) / 4);
+ }
+ else if (length != 0)
{
- if ((sType == "varchar" || sType == "nvarchar" || sType == "varbinary") && (Int32)oLength < 0)
+ if ((sType == "varchar" || sType == "nvarchar" || sType == "varbinary") && length < 0)
{
sb.Append("(max)");
}
@@ -787,7 +794,8 @@ static internal bool TypeAllowsLength(string type, StringComparer comparer)
0 == comparer.Compare(type, "binary") ||
0 == comparer.Compare(type, "varbinary") ||
0 == comparer.Compare(type, "nchar") ||
- 0 == comparer.Compare(type, "char"))
+ 0 == comparer.Compare(type, "char") ||
+ 0 == comparer.Compare(type, "vector"))
{
return true;
}
diff --git a/src/Microsoft/SqlServer/Management/SmoMetadataProvider/SmoSystemDataTypeLookup.cs b/src/Microsoft/SqlServer/Management/SmoMetadataProvider/SmoSystemDataTypeLookup.cs
index 26bb2d26..a57f8762 100644
--- a/src/Microsoft/SqlServer/Management/SmoMetadataProvider/SmoSystemDataTypeLookup.cs
+++ b/src/Microsoft/SqlServer/Management/SmoMetadataProvider/SmoSystemDataTypeLookup.cs
@@ -222,6 +222,8 @@ private static DataTypeSpec GetDataTypeSpec(Smo.SqlDataType sqlDataType)
return DataTypeSpec.Xml;
case Smo.SqlDataType.Json:
return DataTypeSpec.Json;
+ case Smo.SqlDataType.Vector:
+ return DataTypeSpec.Vector;
default:
Debug.Assert(IsSmoUserDefinedDataType(sqlDataType) || (sqlDataType == Smo.SqlDataType.None),
diff --git a/src/Microsoft/SqlServer/Management/SqlEnum/Util.cs b/src/Microsoft/SqlServer/Management/SqlEnum/Util.cs
index 58b67667..8cf143c4 100644
--- a/src/Microsoft/SqlServer/Management/SqlEnum/Util.cs
+++ b/src/Microsoft/SqlServer/Management/SqlEnum/Util.cs
@@ -35,14 +35,15 @@ static public String DbTypeToClrType(String strDBType)
String strType;
switch(strDBType)
{
- case "xml":goto case "text";
- case "json": goto case "text";
- case "nvarchar":goto case "text";
- case "varchar":goto case "text";
- case "sysname":goto case "text";
- case "nchar":goto case "text";
- case "char":goto case "text";
- case "ntext":goto case "text";
+ case "xml":
+ case "json":
+ case "vector":
+ case "nvarchar":
+ case "varchar":
+ case "sysname":
+ case "nchar":
+ case "char":
+ case "ntext":
case "text":
strType = "System.String";
break;
@@ -58,7 +59,7 @@ static public String DbTypeToClrType(String strDBType)
case "long":
strType = "System.Int32";
break;
- case "real":goto case "float";
+ case "real":
case "float":
strType = "System.Double";
break;
@@ -90,11 +91,11 @@ static public String DbTypeToClrType(String strDBType)
strType = "System.Guid";
break;
case "numeric":
+ case "decimal":
strType = "System.Decimal";
break;
- case "decimal": goto case "numeric";
- case "binary":goto case "varbinary";
- case "image":goto case "varbinary";
+ case "binary":
+ case "image":
case "varbinary":
strType = "System.Byte[]";
break;
diff --git a/src/Microsoft/SqlServer/Management/SqlEnum/xml/QueryStoreOptions.xml b/src/Microsoft/SqlServer/Management/SqlEnum/xml/QueryStoreOptions.xml
index a6ecc60e..e7a75260 100644
--- a/src/Microsoft/SqlServer/Management/SqlEnum/xml/QueryStoreOptions.xml
+++ b/src/Microsoft/SqlServer/Management/SqlEnum/xml/QueryStoreOptions.xml
@@ -6,15 +6,15 @@
- dqso.actual_state
+ dqso.actual_state
dqso.desired_state
- dqso.readonly_reason
+ dqso.readonly_reason
dqso.current_storage_size_mb
dqso.max_storage_size_mb
dqso.stale_query_threshold_days
dqso.flush_interval_seconds
dqso.interval_length_minutes
- dqso.query_capture_mode
+ dqso.query_capture_mode
dqso.size_based_cleanup_mode
dqso.max_plans_per_query
diff --git a/src/Microsoft/SqlServer/Management/SqlEnum/xml/README.md b/src/Microsoft/SqlServer/Management/SqlEnum/xml/README.md
index 31c17222..22ca9eec 100644
--- a/src/Microsoft/SqlServer/Management/SqlEnum/xml/README.md
+++ b/src/Microsoft/SqlServer/Management/SqlEnum/xml/README.md
@@ -77,49 +77,56 @@ Used to selectively include/exclude other elements based on the version specifie
Provides the definition of a property. This is used by codegen and during runtime to populate the Property value (usually from the value returned from the SQL query for the object)
- report_type- Specifies the CLR type for this property. The value here will be prefixed with the SMO namespace, so it NEEDS to be used for any SMO types so that the correct SMO namespace is used (since engine builds its own from the same source)
+**report_type** - Specifies the CLR type for this property. The value here will be prefixed with the SMO namespace, so it NEEDS to be used for any SMO types so that the correct SMO namespace is used (since engine builds its own from the same source)
+
+**report_type2** - Specifies the CLR type for this property. The value will be used as is, so should be used for any non-SMO types
+
+**type** - Specifies the T-SQL type (varchar for example) which is then mapped to the appropriate CLR type for the property. See [Util.cs!DbTypeToClrType](/src/Microsoft/SqlServer/Management/SqlEnum/Util.cs) for the mapping
+
+**smo_class_name** - For post_process elements only. Specifies the name of the class that the post_process element is updating. Will be prefixed with the SMO namespace so NEEDS to be used for any SMO types so that the correct SMO namespace is used (since engine builds its own from the same source)
+
+**class_name** - For post_process elements only. Specifies the name of the class that the post_process element is updating. The value is used as is so should be used for any non-SMO types
+
+**cast** - This will make the generated t-SQL cast the property to the type specified with the type attribute (so type='bit' cast='true' will result in the T-SQL looking like CAST(myPropValue AS bit). Use this if the original type is not what you want.
+
+**mode** - The modes this property is available for. Maps to the PropertyMode enum, which is defined in [ObjectProperty.cs](/src/Microsoft/SqlServer/Management/Sdk/Sfc/Enumerator/ObjectProperty.cs). This will add the SfcPropertyFlags.Design or SfcPropertyFlags.Deploy attributes to the property. Properties that make sense in the design (offline) mode should have mode="design" set. For the most part, setting a mode isn't necessary, due to lack of use of the old SFC features based on it.
+
+Setting `mode="design"` can be valuable for readonly properties in order to allow them to have default values for unit testing. To set a default value for a property defined in the xml, it has to have a `default` attribute in the [cfg.xml](../../../../../Codegen/cfg.xml) file used by codegen.
+
+**expensive** - Marks the property as being expensive to fetch - which means that when it is accessed only that property will be fetched (default behavior is to fetch all properties whenever a non-initialized property value is requested).
+
+ This also marks properties that will NOT be pre-populated when calling Script(), so if the property is needed for scripting and is marked as expensive then the Script methods need to ensure that they use the appropriate Get methods that will fetch it if it hasn't been fetched already.
+
+ ○ NOTE : If this attribute is set then calls to Properties.Get (or any of the other methods which don't query for a property) will return NULL until the property is requested via one of the methods that do. See Ways to Retrieve Property in SMO for details on these methods.
+**hidden** - Whether the property is hidden from the user. If this attribute exists (it doesn't matter what the value is) then the property will not have a
+usage - What this property can be used for in SFC requests. Valid values are :
+ • Request (maps to ObjectPropertyUsages.Request)
+ • Filter (maps to ObjectPropertyUsages.Filter
+ • Order (maps to ObjectPropertyUsages.OrderBy)
+
+ If both this and notusage DO NOT exist then the property defaults to :
+
+ • Hidden = FALSE : ObjectPropertyUsages.All, which is an OR of all three values
+ • Hidden = TRUE : None of the above values (only Reserved1 is set)
+
+ Only one attribute of usage or notusage is allowed - if both are specified then usage will be used and notusage ignored.
+
+ NOTE : Any properties which are marked for PostProcessing will automatically have the Filter and OrderBy usages removed from the list of valid usages. This is because the values are calculated client-side so can't be used to generate the request query sent to the server. SqlObject.cs!Load (look for the computedProperties HashMap)
+
+**notusage** - What this property CAN'T be used for in SFC requests. Valid values are :
+
+ • request (maps to ObjectPropertyUsages.Request)
+ • filter (maps to ObjectPropertyUsages.Filter
+ • order (maps to ObjectPropertyUsages.OrderBy)
+
+ If both this and notusage DO NOT exist then the property defaults to :
+
+ • hidden = FALSE : ObjectPropertyUsages.All, which is an OR of all three values
+ • hidden = TRUE : None of the above values (only Reserved1 is set)
- report_type2 -Specifies the CLR type for this property. The value will be used as is, so should be used for any non-SMO types
- type- Specifies the T-SQL type (varchar for example) which is then mapped to the appropriate CLR type for the property. See $\Sql\mpu\shared\SMO\Enumerator\sql\src\Util.cs!DbTypeToClrType for the mapping
- smo_class_name - For post_process elements only. Specifies the name of the class that the post_process element is updating. Will be prefixed with the SMO namespace so NEEDS to be used for any SMO types so that the correct SMO namespace is used (since engine builds its own from the same source)
+ Only one attribute of usage or notusage is allowed - if both are specified then usage will be used and notusage ignored.
- class_name - For post_process elements only. Specifies the name of the class that the post_process element is updating. The value is used as is so should be used for any non-SMO types
- cast - This will make the generated t-SQL cast the property to the type specified with the type attribute (so type='bit' cast='true' will result in the T-SQL looking like CAST(myPropValue AS bit). Use this if the original type is not what you want.
- mode - The modes this property is available for. Maps to the PropertyMode enum, which is defined in $\sql\mpu\shared\managementsdk\sfc\enumerator\core\src\ObjectProperty.cs. This will add the SfcPropertyFlags.Design or SfcPropertyFlags.Deploy attributes to the property. Doesn't appear to actually do anything except for mark the property as being usable for either the Design or Deploy modes of SFC SDK.
- Properties that make sense in the design (offline) mode should have mode="design" set. Properties available in the online mode (should be most SMO properties) should have mode="deploy". If both are true then mode="ALL" should be set.
- expensive - Marks the property as being expensive to fetch - which means that when it is accessed only that property will be fetched (default behavior is to fetch all properties whenever a non-initialized property value is requested).
-
- This also marks properties that will NOT be pre-populated when calling Script(), so if the property is needed for scripting and is marked as expensive then the Script methods need to ensure that they use the appropriate Get methods that will fetch it if it hasn't been fetched already.
-
- ○ NOTE : If this attribute is set then calls to Properties.Get (or any of the other methods which don't query for a property) will return NULL until the property is requested via one of the methods that do. See Ways to Retrieve Property in SMO for details on these methods.
- hidden - Whether the property is hidden from the user. If this attribute exists (it doesn't matter what the value is) then the property will not have a
- usage - What this property can be used for in SFC requests. Valid values are :
- • Request (maps to ObjectPropertyUsages.Request)
- • Filter (maps to ObjectPropertyUsages.Filter
- • Order (maps to ObjectPropertyUsages.OrderBy)
-
- If both this and notusage DO NOT exist then the property defaults to :
-
- • Hidden = FALSE : ObjectPropertyUsages.All, which is an OR of all three values
- • Hidden = TRUE : None of the above values (only Reserved1 is set)
-
- Only one attribute of usage or notusage is allowed - if both are specified then usage will be used and notusage ignored.
-
- NOTE : Any properties which are marked for PostProcessing will automatically have the Filter and OrderBy usages removed from the list of valid usages. This is because the values are calculated client-side so can't be used to generate the request query sent to the server. SqlObject.cs!Load (look for the computedProperties HashMap)
- notusage - What this property CAN'T be used for in SFC requests. Valid values are :
-
- • request (maps to ObjectPropertyUsages.Request)
- • filter (maps to ObjectPropertyUsages.Filter
- • order (maps to ObjectPropertyUsages.OrderBy)
-
- If both this and notusage DO NOT exist then the property defaults to :
-
- • hidden = FALSE : ObjectPropertyUsages.All, which is an OR of all three values
- • hidden = TRUE : None of the above values (only Reserved1 is set)
-
- Only one attribute of usage or notusage is allowed - if both are specified then usage will be used and notusage ignored.
-
- NOTE : Any properties which are marked for PostProcessing will automatically have the Filter and OrderBy usages removed from the list of valid usages. This is because the values are calculated client-side so can't be used to generate the request query sent to the server. SqlObject.cs!Load (look for the computedProperties HashMap)
+ NOTE : Any properties which are marked for PostProcessing will automatically have the Filter and OrderBy usages removed from the list of valid usages. This is because the values are calculated client-side so can't be used to generate the request query sent to the server. SqlObject.cs!Load (look for the computedProperties HashMap)
### post_process
diff --git a/src/UnitTest/Smo/DataTypeTests.cs b/src/UnitTest/Smo/DataTypeTests.cs
index d10a28e5..9901a12a 100644
--- a/src/UnitTest/Smo/DataTypeTests.cs
+++ b/src/UnitTest/Smo/DataTypeTests.cs
@@ -36,6 +36,7 @@ public class DataTypeTests : UnitTestBase
{ SqlDataType.Time, SqlServerVersion.Version100},
{ SqlDataType.UserDefinedTableType, SqlServerVersion.Version100},
{ SqlDataType.Json, SqlServerVersion.Version160},
+ { SqlDataType.Vector, SqlServerVersion.Version170 },
};
///
diff --git a/src/UnitTest/Smo/DatabaseTests.cs b/src/UnitTest/Smo/DatabaseTests.cs
index 6d0756f2..1f3ede92 100644
--- a/src/UnitTest/Smo/DatabaseTests.cs
+++ b/src/UnitTest/Smo/DatabaseTests.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
+using System.Collections.Specialized;
using System.Linq;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Sdk.Sfc;
@@ -124,5 +125,36 @@ public void Database_default_constructor_sets_designmode()
var script = database.Script();
Assert.That(script.Cast(), Is.EqualTo(new[] { "CREATE DATABASE [dbname]" }), "database.Script() in design mode");
}
+
+
+ [TestCategory("Unit")]
+ [TestMethod]
+ public void Database_QueryStoreOptions_supports_DesignMode()
+ {
+ var server = ServerTests.GetDesignModeServer(16);
+ var db = new Database(server, "test");
+ var expectedReadonlyScript = new StringCollection() { "ALTER DATABASE [test] SET QUERY_STORE = ON", "ALTER DATABASE [test] SET QUERY_STORE (OPERATION_MODE = READ_ONLY)",};
+ var expectedCustomScript = new StringCollection() { "ALTER DATABASE [test] SET QUERY_STORE = ON", "ALTER DATABASE [test] SET QUERY_STORE (OPERATION_MODE = READ_ONLY, QUERY_CAPTURE_MODE = CUSTOM, QUERY_CAPTURE_POLICY = (STALE_CAPTURE_POLICY_THRESHOLD = 4 HOURS), MAX_PLANS_PER_QUERY = 210)" };
+ db.Create();
+ Assert.That(db.QueryStoreOptions, Is.Not.Null, "QueryStoreOptions should be supported on 16");
+ db.QueryStoreOptions.DesiredState = QueryStoreOperationMode.ReadOnly;
+ Assert.That(db.QueryStoreOptions.ActualState, Is.EqualTo(QueryStoreOperationMode.Off), "ActualState should have default value");
+ var sp = db.GetScriptingPreferencesForCreate();
+ var script = new StringCollection();
+ db.QueryStoreOptions.ScriptAlter(script, sp);
+ Assert.That(script, Is.EqualTo(expectedReadonlyScript), "Setting ReadOnly");
+ db.QueryStoreOptions.MaxPlansPerQuery = 210;
+ db.QueryStoreOptions.QueryCaptureMode = QueryStoreCaptureMode.Custom;
+ db.QueryStoreOptions.CapturePolicyStaleThresholdInHrs = 4;
+
+ script = new StringCollection();
+ db.QueryStoreOptions.ScriptAlter(script, sp);
+ Assert.That(script, Is.EqualTo(expectedCustomScript), "Setting Custom capture mode");
+
+ Assert.That(db.QueryStoreOptions.MaxPlansPerQuery, Is.EqualTo(210), nameof(QueryStoreOptions.MaxPlansPerQuery));
+ // We could change QueryStoreOptions to override Alter or AlterImpl and set the value in design mode
+ Assert.That(db.QueryStoreOptions.ActualState, Is.EqualTo(QueryStoreOperationMode.Off), "ActualState should not be changed by Alter");
+ }
+
}
}
diff --git a/src/UnitTest/Smo/ServerTests.cs b/src/UnitTest/Smo/ServerTests.cs
index 540d2003..ce889817 100644
--- a/src/UnitTest/Smo/ServerTests.cs
+++ b/src/UnitTest/Smo/ServerTests.cs
@@ -25,7 +25,7 @@ public class ServerTests : UnitTestBase
[TestMethod]
public void GetLcidFromCollationListTest()
{
- var server = new Microsoft.SqlServer.Management.Smo.Server();
+ var server = new Management.Smo.Server();
var comparer = server.GetStringComparer("Japanese_BIN2");
Assert.That(comparer, Is.Not.Null, "Cannot get valid LCID or comparer");
}
@@ -87,7 +87,7 @@ public void Server_IsSupportedProperty_works_in_DesignMode()
});
}
- private Management.Smo.Server GetDesignModeServer(int majorVersion, DatabaseEngineType databaseEngineType = DatabaseEngineType.Standalone, DatabaseEngineEdition edition = DatabaseEngineEdition.Enterprise)
+ internal static Management.Smo.Server GetDesignModeServer(int majorVersion, DatabaseEngineType databaseEngineType = DatabaseEngineType.Standalone, DatabaseEngineEdition edition = DatabaseEngineEdition.Enterprise)
{
var serverConnection = new ServerConnection() {
ServerVersion = new ServerVersion(majorVersion, 0),