diff --git a/bin/nuget/Microsoft.SqlServer.Smo.140.2.5.nupkg b/bin/nuget/Microsoft.SqlServer.Smo.140.2.5.nupkg deleted file mode 100644 index 17c0e698..00000000 Binary files a/bin/nuget/Microsoft.SqlServer.Smo.140.2.5.nupkg and /dev/null differ diff --git a/bin/nuget/Microsoft.SqlServer.Smo.140.2.6.nupkg b/bin/nuget/Microsoft.SqlServer.Smo.140.2.6.nupkg new file mode 100644 index 00000000..a20dbc17 Binary files /dev/null and b/bin/nuget/Microsoft.SqlServer.Smo.140.2.6.nupkg differ diff --git a/src/Microsoft.SqlTools.Credentials/Microsoft.SqlTools.Credentials.csproj b/src/Microsoft.SqlTools.Credentials/Microsoft.SqlTools.Credentials.csproj index 01bc420c..5b8ec632 100644 --- a/src/Microsoft.SqlTools.Credentials/Microsoft.SqlTools.Credentials.csproj +++ b/src/Microsoft.SqlTools.Credentials/Microsoft.SqlTools.Credentials.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/Microsoft.SqlTools.Hosting/Microsoft.SqlTools.Hosting.csproj b/src/Microsoft.SqlTools.Hosting/Microsoft.SqlTools.Hosting.csproj index 1d90eb48..ac92d32c 100644 --- a/src/Microsoft.SqlTools.Hosting/Microsoft.SqlTools.Hosting.csproj +++ b/src/Microsoft.SqlTools.Hosting/Microsoft.SqlTools.Hosting.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj b/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj index 71a2bb4b..9178e6cb 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj +++ b/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingOptions.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingOptions.cs index ffdedd35..30984688 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingOptions.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingOptions.cs @@ -101,6 +101,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts /// ScriptCreate /// ScriptDrop /// ScriptCreateDrop + /// ScriptSelect /// /// /// The default is ScriptCreate. diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingRequest.cs index b7987de0..fc819e25 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingRequest.cs @@ -67,6 +67,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts /// Gets or sets the scripting options. /// public ScriptOptions ScriptOptions { get; set; } + + /// + /// Gets or sets the connection owner URI + /// + public string OwnerUri { get; set; } + } /// @@ -75,6 +81,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts public class ScriptingResult { public string OperationId { get; set; } + + public string Script { get; set; } } /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingSelectRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingSelectRequest.cs deleted file mode 100644 index b829f5dc..00000000 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingSelectRequest.cs +++ /dev/null @@ -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 -{ - /// - /// The type of scripting operation requested - /// - public enum ScriptOperation - { - Select = 0, - Create = 1, - Insert = 2, - Update = 3, - Delete = 4 - } - - /// - /// Script as request parameter type - /// - public class ScriptingScriptAsParams - { - public string OwnerUri { get; set; } - - public ScriptOperation Operation { get; set; } - - public ObjectMetadata Metadata { get; set; } - } - - /// - /// Script as request result type - /// - public class ScriptingScriptAsResult - { - public string OwnerUri { get; set; } - - public string Script { get; set; } - } - - /// - /// Script as request message type - /// - public class ScriptingScriptAsRequest - { - public static readonly - RequestType Type = - RequestType.Create("scripting/scriptas"); - } -} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.cs index 7bc2f1b1..4ef66863 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.cs @@ -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 - /// - /// Script a Table using SMO - /// - /// Table name - /// Schema name - /// String collection of scripts - 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)); - /// - /// Script a View using SMO - /// - /// View name - /// Schema name - /// String collection of scripts - 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"); - /// - /// Script a StoredProcedure using SMO - /// - /// StoredProcedure name - /// Schema name - /// String collection of scripts - 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; - } - } - - /// - /// Script a Schema using SMO - /// - /// Schema name - /// Schema name - /// String collection of scripts - 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; - } - } - - /// - /// Script a Database using SMO - /// - /// Database name - /// Schema name - /// String collection of scripts - 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; - } - } - - /// - /// Script a UserDefinedDataType using SMO - /// - /// UserDefinedDataType name - /// Schema name - /// String collection of scripts - 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; - } - } - - /// - /// Script a UserDefinedTableType using SMO - /// - /// UserDefinedTableType name - /// Schema name - /// String collection of scripts - 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; - } - } - - /// - /// Script a Synonym using SMO - /// - /// Synonym name - /// Schema name - /// String collection of scripts - 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; - } - } - - /// - /// Script a ScalarValuedFunction using SMO - /// - /// ScalarValuedFunction name - /// Schema name - /// String collection of scripts - 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; - } - } - - /// - /// Script a TableValuedFunction using SMO - /// - /// TableValuedFunction name - /// Schema name - /// String collection of scripts - 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"); + } } } \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.tt b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.tt deleted file mode 100644 index da75e8d9..00000000 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Scripter.tt +++ /dev/null @@ -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("/// "); - WriteLine(string.Format("/// Script a {0} using SMO", typeProperty["Name"])); - WriteLine("/// "); - WriteLine(string.Format("/// {0} name", typeProperty["Name"])); - WriteLine(string.Format("/// Schema name")); - WriteLine("/// String collection of scripts"); - - 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> GetSupportedTypes(string xmlFile) - { - List> typeList = null; - XmlDocument doc = new XmlDocument(); - doc.Load(xmlFile); - XmlNodeList supportedTypes = doc.SelectNodes("/SupportedTypes/Type"); - if (supportedTypes != null) - { - typeList = new List>(); - 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 typeProperties = new Dictionary(); - 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; - } - - #> \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs index ab1b31ed..9b0ec8ea 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs @@ -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 sqlScriptGetters = - new Dictionary(); - - private Dictionary sqlScriptGettersFromQuickInfo = - new Dictionary(); - // Dictionary that holds the object name (as appears on the TSQL create statement) private Dictionary sqlObjectTypes = new Dictionary(); private Dictionary sqlObjectTypesFromQuickInfo = new Dictionary(); + private Dictionary targetDatabaseEngineEditionMap = new Dictionary(); + + private Dictionary serverVersionMap = new Dictionary(); + + private Dictionary objectScriptMap = new Dictionary(); + + internal Scripter() {} + /// /// Initialize a Peek Definition helper object /// @@ -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 /// /// Add the given type, scriptgetter and the typeName string to the respective dictionaries /// - 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 /// /// Script a object using the type extracted from declarationItem /// - /// The Declarartion object that matched with the selected token + /// The Declaration object that matched with the selected token /// The text of the selected token /// Schema name /// 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 /// Type of SQL object /// Location object representing URI and range of the script file 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; } - /// - /// Get line number for the create statement - /// - 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; - } /// /// Helper method to create definition error result object /// @@ -453,7 +449,363 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting return Resolver.FindCompletions( parseResult, parserLine, parserColumn, metadataDisplayInfoProvider); } - #endregion + /// + /// Wrapper method that calls Resolver.FindCompletions + /// + /// + /// + /// + /// + /// + 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 objectList = new List(); + 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 + { + /// + /// Left delimiter for an named object + /// + public const char LeftDelimiter = '['; + + /// + /// right delimiter for a named object + /// + public const char RightDelimiter = ']'; + } + + internal static class ScriptingUtils + { + /// + /// Quote the name of a given sql object. + /// + /// object + /// quoted object name + internal static string QuoteObjectName(string sqlObject) + { + return QuoteObjectName(sqlObject, ']'); + } + + /// + /// Quotes the name of a given sql object + /// + /// object + /// quote to use + /// + 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(); + } + + /// + /// 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 filterExpressions = new List(); + 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 } -} +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterSupportedTypes.xml b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterSupportedTypes.xml deleted file mode 100644 index b6aa7471..00000000 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterSupportedTypes.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - Table - Table - Table - table - true - - - View - View - View - view - true - - - StoredProcedure - Procedure - StoredProcedure - stored procedure - true - - - Schema - Schema - Schema - schema - false - - - Database - Database - Database - database - false - - - UserDefinedDataType - Type - UserDefinedDataType - user-defined data type - true - - - UserDefinedTableType - Type - UserDefinedTableType - user-defined table type - true - - - Synonym - Synonym - Synonym - - true - - - ScalarValuedFunction - Function - UserDefinedFunction - scalar-valued function - true - - - TableValuedFunction - Function - UserDefinedFunction - table-valued function - true - - diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingScriptOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingScriptOperation.cs index 3908e548..5680e432 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingScriptOperation.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingScriptOperation.cs @@ -39,6 +39,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting private ScriptingParams Parameters { get; set; } + public string ScriptText { get; private set; } + /// /// Event raised when a scripting operation has resolved which database objects will be scripted. /// @@ -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) diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingService.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingService.cs index 7f62f187..a40adf2f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingService.cs @@ -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 /// 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 }); } + /// + /// Handles request to get select script for an smo object + /// + private void HandleScriptSelectRequest(ScriptingParams parameters, RequestContext 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); + } + }); + } + /// /// Handles request to execute start the list objects operation. /// @@ -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(RequestContext requestContext, EventType 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())); + } + }); + } + /// /// Sends a JSON-RPC event. /// @@ -181,6 +279,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting Task.Run(async () => await requestContext.SendEvent(eventType, parameters)); } + /// + /// Runs the async task that performs the scripting operation. + /// + private void RunSelectTask(ScriptingParams parameters, RequestContext requestContext) + { + Task.Run(() => + { + try + { + this.HandleScriptSelectRequest(parameters, requestContext); + } + catch (Exception e) + { + requestContext.SendError(e); + } + }); + } + /// /// Runs the async task that performs the scripting operation. /// @@ -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 } } } - - /// - /// Script create statements for metadata object - /// - 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; - } - - /// - /// Not yet implemented - /// - private static string ScriptAsUpdate( - IBindingContext bindingContext, - ConnectionInfo connInfo, - ObjectMetadata metadata) - { - return null; - } - - /// - /// Not yet implemented - /// - private static string ScriptAsInsert( - IBindingContext bindingContext, - ConnectionInfo connInfo, - ObjectMetadata metadata) - { - return null; - } - - /// - /// Not yet implemented - /// - 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; - } - - /// - /// Handle Script As Update requests - /// - 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(); - } - finally - { - Monitor.Exit(parseInfo.BuildingMetadataLock); - } - } - - return string.Empty; - } - - /// - /// Handles script as request messages - /// - /// - /// - internal static async Task HandleScriptingScriptAsRequest( - ScriptingScriptAsParams scriptingParams, - RequestContext 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()); - } - } } -} +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Workspace.cs b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Workspace.cs index a665e195..ac78f510 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Workspace.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Workspace.cs @@ -137,7 +137,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace // any extraneous slashes Uri fileUri = new Uri(filePath); filePath = fileUri.LocalPath; - if (filePath.StartsWith("//") || filePath.StartsWith("\\\\")) + if (filePath.StartsWith("//") || filePath.StartsWith("\\\\") || filePath.StartsWith("/")) { filePath = filePath.Substring(1); } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/PeekDefinitionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/PeekDefinitionTests.cs index 83ad15cd..82d52d33 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/PeekDefinitionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/PeekDefinitionTests.cs @@ -75,7 +75,7 @@ CREATE SYNONYM [dbo].[pd_testTable] FOR master.dbo.spt_monitor GO"; private const string TableValuedFunctionTypeName = "TableValuedFunction"; - private const string ScalarValuedFunctionTypeName = "ScalarValuedFunction"; + private const string ScalarValuedFunctionTypeName = "UserDefinedFunction"; private const string UserDefinedDataTypeTypeName = "UserDefinedDataType"; private const string UserDefinedTableTypeTypeName = "UserDefinedTableType"; private const string SynonymTypeName = "Synonym"; @@ -100,7 +100,7 @@ GO"; string objectType = "TABLE"; // Get locations for valid table object - Location[] locations = scripter.GetSqlObjectDefinition(scripter.GetTableScripts, objectName, schemaName, objectType); + Location[] locations = scripter.GetSqlObjectDefinition(objectName, schemaName, objectType); Assert.NotNull(locations); Cleanup(locations); } @@ -121,7 +121,7 @@ GO"; string objectType = "TABLE"; // Get locations for invalid table object - Location[] locations = scripter.GetSqlObjectDefinition(scripter.GetTableScripts, objectName, schemaName, objectType); + Location[] locations = scripter.GetSqlObjectDefinition(objectName, schemaName, objectType); Assert.Null(locations); } @@ -142,7 +142,7 @@ GO"; string objectType = "TABLE"; // Get locations for valid table object with schema name - Location[] locations = scripter.GetSqlObjectDefinition(scripter.GetTableScripts, objectName, schemaName, objectType); + Location[] locations = scripter.GetSqlObjectDefinition(objectName, schemaName, objectType); Assert.NotNull(locations); Cleanup(locations); } @@ -262,7 +262,7 @@ GO"; string schemaName = "sys"; string objectType = "VIEW"; - Location[] locations = scripter.GetSqlObjectDefinition(scripter.GetViewScripts, objectName, schemaName, objectType); + Location[] locations = scripter.GetSqlObjectDefinition(objectName, schemaName, objectType); Assert.NotNull(locations); Cleanup(locations); } @@ -282,7 +282,7 @@ GO"; string schemaName = null; string objectType = "VIEW"; - Location[] locations = scripter.GetSqlObjectDefinition(scripter.GetViewScripts, objectName, schemaName, objectType); + Location[] locations = scripter.GetSqlObjectDefinition(objectName, schemaName, objectType); Assert.Null(locations); } @@ -300,9 +300,9 @@ GO"; string objectName = "sp_columns"; string schemaName = "sys"; - string objectType = "PROCEDURE"; + string objectType = "StoredProcedure"; - Location[] locations = scripter.GetSqlObjectDefinition(scripter.GetStoredProcedureScripts, objectName, schemaName, objectType); + Location[] locations = scripter.GetSqlObjectDefinition(objectName, schemaName, objectType); Assert.NotNull(locations); Cleanup(locations); } @@ -322,7 +322,7 @@ GO"; string schemaName = "dbo"; string objectType = "PROCEDURE"; - Location[] locations = scripter.GetSqlObjectDefinition(scripter.GetStoredProcedureScripts, objectName, schemaName, objectType); + Location[] locations = scripter.GetSqlObjectDefinition(objectName, schemaName, objectType); Assert.Null(locations); } @@ -339,9 +339,9 @@ GO"; Scripter scripter = new Scripter(serverConnection, connInfo); string objectName = "sp_MSrepl_startup"; string schemaName = null; - string objectType = "PROCEDURE"; + string objectType = "StoredProcedure"; - Location[] locations = scripter.GetSqlObjectDefinition(scripter.GetStoredProcedureScripts, objectName, schemaName, objectType); + Location[] locations = scripter.GetSqlObjectDefinition(objectName, schemaName, objectType); Assert.NotNull(locations); Cleanup(locations); } @@ -377,40 +377,7 @@ GO"; Scripter scripter = new Scripter(serverConnection, connInfo); - Scripter.ScriptGetter sqlScriptGetter = null; - switch (objectType) - { - case SynonymTypeName: - sqlScriptGetter = scripter.GetSynonymScripts; - break; - case ScalarValuedFunctionTypeName: - sqlScriptGetter = scripter.GetScalarValuedFunctionScripts; - objectType = "Function"; - break; - case TableValuedFunctionTypeName: - sqlScriptGetter = scripter.GetTableValuedFunctionScripts; - objectType = "Function"; - break; - case TableTypeName: - sqlScriptGetter = scripter.GetTableScripts; - break; - case ViewTypeName: - sqlScriptGetter = scripter.GetViewScripts; - break; - case StoredProcedureTypeName: - sqlScriptGetter = scripter.GetStoredProcedureScripts; - break; - case UserDefinedDataTypeTypeName: - sqlScriptGetter = scripter.GetUserDefinedDataTypeScripts; - objectType = "Type"; - break; - case UserDefinedTableTypeTypeName: - sqlScriptGetter = scripter.GetUserDefinedTableTypeScripts; - objectType = "Type"; - break; - } - - Location[] locations = scripter.GetSqlObjectDefinition(sqlScriptGetter, objectName, schemaName, objectType); + Location[] locations = scripter.GetSqlObjectDefinition(objectName, schemaName, objectType); if (shouldReturnValidResult) { Assert.NotNull(locations); diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj index c99e8f0a..045e5668 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj @@ -27,11 +27,12 @@ + - + diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Scripting/ScriptingServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Scripting/ScriptingServiceTests.cs index 6410a4da..fe7a53b4 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Scripting/ScriptingServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Scripting/ScriptingServiceTests.cs @@ -3,15 +3,17 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; -using Xunit; -using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility; -using Microsoft.SqlTools.ServiceLayer.Metadata.Contracts; -using Microsoft.SqlTools.ServiceLayer.Scripting; -using Moq; -using Microsoft.SqlTools.Hosting.Protocol; -using Microsoft.SqlTools.ServiceLayer.Scripting.Contracts; +using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.SqlTools.ServiceLayer.Connection; +using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility; +using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; +using Microsoft.SqlTools.ServiceLayer.Scripting; +using Microsoft.SqlTools.ServiceLayer.Scripting.Contracts; +using Moq; +using Xunit; + namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Scripting { @@ -26,6 +28,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Scripting private const string DatabaseName = "test-db"; private const string StoredProcName = "test-sp"; private string[] objects = new string[5] {"Table", "View", "Schema", "Database", "SProc"}; + private string[] selectObjects = new string[2] { "Table", "View" }; private LiveConnectionHelper.TestConnectionResult GetLiveAutoCompleteTestObjects() { @@ -44,118 +47,39 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Scripting return result; } - private static ObjectMetadata GenerateMetadata(string objectType) - { - var metadata = new ObjectMetadata() - { - Schema = SchemaName, - Name = objectType - }; - switch(objectType) - { - case("Table"): - metadata.MetadataType = MetadataType.Table; - metadata.Name = TableName; - break; - case("View"): - metadata.MetadataType = MetadataType.View; - metadata.Name = ViewName; - break; - case("Database"): - metadata.MetadataType = MetadataType.Database; - metadata.Name = DatabaseName; - break; - case("Schema"): - metadata.MetadataType = MetadataType.Schema; - metadata.MetadataTypeName = SchemaName; - break; - case("SProc"): - metadata.MetadataType = MetadataType.SProc; - metadata.MetadataTypeName = StoredProcName; - break; - default: - metadata.MetadataType = MetadataType.Table; - metadata.Name = TableName; - break; - } - return metadata; - } - - private async Task>> SendAndValidateScriptRequest(ScriptOperation operation, string objectType) + private async Task>> SendAndValidateScriptRequest(bool isSelectScript) { var result = GetLiveAutoCompleteTestObjects(); - var requestContext = new Mock>(); - requestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object())); + var requestContext = new Mock>(); + requestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object())); - var scriptingParams = new ScriptingScriptAsParams + var scriptingParams = new ScriptingParams { - OwnerUri = result.ConnectionInfo.OwnerUri, - Operation = operation, - Metadata = GenerateMetadata(objectType) + OwnerUri = ConnectionService.BuildConnectionString(result.ConnectionInfo.ConnectionDetails) }; - - await ScriptingService.HandleScriptingScriptAsRequest(scriptingParams, requestContext.Object); + if (isSelectScript) + { + scriptingParams.ScriptOptions = new ScriptOptions { ScriptCreateDrop = "ScriptSelect" }; + List scriptingObjects = new List(); + scriptingObjects.Add(new ScriptingObject { Type = "View", Name = "sysobjects", Schema = "sys" }); + scriptingParams.ScriptingObjects = scriptingObjects; + } + ScriptingService service = new ScriptingService(); + await service.HandleScriptExecuteRequest(scriptingParams, requestContext.Object); return requestContext; } /// - /// Verify the script as select request + /// Verify the script object request /// [Fact] - public async void ScriptingScriptAsSelect() + public async void ScriptingScript() { foreach (string obj in objects) { - Assert.NotNull(await SendAndValidateScriptRequest(ScriptOperation.Select, obj)); - } - } - - /// - /// Verify the script as create request - /// - [Fact] - public async void ScriptingScriptAsCreate() - { - foreach (string obj in objects) - { - Assert.NotNull(await SendAndValidateScriptRequest(ScriptOperation.Create, obj)); - } - } - - /// - /// Verify the script as insert request - /// - [Fact] - public async void ScriptingScriptAsInsert() - { - foreach (string obj in objects) - { - Assert.NotNull(await SendAndValidateScriptRequest(ScriptOperation.Insert, obj)); - } - } - - /// - /// Verify the script as update request - /// - [Fact] - public async void ScriptingScriptAsUpdate() - { - foreach (string obj in objects) - { - Assert.NotNull(await SendAndValidateScriptRequest(ScriptOperation.Select, obj)); - } - } - - /// - /// Verify the script as delete request - /// - [Fact] - public async void ScriptingScriptAsDelete() - { - foreach (string obj in objects) - { - Assert.NotNull(await SendAndValidateScriptRequest(ScriptOperation.Select, obj)); + Assert.NotNull(await SendAndValidateScriptRequest(false)); + Assert.NotNull(await SendAndValidateScriptRequest(true)); } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/Microsoft.SqlTools.ServiceLayer.Test.Common.csproj b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/Microsoft.SqlTools.ServiceLayer.Test.Common.csproj index d2b7fde0..3aae7dca 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/Microsoft.SqlTools.ServiceLayer.Test.Common.csproj +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/Microsoft.SqlTools.ServiceLayer.Test.Common.csproj @@ -12,7 +12,7 @@ - + diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver.Tests/SqlScriptPublishModelTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver.Tests/SqlScriptPublishModelTests.cs index 9ae96baf..693a552f 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver.Tests/SqlScriptPublishModelTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver.Tests/SqlScriptPublishModelTests.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Threading; using System.Threading.Tasks; using Microsoft.SqlTools.ServiceLayer.Scripting.Contracts; using Microsoft.SqlTools.ServiceLayer.Test.Common; @@ -49,11 +48,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task ScriptDatabaseSchema() { using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) - using (SelfCleaningTempFile tempFile = new SelfCleaningTempFile()) { ScriptingParams requestParams = new ScriptingParams { - FilePath = tempFile.FilePath, + ScriptDestination = "ToEditor", ConnectionString = this.Northwind.ConnectionString, ScriptOptions = new ScriptOptions { @@ -62,14 +60,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests }; ScriptingResult result = await testService.Script(requestParams); - ScriptingPlanNotificationParams planEvent = await testService.Driver.WaitForEvent(ScriptingPlanNotificationEvent.Type, TimeSpan.FromSeconds(30)); ScriptingCompleteParams parameters = await testService.Driver.WaitForEvent(ScriptingCompleteEvent.Type, TimeSpan.FromSeconds(30)); Assert.True(parameters.Success); - Assert.Equal(ScriptingFixture.ObjectCountWithDatabase, planEvent.Count); - Assert.True(File.Exists(tempFile.FilePath)); - Assert.True(new FileInfo(tempFile.FilePath).Length > 0); - AssertSchemaInFile(tempFile.FilePath, assert: true); - AssertTableDataInFile(tempFile.FilePath, assert: false); } } @@ -77,11 +69,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task ScriptDatabaseSchemaAndData() { using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) - using (SelfCleaningTempFile tempFile = new SelfCleaningTempFile()) { ScriptingParams requestParams = new ScriptingParams { - FilePath = tempFile.FilePath, + ScriptDestination = "ToEditor", ConnectionString = this.Northwind.ConnectionString, ScriptOptions = new ScriptOptions { @@ -90,14 +81,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests }; ScriptingResult result = await testService.Script(requestParams); - ScriptingPlanNotificationParams planEvent = await testService.Driver.WaitForEvent(ScriptingPlanNotificationEvent.Type, TimeSpan.FromSeconds(30)); ScriptingCompleteParams completeParameters = await testService.Driver.WaitForEvent(ScriptingCompleteEvent.Type, TimeSpan.FromSeconds(30)); Assert.True(completeParameters.Success); - Assert.Equal(ScriptingFixture.ObjectCountWithDatabase, planEvent.Count); - Assert.True(File.Exists(tempFile.FilePath)); - Assert.True(new FileInfo(tempFile.FilePath).Length > 0); - AssertSchemaInFile(tempFile.FilePath, assert: true); - AssertTableDataInFile(tempFile.FilePath, assert: true); } } @@ -105,15 +90,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task ScriptTable() { using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) - using (SelfCleaningTempFile tempFile = new SelfCleaningTempFile()) - { + { ScriptingParams requestParams = new ScriptingParams { - FilePath = tempFile.FilePath, + ScriptDestination = "ToEditor", ConnectionString = this.Northwind.ConnectionString, ScriptOptions = new ScriptOptions { TypeOfDataToScript = "SchemaOnly", + }, ScriptingObjects = new List { @@ -131,8 +116,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests ScriptingCompleteParams parameters = await testService.Driver.WaitForEvent(ScriptingCompleteEvent.Type, TimeSpan.FromSeconds(30)); Assert.True(parameters.Success); Assert.Equal(1, planEvent.Count); - Assert.True(File.Exists(tempFile.FilePath)); - Assert.True(new FileInfo(tempFile.FilePath).Length > 0); } } @@ -140,11 +123,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task ScriptTableUsingIncludeFilter() { using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) - using (SelfCleaningTempFile tempFile = new SelfCleaningTempFile()) { ScriptingParams requestParams = new ScriptingParams { - FilePath = tempFile.FilePath, + ScriptDestination = "ToEditor", ConnectionString = this.Northwind.ConnectionString, ScriptOptions = new ScriptOptions { @@ -166,8 +148,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests ScriptingCompleteParams parameters = await testService.Driver.WaitForEvent(ScriptingCompleteEvent.Type, TimeSpan.FromSeconds(30)); Assert.True(parameters.Success); Assert.Equal(1, planEvent.Count); - Assert.True(File.Exists(tempFile.FilePath)); - Assert.True(new FileInfo(tempFile.FilePath).Length > 0); } } @@ -175,11 +155,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task ScriptTableAndData() { using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) - using (SelfCleaningTempFile tempFile = new SelfCleaningTempFile()) { ScriptingParams requestParams = new ScriptingParams { - FilePath = tempFile.FilePath, + ScriptDestination = "ToEditor", ConnectionString = this.Northwind.ConnectionString, ScriptOptions = new ScriptOptions { @@ -201,8 +180,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests ScriptingCompleteParams parameters = await testService.Driver.WaitForEvent(ScriptingCompleteEvent.Type, TimeSpan.FromSeconds(30)); Assert.True(parameters.Success); Assert.Equal(1, planEvent.Count); - Assert.True(File.Exists(tempFile.FilePath)); - Assert.True(new FileInfo(tempFile.FilePath).Length > 0); } } @@ -210,15 +187,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task ScriptTableDoesNotExist() { using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) - using (SelfCleaningTempFile tempFile = new SelfCleaningTempFile()) { ScriptingParams requestParams = new ScriptingParams { - FilePath = tempFile.FilePath, + ScriptDestination = "ToEditor", ConnectionString = this.Northwind.ConnectionString, ScriptOptions = new ScriptOptions { TypeOfDataToScript = "SchemaOnly", + ContinueScriptingOnError = false }, ScriptingObjects = new List { @@ -243,11 +220,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task ScriptSchemaCancel() { using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) - using (SelfCleaningTempFile tempFile = new SelfCleaningTempFile()) { ScriptingParams requestParams = new ScriptingParams { - FilePath = tempFile.FilePath, + ScriptDestination = "ToEditor", ConnectionString = this.Northwind.ConnectionString, ScriptOptions = new ScriptOptions { @@ -267,11 +243,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task ScriptSchemaInvalidConnectionString() { using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) - using (SelfCleaningTempFile tempFile = new SelfCleaningTempFile()) { ScriptingParams requestParams = new ScriptingParams { - FilePath = tempFile.FilePath, + ScriptDestination = "ToEditor", ConnectionString = "I'm an invalid connection string", ScriptOptions = new ScriptOptions { diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Microsoft.SqlTools.ServiceLayer.TestDriver.csproj b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Microsoft.SqlTools.ServiceLayer.TestDriver.csproj index 2f1b2f20..58fa14be 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Microsoft.SqlTools.ServiceLayer.TestDriver.csproj +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Microsoft.SqlTools.ServiceLayer.TestDriver.csproj @@ -12,7 +12,7 @@ - + diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/PeekDefinitionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/PeekDefinitionTests.cs index fd111d09..bd930448 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/PeekDefinitionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/PeekDefinitionTests.cs @@ -312,9 +312,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer Scripter peekDefinition = new Scripter(null, null); string objectName = "tableName"; string fullObjectName = "master.dbo.tableName"; - DefinitionResult result = peekDefinition.GetDefinitionUsingDeclarationType(DeclarationType.Table, fullObjectName, objectName, null); - Assert.NotNull(result); - Assert.True(result.IsErrorResult); + Assert.Throws(() => peekDefinition.GetDefinitionUsingDeclarationType(DeclarationType.Table, fullObjectName, objectName, null)); } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Microsoft.SqlTools.ServiceLayer.UnitTests.csproj b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Microsoft.SqlTools.ServiceLayer.UnitTests.csproj index 8daaa188..d7c35110 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Microsoft.SqlTools.ServiceLayer.UnitTests.csproj +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Microsoft.SqlTools.ServiceLayer.UnitTests.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Scripting/ScriptingObjectMatcherTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Scripting/ScriptingObjectMatcherTests.cs index 35d40978..2c1ab329 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Scripting/ScriptingObjectMatcherTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Scripting/ScriptingObjectMatcherTests.cs @@ -408,5 +408,50 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Scripting Assert.Equal(2, results.Count()); } + + [Fact] + public void ScriptingObjectEquality() + { + ScriptingObject scriptingObject1 = new ScriptingObject { Type = "Table", Schema = "test", Name = "test_table" }; + ScriptingObject scriptingObject2 = new ScriptingObject { Type = "Table", Schema = "test", Name = "test_table" }; + ScriptingObject scriptingObject3 = null; + Assert.Equal(scriptingObject1, scriptingObject2); + Assert.False(scriptingObject1.Equals(scriptingObject3)); + } + } + + public class ScriptingUtilsTests + { + private static string[] TestObjects = new string[] + { + "Table", + "Table]", + "]Table", + "Tab]le", + "", + "]", + "view" + }; + + private static string[] ExpectedObjects = new string[] + { + "Table", + "Table]]", + "]]Table", + "Tab]]le", + "", + "]]", + "view" + }; + + + [Fact] + public void TestQuoteObjectName() + { + for (int i = 0; i < TestObjects.Length; i++) + { + Assert.Equal(Scripter.ScriptingUtils.QuoteObjectName(TestObjects[i]), ExpectedObjects[i]); + } + } } }