mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-28 17:24:27 -05:00
Removing script as feature from service layer to sqlcore (#2189)
This commit is contained in:
@@ -1725,6 +1725,54 @@ namespace Microsoft.SqlTools.SqlCore
|
||||
}
|
||||
}
|
||||
|
||||
public static string ScriptingParams_ConnectionString_Property_Invalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.ScriptingParams_ConnectionString_Property_Invalid);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ScriptingParams_FilePath_Property_Invalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.ScriptingParams_FilePath_Property_Invalid);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid);
|
||||
}
|
||||
}
|
||||
|
||||
public static string StoredProcedureScriptParameterComment
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.StoredProcedureScriptParameterComment);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ScriptingGeneralError
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.ScriptingGeneralError);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ScriptingExecuteNotSupportedError
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.ScriptingExecuteNotSupportedError);
|
||||
}
|
||||
}
|
||||
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Keys
|
||||
{
|
||||
@@ -2369,6 +2417,24 @@ namespace Microsoft.SqlTools.SqlCore
|
||||
public const string FilterInPrimaryKeyDescription = "FilterInPrimaryKeyDescription";
|
||||
|
||||
|
||||
public const string ScriptingParams_ConnectionString_Property_Invalid = "ScriptingParams_ConnectionString_Property_Invalid";
|
||||
|
||||
|
||||
public const string ScriptingParams_FilePath_Property_Invalid = "ScriptingParams_FilePath_Property_Invalid";
|
||||
|
||||
|
||||
public const string ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid = "ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid";
|
||||
|
||||
|
||||
public const string StoredProcedureScriptParameterComment = "StoredProcedureScriptParameterComment";
|
||||
|
||||
|
||||
public const string ScriptingGeneralError = "ScriptingGeneralError";
|
||||
|
||||
|
||||
public const string ScriptingExecuteNotSupportedError = "ScriptingExecuteNotSupportedError";
|
||||
|
||||
|
||||
private Keys()
|
||||
{ }
|
||||
|
||||
|
||||
@@ -965,4 +965,28 @@
|
||||
<value>Include or exclude objects based on whether the column is in a primary key.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="ScriptingParams_ConnectionString_Property_Invalid" xml:space="preserve">
|
||||
<value>Error parsing ScriptingParams.ConnectionString property.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="ScriptingParams_FilePath_Property_Invalid" xml:space="preserve">
|
||||
<value>Invalid directory specified by the ScriptingParams.FilePath property.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid" xml:space="preserve">
|
||||
<value>Error parsing ScriptingListObjectsCompleteParams.ConnectionString property.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="StoredProcedureScriptParameterComment" xml:space="preserve">
|
||||
<value>-- TODO: Set parameter values here.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="ScriptingGeneralError" xml:space="preserve">
|
||||
<value>An error occurred while scripting the objects.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="ScriptingExecuteNotSupportedError" xml:space="preserve">
|
||||
<value>Scripting as Execute is only supported for Stored Procedures</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -430,3 +430,17 @@ FilterIsNativelyCompiledDescription = Include or exclude objects based on whethe
|
||||
FilterInPrimaryKey = In Primary Key
|
||||
FilterInPrimaryKeyDescription = Include or exclude objects based on whether the column is in a primary key.
|
||||
|
||||
############################################################################
|
||||
# Scripting Service
|
||||
|
||||
ScriptingParams_ConnectionString_Property_Invalid = Error parsing ScriptingParams.ConnectionString property.
|
||||
|
||||
ScriptingParams_FilePath_Property_Invalid = Invalid directory specified by the ScriptingParams.FilePath property.
|
||||
|
||||
ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid = Error parsing ScriptingListObjectsCompleteParams.ConnectionString property.
|
||||
|
||||
|
||||
StoredProcedureScriptParameterComment = -- TODO: Set parameter values here.
|
||||
|
||||
ScriptingGeneralError = An error occurred while scripting the objects.
|
||||
ScriptingExecuteNotSupportedError = Scripting as Execute is only supported for Stored Procedures
|
||||
|
||||
@@ -1062,6 +1062,36 @@
|
||||
<target state="new">Schema and Data</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ScriptingParams_ConnectionString_Property_Invalid">
|
||||
<source>Error parsing ScriptingParams.ConnectionString property.</source>
|
||||
<target state="new">Error parsing ScriptingParams.ConnectionString property.</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ScriptingParams_FilePath_Property_Invalid">
|
||||
<source>Invalid directory specified by the ScriptingParams.FilePath property.</source>
|
||||
<target state="new">Invalid directory specified by the ScriptingParams.FilePath property.</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid">
|
||||
<source>Error parsing ScriptingListObjectsCompleteParams.ConnectionString property.</source>
|
||||
<target state="new">Error parsing ScriptingListObjectsCompleteParams.ConnectionString property.</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StoredProcedureScriptParameterComment">
|
||||
<source>-- TODO: Set parameter values here.</source>
|
||||
<target state="new">-- TODO: Set parameter values here.</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ScriptingGeneralError">
|
||||
<source>An error occurred while scripting the objects.</source>
|
||||
<target state="new">An error occurred while scripting the objects.</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ScriptingExecuteNotSupportedError">
|
||||
<source>Scripting as Execute is only supported for Stored Procedures</source>
|
||||
<target state="new">Scripting as Execute is only supported for Stored Procedures</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
@@ -26,6 +26,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Microsoft.SqlTools.Hosting/Microsoft.SqlTools.Hosting.csproj" PrivateAssets="all" />
|
||||
<ProjectReference Include="../Microsoft.SqlTools.ManagedBatchParser/Microsoft.SqlTools.ManagedBatchParser.csproj" PrivateAssets="all" />
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Localization\*.resx" />
|
||||
@@ -41,7 +43,7 @@
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="bin\$(Configuration)\**\Microsoft.SqlTools.Hosting*.dll">
|
||||
<Content Include="bin\$(Configuration)\**\Microsoft.SqlTools.*.dll">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>lib\</PackagePath>
|
||||
</Content>
|
||||
|
||||
@@ -10,11 +10,10 @@ using System.Threading.Tasks;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlTools.SqlCore.Connection;
|
||||
using Microsoft.SqlTools.SqlCore.ObjectExplorer;
|
||||
using Microsoft.SqlTools.SqlCore.ObjectExplorer.Nodes;
|
||||
using Microsoft.SqlTools.SqlCore.ObjectExplorer.SmoModel;
|
||||
|
||||
namespace Microsoft.SqlTools.CoreSql.ObjectExplorer
|
||||
namespace Microsoft.SqlTools.SqlCore.ObjectExplorer
|
||||
{
|
||||
/// <summary>
|
||||
/// Stateless object explorer class can be used to handle object explorer requests without creating a session. It requires a connection string and a node path to query objects from the server.
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.Core;
|
||||
using Microsoft.SqlTools.SqlCore.Scripting.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting
|
||||
{
|
||||
public class AsyncScriptAsScriptingOperation
|
||||
{
|
||||
public static async Task<string> GetScriptAsScript(ScriptingParams parameters, AccessToken? accessToken)
|
||||
{
|
||||
var scriptAsOperation = new ScriptAsScriptingOperation(parameters, accessToken?.Token);
|
||||
TaskCompletionSource<string> scriptAsTask = new TaskCompletionSource<string>();
|
||||
|
||||
scriptAsOperation.CompleteNotification += (sender, args) =>
|
||||
{
|
||||
if (args.HasError)
|
||||
{
|
||||
scriptAsTask.SetException(new Exception(args.ErrorMessage));
|
||||
}
|
||||
scriptAsTask.SetResult(scriptAsOperation.ScriptText);
|
||||
};
|
||||
|
||||
scriptAsOperation.ProgressNotification += (sender, args) =>
|
||||
{
|
||||
if(args.ErrorMessage != null)
|
||||
{
|
||||
scriptAsTask.SetException(new Exception(args.ErrorMessage));
|
||||
}
|
||||
};
|
||||
|
||||
scriptAsOperation.Execute();
|
||||
return await scriptAsTask.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameters sent to when a scripting operation has completed.
|
||||
/// </summary>
|
||||
public class ScriptingCompleteParams : ScriptingEventParams
|
||||
{
|
||||
/// <summary>
|
||||
/// Get or sets the error details for an error that occurred during the scripting operation.
|
||||
/// </summary>
|
||||
public string ErrorDetails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets the error message for an error that occurred during the scripting operation.
|
||||
/// </summary>
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets a value to indicate an error occurred during the scripting operation.
|
||||
/// </summary>
|
||||
public bool HasError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets a value to indicate the scripting operation was canceled.
|
||||
/// </summary>
|
||||
public bool Canceled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets a value to indicate the scripting operation successfully completed.
|
||||
/// </summary>
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all scripting event parameters.
|
||||
/// </summary>
|
||||
public abstract class ScriptingEventParams
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the operation id of the scripting operation this event is associated with.
|
||||
/// </summary>
|
||||
public string OperationId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sequence number. The sequence number starts at 1, and is incremented each time a scripting event is
|
||||
/// raised for the current scripting operation.
|
||||
/// </summary>
|
||||
public int SequenceNumber { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to represent a database object that can be scripted.
|
||||
/// </summary>
|
||||
public sealed class ScriptingObject : IEquatable<ScriptingObject>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the database object type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This underlying values are determined by the SqlScriptPublishModel.GetDatabaseObjectTypes() and
|
||||
/// can change depending on the version of SMO used by the tools service. Values can be:
|
||||
/// Table,
|
||||
/// View,
|
||||
/// StoredProcedure,
|
||||
/// UserDefinedFunction,
|
||||
/// UserDefinedDataType,
|
||||
/// User,
|
||||
/// Default,
|
||||
/// Rule,
|
||||
/// DatabaseRole,
|
||||
/// ApplicationRole,
|
||||
/// SqlAssembly,
|
||||
/// DdlTrigger,
|
||||
/// Synonym,
|
||||
/// XmlSchemaCollection,
|
||||
/// Schema,
|
||||
/// PlanGuide,
|
||||
/// UserDefinedType,
|
||||
/// UserDefinedAggregate,
|
||||
/// FullTextCatalog,
|
||||
/// UserDefinedTableType
|
||||
/// </remarks>
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the schema of the database object.
|
||||
/// </summary>
|
||||
public string Schema { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the database object name.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parent object name
|
||||
/// </summary>
|
||||
public string ParentName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parent object type name, such as Table, View, etc.
|
||||
/// </summary>
|
||||
public string ParentTypeName { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string objectName = string.Empty;
|
||||
if (!string.IsNullOrEmpty(this.Schema))
|
||||
{
|
||||
objectName += this.Schema + ".";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(this.ParentName))
|
||||
{
|
||||
objectName += this.ParentName + ".";
|
||||
}
|
||||
return objectName + this.Name;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return
|
||||
StringComparer.OrdinalIgnoreCase.GetHashCode(this.Type ?? string.Empty) ^
|
||||
StringComparer.OrdinalIgnoreCase.GetHashCode(this.Schema ?? string.Empty) ^
|
||||
StringComparer.OrdinalIgnoreCase.GetHashCode(this.ParentName ?? string.Empty) ^
|
||||
StringComparer.OrdinalIgnoreCase.GetHashCode(this.ParentTypeName ?? string.Empty) ^
|
||||
StringComparer.OrdinalIgnoreCase.GetHashCode(this.Name ?? string.Empty);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return
|
||||
obj != null &&
|
||||
this.GetType() == obj.GetType() &&
|
||||
this.Equals((ScriptingObject)obj);
|
||||
}
|
||||
|
||||
public bool Equals(ScriptingObject other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return
|
||||
string.Equals(this.Type, other.Type, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(this.Schema, other.Schema, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(this.ParentName, other.ParentName, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(this.ParentTypeName, other.ParentTypeName, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(this.ParentTypeName, other.ParentTypeName, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(this.Name, other.Name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Scripting Operation type
|
||||
/// </summary>
|
||||
public enum ScriptingOperationType
|
||||
{
|
||||
Select = 0,
|
||||
Create = 1,
|
||||
Insert = 2,
|
||||
Update = 3,
|
||||
Delete = 4,
|
||||
Execute = 5,
|
||||
Alter = 6
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameters for a script request.
|
||||
/// </summary>
|
||||
public class ScriptingParams
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the file path used when writing out the script.
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether scripting to a single file or file per object.
|
||||
/// </summary>
|
||||
public string ScriptDestination { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets connection string of the target database the scripting operation will run against.
|
||||
/// </summary>
|
||||
public string ConnectionString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of scripting objects to script.
|
||||
/// </summary>
|
||||
public List<ScriptingObject> ScriptingObjects { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of scripting object which specify the include criteria of objects to script.
|
||||
/// </summary>
|
||||
public List<ScriptingObject> IncludeObjectCriteria { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of scripting object which specify the exclude criteria of objects to not script.
|
||||
/// </summary>
|
||||
public List<ScriptingObject> ExcludeObjectCriteria { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of schema name of objects to script.
|
||||
/// </summary>
|
||||
public List<string> IncludeSchemas { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of schema name of objects to not script.
|
||||
/// </summary>
|
||||
public List<string> ExcludeSchemas { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of type name of objects to script.
|
||||
/// </summary>
|
||||
public List<string> IncludeTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of type name of objects to not script
|
||||
/// </summary>
|
||||
public List<string> ExcludeTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the scripting options.
|
||||
/// </summary>
|
||||
public ScriptOptions ScriptOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the connection owner URI
|
||||
/// </summary>
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The script operation
|
||||
/// </summary>
|
||||
public ScriptingOperationType Operation { get; set; } = ScriptingOperationType.Create;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameters to indicate the script operation has resolved the objects to be scripted.
|
||||
/// </summary>
|
||||
public class ScriptingPlanNotificationParams : ScriptingEventParams
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the list of database objects whose progress has changed.
|
||||
/// </summary>
|
||||
public List<ScriptingObject> ScriptingObjects { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the count of database objects whose progress has changed.
|
||||
/// </summary>
|
||||
public int Count { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameters sent when a scripting operation has made progress.
|
||||
/// </summary>
|
||||
public class ScriptingProgressNotificationParams : ScriptingEventParams
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the scripting object whose progress has changed.
|
||||
/// </summary>
|
||||
public ScriptingObject ScriptingObject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status of the scripting operation for the scripting object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Values can be: 'Completed', 'Progress', and 'Error'.
|
||||
/// </remarks>
|
||||
public string Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or count of completed scripting operations.
|
||||
/// </summary>
|
||||
public int CompletedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets this total count of objects to script.
|
||||
/// </summary>
|
||||
public int TotalCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the error details if an error occurred scripting a database object.
|
||||
/// </summary>
|
||||
public string ErrorDetails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets the error message for an error that occurred scripting a database object.
|
||||
/// </summary>
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
713
src/Microsoft.SqlTools.SqlCore/Scripting/ScriptAsOptions.cs
Normal file
713
src/Microsoft.SqlTools.SqlCore/Scripting/ScriptAsOptions.cs
Normal file
@@ -0,0 +1,713 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// A wrpaper of ScriptOptions to map the option name with the oen in SMO.ScriptingOptions
|
||||
/// </summary>
|
||||
public class ScriptAsOptions : ScriptOptions
|
||||
{
|
||||
public ScriptAsOptions(ScriptOptions scriptOptions)
|
||||
{
|
||||
Validate.IsNotNull(nameof(scriptOptions), scriptOptions);
|
||||
ScriptOptions = scriptOptions;
|
||||
}
|
||||
|
||||
public ScriptOptions ScriptOptions { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Generate ANSI padding statements
|
||||
/// </summary>
|
||||
public override bool? ScriptAnsiPadding
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptAnsiPadding;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptAnsiPadding = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Append the generated script to a file
|
||||
/// </summary>
|
||||
public override bool? AppendToFile
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.AppendToFile;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.AppendToFile = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Continue to script if an error occurs. Otherwise, stop.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public override bool? ContinueScriptingOnError
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ContinueScriptingOnError;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ContinueScriptingOnError = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert user-defined data types to base types.
|
||||
/// </summary>
|
||||
public override bool? ConvertUDDTToBaseType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ConvertUDDTToBaseType;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ConvertUDDTToBaseType = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate script for dependent objects for each object scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is false.
|
||||
/// </remarks>
|
||||
public override bool? GenerateScriptForDependentObjects
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.GenerateScriptForDependentObjects;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.GenerateScriptForDependentObjects = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include descriptive headers for each object generated.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public override bool? IncludeDescriptiveHeaders
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.IncludeDescriptiveHeaders;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.IncludeDescriptiveHeaders = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that an object with the given name exists before dropping or altering or that an object with the given name does not exist before creating.
|
||||
/// </summary>
|
||||
public override bool? IncludeIfNotExists
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.IncludeIfNotExists;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.IncludeIfNotExists = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script options to set vardecimal storage format.
|
||||
/// </summary>
|
||||
public override bool? IncludeVarDecimal
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.IncludeVarDecimal;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.IncludeVarDecimal = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include system generated constraint names to enforce declarative referential integrity.
|
||||
/// </summary>
|
||||
public override bool? ScriptDriIncludeSystemNames
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptDriIncludeSystemNames;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptDriIncludeSystemNames = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include statements in the script that are not supported on the specified SQL Server database engine type.
|
||||
/// </summary>
|
||||
public override bool? IncludeUnsupportedStatements
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.IncludeUnsupportedStatements;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.IncludeUnsupportedStatements = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prefix object names with the object schema.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public override bool? SchemaQualify
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.SchemaQualify;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.SchemaQualify = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script options to set bindings option.
|
||||
/// </summary>
|
||||
public override bool? Bindings
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.Bindings;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.Bindings = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the objects that use collation.
|
||||
/// </summary>
|
||||
public override bool? Collation
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.Collation;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.Collation = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the default values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public override bool? Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.Default;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.Default = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script Object CREATE/DROP statements.
|
||||
/// Possible values:
|
||||
/// ScriptCreate
|
||||
/// ScriptDrop
|
||||
/// ScriptCreateDrop
|
||||
/// ScriptSelect
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is ScriptCreate.
|
||||
/// </remarks>
|
||||
public override string ScriptCreateDrop
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptCreateDrop;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptCreateDrop = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the Extended Properties for each object scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public override bool? ScriptExtendedProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptExtendedProperties;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptExtendedProperties = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script only features compatible with the specified version of SQL Server. Possible values:
|
||||
/// Script90Compat
|
||||
/// Script100Compat
|
||||
/// Script105Compat
|
||||
/// Script110Compat
|
||||
/// Script120Compat
|
||||
/// Script130Compat
|
||||
/// Script140Compat
|
||||
/// Script150Compat
|
||||
/// Script160Compat
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is Script140Compat.
|
||||
/// </remarks>
|
||||
public override string ScriptCompatibilityOption
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptCompatibilityOption;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptCompatibilityOption = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script only features compatible with the specified SQL Server database engine type.
|
||||
/// Possible Values:
|
||||
/// SingleInstance
|
||||
/// SqlAzure
|
||||
/// </summary>
|
||||
public override string TargetDatabaseEngineType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.TargetDatabaseEngineType;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.TargetDatabaseEngineType = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script only features compatible with the specified SQL Server database engine edition.
|
||||
/// Possible Values:
|
||||
/// SqlServerPersonalEdition
|
||||
/// SqlServerStandardEdition
|
||||
/// SqlServerEnterpriseEdition
|
||||
/// SqlServerExpressEdition
|
||||
/// SqlAzureDatabaseEdition
|
||||
/// SqlDatawarehouseEdition
|
||||
/// SqlServerStretchEdition
|
||||
/// </summary>
|
||||
public override string TargetDatabaseEngineEdition
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.TargetDatabaseEngineEdition;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.TargetDatabaseEngineEdition = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script all logins available on the server. Passwords will not be scripted.
|
||||
/// </summary>
|
||||
public override bool? ScriptLogins
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptLogins;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptLogins = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate object-level permissions.
|
||||
/// </summary>
|
||||
public override bool? ScriptObjectLevelPermissions
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptObjectLevelPermissions;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptObjectLevelPermissions = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script owner for the objects.
|
||||
/// </summary>
|
||||
public override bool? ScriptOwner
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptOwner;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptOwner = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script statistics, and optionally include histograms, for each selected table or view.
|
||||
/// Possible values:
|
||||
/// ScriptStatsNone
|
||||
/// ScriptStatsDDL
|
||||
/// ScriptStatsAll
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is ScriptStatsNone.
|
||||
/// </remarks>
|
||||
public override string ScriptStatistics
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptStatistics;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptStatistics = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate USE DATABASE statement.
|
||||
/// </summary>
|
||||
public override bool? ScriptUseDatabase
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptUseDatabase;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptUseDatabase = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate script that contains schema only or schema and data.
|
||||
/// Possible Values:
|
||||
/// SchemaAndData
|
||||
/// DataOnly
|
||||
/// SchemaOnly
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is SchemaOnly.
|
||||
/// </remarks>
|
||||
public override string TypeOfDataToScript
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.TypeOfDataToScript;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.TypeOfDataToScript = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scripts the change tracking information.
|
||||
/// </summary>
|
||||
public override bool? ScriptChangeTracking
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptChangeTracking;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptChangeTracking = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the check constraints for each table or view scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public override bool? ScriptCheckConstraints
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptCheckConstraints;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptCheckConstraints = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scripts the data compression information.
|
||||
/// </summary>
|
||||
public override bool? ScriptDataCompressionOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptDataCompressionOptions;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptDataCompressionOptions = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the foreign keys for each table scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public override bool? ScriptForeignKeys
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptForeignKeys;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptForeignKeys = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the full-text indexes for each table or indexed view scripted.
|
||||
/// </summary>
|
||||
public override bool? ScriptFullTextIndexes
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptFullTextIndexes;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptFullTextIndexes = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the indexes (including XML and clustered indexes) for each table or indexed view scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public override bool? ScriptIndexes
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptIndexes;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptIndexes = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the primary keys for each table or view scripted
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public override bool? ScriptPrimaryKeys
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptPrimaryKeys;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptPrimaryKeys = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the triggers for each table or view scripted
|
||||
/// </summary>
|
||||
public override bool? ScriptTriggers
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.ScriptTriggers;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.ScriptTriggers = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script the unique keys for each table or view scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public override bool? UniqueKeys
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScriptOptions.UniqueKeys;
|
||||
}
|
||||
set
|
||||
{
|
||||
ScriptOptions.UniqueKeys = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns Generate ANSI padding statements
|
||||
/// </summary>
|
||||
public bool? AnsiPadding { get { return ScriptOptions.ScriptAnsiPadding; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns ConvertUDDTToBaseType
|
||||
/// </summary>
|
||||
public bool? ConvertUserDefinedDataTypesToBaseType { get { return ScriptOptions.ConvertUDDTToBaseType; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns IncludeDescriptiveHeaders
|
||||
/// </summary>
|
||||
public bool? IncludeHeaders { get { return ScriptOptions.IncludeDescriptiveHeaders; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns ScriptDriIncludeSystemNames
|
||||
/// </summary>
|
||||
public bool? DriIncludeSystemNames { get { return ScriptOptions.ScriptDriIncludeSystemNames; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns SchemaQualify
|
||||
/// </summary>
|
||||
public bool? SchemaQualifyForeignKeysReferences { get { return ScriptOptions.SchemaQualify; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns false if Collation is true
|
||||
/// </summary>
|
||||
public bool? NoCollation { get { return !ScriptOptions.Collation; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of Default Property
|
||||
/// </summary>
|
||||
public bool? DriDefaults { get { return ScriptOptions.Default; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptExtendedProperties Property
|
||||
/// </summary>
|
||||
public bool? ExtendedProperties { get { return ScriptOptions.ScriptExtendedProperties; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptObjectLevelPermissions Property
|
||||
/// </summary>
|
||||
public bool? Permissions { get { return ScriptOptions.ScriptObjectLevelPermissions; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptStatistics Property
|
||||
/// </summary>
|
||||
public string Statistics { get { return ScriptOptions.ScriptStatistics; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptChangeTracking Property
|
||||
/// </summary>
|
||||
public bool? ChangeTracking { get { return ScriptOptions.ScriptChangeTracking; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptCheckConstraints Property
|
||||
/// </summary>
|
||||
public bool? DriChecks { get { return ScriptOptions.ScriptCheckConstraints; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptDataCompressionOptions Property
|
||||
/// </summary>
|
||||
public bool? ScriptDataCompression { get { return ScriptOptions.ScriptDataCompressionOptions; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptForeignKeys Property
|
||||
/// </summary>
|
||||
public bool? DriForeignKeys { get { return ScriptOptions.ScriptForeignKeys; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptFullTextIndexes Property
|
||||
/// </summary>
|
||||
public bool? FullTextIndexes { get { return ScriptOptions.ScriptFullTextIndexes; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptIndexes Property
|
||||
/// </summary>
|
||||
public bool? Indexes { get { return ScriptOptions.ScriptIndexes; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptPrimaryKeys Property
|
||||
/// </summary>
|
||||
public bool? DriPrimaryKey { get { return ScriptOptions.ScriptPrimaryKeys; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of ScriptTriggers Property
|
||||
/// </summary>
|
||||
public bool? Triggers { get { return ScriptOptions.ScriptTriggers; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of UniqueKeys Property
|
||||
/// </summary>
|
||||
public bool? DriUniqueKeys { get { return ScriptOptions.UniqueKeys; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,701 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.SqlScriptPublish;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
|
||||
using Microsoft.SqlTools.SqlCore.Connection;
|
||||
using Microsoft.SqlTools.SqlCore.Scripting.Contracts;
|
||||
using Microsoft.SqlTools.SqlCore.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to generate script as for one smo object
|
||||
/// </summary>
|
||||
public class ScriptAsScriptingOperation : SmoScriptingOperation
|
||||
{
|
||||
private static readonly Dictionary<string, SqlServerVersion> scriptCompatibilityMap = LoadScriptCompatibilityMap();
|
||||
/// <summary>
|
||||
/// Left delimiter for an named object
|
||||
/// </summary>
|
||||
public const char LeftDelimiter = '[';
|
||||
|
||||
/// <summary>
|
||||
/// right delimiter for a named object
|
||||
/// </summary>
|
||||
public const char RightDelimiter = ']';
|
||||
|
||||
public ScriptAsScriptingOperation(ScriptingParams parameters, ServerConnection serverConnection): base(parameters)
|
||||
{
|
||||
Validate.IsNotNull("serverConnection", serverConnection);
|
||||
ServerConnection = serverConnection;
|
||||
}
|
||||
|
||||
public ScriptAsScriptingOperation(ScriptingParams parameters, string azureAccountToken) : base(parameters)
|
||||
{
|
||||
SqlConnection sqlConnection = new SqlConnection(this.Parameters.ConnectionString);
|
||||
sqlConnection.RetryLogicProvider = SqlRetryProviders.ServerlessDBRetryProvider();
|
||||
if (azureAccountToken != null)
|
||||
{
|
||||
sqlConnection.AccessToken = azureAccountToken;
|
||||
}
|
||||
|
||||
ServerConnection = new ServerConnection(sqlConnection);
|
||||
if (azureAccountToken != null)
|
||||
{
|
||||
ServerConnection.AccessToken = new AzureAccessToken(azureAccountToken);
|
||||
}
|
||||
|
||||
disconnectAtDispose = true;
|
||||
}
|
||||
|
||||
internal ServerConnection ServerConnection { get; set; }
|
||||
|
||||
private string serverName;
|
||||
private string databaseName;
|
||||
private bool disconnectAtDispose = false;
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
this.ValidateScriptDatabaseParams();
|
||||
|
||||
this.CancellationToken.ThrowIfCancellationRequested();
|
||||
string resultScript = string.Empty;
|
||||
// TODO: try to use one of the existing connections
|
||||
|
||||
Server server = new Server(ServerConnection);
|
||||
if (!ServerConnection.IsOpen)
|
||||
{
|
||||
ServerConnection.Connect();
|
||||
}
|
||||
|
||||
UrnCollection urns = CreateUrns(ServerConnection);
|
||||
ScriptingOptions options = new ScriptingOptions();
|
||||
SetScriptBehavior(options);
|
||||
ScriptAsOptions scriptAsOptions = new ScriptAsOptions(this.Parameters.ScriptOptions);
|
||||
PopulateAdvancedScriptOptions(scriptAsOptions, options);
|
||||
options.WithDependencies = false;
|
||||
// TODO: Not including the header by default. We have to get this option from client
|
||||
options.IncludeHeaders = false;
|
||||
|
||||
// Scripting data is not avaialable in the scripter
|
||||
options.ScriptData = false;
|
||||
SetScriptingOptions(options);
|
||||
|
||||
switch (this.Parameters.Operation)
|
||||
{
|
||||
case ScriptingOperationType.Create:
|
||||
case ScriptingOperationType.Alter:
|
||||
case ScriptingOperationType.Delete: // Using Delete here is wrong. delete usually means delete rows from table but sqlopsstudio sending the operation name as delete instead of drop
|
||||
resultScript = GenerateScriptAs(server, urns, options);
|
||||
break;
|
||||
case ScriptingOperationType.Select:
|
||||
resultScript = GenerateScriptSelect(server, urns);
|
||||
break;
|
||||
case ScriptingOperationType.Execute:
|
||||
resultScript = GenerareScriptAsExecute(server, urns, options);
|
||||
break;
|
||||
}
|
||||
|
||||
this.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
Logger.Verbose(
|
||||
string.Format(
|
||||
"Sending script complete notification event for operation {0}",
|
||||
this.OperationId
|
||||
));
|
||||
|
||||
ScriptText = resultScript;
|
||||
|
||||
this.SendCompletionNotificationEvent(new ScriptingCompleteParams
|
||||
{
|
||||
Success = true,
|
||||
});
|
||||
|
||||
this.SendPlanNotificationEvent(new ScriptingPlanNotificationParams
|
||||
{
|
||||
ScriptingObjects = this.Parameters.ScriptingObjects,
|
||||
Count = 1,
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e.IsOperationCanceledException())
|
||||
{
|
||||
Logger.Information(string.Format("Scripting operation {0} was canceled", this.OperationId));
|
||||
this.SendCompletionNotificationEvent(new ScriptingCompleteParams
|
||||
{
|
||||
Canceled = true,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error(string.Format("Scripting operation {0} failed with exception {1}", this.OperationId, e));
|
||||
this.SendCompletionNotificationEvent(new ScriptingCompleteParams
|
||||
{
|
||||
OperationId = OperationId,
|
||||
HasError = true,
|
||||
ErrorMessage = $"{SR.ScriptingGeneralError} {e.Message}",
|
||||
ErrorDetails = e.ToString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disconnectAtDispose && ServerConnection != null && ServerConnection.IsOpen)
|
||||
{
|
||||
ServerConnection.Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateScriptSelect(Server server, UrnCollection urns)
|
||||
{
|
||||
string script = string.Empty;
|
||||
ScriptingObject scriptingObject = this.Parameters.ScriptingObjects[0];
|
||||
Urn objectUrn = urns[0];
|
||||
string typeName = objectUrn.GetNameForType(scriptingObject.Type);
|
||||
|
||||
// select from service broker
|
||||
if (string.Compare(typeName, "ServiceBroker", StringComparison.CurrentCultureIgnoreCase) == 0)
|
||||
{
|
||||
script = ScriptingHelper.SelectAllValuesFromTransmissionQueue(objectUrn);
|
||||
}
|
||||
|
||||
// select from queues
|
||||
else if (string.Compare(typeName, "Queues", StringComparison.CurrentCultureIgnoreCase) == 0 ||
|
||||
string.Compare(typeName, "SystemQueues", StringComparison.CurrentCultureIgnoreCase) == 0)
|
||||
{
|
||||
script = ScriptingHelper.SelectAllValues(objectUrn);
|
||||
}
|
||||
|
||||
// select from table or view
|
||||
else
|
||||
{
|
||||
Database db = server.Databases[databaseName];
|
||||
bool isDw = db.IsSqlDw;
|
||||
script = ScriptingHelper.SelectFromTableOrView(server, objectUrn, isDw);
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
private string GenerareScriptAsExecute(Server server, UrnCollection urns, ScriptingOptions options)
|
||||
{
|
||||
string script = string.Empty;
|
||||
ScriptingObject scriptingObject = this.Parameters.ScriptingObjects[0];
|
||||
Urn urn = urns[0];
|
||||
|
||||
// get the object
|
||||
StoredProcedure sp = server.GetSmoObject(urn) as StoredProcedure;
|
||||
|
||||
Database parentObject = server.GetSmoObject(urn.Parent) as Database;
|
||||
|
||||
StringBuilder executeStatement = new StringBuilder();
|
||||
|
||||
// list of DECLARE <variable> <type>
|
||||
StringBuilder declares = new StringBuilder();
|
||||
// Parameters to be passed
|
||||
StringBuilder parameterList = new StringBuilder();
|
||||
if (sp == null || parentObject == null)
|
||||
{
|
||||
throw new InvalidOperationException(SR.ScriptingExecuteNotSupportedError);
|
||||
}
|
||||
WriteUseDatabase(parentObject, executeStatement, options);
|
||||
|
||||
// character string to put in front of each parameter. First one is just carriage return
|
||||
// the rest will have a "," in front as well.
|
||||
string newLine = Environment.NewLine;
|
||||
string paramListPreChar = $"{newLine} ";
|
||||
for (int i = 0; i < sp.Parameters.Count; i++)
|
||||
{
|
||||
StoredProcedureParameter spp = sp.Parameters[i];
|
||||
|
||||
declares.AppendFormat("DECLARE {0} {1}{2}"
|
||||
, QuoteObjectName(spp.Name)
|
||||
, GetDatatype(spp.DataType, options)
|
||||
, newLine);
|
||||
|
||||
parameterList.AppendFormat("{0}{1}"
|
||||
, paramListPreChar
|
||||
, QuoteObjectName(spp.Name));
|
||||
|
||||
// if this is the first time through change the prefix to include a ","
|
||||
if (i == 0)
|
||||
{
|
||||
paramListPreChar = $"{newLine} ,";
|
||||
}
|
||||
|
||||
// mark any output parameters as such.
|
||||
if (spp.IsOutputParameter)
|
||||
{
|
||||
parameterList.Append(" OUTPUT");
|
||||
}
|
||||
}
|
||||
|
||||
// build the execute statement
|
||||
if (sp.ImplementationType == ImplementationType.TransactSql)
|
||||
{
|
||||
executeStatement.Append("EXECUTE @RC = ");
|
||||
}
|
||||
else
|
||||
{
|
||||
executeStatement.Append("EXECUTE ");
|
||||
}
|
||||
|
||||
// get the object name
|
||||
executeStatement.Append(GenerateSchemaQualifiedName(sp.Schema, sp.Name, options.SchemaQualify));
|
||||
|
||||
string formatString = sp.ImplementationType == ImplementationType.TransactSql
|
||||
? "DECLARE @RC int{5}{0}{5}{1}{5}{5}{2} {3}{5}{4}"
|
||||
: "{0}{5}{1}{5}{5}{2} {3}{5}{4}";
|
||||
|
||||
script = string.Format(CultureInfo.InvariantCulture, formatString,
|
||||
declares,
|
||||
SR.StoredProcedureScriptParameterComment,
|
||||
executeStatement,
|
||||
parameterList,
|
||||
CommonConstants.DefaultBatchSeperator,
|
||||
newLine);
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a schema qualified name (e.g. [schema].[objectName]) for an object if the option for SchemaQualify is true
|
||||
/// </summary>
|
||||
/// <param name="schema">The schema name. May be null or empty in which case it will be ignored</param>
|
||||
/// <param name="objectName">The object name.</param>
|
||||
/// <param name="schemaQualify">Whether to schema qualify the object or not</param>
|
||||
/// <returns>The object name, quoted as appropriate and schema-qualified if the option is set</returns>
|
||||
static private string GenerateSchemaQualifiedName(string schema, string objectName, bool schemaQualify)
|
||||
{
|
||||
var qualifiedName = new StringBuilder();
|
||||
|
||||
if (schemaQualify && !String.IsNullOrEmpty(schema))
|
||||
{
|
||||
// schema.name
|
||||
qualifiedName.AppendFormat(CultureInfo.InvariantCulture, "{0}.{1}", GetDelimitedString(schema), GetDelimitedString(objectName));
|
||||
}
|
||||
else
|
||||
{
|
||||
// name
|
||||
qualifiedName.AppendFormat(CultureInfo.InvariantCulture, "{0}", GetDelimitedString(objectName));
|
||||
}
|
||||
|
||||
return qualifiedName.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// getting delimited string
|
||||
/// </summary>
|
||||
/// <param name="str">string</param>
|
||||
/// <returns>string</returns>
|
||||
static private string GetDelimitedString(string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuilder qualifiedName = new StringBuilder();
|
||||
qualifiedName.AppendFormat("{0}{1}{2}",
|
||||
LeftDelimiter,
|
||||
QuoteObjectName(str),
|
||||
RightDelimiter);
|
||||
return qualifiedName.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// turn a smo datatype object into a type that can be inserted into tsql, e.g. nvarchar(20)
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
internal static string GetDatatype(DataType type, ScriptingOptions options)
|
||||
{
|
||||
// string we'll return.
|
||||
string rv = string.Empty;
|
||||
|
||||
string dataType = type.Name;
|
||||
switch (type.SqlDataType)
|
||||
{
|
||||
// char, nchar, nchar, nvarchar, varbinary, nvarbinary are all displayed as type(length)
|
||||
// length of -1 is taken to be type(max). max isn't localizable.
|
||||
case SqlDataType.Char:
|
||||
case SqlDataType.NChar:
|
||||
case SqlDataType.VarChar:
|
||||
case SqlDataType.NVarChar:
|
||||
case SqlDataType.Binary:
|
||||
case SqlDataType.VarBinary:
|
||||
rv = string.Format(CultureInfo.InvariantCulture,
|
||||
"{0}({1})",
|
||||
dataType,
|
||||
type.MaximumLength);
|
||||
break;
|
||||
case SqlDataType.VarCharMax:
|
||||
case SqlDataType.NVarCharMax:
|
||||
case SqlDataType.VarBinaryMax:
|
||||
rv = string.Format(CultureInfo.InvariantCulture,
|
||||
"{0}(max)",
|
||||
dataType);
|
||||
break;
|
||||
// numeric and decimal are displayed as type precision,scale
|
||||
case SqlDataType.Numeric:
|
||||
case SqlDataType.Decimal:
|
||||
rv = string.Format(CultureInfo.InvariantCulture,
|
||||
"{0}({1},{2})",
|
||||
dataType,
|
||||
type.NumericPrecision,
|
||||
type.NumericScale);
|
||||
break;
|
||||
//time, datetimeoffset and datetime2 are displayed as type scale
|
||||
case SqlDataType.Time:
|
||||
case SqlDataType.DateTimeOffset:
|
||||
case SqlDataType.DateTime2:
|
||||
rv = string.Format(CultureInfo.InvariantCulture,
|
||||
"{0}({1})",
|
||||
dataType,
|
||||
type.NumericScale);
|
||||
break;
|
||||
// anything else is just type.
|
||||
case SqlDataType.Xml:
|
||||
if (type.Schema != null && type.Schema.Length > 0 && dataType != null && dataType.Length > 0)
|
||||
{
|
||||
rv = String.Format(CultureInfo.InvariantCulture
|
||||
, "xml ({0}{2}{1}.{0}{3}{1})"
|
||||
, LeftDelimiter
|
||||
, RightDelimiter
|
||||
, QuoteObjectName(type.Schema)
|
||||
, QuoteObjectName(dataType));
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = "xml";
|
||||
}
|
||||
break;
|
||||
case SqlDataType.UserDefinedDataType:
|
||||
case SqlDataType.UserDefinedTableType:
|
||||
case SqlDataType.UserDefinedType:
|
||||
//User defined types may be in a non-DBO schema so append it if necessary
|
||||
rv = GenerateSchemaQualifiedName(type.Schema, dataType, options.SchemaQualify);
|
||||
break;
|
||||
default:
|
||||
rv = dataType;
|
||||
break;
|
||||
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Double quotes certain characters in object name
|
||||
/// </summary>
|
||||
/// <param name="sqlObject"></param>
|
||||
public static string QuoteObjectName(string sqlObject)
|
||||
{
|
||||
|
||||
int len = sqlObject.Length;
|
||||
StringBuilder result = new StringBuilder(sqlObject.Length);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (sqlObject[i] == ']')
|
||||
{
|
||||
result.Append(']');
|
||||
}
|
||||
result.Append(sqlObject[i]);
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
private static void WriteUseDatabase(Database parentObject, StringBuilder stringBuilder , ScriptingOptions options)
|
||||
{
|
||||
if (options.IncludeDatabaseContext)
|
||||
{
|
||||
string useDb = string.Format(CultureInfo.InvariantCulture, "USE {0}", CommonConstants.DefaultBatchSeperator);
|
||||
if (!options.NoCommandTerminator)
|
||||
{
|
||||
stringBuilder.Append(useDb);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
stringBuilder.Append(useDb);
|
||||
stringBuilder.Append(Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateScriptAs(Server server, UrnCollection urns, ScriptingOptions options)
|
||||
{
|
||||
SqlServer.Management.Smo.Scripter scripter = null;
|
||||
string resultScript = string.Empty;
|
||||
try
|
||||
{
|
||||
scripter = new SqlServer.Management.Smo.Scripter(server);
|
||||
if(this.Parameters.Operation == ScriptingOperationType.Alter)
|
||||
{
|
||||
options.ScriptForAlter = true;
|
||||
foreach (var urn in urns)
|
||||
{
|
||||
SqlSmoObject smoObject = server.GetSmoObject(urn);
|
||||
|
||||
// without calling the toch method, no alter script get generated from smo
|
||||
smoObject.Touch();
|
||||
}
|
||||
}
|
||||
|
||||
scripter.Options = options;
|
||||
scripter.ScriptingError += ScripterScriptingError;
|
||||
var result = scripter.Script(urns);
|
||||
resultScript = GetScript(options, result);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (scripter != null)
|
||||
{
|
||||
scripter.ScriptingError -= this.ScripterScriptingError;
|
||||
}
|
||||
}
|
||||
|
||||
return resultScript;
|
||||
}
|
||||
|
||||
private string GetScript(ScriptingOptions options, StringCollection stringCollection)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (var item in stringCollection)
|
||||
{
|
||||
sb.Append(item);
|
||||
if (options != null && !options.NoCommandTerminator)
|
||||
{
|
||||
//Ensure the batch separator is always on a new line (to avoid syntax errors)
|
||||
//but don't write an extra if we already have one as this can affect definitions
|
||||
//of objects such as Stored Procedures (see TFS#9125366)
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}{2}",
|
||||
item.EndsWith(Environment.NewLine) ? string.Empty : Environment.NewLine,
|
||||
CommonConstants.DefaultBatchSeperator,
|
||||
Environment.NewLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, Environment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private UrnCollection CreateUrns(ServerConnection serverConnection)
|
||||
{
|
||||
IEnumerable<ScriptingObject> selectedObjects = new List<ScriptingObject>(this.Parameters.ScriptingObjects);
|
||||
|
||||
serverName = serverConnection.TrueName;
|
||||
databaseName = new SqlConnectionStringBuilder(this.Parameters.ConnectionString).InitialCatalog;
|
||||
UrnCollection urnCollection = new UrnCollection();
|
||||
foreach (var scriptingObject in selectedObjects)
|
||||
{
|
||||
if(string.IsNullOrEmpty(scriptingObject.Schema))
|
||||
{
|
||||
// TODO: get the default schema
|
||||
scriptingObject.Schema = "dbo";
|
||||
}
|
||||
urnCollection.Add(scriptingObject.ToUrn(serverName, databaseName));
|
||||
}
|
||||
return urnCollection;
|
||||
}
|
||||
|
||||
private void SetScriptBehavior(ScriptingOptions options)
|
||||
{
|
||||
// TODO: have to add Scripting behavior to Smo ScriptingOptions class
|
||||
// so it would support ScriptDropAndScreate
|
||||
switch (this.Parameters.ScriptOptions.ScriptCreateDrop)
|
||||
{
|
||||
case "ScriptCreate":
|
||||
options.ScriptDrops = false;
|
||||
break;
|
||||
case "ScriptDrop":
|
||||
options.ScriptDrops = true;
|
||||
break;
|
||||
default:
|
||||
options.ScriptDrops = false;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, SqlServerVersion> LoadScriptCompatibilityMap()
|
||||
{
|
||||
return new Dictionary<string, SqlServerVersion>
|
||||
{
|
||||
{SqlScriptOptions.ScriptCompatibilityOptions.Script160Compat.ToString(), SqlServerVersion.Version160},
|
||||
{SqlScriptOptions.ScriptCompatibilityOptions.Script150Compat.ToString(), SqlServerVersion.Version150},
|
||||
{SqlScriptOptions.ScriptCompatibilityOptions.Script140Compat.ToString(), SqlServerVersion.Version140},
|
||||
{SqlScriptOptions.ScriptCompatibilityOptions.Script130Compat.ToString(), SqlServerVersion.Version130},
|
||||
{SqlScriptOptions.ScriptCompatibilityOptions.Script120Compat.ToString(), SqlServerVersion.Version120},
|
||||
{SqlScriptOptions.ScriptCompatibilityOptions.Script110Compat.ToString(), SqlServerVersion.Version110},
|
||||
{SqlScriptOptions.ScriptCompatibilityOptions.Script105Compat.ToString(), SqlServerVersion.Version105},
|
||||
{SqlScriptOptions.ScriptCompatibilityOptions.Script100Compat.ToString(), SqlServerVersion.Version100},
|
||||
{SqlScriptOptions.ScriptCompatibilityOptions.Script90Compat.ToString(), SqlServerVersion.Version90}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private void SetScriptingOptions(ScriptingOptions scriptingOptions)
|
||||
{
|
||||
scriptingOptions.AllowSystemObjects = true;
|
||||
|
||||
// setting this forces SMO to correctly script objects that have been renamed
|
||||
scriptingOptions.EnforceScriptingOptions = true;
|
||||
|
||||
//We always want role memberships for users and database roles to be scripted
|
||||
scriptingOptions.IncludeDatabaseRoleMemberships = true;
|
||||
SqlServerVersion targetServerVersion;
|
||||
if(scriptCompatibilityMap.TryGetValue(this.Parameters.ScriptOptions.ScriptCompatibilityOption, out targetServerVersion))
|
||||
{
|
||||
scriptingOptions.TargetServerVersion = targetServerVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If you are getting this assertion fail it means you are working for higher
|
||||
//version of SQL Server. You need to update this part of code.
|
||||
Logger.Warning("This part of the code is not updated corresponding to latest version change");
|
||||
}
|
||||
|
||||
// for cloud scripting to work we also have to have Script Compat set to 105.
|
||||
// the defaults from scripting options should take care of it
|
||||
SqlScriptOptions.ScriptDatabaseEngineType targetDatabaseEngineType;
|
||||
if (Enum.TryParse<SqlScriptOptions.ScriptDatabaseEngineType>(this.Parameters.ScriptOptions.TargetDatabaseEngineType, out targetDatabaseEngineType))
|
||||
{
|
||||
switch (targetDatabaseEngineType)
|
||||
{
|
||||
case SqlScriptOptions.ScriptDatabaseEngineType.SingleInstance:
|
||||
scriptingOptions.TargetDatabaseEngineType = DatabaseEngineType.Standalone;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptDatabaseEngineType.SqlAzure:
|
||||
scriptingOptions.TargetDatabaseEngineType = DatabaseEngineType.SqlAzureDatabase;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SqlScriptOptions.ScriptDatabaseEngineEdition targetDatabaseEngineEdition;
|
||||
if (Enum.TryParse<SqlScriptOptions.ScriptDatabaseEngineEdition>(this.Parameters.ScriptOptions.TargetDatabaseEngineEdition, out targetDatabaseEngineEdition))
|
||||
{
|
||||
switch (targetDatabaseEngineEdition)
|
||||
{
|
||||
case SqlScriptOptions.ScriptDatabaseEngineEdition.SqlServerPersonalEdition:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.Personal;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptDatabaseEngineEdition.SqlServerStandardEdition:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.Standard;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptDatabaseEngineEdition.SqlServerEnterpriseEdition:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.Enterprise;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptDatabaseEngineEdition.SqlServerExpressEdition:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.Express;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptDatabaseEngineEdition.SqlAzureDatabaseEdition:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.SqlDatabase;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptDatabaseEngineEdition.SqlDatawarehouseEdition:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.SqlDataWarehouse;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptDatabaseEngineEdition.SqlServerStretchEdition:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.SqlStretchDatabase;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptDatabaseEngineEdition.SqlServerManagedInstanceEdition:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.SqlManagedInstance;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptDatabaseEngineEdition.SqlServerOnDemandEdition:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.SqlOnDemand;
|
||||
break;
|
||||
default:
|
||||
scriptingOptions.TargetDatabaseEngineEdition = DatabaseEngineEdition.Standard;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (scriptingOptions.TargetDatabaseEngineEdition == DatabaseEngineEdition.SqlDataWarehouse)
|
||||
{
|
||||
scriptingOptions.Triggers = false;
|
||||
}
|
||||
|
||||
scriptingOptions.NoVardecimal = false; //making IncludeVarDecimal true for DPW
|
||||
|
||||
// scripting of stats is a combination of the Statistics
|
||||
// and the OptimizerData flag
|
||||
SqlScriptOptions.ScriptStatisticsOptions scriptStatistics;
|
||||
if (Enum.TryParse<SqlScriptOptions.ScriptStatisticsOptions>(this.Parameters.ScriptOptions.ScriptStatistics, out scriptStatistics))
|
||||
{
|
||||
switch (scriptStatistics)
|
||||
{
|
||||
case SqlScriptOptions.ScriptStatisticsOptions.ScriptStatsAll:
|
||||
scriptingOptions.Statistics = true;
|
||||
scriptingOptions.OptimizerData = true;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptStatisticsOptions.ScriptStatsDDL:
|
||||
scriptingOptions.Statistics = true;
|
||||
scriptingOptions.OptimizerData = false;
|
||||
break;
|
||||
case SqlScriptOptions.ScriptStatisticsOptions.ScriptStatsNone:
|
||||
scriptingOptions.Statistics = false;
|
||||
scriptingOptions.OptimizerData = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If Histogram and Update Statics are True then include DriIncludeSystemNames and AnsiPadding by default
|
||||
if (scriptingOptions.Statistics == true && scriptingOptions.OptimizerData == true)
|
||||
{
|
||||
scriptingOptions.DriIncludeSystemNames = true;
|
||||
scriptingOptions.AnsiPadding = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ScripterScriptingError(object sender, ScriptingErrorEventArgs e)
|
||||
{
|
||||
this.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
Logger.Verbose(
|
||||
string.Format(
|
||||
"Sending scripting error progress event, Urn={0}, OperationId={1}, Completed={2}, Error={3}",
|
||||
e.Current,
|
||||
this.OperationId,
|
||||
false,
|
||||
e?.InnerException?.ToString() ?? "null"));
|
||||
|
||||
this.SendProgressNotificationEvent(new ScriptingProgressNotificationParams
|
||||
{
|
||||
ScriptingObject = e.Current?.ToScriptingObject(),
|
||||
Status = "Failed",
|
||||
ErrorMessage = e?.InnerException?.Message,
|
||||
ErrorDetails = e?.InnerException?.ToString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.SqlScriptPublish;
|
||||
using Microsoft.SqlTools.SqlCore.Scripting.Contracts;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods used by the scripting service.
|
||||
/// </summary>
|
||||
public static class ScriptingExtensionMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the status of a scripting operation for the passed scripting event.
|
||||
/// </summary>
|
||||
/// <param name="e">The scripting event.</param>
|
||||
/// <returns>The status.</returns>
|
||||
public static string GetStatus(this ScriptEventArgs e)
|
||||
{
|
||||
Validate.IsNotNull("e", e);
|
||||
|
||||
string status = null;
|
||||
|
||||
if (e.Error != null)
|
||||
{
|
||||
status = "Error";
|
||||
}
|
||||
else if (e.Completed)
|
||||
{
|
||||
status = "Completed";
|
||||
}
|
||||
else
|
||||
{
|
||||
status = "Progress";
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of ScriptingObject instances for the passed SqlScriptPublishModel instance.
|
||||
/// </summary>
|
||||
/// <param name="publishModel">The sql script publish model instance.</param>
|
||||
/// <returns>The list of scripting objects.</returns>
|
||||
public static List<ScriptingObject> GetDatabaseObjects(this SqlScriptPublishModel publishModel)
|
||||
{
|
||||
Validate.IsNotNull("publishModel", publishModel);
|
||||
|
||||
List<ScriptingObject> databaseObjects = new List<ScriptingObject>();
|
||||
|
||||
IEnumerable<DatabaseObjectType> objectTypes = publishModel.GetDatabaseObjectTypes();
|
||||
Logger.Verbose(
|
||||
string.Format(
|
||||
"Loaded SMO object type count {0}, types: {1}",
|
||||
objectTypes.Count(),
|
||||
string.Join(", ", objectTypes)));
|
||||
|
||||
foreach (DatabaseObjectType objectType in objectTypes)
|
||||
{
|
||||
IEnumerable<KeyValuePair<string, string>> databaseObjectsOfType = publishModel.EnumChildrenForDatabaseObjectType(objectType);
|
||||
|
||||
Logger.Verbose(
|
||||
string.Format(
|
||||
"Loaded SMO urn object count {0} for type {1}, urns: {2}",
|
||||
objectType,
|
||||
databaseObjectsOfType.Count(),
|
||||
string.Join(", ", databaseObjectsOfType.Select(p => p.Value))));
|
||||
|
||||
databaseObjects.AddRange(databaseObjectsOfType.Select(d => new Urn(d.Value).ToScriptingObject()));
|
||||
}
|
||||
|
||||
return databaseObjects;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a SMO Urn instance based on the passed ScriptingObject instance.
|
||||
/// </summary>
|
||||
/// <param name="scriptingObject">The scripting object instance.</param>
|
||||
/// <param name="database">The name of the database referenced by the Urn.</param>
|
||||
/// <returns>The Urn instance.</returns>
|
||||
public static Urn ToUrn(this ScriptingObject scriptingObject, string server, string database)
|
||||
{
|
||||
Validate.IsNotNull("scriptingObject", scriptingObject);
|
||||
Validate.IsNotNullOrEmptyString("server", server);
|
||||
Validate.IsNotNullOrWhitespaceString("database", database);
|
||||
|
||||
Validate.IsNotNullOrWhitespaceString("scriptingObject.Name", scriptingObject.Name);
|
||||
Validate.IsNotNullOrWhitespaceString("scriptingObject.Type", scriptingObject.Type);
|
||||
|
||||
// Leaving the server name blank will automatically match whatever the server SMO is running against.
|
||||
StringBuilder urnBuilder = new StringBuilder();
|
||||
urnBuilder.AppendFormat("Server[@Name='{0}']/", server.ToUpper(System.Globalization.CultureInfo.InvariantCulture));
|
||||
urnBuilder.AppendFormat("Database[@Name='{0}']/", Urn.EscapeString(database));
|
||||
|
||||
bool hasParentObject = !string.IsNullOrWhiteSpace(scriptingObject.ParentName)
|
||||
&& !string.IsNullOrWhiteSpace(scriptingObject.ParentTypeName);
|
||||
if (hasParentObject)
|
||||
{
|
||||
urnBuilder.AppendFormat("{0}[@Name='{1}'", scriptingObject.ParentTypeName, Urn.EscapeString(scriptingObject.ParentName));
|
||||
if (!string.IsNullOrWhiteSpace(scriptingObject.Schema))
|
||||
{
|
||||
urnBuilder.AppendFormat(" and @Schema = '{0}'", Urn.EscapeString(scriptingObject.Schema));
|
||||
}
|
||||
urnBuilder.Append("]/");
|
||||
}
|
||||
|
||||
urnBuilder.AppendFormat("{0}[@Name='{1}'", scriptingObject.Type, Urn.EscapeString(scriptingObject.Name));
|
||||
|
||||
// add schema to object only if there is no parent object specified
|
||||
// the parent object field is only set for objects that don't have schema themselves
|
||||
// so if parent is not null then the schema filter will already be set that part of the urn above
|
||||
if (!string.IsNullOrWhiteSpace(scriptingObject.Schema) && !hasParentObject)
|
||||
{
|
||||
urnBuilder.AppendFormat(" and @Schema = '{0}'", Urn.EscapeString(scriptingObject.Schema));
|
||||
}
|
||||
|
||||
urnBuilder.Append("]");
|
||||
|
||||
return new Urn(urnBuilder.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ScriptingObject instance based on the passed SMO Urn instance.
|
||||
/// </summary>
|
||||
/// <param name="urn">The urn instance.</param>
|
||||
/// <returns>The scripting object instance.</returns>
|
||||
public static ScriptingObject ToScriptingObject(this Urn urn)
|
||||
{
|
||||
Validate.IsNotNull("urn", urn);
|
||||
|
||||
return new ScriptingObject
|
||||
{
|
||||
Type = urn.Type,
|
||||
Schema = urn.GetAttribute("Schema"),
|
||||
Name = urn.GetAttribute("Name"),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
318
src/Microsoft.SqlTools.SqlCore/Scripting/ScriptingHelper.cs
Normal file
318
src/Microsoft.SqlTools.SqlCore/Scripting/ScriptingHelper.cs
Normal file
@@ -0,0 +1,318 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for scripting
|
||||
/// </summary>
|
||||
public static class ScriptingHelper
|
||||
{
|
||||
internal static string SelectAllValuesFromTransmissionQueue(Urn urn)
|
||||
{
|
||||
string script = string.Empty;
|
||||
StringBuilder selectQuery = new StringBuilder();
|
||||
|
||||
/*
|
||||
SELECT TOP *, casted_message_body =
|
||||
CASE MESSAGE_TYPE_NAME WHEN 'X'
|
||||
THEN CAST(MESSAGE_BODY AS NVARCHAR(MAX))
|
||||
ELSE MESSAGE_BODY
|
||||
END
|
||||
FROM [new].[sys].[transmission_queue]
|
||||
*/
|
||||
selectQuery.Append("SELECT TOP (1000) ");
|
||||
selectQuery.Append("*, casted_message_body = \r\nCASE message_type_name WHEN 'X' \r\n THEN CAST(message_body AS NVARCHAR(MAX)) \r\n ELSE message_body \r\nEND \r\n");
|
||||
|
||||
// from clause
|
||||
selectQuery.Append("FROM ");
|
||||
Urn dbUrn = urn;
|
||||
|
||||
// database
|
||||
while (dbUrn.Parent != null && dbUrn.Type != "Database")
|
||||
{
|
||||
dbUrn = dbUrn.Parent;
|
||||
}
|
||||
selectQuery.AppendFormat("{0}{1}{2}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
QuoteObjectName(dbUrn.GetAttribute("Name"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
//SYS
|
||||
selectQuery.AppendFormat(".{0}sys{1}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
//TRANSMISSION QUEUE
|
||||
selectQuery.AppendFormat(".{0}transmission_queue{1}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
|
||||
script = selectQuery.ToString();
|
||||
return script;
|
||||
}
|
||||
|
||||
internal static string SelectAllValues(Urn urn)
|
||||
{
|
||||
string script = string.Empty;
|
||||
StringBuilder selectQuery = new StringBuilder();
|
||||
selectQuery.Append("SELECT TOP (1000) ");
|
||||
selectQuery.Append("*, casted_message_body = \r\nCASE message_type_name WHEN 'X' \r\n THEN CAST(message_body AS NVARCHAR(MAX)) \r\n ELSE message_body \r\nEND \r\n");
|
||||
|
||||
// from clause
|
||||
selectQuery.Append("FROM ");
|
||||
Urn dbUrn = urn;
|
||||
|
||||
// database
|
||||
while (dbUrn.Parent != null && dbUrn.Type != "Database")
|
||||
{
|
||||
dbUrn = dbUrn.Parent;
|
||||
}
|
||||
selectQuery.AppendFormat("{0}{1}{2}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
QuoteObjectName(dbUrn.GetAttribute("Name"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
// schema
|
||||
selectQuery.AppendFormat(".{0}{1}{2}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
QuoteObjectName(urn.GetAttribute("Schema"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
// object
|
||||
selectQuery.AppendFormat(".{0}{1}{2}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
QuoteObjectName(urn.GetAttribute("Name"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
|
||||
//Adding no lock in the end.
|
||||
selectQuery.AppendFormat(" WITH(NOLOCK)");
|
||||
|
||||
script = selectQuery.ToString();
|
||||
return script;
|
||||
}
|
||||
|
||||
internal static class ScriptingGlobals
|
||||
{
|
||||
/// <summary>
|
||||
/// Left delimiter for an named object
|
||||
/// </summary>
|
||||
public const char LeftDelimiter = '[';
|
||||
|
||||
/// <summary>
|
||||
/// right delimiter for a named object
|
||||
/// </summary>
|
||||
public const char RightDelimiter = ']';
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DataTable GetColumnNames(Server server, Urn urn, bool isDw)
|
||||
{
|
||||
List<string> filterExpressions = new List<string>();
|
||||
if (server.Version.Major >= 10)
|
||||
{
|
||||
// We don't have to include sparce columns as all the sparce columns data.
|
||||
// Can be obtain from column set columns.
|
||||
filterExpressions.Add("@IsSparse=0");
|
||||
}
|
||||
|
||||
// Check if we're called for EDIT for SQL2016+/Sterling+.
|
||||
// We need to omit temporal columns if such are present on this table.
|
||||
if (server.Version.Major >= 13 || (DatabaseEngineType.SqlAzureDatabase == server.DatabaseEngineType && server.Version.Major >= 12 && !isDw))
|
||||
{
|
||||
// We're called in order to generate a list of columns for EDIT TOP N rows.
|
||||
// Don't return auto-generated, auto-populated, read-only temporal columns.
|
||||
filterExpressions.Add("@GeneratedAlwaysType=0");
|
||||
}
|
||||
|
||||
// Check if we're called for EDIT for SQL2022+/Sterling+.
|
||||
// We need to omit dropped ledger columns if such are present
|
||||
if (server.Version.Major >= 16 || (DatabaseEngineType.SqlAzureDatabase == server.DatabaseEngineType && server.Version.Major >= 12 && !isDw))
|
||||
{
|
||||
filterExpressions.Add("@IsDroppedLedgerColumn=0");
|
||||
}
|
||||
|
||||
// Check if we're called for SQL2017/Sterling+.
|
||||
// We need to omit graph internal columns if such are present on this table.
|
||||
if (server.Version.Major >= 14 || (DatabaseEngineType.SqlAzureDatabase == server.DatabaseEngineType && !isDw))
|
||||
{
|
||||
// from Smo.GraphType:
|
||||
// 0 = None
|
||||
// 1 = GraphId
|
||||
// 2 = GraphIdComputed
|
||||
// 3 = GraphFromId
|
||||
// 4 = GraphFromObjId
|
||||
// 5 = GraphFromIdComputed
|
||||
// 6 = GraphToId
|
||||
// 7 = GraphToObjId
|
||||
// 8 = GraphToIdComputed
|
||||
//
|
||||
// We only want to show types 0, 2, 5, and 8:
|
||||
filterExpressions.Add("(@GraphType=0 or @GraphType=2 or @GraphType=5 or @GraphType=8)");
|
||||
}
|
||||
|
||||
Request request = new Request();
|
||||
// If we have any filters on the columns, add them.
|
||||
if (filterExpressions.Count > 0)
|
||||
{
|
||||
request.Urn = String.Format("{0}/Column[{1}]", urn.ToString(), string.Join(" and ", filterExpressions.ToArray()));
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Urn = String.Format("{0}/Column", urn.ToString());
|
||||
}
|
||||
|
||||
request.Fields = new String[] { "Name" };
|
||||
|
||||
// get the columns in the order they were created
|
||||
OrderBy order = new OrderBy();
|
||||
order.Dir = OrderBy.Direction.Asc;
|
||||
order.Field = "ID";
|
||||
request.OrderByList = new OrderBy[] { order };
|
||||
|
||||
Enumerator en = new Enumerator();
|
||||
|
||||
// perform the query.
|
||||
DataTable? dt = null;
|
||||
EnumResult result = en.Process(server.ConnectionContext, request);
|
||||
|
||||
if (result.Type == ResultType.DataTable)
|
||||
{
|
||||
dt = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
dt = ((DataSet)result).Tables[0];
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
public static string SelectFromTableOrView(Server server, Urn urn, bool isDw)
|
||||
{
|
||||
DataTable dt = GetColumnNames(server, urn, isDw);
|
||||
StringBuilder selectQuery = new StringBuilder();
|
||||
|
||||
// build the first line
|
||||
if (dt != null && dt.Rows.Count > 0)
|
||||
{
|
||||
|
||||
selectQuery.Append("SELECT TOP (1000) ");
|
||||
|
||||
// first column
|
||||
selectQuery.AppendFormat("{0}{1}{2}\r\n",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
QuoteObjectName(dt.Rows[0][0] as string, ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
// add all other columns on separate lines. Make the names align.
|
||||
for (int i = 1; i < dt.Rows.Count; i++)
|
||||
{
|
||||
selectQuery.AppendFormat(" ,{0}{1}{2}\r\n",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
QuoteObjectName(dt.Rows[i][0] as string, ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selectQuery.Append("SELECT TOP (1000) * ");
|
||||
}
|
||||
|
||||
// from clause
|
||||
selectQuery.Append(" FROM ");
|
||||
|
||||
if (server.ServerType != DatabaseEngineType.SqlAzureDatabase)
|
||||
{
|
||||
// Azure doesn't allow qualifying object names with the DB, so only add it on if we're not in Azure database URN
|
||||
Urn dbUrn = urn.Parent;
|
||||
selectQuery.AppendFormat("{0}{1}{2}.",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
QuoteObjectName(dbUrn.GetAttribute("Name"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
}
|
||||
|
||||
// schema
|
||||
selectQuery.AppendFormat("{0}{1}{2}.",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
QuoteObjectName(urn.GetAttribute("Schema"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
// object
|
||||
selectQuery.AppendFormat("{0}{1}{2}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
QuoteObjectName(urn.GetAttribute("Name"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
|
||||
// In Hekaton M5, if it's a memory optimized table, we need to provide SNAPSHOT hint for SELECT.
|
||||
if (urn.Type.Equals("Table") && IsXTPSupportedOnServer(server))
|
||||
{
|
||||
try
|
||||
{
|
||||
Table table = (Table)server.GetSmoObject(urn);
|
||||
table.Refresh();
|
||||
if (table.IsMemoryOptimized)
|
||||
{
|
||||
selectQuery.Append(" WITH (SNAPSHOT)");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// log any exceptions determining if InMemory, but don't treat as fatal exception
|
||||
Logger.Error("Could not determine if is InMemory table " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return selectQuery.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Quote the name of a given sql object.
|
||||
/// </summary>
|
||||
/// <param name="sqlObject">object</param>
|
||||
/// <returns>quoted object name</returns>
|
||||
internal static string QuoteObjectName(string sqlObject)
|
||||
{
|
||||
return QuoteObjectName(sqlObject, ']');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Quotes the name of a given sql object
|
||||
/// </summary>
|
||||
/// <param name="sqlObject">object</param>
|
||||
/// <param name="quote">quote to use</param>
|
||||
/// <returns></returns>
|
||||
internal static string QuoteObjectName(string sqlObject, char quote)
|
||||
{
|
||||
int len = sqlObject.Length;
|
||||
StringBuilder result = new StringBuilder(sqlObject.Length);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (sqlObject[i] == quote)
|
||||
{
|
||||
result.Append(quote);
|
||||
}
|
||||
result.Append(sqlObject[i]);
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value whether the server supports XTP or not s
|
||||
internal static bool IsXTPSupportedOnServer(Server server)
|
||||
{
|
||||
bool isXTPSupported = false;
|
||||
if (server.ConnectionContext.ExecuteScalar("SELECT SERVERPROPERTY('IsXTPSupported')") != DBNull.Value)
|
||||
{
|
||||
isXTPSupported = server.IsXTPSupported;
|
||||
}
|
||||
return isXTPSupported;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for scripting operations. Because scripting operations can be very long
|
||||
/// running, there my be multiple concurrent scripting operations. To distinguish events
|
||||
/// between concurrent scripting operations, use the operation id.
|
||||
/// </summary>
|
||||
public abstract class ScriptingOperation : IDisposable
|
||||
{
|
||||
private CancellationTokenSource cancellation = new CancellationTokenSource();
|
||||
|
||||
protected ScriptingOperation()
|
||||
{
|
||||
this.OperationId = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
protected CancellationToken CancellationToken { get { return this.cancellation.Token; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique id associated with this instance.
|
||||
/// </summary>
|
||||
public string OperationId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Excecutes the scripting operation.
|
||||
/// </summary>
|
||||
public abstract void Execute();
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the scripting operation.
|
||||
/// </summary>
|
||||
public virtual void Cancel()
|
||||
{
|
||||
if (!this.cancellation.IsCancellationRequested)
|
||||
{
|
||||
Logger.Verbose(string.Format("Cancel invoked for OperationId {0}", this.OperationId));
|
||||
this.cancellation.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the scripting operation.
|
||||
/// </summary>
|
||||
public abstract void Dispose();
|
||||
}
|
||||
}
|
||||
263
src/Microsoft.SqlTools.SqlCore/Scripting/ScriptingOptions.cs
Normal file
263
src/Microsoft.SqlTools.SqlCore/Scripting/ScriptingOptions.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the scripting options.
|
||||
/// </summary>
|
||||
public class ScriptOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Generate ANSI padding statements
|
||||
/// </summary>
|
||||
public virtual bool? ScriptAnsiPadding { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Append the generated script to a file
|
||||
/// </summary>
|
||||
public virtual bool? AppendToFile { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Continue to script if an error occurs. Otherwise, stop.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public virtual bool? ContinueScriptingOnError { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Convert user-defined data types to base types.
|
||||
/// </summary>
|
||||
public virtual bool? ConvertUDDTToBaseType { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Generate script for dependent objects for each object scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is false.
|
||||
/// </remarks>
|
||||
public virtual bool? GenerateScriptForDependentObjects { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Include descriptive headers for each object generated.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public virtual bool? IncludeDescriptiveHeaders { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Check that an object with the given name exists before dropping or altering or that an object with the given name does not exist before creating.
|
||||
/// </summary>
|
||||
public virtual bool? IncludeIfNotExists { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Script options to set vardecimal storage format.
|
||||
/// </summary>
|
||||
public virtual bool? IncludeVarDecimal { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Include system generated constraint names to enforce declarative referential integrity.
|
||||
/// </summary>
|
||||
public virtual bool? ScriptDriIncludeSystemNames { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Include statements in the script that are not supported on the specified SQL Server database engine type.
|
||||
/// </summary>
|
||||
public virtual bool? IncludeUnsupportedStatements { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Prefix object names with the object schema.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public virtual bool? SchemaQualify { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Script options to set bindings option.
|
||||
/// </summary>
|
||||
public virtual bool? Bindings { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Script the objects that use collation.
|
||||
/// </summary>
|
||||
public virtual bool? Collation { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Script the default values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public virtual bool? Default { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Script Object CREATE/DROP statements.
|
||||
/// Possible values:
|
||||
/// ScriptCreate
|
||||
/// ScriptDrop
|
||||
/// ScriptCreateDrop
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is ScriptCreate.
|
||||
/// </remarks>
|
||||
public virtual string ScriptCreateDrop { get; set; } = "ScriptCreate";
|
||||
|
||||
/// <summary>
|
||||
/// Script the Extended Properties for each object scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is true.
|
||||
/// </remarks>
|
||||
public virtual bool? ScriptExtendedProperties { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Script only features compatible with the specified version of SQL Server. Possible values:
|
||||
/// Script90Compat
|
||||
/// Script100Compat
|
||||
/// Script105Compat
|
||||
/// Script110Compat
|
||||
/// Script120Compat
|
||||
/// Script130Compat
|
||||
/// Script140Compat
|
||||
/// Script150Compat
|
||||
/// Script160Compat
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is Script140Compat.
|
||||
/// </remarks>
|
||||
public virtual string ScriptCompatibilityOption { get; set; } = "Script140Compat";
|
||||
|
||||
/// <summary>
|
||||
/// Script only features compatible with the specified SQL Server database engine type.
|
||||
/// Possible Values:
|
||||
/// SingleInstance
|
||||
/// SqlAzure
|
||||
/// </summary>
|
||||
public virtual string TargetDatabaseEngineType { get; set; } = "SingleInstance";
|
||||
|
||||
/// <summary>
|
||||
/// Script only features compatible with the specified SQL Server database engine edition.
|
||||
/// Possible Values:
|
||||
/// SqlServerPersonalEdition
|
||||
/// SqlServerStandardEdition
|
||||
/// SqlServerEnterpriseEdition
|
||||
/// SqlServerExpressEdition
|
||||
/// SqlAzureDatabaseEdition
|
||||
/// SqlDatawarehouseEdition
|
||||
/// SqlServerStretchEdition
|
||||
/// SqlManagedInstanceEdition
|
||||
/// SqlServerOnDemandEdition
|
||||
/// </summary>
|
||||
public virtual string TargetDatabaseEngineEdition { get; set; } = "SqlServerEnterpriseEdition";
|
||||
|
||||
/// <summary>
|
||||
/// Script all logins available on the server. Passwords will not be scripted.
|
||||
/// </summary>
|
||||
public virtual bool? ScriptLogins { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Generate object-level permissions.
|
||||
/// </summary>
|
||||
public virtual bool? ScriptObjectLevelPermissions { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Script owner for the objects.
|
||||
/// </summary>
|
||||
public virtual bool? ScriptOwner { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Script statistics, and optionally include histograms, for each selected table or view.
|
||||
/// Possible values:
|
||||
/// ScriptStatsNone
|
||||
/// ScriptStatsDDL
|
||||
/// ScriptStatsAll
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is ScriptStatsNone.
|
||||
/// </remarks>
|
||||
public virtual string ScriptStatistics { get; set; } = "ScriptStatsNone";
|
||||
|
||||
/// <summary>
|
||||
/// Generate USE DATABASE statement.
|
||||
/// </summary>
|
||||
public virtual bool? ScriptUseDatabase { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Generate script that contains schema only or schema and data.
|
||||
/// Possible Values:
|
||||
/// SchemaAndData
|
||||
/// DataOnly
|
||||
/// SchemaOnly
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is SchemaOnly.
|
||||
/// </remarks>
|
||||
public virtual string TypeOfDataToScript { get; set; } = "SchemaOnly";
|
||||
|
||||
/// <summary>
|
||||
/// Scripts the change tracking information.
|
||||
/// </summary>
|
||||
public virtual bool? ScriptChangeTracking { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Script the check constraints for each table or view scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public virtual bool? ScriptCheckConstraints { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Scripts the data compression information.
|
||||
/// </summary>
|
||||
public virtual bool? ScriptDataCompressionOptions { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Script the foreign keys for each table scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public virtual bool? ScriptForeignKeys { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Script the full-text indexes for each table or indexed view scripted.
|
||||
/// </summary>
|
||||
public virtual bool? ScriptFullTextIndexes { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Script the indexes (including XML and clustered indexes) for each table or indexed view scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public virtual bool? ScriptIndexes { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Script the primary keys for each table or view scripted
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public virtual bool? ScriptPrimaryKeys { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Script the triggers for each table or view scripted
|
||||
/// </summary>
|
||||
public virtual bool? ScriptTriggers { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Script the unique keys for each table or view scripted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public virtual bool? UniqueKeys { get; set; } = true;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
|
||||
using Microsoft.SqlTools.SqlCore.Connection;
|
||||
using Microsoft.SqlTools.SqlCore.Scripting.Contracts;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using static Microsoft.SqlServer.Management.SqlScriptPublish.SqlScriptOptions;
|
||||
|
||||
namespace Microsoft.SqlTools.SqlCore.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all SMO scripting operations
|
||||
/// </summary>
|
||||
public abstract class SmoScriptingOperation : ScriptingOperation
|
||||
{
|
||||
private bool disposed = false;
|
||||
|
||||
public SmoScriptingOperation(ScriptingParams parameters)
|
||||
{
|
||||
Validate.IsNotNull("parameters", parameters);
|
||||
|
||||
this.Parameters = parameters;
|
||||
}
|
||||
|
||||
protected ScriptingParams Parameters { get; set; }
|
||||
|
||||
public string ScriptText { get; protected set; }
|
||||
|
||||
/// <remarks>
|
||||
/// An event can be completed by the following conditions: success, cancel, error.
|
||||
/// </remarks>
|
||||
public event EventHandler<ScriptingCompleteParams> CompleteNotification;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when a scripting operation has made forward progress.
|
||||
/// </summary>
|
||||
public event EventHandler<ScriptingProgressNotificationParams> ProgressNotification;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when a scripting operation has resolved which database objects will be scripted.
|
||||
/// </summary>
|
||||
public event EventHandler<ScriptingPlanNotificationParams> PlanNotification;
|
||||
|
||||
protected virtual void SendCompletionNotificationEvent(ScriptingCompleteParams parameters)
|
||||
{
|
||||
this.SetCommonEventProperties(parameters);
|
||||
this.CompleteNotification?.Invoke(this, parameters);
|
||||
}
|
||||
|
||||
protected virtual void SendProgressNotificationEvent(ScriptingProgressNotificationParams parameters)
|
||||
{
|
||||
this.SetCommonEventProperties(parameters);
|
||||
this.ProgressNotification?.Invoke(this, parameters);
|
||||
}
|
||||
|
||||
protected virtual void SendPlanNotificationEvent(ScriptingPlanNotificationParams parameters)
|
||||
{
|
||||
this.SetCommonEventProperties(parameters);
|
||||
this.PlanNotification?.Invoke(this, parameters);
|
||||
}
|
||||
|
||||
protected virtual void SetCommonEventProperties(ScriptingEventParams parameters)
|
||||
{
|
||||
parameters.OperationId = this.OperationId;
|
||||
}
|
||||
|
||||
protected string GetServerNameFromLiveInstance(string connectionString, string azureAccessToken)
|
||||
{
|
||||
string serverName = null;
|
||||
using (SqlConnection connection = new SqlConnection(connectionString))
|
||||
{
|
||||
connection.RetryLogicProvider = SqlRetryProviders.ServerlessDBRetryProvider();
|
||||
if (azureAccessToken != null)
|
||||
{
|
||||
connection.AccessToken = azureAccessToken;
|
||||
}
|
||||
connection.Open();
|
||||
|
||||
try
|
||||
{
|
||||
ServerConnection serverConnection;
|
||||
if (azureAccessToken == null)
|
||||
{
|
||||
serverConnection = new ServerConnection(connection);
|
||||
}
|
||||
else
|
||||
{
|
||||
serverConnection = new ServerConnection(connection, new AzureAccessToken(azureAccessToken));
|
||||
}
|
||||
serverName = serverConnection.TrueName;
|
||||
}
|
||||
catch (SqlException e)
|
||||
{
|
||||
Logger.Verbose(
|
||||
string.Format("Exception getting server name", e));
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Verbose(string.Format("Resolved server name '{0}'", serverName));
|
||||
return serverName;
|
||||
}
|
||||
|
||||
protected void ValidateScriptDatabaseParams()
|
||||
{
|
||||
try
|
||||
{
|
||||
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(this.Parameters.ConnectionString);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ArgumentException(SR.ScriptingParams_ConnectionString_Property_Invalid, e);
|
||||
}
|
||||
if (this.Parameters.FilePath == null && this.Parameters.ScriptDestination != "ToEditor")
|
||||
{
|
||||
throw new ArgumentException(SR.ScriptingParams_FilePath_Property_Invalid);
|
||||
}
|
||||
else if (this.Parameters.FilePath != null && this.Parameters.ScriptDestination != "ToEditor")
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(this.Parameters.FilePath)))
|
||||
{
|
||||
throw new ArgumentException(SR.ScriptingParams_FilePath_Property_Invalid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static void PopulateAdvancedScriptOptions(ScriptOptions scriptOptionsParameters, object advancedOptions)
|
||||
{
|
||||
if (scriptOptionsParameters == null)
|
||||
{
|
||||
Logger.Verbose("No advanced options set, the ScriptOptions object is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (PropertyInfo optionPropInfo in scriptOptionsParameters.GetType().GetProperties())
|
||||
{
|
||||
PropertyInfo advancedOptionPropInfo = advancedOptions.GetType().GetProperty(optionPropInfo.Name);
|
||||
if (advancedOptionPropInfo == null)
|
||||
{
|
||||
Logger.Warning(string.Format("Invalid property info name {0} could not be mapped to a property on SqlScriptOptions.", optionPropInfo.Name));
|
||||
continue;
|
||||
}
|
||||
|
||||
object optionValue = optionPropInfo.GetValue(scriptOptionsParameters, index: null);
|
||||
if (optionValue == null)
|
||||
{
|
||||
Logger.Verbose(string.Format("Skipping ScriptOptions.{0} since value is null", optionPropInfo.Name));
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// The ScriptOptions property types from the request will be either a string or a bool?.
|
||||
// The SqlScriptOptions property types from SMO will all be an Enum. Using reflection, we
|
||||
// map the request ScriptOptions values to the SMO SqlScriptOptions values.
|
||||
//
|
||||
|
||||
try
|
||||
{
|
||||
object smoValue = null;
|
||||
if (optionPropInfo.PropertyType == typeof(bool?))
|
||||
{
|
||||
if (advancedOptionPropInfo.PropertyType == typeof(bool))
|
||||
{
|
||||
|
||||
smoValue = (bool)optionValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
smoValue = (bool)optionValue ? BooleanTypeOptions.True : BooleanTypeOptions.False;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
smoValue = Enum.Parse(advancedOptionPropInfo.PropertyType, (string)optionValue, ignoreCase: true);
|
||||
}
|
||||
|
||||
Logger.Verbose(string.Format("Setting ScriptOptions.{0} to value {1}", optionPropInfo.Name, smoValue));
|
||||
advancedOptionPropInfo.SetValue(advancedOptions, smoValue);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning(
|
||||
string.Format("An exception occurred setting option {0} to value {1}: {2}", optionPropInfo.Name, optionValue, e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the scripting operation.
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
this.Cancel();
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user