mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-16 09:35:36 -05:00
Task/script refactor (#446)
* scripting working with race conditions * new service works with no race conditions * use new scripting service and commented out tests * refactored peek definition to use mssql-scripter * fixed peek definition tests * removed auto gen comment * fixed peek definition highlighting bug * made scripting async and fixed event handlers * fixed tests (without cancel and plan notifs) * removed dead code * added nuget package * CR comments + select script service implementation * minor fixes and added test * CR comments and script select * added unit tests * code review comments and cleanup
This commit is contained in:
@@ -101,6 +101,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts
|
||||
/// ScriptCreate
|
||||
/// ScriptDrop
|
||||
/// ScriptCreateDrop
|
||||
/// ScriptSelect
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is ScriptCreate.
|
||||
|
||||
@@ -67,6 +67,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts
|
||||
/// 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>
|
||||
@@ -75,6 +81,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts
|
||||
public class ScriptingResult
|
||||
{
|
||||
public string OperationId { get; set; }
|
||||
|
||||
public string Script { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// 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.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Metadata.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of scripting operation requested
|
||||
/// </summary>
|
||||
public enum ScriptOperation
|
||||
{
|
||||
Select = 0,
|
||||
Create = 1,
|
||||
Insert = 2,
|
||||
Update = 3,
|
||||
Delete = 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script as request parameter type
|
||||
/// </summary>
|
||||
public class ScriptingScriptAsParams
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public ScriptOperation Operation { get; set; }
|
||||
|
||||
public ObjectMetadata Metadata { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script as request result type
|
||||
/// </summary>
|
||||
public class ScriptingScriptAsResult
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public string Script { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script as request message type
|
||||
/// </summary>
|
||||
public class ScriptingScriptAsRequest
|
||||
{
|
||||
public static readonly
|
||||
RequestType<ScriptingScriptAsParams, ScriptingScriptAsResult> Type =
|
||||
RequestType<ScriptingScriptAsParams, ScriptingScriptAsResult>.Create("scripting/scriptas");
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// THIS FILE IS GENERATED BY A CODEGEN TOOL. DO NOT EDIT!!!!
|
||||
// IF YOU NEED TO MAKE CHANGES, EDIT THE .TT FILE!!!
|
||||
|
||||
// To regenerate either (1) save the .TT file from Visual Studio or (2) run the build script codegen task.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
@@ -14,235 +10,67 @@ using System.Collections.Specialized;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
{
|
||||
internal partial class Scripter
|
||||
{
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
AddSupportedType(DeclarationType.Table, GetTableScripts, "Table", "table");
|
||||
AddSupportedType(DeclarationType.View, GetViewScripts, "View", "view");
|
||||
AddSupportedType(DeclarationType.StoredProcedure, GetStoredProcedureScripts, "Procedure", "stored procedure");
|
||||
AddSupportedType(DeclarationType.Schema, GetSchemaScripts, "Schema", "schema");
|
||||
AddSupportedType(DeclarationType.Database, GetDatabaseScripts, "Database", "database");
|
||||
AddSupportedType(DeclarationType.UserDefinedDataType, GetUserDefinedDataTypeScripts, "Type", "user-defined data type");
|
||||
AddSupportedType(DeclarationType.UserDefinedTableType, GetUserDefinedTableTypeScripts, "Type", "user-defined table type");
|
||||
AddSupportedType(DeclarationType.Synonym, GetSynonymScripts, "Synonym", "");
|
||||
AddSupportedType(DeclarationType.ScalarValuedFunction, GetScalarValuedFunctionScripts, "Function", "scalar-valued function");
|
||||
AddSupportedType(DeclarationType.TableValuedFunction, GetTableValuedFunctionScripts, "Function", "table-valued function");
|
||||
}
|
||||
// Instantiate the mapping dictionaries
|
||||
|
||||
/// <summary>
|
||||
/// Script a Table using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">Table name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetTableScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Table smoObject = string.IsNullOrEmpty(schemaName) ? new Table(this.Database, objectName) : new Table(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Mapping for supported type
|
||||
AddSupportedType(DeclarationType.Table, "Table", "table", typeof(Table));
|
||||
AddSupportedType(DeclarationType.View, "View", "view", typeof(View));
|
||||
AddSupportedType(DeclarationType.StoredProcedure, "Procedure", "stored procedure", typeof(StoredProcedure));
|
||||
AddSupportedType(DeclarationType.Schema, "Schema", "schema", typeof(Schema));
|
||||
AddSupportedType(DeclarationType.UserDefinedDataType, "UserDefinedDataType", "user-defined data type", typeof(UserDefinedDataType));
|
||||
AddSupportedType(DeclarationType.UserDefinedTableType, "UserDefinedTableType", "user-defined table type", typeof(UserDefinedTableType));
|
||||
AddSupportedType(DeclarationType.Synonym, "Synonym", "", typeof(Synonym));
|
||||
AddSupportedType(DeclarationType.ScalarValuedFunction, "Function", "scalar-valued function", typeof(UserDefinedFunction));
|
||||
AddSupportedType(DeclarationType.TableValuedFunction, "Function", "table-valued function", typeof(UserDefinedFunction));
|
||||
|
||||
/// <summary>
|
||||
/// Script a View using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">View name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetViewScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
View smoObject = string.IsNullOrEmpty(schemaName) ? new View(this.Database, objectName) : new View(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetViewScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Mapping for database engine edition
|
||||
targetDatabaseEngineEditionMap.Add(DatabaseEngineEdition.Unknown, "SqlServerEnterpriseEdition"); //default case
|
||||
targetDatabaseEngineEditionMap.Add(DatabaseEngineEdition.Personal, "SqlServerPersonalEdition");
|
||||
targetDatabaseEngineEditionMap.Add(DatabaseEngineEdition.Standard, "SqlServerStandardEdition");
|
||||
targetDatabaseEngineEditionMap.Add(DatabaseEngineEdition.Enterprise, "SqlServerEnterpriseEdition");
|
||||
targetDatabaseEngineEditionMap.Add(DatabaseEngineEdition.Express, "SqlServerExpressEdition");
|
||||
targetDatabaseEngineEditionMap.Add(DatabaseEngineEdition.SqlDatabase, "SqlAzureDatabaseEdition");
|
||||
targetDatabaseEngineEditionMap.Add(DatabaseEngineEdition.SqlDataWarehouse, "SqlDatawarehouseEdition");
|
||||
targetDatabaseEngineEditionMap.Add(DatabaseEngineEdition.SqlStretchDatabase, "SqlServerStretchEdition");
|
||||
|
||||
/// <summary>
|
||||
/// Script a StoredProcedure using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">StoredProcedure name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetStoredProcedureScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
StoredProcedure smoObject = string.IsNullOrEmpty(schemaName) ? new StoredProcedure(this.Database, objectName) : new StoredProcedure(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetStoredProcedureScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a Schema using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">Schema name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetSchemaScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Schema smoObject = new Schema(this.Database, objectName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetSchemaScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a Database using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">Database name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetDatabaseScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Database smoObject = new Database(new Server(this.serverConnection), objectName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetDatabaseScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a UserDefinedDataType using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">UserDefinedDataType name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetUserDefinedDataTypeScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserDefinedDataType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedDataType(this.Database, objectName) : new UserDefinedDataType(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedDataTypeScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a UserDefinedTableType using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">UserDefinedTableType name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetUserDefinedTableTypeScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserDefinedTableType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedTableType(this.Database, objectName) : new UserDefinedTableType(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedTableTypeScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a Synonym using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">Synonym name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetSynonymScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Synonym smoObject = string.IsNullOrEmpty(schemaName) ? new Synonym(this.Database, objectName) : new Synonym(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetSynonymScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a ScalarValuedFunction using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">ScalarValuedFunction name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetScalarValuedFunctionScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetScalarValuedFunctionScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a TableValuedFunction using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">TableValuedFunction name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetTableValuedFunctionScripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableValuedFunctionScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Mapping for database engine type
|
||||
serverVersionMap.Add(9, "Script90Compat");
|
||||
serverVersionMap.Add(10, "Script100Compat");
|
||||
serverVersionMap.Add(11, "Script110Compat");
|
||||
serverVersionMap.Add(12, "Script120Compat");
|
||||
serverVersionMap.Add(13, "Script140Compat");
|
||||
serverVersionMap.Add(14, "Script140Compat");
|
||||
|
||||
// Mapping the object types for scripting
|
||||
objectScriptMap.Add("table", "Table");
|
||||
objectScriptMap.Add("view", "View");
|
||||
objectScriptMap.Add("storedprocedure", "Procedure");
|
||||
objectScriptMap.Add("userdefinedfunction", "Function");
|
||||
objectScriptMap.Add("userdefineddataType", "Type");
|
||||
objectScriptMap.Add("user", "User");
|
||||
objectScriptMap.Add("default", "Default");
|
||||
objectScriptMap.Add("rule", "Rule");
|
||||
objectScriptMap.Add("databaserole", "Role");
|
||||
objectScriptMap.Add("applicationrole", "Application Role");
|
||||
objectScriptMap.Add("sqlassembly", "Assembly");
|
||||
objectScriptMap.Add("ddltrigger", "Trigger");
|
||||
objectScriptMap.Add("synonym", "Synonym");
|
||||
objectScriptMap.Add("xmlschemacollection", "Xml Schema Collection");
|
||||
objectScriptMap.Add("schema", "Schema");
|
||||
objectScriptMap.Add("planguide", "sp_create_plan_guide");
|
||||
objectScriptMap.Add("userdefinedType", "Type");
|
||||
objectScriptMap.Add("userdefinedaggregate", "Aggregate");
|
||||
objectScriptMap.Add("fulltextcatalog", "Fulltext Catalog");
|
||||
objectScriptMap.Add("userdefinedtabletype", "Type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
<#@ template debug="false" hostspecific="true" language="C#" #>
|
||||
<#@ output extension=".cs" #>
|
||||
<#@ assembly name="System.Xml.dll" #>
|
||||
<#@ import namespace="System" #>
|
||||
<#@ import namespace="System.Globalization" #>
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ import namespace="System.Xml" #>
|
||||
<#@ import namespace="System.Collections.Generic" #>
|
||||
<#@ import namespace="System.IO" #>
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// THIS FILE IS GENERATED BY A CODEGEN TOOL. DO NOT EDIT!!!!
|
||||
// IF YOU NEED TO MAKE CHANGES, EDIT THE .TT FILE!!!
|
||||
|
||||
// To regenerate either (1) save the .TT file from Visual Studio or (2) run the build script codegen task.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
{
|
||||
internal partial class Scripter
|
||||
{
|
||||
|
||||
<#
|
||||
///
|
||||
/// Generate Initialize method
|
||||
///
|
||||
var indent = " ";
|
||||
var directory = Path.GetDirectoryName(Host.TemplateFile);
|
||||
string xmlFile = Path.Combine(directory, "ScripterSupportedTypes.xml");
|
||||
var supportedTypes = GetSupportedTypes(xmlFile);
|
||||
if (supportedTypes != null && supportedTypes.Count > 0)
|
||||
{
|
||||
WriteLine("private void Initialize()");
|
||||
PushIndent(indent);
|
||||
PushIndent(indent);
|
||||
WriteLine("{");
|
||||
PushIndent(indent);
|
||||
foreach(var typeProperty in supportedTypes)
|
||||
{
|
||||
string functionCall = string.Format("AddSupportedType(DeclarationType.{0}, Get{0}Scripts, \"{1}\", \"{2}\");", typeProperty["Name"], typeProperty["CreateSyntax"], typeProperty["QuickInfoType"]);
|
||||
WriteLine(functionCall);
|
||||
}
|
||||
PopIndent();
|
||||
WriteLine("}\n");
|
||||
|
||||
///
|
||||
/// Generate scriptGetters for each type
|
||||
///
|
||||
|
||||
foreach(var typeProperty in supportedTypes)
|
||||
{
|
||||
string statement;
|
||||
// Write comments
|
||||
WriteLine("/// <summary>");
|
||||
WriteLine(string.Format("/// Script a {0} using SMO", typeProperty["Name"]));
|
||||
WriteLine("/// </summary>");
|
||||
WriteLine(string.Format("/// <param name=\"objectName\">{0} name</param>", typeProperty["Name"]));
|
||||
WriteLine(string.Format("/// <param name=\"schemaName\">Schema name</param>"));
|
||||
WriteLine("/// <returns>String collection of scripts</returns>");
|
||||
|
||||
WriteLine(string.Format("internal StringCollection Get{0}Scripts(string objectName, string schemaName, ScriptingOptions scriptingOptions = null)", typeProperty["Name"]));
|
||||
WriteLine("{");
|
||||
PushIndent(indent);
|
||||
|
||||
// Write try block to retrieve object and return script
|
||||
WriteLine("try");
|
||||
WriteLine("{");
|
||||
if(typeProperty["SupportsSchemaQuery"].IndexOf("true", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
statement = string.Format("{0} smoObject = string.IsNullOrEmpty(schemaName) ? new {0}(this.Database, objectName) : new {0}(this.Database, objectName, schemaName);", typeProperty["AccessClass"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's a database
|
||||
if (typeProperty["AccessClass"] == "Database")
|
||||
{
|
||||
statement = string.Format("{0} smoObject = new {0}(new Server(this.serverConnection), objectName);", typeProperty["Name"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement = string.Format("{0} smoObject = new {0}(this.Database, objectName);", typeProperty["Name"]);
|
||||
}
|
||||
}
|
||||
PushIndent(indent);
|
||||
WriteLine(statement);
|
||||
WriteLine("smoObject.Refresh();");
|
||||
WriteLine("return (scriptingOptions == null) ? smoObject.Script() : smoObject.Script(scriptingOptions);");
|
||||
PopIndent();
|
||||
WriteLine("}");
|
||||
|
||||
// Write catch block to catch and log exceptions
|
||||
WriteLine("catch (Exception ex)");
|
||||
WriteLine("{");
|
||||
PushIndent(indent);
|
||||
statement = string.Format("LogLevel.Error,\"Exception at PeekDefinition Get{0}Scripts : \" + ex.Message", typeProperty["Name"]);
|
||||
WriteLine("Logger.Write(" + statement + ");");
|
||||
WriteLine("return null;");
|
||||
PopIndent();
|
||||
WriteLine("}");
|
||||
PopIndent();
|
||||
WriteLine("}\n");
|
||||
}
|
||||
}
|
||||
PopIndent();
|
||||
PopIndent();
|
||||
#>
|
||||
}
|
||||
}
|
||||
<#+
|
||||
///
|
||||
/// Get the supported types from the xml file
|
||||
///
|
||||
public static List<Dictionary<string, string>> GetSupportedTypes(string xmlFile)
|
||||
{
|
||||
List<Dictionary<string, string>> typeList = null;
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(xmlFile);
|
||||
XmlNodeList supportedTypes = doc.SelectNodes("/SupportedTypes/Type");
|
||||
if (supportedTypes != null)
|
||||
{
|
||||
typeList = new List<Dictionary<string, string>>();
|
||||
foreach (var type in supportedTypes)
|
||||
{
|
||||
XmlElement node = type as XmlElement;
|
||||
if (node != null)
|
||||
{
|
||||
string typeName = (node["Name"] != null) ? node["Name"].InnerText : null;
|
||||
string createSyntax = (node["CreateSyntax"] != null) ? node["CreateSyntax"].InnerText : null;
|
||||
string accessClass = (node["AccessClass"] != null) ? node["AccessClass"].InnerText : null;
|
||||
string supportsSchemaQuery = (node["SupportsSchemaQuery"] != null) ? node["SupportsSchemaQuery"].InnerText : null;
|
||||
string quickInfoType = (node["QuickInfoType"] != null) ? node["QuickInfoType"].InnerText : null;
|
||||
if (typeName != null && createSyntax != null && accessClass != null && supportsSchemaQuery!= null)
|
||||
{
|
||||
Dictionary<string, string> typeProperties = new Dictionary<string, string>();
|
||||
typeProperties.Add("Name", typeName);
|
||||
typeProperties.Add("CreateSyntax", createSyntax);
|
||||
typeProperties.Add("AccessClass", accessClass);
|
||||
typeProperties.Add("SupportsSchemaQuery", supportsSchemaQuery);
|
||||
typeProperties.Add("QuickInfoType", quickInfoType);
|
||||
typeList.Add(typeProperties);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return typeList;
|
||||
}
|
||||
|
||||
#>
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.Common;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -19,10 +18,13 @@ using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Scripting.Contracts;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using ConnectionType = Microsoft.SqlTools.ServiceLayer.Connection.ConnectionType;
|
||||
using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location;
|
||||
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
{
|
||||
@@ -35,20 +37,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
private Database database;
|
||||
private string tempPath;
|
||||
|
||||
internal delegate StringCollection ScriptGetter(string objectName, string schemaName, ScriptingOptions scriptingOptions);
|
||||
|
||||
// Dictionary that holds the script getter for each type
|
||||
private Dictionary<DeclarationType, ScriptGetter> sqlScriptGetters =
|
||||
new Dictionary<DeclarationType, ScriptGetter>();
|
||||
|
||||
private Dictionary<string, ScriptGetter> sqlScriptGettersFromQuickInfo =
|
||||
new Dictionary<string, ScriptGetter>();
|
||||
|
||||
// Dictionary that holds the object name (as appears on the TSQL create statement)
|
||||
private Dictionary<DeclarationType, string> sqlObjectTypes = new Dictionary<DeclarationType, string>();
|
||||
|
||||
private Dictionary<string, string> sqlObjectTypesFromQuickInfo = new Dictionary<string, string>();
|
||||
|
||||
private Dictionary<DatabaseEngineEdition, string> targetDatabaseEngineEditionMap = new Dictionary<DatabaseEngineEdition, string>();
|
||||
|
||||
private Dictionary<int, string> serverVersionMap = new Dictionary<int, string>();
|
||||
|
||||
private Dictionary<string, string> objectScriptMap = new Dictionary<string, string>();
|
||||
|
||||
internal Scripter() {}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a Peek Definition helper object
|
||||
/// </summary>
|
||||
@@ -60,7 +61,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
this.tempPath = FileUtilities.GetPeekDefinitionTempFolder();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
|
||||
internal Database Database
|
||||
{
|
||||
get
|
||||
@@ -114,13 +115,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
/// <summary>
|
||||
/// Add the given type, scriptgetter and the typeName string to the respective dictionaries
|
||||
/// </summary>
|
||||
private void AddSupportedType(DeclarationType type, ScriptGetter scriptGetter, string typeName, string quickInfoType)
|
||||
private void AddSupportedType(DeclarationType type, string typeName, string quickInfoType, Type smoObjectType)
|
||||
{
|
||||
sqlScriptGetters.Add(type, scriptGetter);
|
||||
sqlObjectTypes.Add(type, typeName);
|
||||
if (!string.IsNullOrEmpty(quickInfoType))
|
||||
{
|
||||
sqlScriptGettersFromQuickInfo.Add(quickInfoType.ToLowerInvariant(), scriptGetter);
|
||||
sqlObjectTypesFromQuickInfo.Add(quickInfoType.ToLowerInvariant(), typeName);
|
||||
}
|
||||
}
|
||||
@@ -186,7 +185,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
string tokenType = GetTokenTypeFromQuickInfo(quickInfoText, tokenText, caseSensitivity);
|
||||
if (tokenType != null)
|
||||
{
|
||||
if (sqlScriptGettersFromQuickInfo.ContainsKey(tokenType.ToLowerInvariant()))
|
||||
if (sqlObjectTypesFromQuickInfo.ContainsKey(tokenType.ToLowerInvariant()))
|
||||
{
|
||||
// With SqlLogin authentication, the defaultSchema property throws an Exception when accessed.
|
||||
// This workaround ensures that a schema name is present by attempting
|
||||
@@ -198,7 +197,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
|
||||
}
|
||||
Location[] locations = GetSqlObjectDefinition(
|
||||
sqlScriptGettersFromQuickInfo[tokenType.ToLowerInvariant()],
|
||||
tokenText,
|
||||
schemaName,
|
||||
sqlObjectTypesFromQuickInfo[tokenType.ToLowerInvariant()]
|
||||
@@ -224,13 +222,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
/// <summary>
|
||||
/// Script a object using the type extracted from declarationItem
|
||||
/// </summary>
|
||||
/// <param name="declarationItem">The Declarartion object that matched with the selected token</param>
|
||||
/// <param name="declarationItem">The Declaration object that matched with the selected token</param>
|
||||
/// <param name="tokenText">The text of the selected token</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns></returns>
|
||||
internal DefinitionResult GetDefinitionUsingDeclarationType(DeclarationType type, string databaseQualifiedName, string tokenText, string schemaName)
|
||||
{
|
||||
if (sqlScriptGetters.ContainsKey(type) && sqlObjectTypes.ContainsKey(type))
|
||||
if (sqlObjectTypes.ContainsKey(type))
|
||||
{
|
||||
// With SqlLogin authentication, the defaultSchema property throws an Exception when accessed.
|
||||
// This workaround ensures that a schema name is present by attempting
|
||||
@@ -242,7 +240,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
|
||||
}
|
||||
Location[] locations = GetSqlObjectDefinition(
|
||||
sqlScriptGetters[type],
|
||||
tokenText,
|
||||
schemaName,
|
||||
sqlObjectTypes[type]
|
||||
@@ -268,32 +265,43 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
/// <param name="objectType">Type of SQL object</param>
|
||||
/// <returns>Location object representing URI and range of the script file</returns>
|
||||
internal Location[] GetSqlObjectDefinition(
|
||||
ScriptGetter sqlScriptGetter,
|
||||
string objectName,
|
||||
string schemaName,
|
||||
string objectType)
|
||||
{
|
||||
StringCollection scripts = sqlScriptGetter(objectName, schemaName, null);
|
||||
// script file destination
|
||||
string tempFileName = (schemaName != null) ? Path.Combine(this.tempPath, string.Format("{0}.{1}.sql", schemaName, objectName))
|
||||
: Path.Combine(this.tempPath, string.Format("{0}.sql", objectName));
|
||||
|
||||
if (scripts != null)
|
||||
{
|
||||
int lineNumber = 0;
|
||||
using (StreamWriter scriptFile = new StreamWriter(File.Open(tempFileName, FileMode.Create, FileAccess.ReadWrite)))
|
||||
{
|
||||
ScriptingScriptOperation operation = InitScriptOperation(objectName, schemaName, objectType);
|
||||
operation.Execute();
|
||||
string script = operation.ScriptText;
|
||||
|
||||
foreach (string script in scripts)
|
||||
bool objectFound = false;
|
||||
int createStatementLineNumber = 0;
|
||||
|
||||
File.WriteAllText(tempFileName, script);
|
||||
string[] lines = File.ReadAllLines(tempFileName);
|
||||
int lineCount = 0;
|
||||
string createSyntax = null;
|
||||
if (objectScriptMap.ContainsKey(objectType.ToLower()))
|
||||
{
|
||||
createSyntax = string.Format("CREATE {0}", objectScriptMap[objectType.ToLower()]);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (LineContainsObject(line, objectName, createSyntax))
|
||||
{
|
||||
string createSyntax = string.Format("CREATE {0}", objectType);
|
||||
if (script.IndexOf(createSyntax, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
scriptFile.WriteLine(script);
|
||||
lineNumber = GetStartOfCreate(script, createSyntax);
|
||||
}
|
||||
createStatementLineNumber = lineCount;
|
||||
objectFound = true;
|
||||
break;
|
||||
}
|
||||
lineCount++;
|
||||
}
|
||||
return GetLocationFromFile(tempFileName, lineNumber);
|
||||
}
|
||||
if (objectFound)
|
||||
{
|
||||
Location[] locations = GetLocationFromFile(tempFileName, createStatementLineNumber);
|
||||
return locations;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -341,33 +349,21 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
tempFileName = new Uri(tempFileName).AbsoluteUri;
|
||||
}
|
||||
// Create a location array containing the tempFile Uri, as expected by VSCode.
|
||||
Location[] locations = new[] {
|
||||
new Location {
|
||||
Location[] locations = new[]
|
||||
{
|
||||
new Location
|
||||
{
|
||||
Uri = tempFileName,
|
||||
Range = new Range {
|
||||
Start = new Position { Line = lineNumber, Character = 1},
|
||||
End = new Position { Line = lineNumber + 1, Character = 1}
|
||||
Range = new Range
|
||||
{
|
||||
Start = new Position { Line = lineNumber, Character = 0},
|
||||
End = new Position { Line = lineNumber + 1, Character = 0}
|
||||
}
|
||||
}
|
||||
};
|
||||
return locations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get line number for the create statement
|
||||
/// </summary>
|
||||
private int GetStartOfCreate(string script, string createString)
|
||||
{
|
||||
string[] lines = script.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
|
||||
for (int lineNumber = 0; lineNumber < lines.Length; lineNumber++)
|
||||
{
|
||||
if (lines[lineNumber].IndexOf(createString, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return lineNumber;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Helper method to create definition error result object
|
||||
/// </summary>
|
||||
@@ -453,7 +449,363 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
return Resolver.FindCompletions(
|
||||
parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that calls Resolver.FindCompletions
|
||||
/// </summary>
|
||||
/// <param name="objectName"></param>
|
||||
/// <param name="schemaName"></param>
|
||||
/// <param name="objectType"></param>
|
||||
/// <param name="tempFileName"></param>
|
||||
/// <returns></returns>
|
||||
internal ScriptingScriptOperation InitScriptOperation(string objectName, string schemaName, string objectType)
|
||||
{
|
||||
// object that has to be scripted
|
||||
ScriptingObject scriptingObject = new ScriptingObject
|
||||
{
|
||||
Name = objectName,
|
||||
Schema = schemaName,
|
||||
Type = objectType
|
||||
};
|
||||
|
||||
// scripting options
|
||||
ScriptOptions options = new ScriptOptions
|
||||
{
|
||||
ScriptCreateDrop = "ScriptCreate",
|
||||
TypeOfDataToScript = "SchemaOnly",
|
||||
ScriptStatistics = "ScriptStatsNone",
|
||||
TargetDatabaseEngineEdition = GetTargetDatabaseEngineEdition(),
|
||||
TargetDatabaseEngineType = GetTargetDatabaseEngineType(),
|
||||
ScriptCompatibilityOption = GetScriptCompatibilityOption(),
|
||||
IncludeIfNotExists = true
|
||||
};
|
||||
|
||||
List<ScriptingObject> objectList = new List<ScriptingObject>();
|
||||
objectList.Add(scriptingObject);
|
||||
|
||||
// create parameters for the scripting operation
|
||||
|
||||
ScriptingParams parameters = new ScriptingParams
|
||||
{
|
||||
ConnectionString = ConnectionService.BuildConnectionString(this.connectionInfo.ConnectionDetails),
|
||||
ScriptingObjects = objectList,
|
||||
ScriptOptions = options,
|
||||
ScriptDestination = "ToEditor"
|
||||
};
|
||||
|
||||
return new ScriptingScriptOperation(parameters);
|
||||
}
|
||||
|
||||
internal string GetTargetDatabaseEngineEdition()
|
||||
{
|
||||
DatabaseEngineEdition dbEngineEdition = this.serverConnection.DatabaseEngineEdition;
|
||||
string dbEngineEditionString = targetDatabaseEngineEditionMap[dbEngineEdition];
|
||||
return (dbEngineEditionString != null) ? dbEngineEditionString : "SqlServerEnterpriseEdition";
|
||||
}
|
||||
|
||||
internal string GetScriptCompatibilityOption()
|
||||
{
|
||||
int serverVersion = this.serverConnection.ServerVersion.Major;
|
||||
string dbEngineTypeString = serverVersionMap[serverVersion];
|
||||
return (dbEngineTypeString != null) ? dbEngineTypeString : "Script140Compat";
|
||||
}
|
||||
|
||||
internal string GetTargetDatabaseEngineType()
|
||||
{
|
||||
return connectionInfo.IsAzure ? "SqlAzure" : "SingleInstance";
|
||||
}
|
||||
|
||||
internal bool LineContainsObject(string line, string objectName, string createSyntax)
|
||||
{
|
||||
if (line.IndexOf(createSyntax, StringComparison.OrdinalIgnoreCase) >= 0 &&
|
||||
line.IndexOf(objectName, StringComparison.OrdinalIgnoreCase) >=0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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 = ']';
|
||||
}
|
||||
|
||||
internal static class ScriptingUtils
|
||||
{
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
ScriptingUtils.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,
|
||||
ScriptingUtils.QuoteObjectName(dbUrn.GetAttribute("Name"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
// schema
|
||||
selectQuery.AppendFormat(".{0}{1}{2}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
ScriptingUtils.QuoteObjectName(urn.GetAttribute("Schema"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
// object
|
||||
selectQuery.AppendFormat(".{0}{1}{2}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
ScriptingUtils.QuoteObjectName(urn.GetAttribute("Name"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
|
||||
//Adding no lock in the end.
|
||||
selectQuery.AppendFormat(" WITH(NOLOCK)");
|
||||
|
||||
script = selectQuery.ToString();
|
||||
return script;
|
||||
}
|
||||
|
||||
internal 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))
|
||||
{
|
||||
// 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 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;
|
||||
}
|
||||
|
||||
internal string SelectFromTableOrView(Server server, Urn urn, bool isDw)
|
||||
{
|
||||
string script = string.Empty;
|
||||
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,
|
||||
ScriptingUtils.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,
|
||||
ScriptingUtils.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,
|
||||
ScriptingUtils.QuoteObjectName(dbUrn.GetAttribute("Name"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
}
|
||||
// schema
|
||||
selectQuery.AppendFormat("{0}{1}{2}.",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
ScriptingUtils.QuoteObjectName(urn.GetAttribute("Schema"), ScriptingGlobals.RightDelimiter),
|
||||
ScriptingGlobals.RightDelimiter);
|
||||
// object
|
||||
selectQuery.AppendFormat("{0}{1}{2}",
|
||||
ScriptingGlobals.LeftDelimiter,
|
||||
ScriptingUtils.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") && ScriptingUtils.IsXTPSupportedOnServer(server))
|
||||
{
|
||||
Table table = (Table)server.GetSmoObject(urn);
|
||||
table.Refresh();
|
||||
if (table.IsMemoryOptimized)
|
||||
{
|
||||
selectQuery.Append(" WITH (SNAPSHOT)");
|
||||
}
|
||||
}
|
||||
|
||||
script = selectQuery.ToString();
|
||||
return script;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<!--
|
||||
For each supported type
|
||||
Name - As denoted in the Microsoft.SqlServer.Management.SqlParser.Intellisense.DeclarationType Enumeration for the object
|
||||
Create Syntax - The keyword used in the create t-sql statement for the object - e.g create TABLE, create PROCEDURE etc.
|
||||
AccessClass - The SMO class denoting the object e.g. Table, UserDefinedTableType etc.
|
||||
QuickInfoType - The type of the object as displayed in the Babel.CodeObjectQuickInfo.Text string (optional)
|
||||
SupportsSchemaQuery - Boolean denoting if the object can be queried/accessed using the schema name
|
||||
-->
|
||||
<SupportedTypes>
|
||||
<Type>
|
||||
<Name>Table</Name>
|
||||
<CreateSyntax>Table</CreateSyntax>
|
||||
<AccessClass>Table</AccessClass>
|
||||
<QuickInfoType>table</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>View</Name>
|
||||
<CreateSyntax>View</CreateSyntax>
|
||||
<AccessClass>View</AccessClass>
|
||||
<QuickInfoType>view</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>StoredProcedure</Name>
|
||||
<CreateSyntax>Procedure</CreateSyntax>
|
||||
<AccessClass>StoredProcedure</AccessClass>
|
||||
<QuickInfoType>stored procedure</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>Schema</Name>
|
||||
<CreateSyntax>Schema</CreateSyntax>
|
||||
<AccessClass>Schema</AccessClass>
|
||||
<QuickInfoType>schema</QuickInfoType>
|
||||
<SupportsSchemaQuery>false</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>Database</Name>
|
||||
<CreateSyntax>Database</CreateSyntax>
|
||||
<AccessClass>Database</AccessClass>
|
||||
<QuickInfoType>database</QuickInfoType>
|
||||
<SupportsSchemaQuery>false</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>UserDefinedDataType</Name>
|
||||
<CreateSyntax>Type</CreateSyntax>
|
||||
<AccessClass>UserDefinedDataType</AccessClass>
|
||||
<QuickInfoType>user-defined data type</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>UserDefinedTableType</Name>
|
||||
<CreateSyntax>Type</CreateSyntax>
|
||||
<AccessClass>UserDefinedTableType</AccessClass>
|
||||
<QuickInfoType>user-defined table type</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>Synonym</Name>
|
||||
<CreateSyntax>Synonym</CreateSyntax>
|
||||
<AccessClass>Synonym</AccessClass>
|
||||
<QuickInfoType></QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>ScalarValuedFunction</Name>
|
||||
<CreateSyntax>Function</CreateSyntax>
|
||||
<AccessClass>UserDefinedFunction</AccessClass>
|
||||
<QuickInfoType>scalar-valued function</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>TableValuedFunction</Name>
|
||||
<CreateSyntax>Function</CreateSyntax>
|
||||
<AccessClass>UserDefinedFunction</AccessClass>
|
||||
<QuickInfoType>table-valued function</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
</SupportedTypes>
|
||||
@@ -39,6 +39,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
|
||||
private ScriptingParams Parameters { get; set; }
|
||||
|
||||
public string ScriptText { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when a scripting operation has resolved which database objects will be scripted.
|
||||
/// </summary>
|
||||
@@ -71,6 +73,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
publishModel.ScriptItemsCollected += this.OnPublishModelScriptItemsCollected;
|
||||
publishModel.ScriptProgress += this.OnPublishModelScriptProgress;
|
||||
publishModel.ScriptError += this.OnPublishModelScriptError;
|
||||
publishModel.AllowSystemObjects = true;
|
||||
|
||||
ScriptDestination destination = !string.IsNullOrWhiteSpace(this.Parameters.ScriptDestination)
|
||||
? (ScriptDestination)Enum.Parse(typeof(ScriptDestination), this.Parameters.ScriptDestination)
|
||||
@@ -98,6 +101,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
this.eventSequenceNumber,
|
||||
this.totalScriptedObjectCount,
|
||||
this.scriptedObjectCount));
|
||||
|
||||
ScriptText = publishModel.RawScript;
|
||||
|
||||
this.SendCompletionNotificationEvent(new ScriptingCompleteParams
|
||||
{
|
||||
@@ -138,23 +143,23 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
|
||||
private void SendCompletionNotificationEvent(ScriptingCompleteParams parameters)
|
||||
{
|
||||
this.SetCommomEventProperties(parameters);
|
||||
this.SetCommonEventProperties(parameters);
|
||||
this.CompleteNotification?.Invoke(this, parameters);
|
||||
}
|
||||
|
||||
private void SendPlanNotificationEvent(ScriptingPlanNotificationParams parameters)
|
||||
{
|
||||
this.SetCommomEventProperties(parameters);
|
||||
this.SetCommonEventProperties(parameters);
|
||||
this.PlanNotification?.Invoke(this, parameters);
|
||||
}
|
||||
|
||||
private void SendProgressNotificationEvent(ScriptingProgressNotificationParams parameters)
|
||||
{
|
||||
this.SetCommomEventProperties(parameters);
|
||||
this.SetCommonEventProperties(parameters);
|
||||
this.ProgressNotification?.Invoke(this, parameters);
|
||||
}
|
||||
|
||||
private void SetCommomEventProperties(ScriptingEventParams parameters)
|
||||
private void SetCommonEventProperties(ScriptingEventParams parameters)
|
||||
{
|
||||
parameters.OperationId = this.OperationId;
|
||||
parameters.SequenceNumber = this.eventSequenceNumber;
|
||||
@@ -234,7 +239,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
{
|
||||
publishModel.SelectedObjects.Add(scriptingObject.ToUrn(server, database));
|
||||
}
|
||||
|
||||
return publishModel;
|
||||
}
|
||||
|
||||
@@ -334,11 +338,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
{
|
||||
throw new ArgumentException(SR.ScriptingParams_ConnectionString_Property_Invalid, e);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(Path.GetDirectoryName(this.Parameters.FilePath)))
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPublishModelScriptError(object sender, ScriptEventArgs e)
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.SqlClient;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@@ -19,6 +21,8 @@ using Microsoft.SqlTools.ServiceLayer.Metadata.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Scripting.Contracts;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
{
|
||||
@@ -55,7 +59,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
}
|
||||
return connectionService;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
connectionService = value;
|
||||
@@ -93,7 +96,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
/// <param name="context"></param>
|
||||
public void InitializeService(ServiceHost serviceHost)
|
||||
{
|
||||
serviceHost.SetRequestHandler(ScriptingScriptAsRequest.Type, HandleScriptingScriptAsRequest);
|
||||
serviceHost.SetRequestHandler(ScriptingRequest.Type, this.HandleScriptExecuteRequest);
|
||||
serviceHost.SetRequestHandler(ScriptingCancelRequest.Type, this.HandleScriptCancelRequest);
|
||||
serviceHost.SetRequestHandler(ScriptingListObjectsRequest.Type, this.HandleListObjectsRequest);
|
||||
@@ -106,6 +108,61 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles request to get select script for an smo object
|
||||
/// </summary>
|
||||
private void HandleScriptSelectRequest(ScriptingParams parameters, RequestContext<ScriptingResult> requestContext)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string script = String.Empty;
|
||||
ScriptingObject scriptingObject = parameters.ScriptingObjects[0];
|
||||
|
||||
// convert owner uri received from parameters to lookup for its
|
||||
// associated connection and build a connection string out of it
|
||||
SqlConnection sqlConn = new SqlConnection(parameters.ConnectionString);
|
||||
ServerConnection serverConn = new ServerConnection(sqlConn);
|
||||
Server server = new Server(serverConn);
|
||||
server.DefaultTextMode = true;
|
||||
SqlConnectionStringBuilder connStringBuilder = new SqlConnectionStringBuilder(parameters.ConnectionString);
|
||||
string urnString = string.Format(
|
||||
"Server[@Name='{0}']/Database[@Name='{1}']/{2}[@Name='{3}' {4}]",
|
||||
server.Name.ToUpper(),
|
||||
connStringBuilder.InitialCatalog,
|
||||
scriptingObject.Type,
|
||||
scriptingObject.Name,
|
||||
scriptingObject.Schema != null ? string.Format("and @Schema = '{0}'", scriptingObject.Schema) : string.Empty);
|
||||
Urn urn = new Urn(urnString);
|
||||
string name = urn.GetNameForType(scriptingObject.Type);
|
||||
if (string.Compare(name, "ServiceBroker", StringComparison.CurrentCultureIgnoreCase) == 0)
|
||||
{
|
||||
script = Scripter.SelectAllValuesFromTransmissionQueue(urn);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.Compare(name, "Queues", StringComparison.CurrentCultureIgnoreCase) == 0 ||
|
||||
string.Compare(name, "SystemQueues", StringComparison.CurrentCultureIgnoreCase) == 0)
|
||||
{
|
||||
script = Scripter.SelectAllValues(urn);
|
||||
}
|
||||
else
|
||||
{
|
||||
Database db = server.Databases[connStringBuilder.InitialCatalog];
|
||||
bool isDw = db.IsSqlDw;
|
||||
script = new Scripter().SelectFromTableOrView(server, urn, isDw);
|
||||
}
|
||||
}
|
||||
requestContext.SendResult(new ScriptingResult { Script = script});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
requestContext.SendError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles request to execute start the list objects operation.
|
||||
/// </summary>
|
||||
@@ -133,14 +190,34 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
{
|
||||
try
|
||||
{
|
||||
ScriptingScriptOperation operation = new ScriptingScriptOperation(parameters);
|
||||
operation.PlanNotification += (sender, e) => this.SendEvent(requestContext, ScriptingPlanNotificationEvent.Type, e);
|
||||
operation.ProgressNotification += (sender, e) => this.SendEvent(requestContext, ScriptingProgressNotificationEvent.Type, e);
|
||||
operation.CompleteNotification += (sender, e) => this.SendEvent(requestContext, ScriptingCompleteEvent.Type, e);
|
||||
// convert owner uri received from parameters to lookup for its
|
||||
// associated connection and build a connection string out of it
|
||||
// if a connection string doesn't already exist
|
||||
if (parameters.ConnectionString == null)
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
ScriptingService.ConnectionServiceInstance.TryFindConnection(
|
||||
parameters.OwnerUri, out connInfo);
|
||||
if (connInfo != null)
|
||||
{
|
||||
parameters.ConnectionString = ConnectionService.BuildConnectionString(connInfo.ConnectionDetails);
|
||||
}
|
||||
}
|
||||
|
||||
RunTask(requestContext, operation);
|
||||
// if the scripting operation is for select
|
||||
if (parameters.ScriptOptions.ScriptCreateDrop == "ScriptSelect")
|
||||
{
|
||||
RunSelectTask(parameters, requestContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptingScriptOperation operation = new ScriptingScriptOperation(parameters);
|
||||
operation.PlanNotification += (sender, e) => this.SendEvent(requestContext, ScriptingPlanNotificationEvent.Type, e);
|
||||
operation.ProgressNotification += (sender, e) => this.SendEvent(requestContext, ScriptingProgressNotificationEvent.Type, e);
|
||||
operation.CompleteNotification += (sender, e) => this.SendScriptingCompleteEvent(requestContext, ScriptingCompleteEvent.Type, e, operation, parameters.ScriptDestination);
|
||||
|
||||
await requestContext.SendResult(new ScriptingResult { OperationId = operation.OperationId });
|
||||
RunTask(requestContext, operation);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -173,6 +250,27 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
}
|
||||
}
|
||||
|
||||
private async void SendScriptingCompleteEvent<TParams>(RequestContext<ScriptingResult> requestContext, EventType<TParams> eventType, TParams parameters,
|
||||
ScriptingScriptOperation operation, string scriptDestination)
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
await requestContext.SendEvent(eventType, parameters);
|
||||
if (scriptDestination == "ToEditor")
|
||||
{
|
||||
await requestContext.SendResult(new ScriptingResult { OperationId = operation.OperationId, Script = operation.ScriptText });
|
||||
}
|
||||
else if (scriptDestination == "ToSingleFile")
|
||||
{
|
||||
await requestContext.SendResult(new ScriptingResult { OperationId = operation.OperationId });
|
||||
}
|
||||
else
|
||||
{
|
||||
await requestContext.SendError(string.Format("Operation {0} failed", operation.ToString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a JSON-RPC event.
|
||||
/// </summary>
|
||||
@@ -181,6 +279,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
Task.Run(async () => await requestContext.SendEvent(eventType, parameters));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the async task that performs the scripting operation.
|
||||
/// </summary>
|
||||
private void RunSelectTask(ScriptingParams parameters, RequestContext<ScriptingResult> requestContext)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
this.HandleScriptSelectRequest(parameters, requestContext);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
requestContext.SendError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the async task that performs the scripting operation.
|
||||
/// </summary>
|
||||
@@ -190,7 +306,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.Assert(!this.ActiveOperations.ContainsKey(operation.OperationId), "Operation id must be unique");
|
||||
this.ActiveOperations[operation.OperationId] = operation;
|
||||
operation.Execute();
|
||||
}
|
||||
@@ -221,213 +336,5 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script create statements for metadata object
|
||||
/// </summary>
|
||||
private static string ScriptAsCreate(
|
||||
IBindingContext bindingContext,
|
||||
ConnectionInfo connInfo,
|
||||
ObjectMetadata metadata)
|
||||
{
|
||||
Scripter scripter = new Scripter(bindingContext.ServerConnection, connInfo);
|
||||
StringCollection results = null;
|
||||
switch(metadata.MetadataTypeName)
|
||||
{
|
||||
case ("Table"):
|
||||
results = scripter.GetTableScripts(metadata.Name, metadata.Schema);
|
||||
break;
|
||||
case ("View"):
|
||||
results = scripter.GetViewScripts(metadata.Name, metadata.Schema);
|
||||
break;
|
||||
case("StoredProcedure"):
|
||||
results = scripter.GetStoredProcedureScripts(metadata.Name, metadata.Schema);
|
||||
break;
|
||||
case("Schema"):
|
||||
results = scripter.GetSchemaScripts(metadata.Name, metadata.Schema);
|
||||
break;
|
||||
case("Database"):
|
||||
results = scripter.GetDatabaseScripts(metadata.Name, metadata.Schema);
|
||||
break;
|
||||
default:
|
||||
results = null;
|
||||
break;
|
||||
}
|
||||
StringBuilder builder = null;
|
||||
if (results != null)
|
||||
{
|
||||
builder = new StringBuilder();
|
||||
foreach (var result in results)
|
||||
{
|
||||
builder.AppendLine(result);
|
||||
builder.AppendLine();
|
||||
}
|
||||
}
|
||||
return builder != null ? builder.ToString() : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not yet implemented
|
||||
/// </summary>
|
||||
private static string ScriptAsUpdate(
|
||||
IBindingContext bindingContext,
|
||||
ConnectionInfo connInfo,
|
||||
ObjectMetadata metadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not yet implemented
|
||||
/// </summary>
|
||||
private static string ScriptAsInsert(
|
||||
IBindingContext bindingContext,
|
||||
ConnectionInfo connInfo,
|
||||
ObjectMetadata metadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not yet implemented
|
||||
/// </summary>
|
||||
private static string ScriptAsDelete(
|
||||
IBindingContext bindingContext,
|
||||
ConnectionInfo connInfo,
|
||||
ObjectMetadata metadata)
|
||||
{
|
||||
Scripter scripter = new Scripter(bindingContext.ServerConnection, connInfo);
|
||||
StringCollection results = null;
|
||||
ScriptingOptions options = new ScriptingOptions();
|
||||
options.ScriptDrops = true;
|
||||
switch(metadata.MetadataTypeName)
|
||||
{
|
||||
case ("Table"):
|
||||
results = scripter.GetTableScripts(metadata.Name, metadata.Schema, options);
|
||||
break;
|
||||
case ("View"):
|
||||
results = scripter.GetViewScripts(metadata.Name, metadata.Schema, options);
|
||||
break;
|
||||
case("StoredProcedure"):
|
||||
results = scripter.GetStoredProcedureScripts(metadata.Name, metadata.Schema, options);
|
||||
break;
|
||||
case("Schema"):
|
||||
results = scripter.GetSchemaScripts(metadata.Name, metadata.Schema, options);
|
||||
break;
|
||||
case("Database"):
|
||||
results = scripter.GetDatabaseScripts(metadata.Name, metadata.Schema, options);
|
||||
break;
|
||||
default:
|
||||
results = null;
|
||||
break;
|
||||
}
|
||||
StringBuilder builder = null;
|
||||
if (results != null)
|
||||
{
|
||||
builder = new StringBuilder();
|
||||
foreach (var result in results)
|
||||
{
|
||||
builder.AppendLine(result);
|
||||
builder.AppendLine();
|
||||
}
|
||||
}
|
||||
return builder != null ? builder.ToString() : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle Script As Update requests
|
||||
/// </summary>
|
||||
private static string QueueScriptOperation(
|
||||
ScriptOperation operation,
|
||||
ConnectionInfo connInfo,
|
||||
ObjectMetadata metadata)
|
||||
{
|
||||
// get or create the current parse info object
|
||||
ScriptParseInfo parseInfo = LanguageServiceInstance.GetScriptParseInfo(connInfo.OwnerUri);
|
||||
if (Monitor.TryEnter(parseInfo.BuildingMetadataLock, LanguageService.BindingTimeout))
|
||||
{
|
||||
try
|
||||
{
|
||||
QueueItem queueItem = LanguageServiceInstance.BindingQueue.QueueBindingOperation(
|
||||
key: parseInfo.ConnectionKey,
|
||||
bindingTimeout: ScriptingService.ScriptingOperationTimeout,
|
||||
bindOperation: (bindingContext, cancelToken) =>
|
||||
{
|
||||
if (operation == ScriptOperation.Select)
|
||||
{
|
||||
return string.Format(
|
||||
@"SELECT TOP 1000 * " + Environment.NewLine + @"FROM {0}.{1}",
|
||||
metadata.Schema, metadata.Name);
|
||||
}
|
||||
else if (operation == ScriptOperation.Create)
|
||||
{
|
||||
return ScriptAsCreate(bindingContext, connInfo, metadata);
|
||||
}
|
||||
else if (operation == ScriptOperation.Update)
|
||||
{
|
||||
return ScriptAsUpdate(bindingContext, connInfo, metadata);
|
||||
}
|
||||
else if (operation == ScriptOperation.Insert)
|
||||
{
|
||||
return ScriptAsInsert(bindingContext, connInfo, metadata);
|
||||
}
|
||||
else if (operation == ScriptOperation.Delete)
|
||||
{
|
||||
return ScriptAsDelete(bindingContext, connInfo, metadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
|
||||
return queueItem.GetResultAsT<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(parseInfo.BuildingMetadataLock);
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles script as request messages
|
||||
/// </summary>
|
||||
/// <param name="scriptingParams"></param>
|
||||
/// <param name="requestContext"></param>
|
||||
internal static async Task HandleScriptingScriptAsRequest(
|
||||
ScriptingScriptAsParams scriptingParams,
|
||||
RequestContext<ScriptingScriptAsResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
ScriptingService.ConnectionServiceInstance.TryFindConnection(
|
||||
scriptingParams.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
ObjectMetadata metadata = scriptingParams.Metadata;
|
||||
string script = string.Empty;
|
||||
|
||||
if (connInfo != null)
|
||||
{
|
||||
script = QueueScriptOperation(scriptingParams.Operation, connInfo, metadata);
|
||||
}
|
||||
|
||||
await requestContext.SendResult(new ScriptingScriptAsResult
|
||||
{
|
||||
OwnerUri = scriptingParams.OwnerUri,
|
||||
Script = script
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await requestContext.SendError(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user