mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-17 09:35:37 -05:00
Add Scripter class and use it in the ScriptingService (#286)
* Initial scripting commit * Fix the script CREATE integration test * Use language service binding queue for scripting * Update scripting service to have methods for each operation * Add scripter class * Fix build break. * Fix a few bugs * Use scripter class instead of PeekDefinition class. * Fix scripting test break * Fix header incorrectly saying file is generated. * Add localization tests to address a large block of code not covered by automation. * Moving system usings to top of using list
This commit is contained in:
204
src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.cs
Normal file
204
src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
//
|
||||
// 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
|
||||
{
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
AddSupportedType(DeclarationType.Table, GetTableScripts, "Table", "table");
|
||||
AddSupportedType(DeclarationType.View, GetViewScripts, "View", "view");
|
||||
AddSupportedType(DeclarationType.StoredProcedure, GetStoredProcedureScripts, "Procedure", "stored procedure");
|
||||
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");
|
||||
}
|
||||
|
||||
/// <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 smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetViewScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetStoredProcedureScripts : " + 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 smoObject.Script();
|
||||
}
|
||||
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 smoObject.Script();
|
||||
}
|
||||
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 smoObject.Script();
|
||||
}
|
||||
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 smoObject.Script();
|
||||
}
|
||||
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 smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableValuedFunctionScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
149
src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.tt
Normal file
149
src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.tt
Normal file
@@ -0,0 +1,149 @@
|
||||
<#@ 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
|
||||
{
|
||||
statement = string.Format("{0} smoObject = new {0}(this.Database, objectName);", typeProperty["Name"]);
|
||||
}
|
||||
PushIndent(indent);
|
||||
WriteLine(statement);
|
||||
WriteLine("smoObject.Refresh();");
|
||||
WriteLine("return smoObject.Script();");
|
||||
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;
|
||||
}
|
||||
|
||||
#>
|
||||
457
src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs
Normal file
457
src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs
Normal file
@@ -0,0 +1,457 @@
|
||||
//
|
||||
// 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.Data.Common;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using ConnectionType = Microsoft.SqlTools.ServiceLayer.Connection.ConnectionType;
|
||||
using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
{
|
||||
internal partial class Scripter
|
||||
{
|
||||
private bool error;
|
||||
private string errorMessage;
|
||||
private ServerConnection serverConnection;
|
||||
private ConnectionInfo connectionInfo;
|
||||
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>();
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a Peek Definition helper object
|
||||
/// </summary>
|
||||
/// <param name="serverConnection">SMO Server connection</param>
|
||||
internal Scripter(ServerConnection serverConnection, ConnectionInfo connInfo)
|
||||
{
|
||||
this.serverConnection = serverConnection;
|
||||
this.connectionInfo = connInfo;
|
||||
this.tempPath = FileUtilities.GetPeekDefinitionTempFolder();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
internal Database Database
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.database == null)
|
||||
{
|
||||
if (this.serverConnection != null && !string.IsNullOrEmpty(this.serverConnection.DatabaseName))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Reuse existing connection
|
||||
Server server = new Server(this.serverConnection);
|
||||
// The default database name is the database name of the server connection
|
||||
string dbName = this.serverConnection.DatabaseName;
|
||||
if (this.connectionInfo != null)
|
||||
{
|
||||
// If there is a query DbConnection, use that connection to get the database name
|
||||
// This is preferred since it has the most current database name (in case of database switching)
|
||||
DbConnection connection;
|
||||
if (connectionInfo.TryGetConnection(ConnectionType.Query, out connection))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(connection.Database))
|
||||
{
|
||||
dbName = connection.Database;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.database = new Database(server, dbName);
|
||||
this.database.Refresh();
|
||||
}
|
||||
catch (ConnectionFailureException cfe)
|
||||
{
|
||||
Logger.Write(LogLevel.Error, "Exception at PeekDefinition Database.get() : " + cfe.Message);
|
||||
this.error = true;
|
||||
this.errorMessage = (connectionInfo != null && connectionInfo.IsAzure) ? SR.PeekDefinitionAzureError(cfe.Message) : SR.PeekDefinitionError(cfe.Message);
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error, "Exception at PeekDefinition Database.get() : " + ex.Message);
|
||||
this.error = true;
|
||||
this.errorMessage = SR.PeekDefinitionError(ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.database;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
sqlScriptGetters.Add(type, scriptGetter);
|
||||
sqlObjectTypes.Add(type, typeName);
|
||||
if (!string.IsNullOrEmpty(quickInfoType))
|
||||
{
|
||||
sqlScriptGettersFromQuickInfo.Add(quickInfoType.ToLowerInvariant(), scriptGetter);
|
||||
sqlObjectTypesFromQuickInfo.Add(quickInfoType.ToLowerInvariant(), typeName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the script of the selected token based on the type of the token
|
||||
/// </summary>
|
||||
/// <param name="declarationItems"></param>
|
||||
/// <param name="tokenText"></param>
|
||||
/// <param name="schemaName"></param>
|
||||
/// <returns>Location object of the script file</returns>
|
||||
internal DefinitionResult GetScript(ParseResult parseResult, Position position, IMetadataDisplayInfoProvider metadataDisplayInfoProvider, string tokenText, string schemaName)
|
||||
{
|
||||
int parserLine = position.Line + 1;
|
||||
int parserColumn = position.Character + 1;
|
||||
// Get DeclarationItems from The Intellisense Resolver for the selected token. The type of the selected token is extracted from the declarationItem.
|
||||
IEnumerable<Declaration> declarationItems = GetCompletionsForToken(parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
|
||||
if (declarationItems != null && declarationItems.Count() > 0)
|
||||
{
|
||||
foreach (Declaration declarationItem in declarationItems)
|
||||
{
|
||||
if (declarationItem.Title == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (this.Database == null)
|
||||
{
|
||||
return GetDefinitionErrorResult(SR.PeekDefinitionDatabaseError);
|
||||
}
|
||||
StringComparison caseSensitivity = this.Database.CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
|
||||
// if declarationItem matches the selected token, script SMO using that type
|
||||
if (declarationItem.Title.Equals(tokenText, caseSensitivity))
|
||||
{
|
||||
return GetDefinitionUsingDeclarationType(declarationItem.Type, declarationItem.DatabaseQualifiedName, tokenText, schemaName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no declarationItem matched the selected token, we try to find the type of the token using QuickInfo.Text
|
||||
string quickInfoText = GetQuickInfoForToken(parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
|
||||
return GetDefinitionUsingQuickInfoText(quickInfoText, tokenText, schemaName);
|
||||
}
|
||||
// no definition found
|
||||
return GetDefinitionErrorResult(SR.PeekDefinitionNoResultsError);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script an object using the type extracted from quickInfo Text
|
||||
/// </summary>
|
||||
/// <param name="quickInfoText">the text from the quickInfo for the selected token</param>
|
||||
/// <param name="tokenText">The text of the selected token</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns></returns>
|
||||
internal DefinitionResult GetDefinitionUsingQuickInfoText(string quickInfoText, string tokenText, string schemaName)
|
||||
{
|
||||
if (this.Database == null)
|
||||
{
|
||||
return GetDefinitionErrorResult(SR.PeekDefinitionDatabaseError);
|
||||
}
|
||||
StringComparison caseSensitivity = this.Database.CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
|
||||
string tokenType = GetTokenTypeFromQuickInfo(quickInfoText, tokenText, caseSensitivity);
|
||||
if (tokenType != null)
|
||||
{
|
||||
if (sqlScriptGettersFromQuickInfo.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
|
||||
// to get the schema name from the declaration item.
|
||||
// If all fails, the default schema name is assumed to be "dbo"
|
||||
if ((connectionInfo != null && connectionInfo.ConnectionDetails.AuthenticationType.Equals(Constants.SqlLoginAuthenticationType)) && string.IsNullOrEmpty(schemaName))
|
||||
{
|
||||
string fullObjectName = this.GetFullObjectNameFromQuickInfo(quickInfoText, tokenText, caseSensitivity);
|
||||
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
|
||||
}
|
||||
Location[] locations = GetSqlObjectDefinition(
|
||||
sqlScriptGettersFromQuickInfo[tokenType.ToLowerInvariant()],
|
||||
tokenText,
|
||||
schemaName,
|
||||
sqlObjectTypesFromQuickInfo[tokenType.ToLowerInvariant()]
|
||||
);
|
||||
DefinitionResult result = new DefinitionResult
|
||||
{
|
||||
IsErrorResult = this.error,
|
||||
Message = this.errorMessage,
|
||||
Locations = locations
|
||||
};
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If a type was found but is not in sqlScriptGettersFromQuickInfo, then the type is not supported
|
||||
return GetDefinitionErrorResult(SR.PeekDefinitionTypeNotSupportedError);
|
||||
}
|
||||
}
|
||||
// no definition found
|
||||
return GetDefinitionErrorResult(SR.PeekDefinitionNoResultsError);
|
||||
}
|
||||
|
||||
/// <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="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))
|
||||
{
|
||||
// With SqlLogin authentication, the defaultSchema property throws an Exception when accessed.
|
||||
// This workaround ensures that a schema name is present by attempting
|
||||
// to get the schema name from the declaration item.
|
||||
// If all fails, the default schema name is assumed to be "dbo"
|
||||
if ((connectionInfo != null && connectionInfo.ConnectionDetails.AuthenticationType.Equals(Constants.SqlLoginAuthenticationType)) && string.IsNullOrEmpty(schemaName))
|
||||
{
|
||||
string fullObjectName = databaseQualifiedName;
|
||||
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
|
||||
}
|
||||
Location[] locations = GetSqlObjectDefinition(
|
||||
sqlScriptGetters[type],
|
||||
tokenText,
|
||||
schemaName,
|
||||
sqlObjectTypes[type]
|
||||
);
|
||||
DefinitionResult result = new DefinitionResult
|
||||
{
|
||||
IsErrorResult = this.error,
|
||||
Message = this.errorMessage,
|
||||
Locations = locations
|
||||
};
|
||||
return result;
|
||||
}
|
||||
// If a type was found but is not in sqlScriptGetters, then the type is not supported
|
||||
return GetDefinitionErrorResult(SR.PeekDefinitionTypeNotSupportedError);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a object using SMO and write to a file.
|
||||
/// </summary>
|
||||
/// <param name="sqlScriptGetter">Function that returns the SMO scripts for an object</param>
|
||||
/// <param name="objectName">SQL object name</param>
|
||||
/// <param name="schemaName">Schema name or null</param>
|
||||
/// <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);
|
||||
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)))
|
||||
{
|
||||
|
||||
foreach (string script in scripts)
|
||||
{
|
||||
string createSyntax = string.Format("CREATE {0}", objectType);
|
||||
if (script.IndexOf(createSyntax, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
scriptFile.WriteLine(script);
|
||||
lineNumber = GetStartOfCreate(script, createSyntax);
|
||||
}
|
||||
}
|
||||
}
|
||||
return GetLocationFromFile(tempFileName, lineNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.error = true;
|
||||
this.errorMessage = SR.PeekDefinitionNoResultsError;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#region Helper Methods
|
||||
/// <summary>
|
||||
/// Return schema name from the full name of the database. If schema is missing return dbo as schema name.
|
||||
/// </summary>
|
||||
/// <param name="fullObjectName"> The full database qualified name(database.schema.object)</param>
|
||||
/// <param name="objectName"> Object name</param>
|
||||
/// <returns>Schema name</returns>
|
||||
internal string GetSchemaFromDatabaseQualifiedName(string fullObjectName, string objectName)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(fullObjectName))
|
||||
{
|
||||
string[] tokens = fullObjectName.Split('.');
|
||||
for (int i = tokens.Length - 1; i > 0; i--)
|
||||
{
|
||||
if (tokens[i].Equals(objectName))
|
||||
{
|
||||
return tokens[i - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return "dbo";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a file to a location array containing a location object as expected by the extension
|
||||
/// </summary>
|
||||
internal Location[] GetLocationFromFile(string tempFileName, int lineNumber)
|
||||
{
|
||||
// Get absolute Uri based on uri format. This works around a dotnetcore URI bug for linux paths.
|
||||
if (Path.DirectorySeparatorChar.Equals('/'))
|
||||
{
|
||||
tempFileName = "file:" + tempFileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempFileName = new Uri(tempFileName).AbsoluteUri;
|
||||
}
|
||||
// Create a location array containing the tempFile Uri, as expected by VSCode.
|
||||
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}
|
||||
}
|
||||
}
|
||||
};
|
||||
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>
|
||||
/// <param name="errorMessage">Error message</param>
|
||||
/// <returns> DefinitionResult</returns>
|
||||
internal DefinitionResult GetDefinitionErrorResult(string errorMessage)
|
||||
{
|
||||
return new DefinitionResult
|
||||
{
|
||||
IsErrorResult = true,
|
||||
Message = errorMessage,
|
||||
Locations = null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return full object name(database.schema.objectName) from the quickInfo text("type database.schema.objectName")
|
||||
/// </summary>
|
||||
/// <param name="quickInfoText">QuickInfo Text for this token</param>
|
||||
/// <param name="tokenText">Token Text</param>
|
||||
/// <param name="caseSensitivity">StringComparison enum</param>
|
||||
/// <returns></returns>
|
||||
internal string GetFullObjectNameFromQuickInfo(string quickInfoText, string tokenText, StringComparison caseSensitivity)
|
||||
{
|
||||
if (string.IsNullOrEmpty(quickInfoText) || string.IsNullOrEmpty(tokenText))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// extract full object name from quickInfo text
|
||||
string[] tokens = quickInfoText.Split(' ');
|
||||
List<string> tokenList = tokens.Where(el => el.IndexOf(tokenText, caseSensitivity) >= 0).ToList();
|
||||
return (tokenList?.Count() > 0) ? tokenList[0] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return token type from the quickInfo text("type database.schema.objectName")
|
||||
/// </summary>
|
||||
/// <param name="quickInfoText">QuickInfo Text for this token</param>
|
||||
/// <param name="tokenText"Token Text></param>
|
||||
/// <param name="caseSensitivity">StringComparison enum</param>
|
||||
/// <returns></returns>
|
||||
internal string GetTokenTypeFromQuickInfo(string quickInfoText, string tokenText, StringComparison caseSensitivity)
|
||||
{
|
||||
if (string.IsNullOrEmpty(quickInfoText) || string.IsNullOrEmpty(tokenText))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// extract string denoting the token type from quickInfo text
|
||||
string[] tokens = quickInfoText.Split(' ');
|
||||
List<int> indexList = tokens.Select((s, i) => new { i, s }).Where(el => (el.s).IndexOf(tokenText, caseSensitivity) >= 0).Select(el => el.i).ToList();
|
||||
return (indexList?.Count() > 0) ? String.Join(" ", tokens.Take(indexList[0])) : null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that calls Resolver.GetQuickInfo
|
||||
/// </summary>
|
||||
internal string GetQuickInfoForToken(ParseResult parseResult, int parserLine, int parserColumn, IMetadataDisplayInfoProvider metadataDisplayInfoProvider)
|
||||
{
|
||||
if (parseResult == null || metadataDisplayInfoProvider == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Babel.CodeObjectQuickInfo quickInfo = Resolver.GetQuickInfo(
|
||||
parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
|
||||
return quickInfo?.Text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that calls Resolver.FindCompletions
|
||||
/// </summary>
|
||||
/// <param name="parseResult"></param>
|
||||
/// <param name="parserLine"></param>
|
||||
/// <param name="parserColumn"></param>
|
||||
/// <param name="metadataDisplayInfoProvider"></param>
|
||||
/// <returns></returns>
|
||||
internal IEnumerable<Declaration> GetCompletionsForToken(ParseResult parseResult, int parserLine, int parserColumn, IMetadataDisplayInfoProvider metadataDisplayInfoProvider)
|
||||
{
|
||||
if (parseResult == null || metadataDisplayInfoProvider == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Resolver.FindCompletions(
|
||||
parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<!--
|
||||
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>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>
|
||||
@@ -4,9 +4,16 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.Metadata.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Scripting.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
@@ -15,11 +22,56 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
/// Main class for Scripting Service functionality
|
||||
/// </summary>
|
||||
public sealed class ScriptingService
|
||||
{
|
||||
{
|
||||
private const int ScriptingOperationTimeout = 60000;
|
||||
|
||||
private static readonly Lazy<ScriptingService> LazyInstance = new Lazy<ScriptingService>(() => new ScriptingService());
|
||||
|
||||
public static ScriptingService Instance => LazyInstance.Value;
|
||||
|
||||
private static ConnectionService connectionService = null;
|
||||
|
||||
private static LanguageService languageServices = null;
|
||||
|
||||
/// <summary>
|
||||
/// Internal for testing purposes only
|
||||
/// </summary>
|
||||
internal static ConnectionService ConnectionServiceInstance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (connectionService == null)
|
||||
{
|
||||
connectionService = ConnectionService.Instance;
|
||||
}
|
||||
return connectionService;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
connectionService = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal for testing purposes only
|
||||
/// </summary>
|
||||
internal static LanguageService LanguageServiceInstance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (languageServices == null)
|
||||
{
|
||||
languageServices = LanguageService.Instance;
|
||||
}
|
||||
return languageServices;
|
||||
}
|
||||
set
|
||||
{
|
||||
languageServices = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Scripting Service instance
|
||||
/// </summary>
|
||||
@@ -30,6 +82,135 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
serviceHost.SetRequestHandler(ScriptingScriptAsRequest.Type, HandleScriptingScriptAsRequest);
|
||||
}
|
||||
|
||||
/// <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;
|
||||
if (metadata.MetadataType == MetadataType.Table)
|
||||
{
|
||||
results = scripter.GetTableScripts(metadata.Name, metadata.Schema);
|
||||
}
|
||||
else if (metadata.MetadataType == MetadataType.SProc)
|
||||
{
|
||||
results = scripter.GetStoredProcedureScripts(metadata.Name, metadata.Schema);
|
||||
}
|
||||
else if (metadata.MetadataType == MetadataType.View)
|
||||
{
|
||||
results = scripter.GetViewScripts(metadata.Name, metadata.Schema);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return 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 100 * " + 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>
|
||||
@@ -39,44 +220,31 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
|
||||
ScriptingScriptAsParams scriptingParams,
|
||||
RequestContext<ScriptingScriptAsResult> requestContext)
|
||||
{
|
||||
string script = string.Empty;
|
||||
if (scriptingParams.Operation == ScriptOperation.Select)
|
||||
try
|
||||
{
|
||||
script = string.Format(
|
||||
@"SELECT *
|
||||
FROM {0}.{1}",
|
||||
scriptingParams.Metadata.Schema, scriptingParams.Metadata.Name);
|
||||
}
|
||||
else if (scriptingParams.Operation == ScriptOperation.Create)
|
||||
{
|
||||
script = string.Format(
|
||||
@"CREATE {0}.{1}",
|
||||
scriptingParams.Metadata.Schema, scriptingParams.Metadata.Name);
|
||||
}
|
||||
else if (scriptingParams.Operation == ScriptOperation.Update)
|
||||
{
|
||||
script = string.Format(
|
||||
@"UPDATE {0}.{1}",
|
||||
scriptingParams.Metadata.Schema, scriptingParams.Metadata.Name);
|
||||
}
|
||||
else if (scriptingParams.Operation == ScriptOperation.Insert)
|
||||
{
|
||||
script = string.Format(
|
||||
@"INSERT {0}.{1}",
|
||||
scriptingParams.Metadata.Schema, scriptingParams.Metadata.Name);
|
||||
}
|
||||
else if (scriptingParams.Operation == ScriptOperation.Delete)
|
||||
{
|
||||
script = string.Format(
|
||||
@"DELETE {0}.{1}",
|
||||
scriptingParams.Metadata.Schema, scriptingParams.Metadata.Name);
|
||||
}
|
||||
ConnectionInfo connInfo;
|
||||
ScriptingService.ConnectionServiceInstance.TryFindConnection(
|
||||
scriptingParams.OwnerUri,
|
||||
out connInfo);
|
||||
|
||||
await requestContext.SendResult(new ScriptingScriptAsResult()
|
||||
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)
|
||||
{
|
||||
OwnerUri = scriptingParams.OwnerUri,
|
||||
Script = script
|
||||
});
|
||||
await requestContext.SendError(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user