Adding service operations for external languages (#918)

* Added service operations for external languages
This commit is contained in:
Leila Lali
2020-02-21 08:52:58 -08:00
committed by GitHub
parent 927b0d73ca
commit 73fc70fbbc
17 changed files with 1440 additions and 219 deletions

View File

@@ -19,7 +19,7 @@ using Microsoft.SqlTools.ServiceLayer.FileBrowser;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
using Microsoft.SqlTools.ServiceLayer.ServerConfigurations;
using Microsoft.SqlTools.ServiceLayer.LanguageExtensions;
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility;
using Microsoft.SqlTools.ServiceLayer.Metadata;
using Microsoft.SqlTools.ServiceLayer.Profiler;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
@@ -127,8 +127,8 @@ namespace Microsoft.SqlTools.ServiceLayer
ServerConfigService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(ServerConfigService.Instance);
LanguageExtensionsService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(LanguageExtensionsService.Instance);
ExternalLanguageService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(ExternalLanguageService.Instance);
InitializeHostedServices(serviceProvider, serviceHost);
serviceHost.ServiceProvider = serviceProvider;

View File

@@ -0,0 +1,39 @@
//
// 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;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
{
public class ExternalLanguageDeleteRequestParams
{
/// <summary>
/// Connection uri
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// Language name
/// </summary>
public string LanguageName { get; set; }
}
/// <summary>
/// Response class for external language status
/// </summary>
public class ExternalLanguageDeleteResponseParams
{
}
/// <summary>
/// Request class for external language status
/// </summary>
public class ExternalLanguageDeleteRequest
{
public static readonly
RequestType<ExternalLanguageDeleteRequestParams, ExternalLanguageDeleteResponseParams> Type =
RequestType<ExternalLanguageDeleteRequestParams, ExternalLanguageDeleteResponseParams>.Create("languageExtension/delete");
}
}

View File

@@ -0,0 +1,39 @@
//
// 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 System.Collections.Generic;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
{
public class ExternalLanguageListRequestParams
{
/// <summary>
/// Connection uri
/// </summary>
public string OwnerUri { get; set; }
}
/// <summary>
/// Response class for external language list
/// </summary>
public class ExternalLanguageListResponseParams
{
/// <summary>
/// Language status
/// </summary>
public List<ExternalLanguage> Languages { get; set; }
}
/// <summary>
/// Request class for external language list
/// </summary>
public class ExternalLanguageListRequest
{
public static readonly
RequestType<ExternalLanguageListRequestParams, ExternalLanguageListResponseParams> Type =
RequestType<ExternalLanguageListRequestParams, ExternalLanguageListResponseParams>.Create("languageExtension/list");
}
}

View File

@@ -0,0 +1,83 @@
//
// 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.IO;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
{
public enum ExternalLanguagePlatform
{
None,
Windows,
Linux
}
/// <summary>
/// Language metadata
/// </summary>
public class ExternalLanguage
{
/// <summary>
/// Language Name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Language Owner
/// </summary>
public string Owner { get; set; }
public List<ExternalLanguageContent> Contents { get; set; }
/// <summary>
/// Created Date
/// </summary>
public string CreatedDate { get; set; }
}
public class ExternalLanguageContent
{
public bool IsLocalFile { get; set; }
/// <summary>
/// Path to extension file
/// </summary>
public string PathToExtension { get; set; }
/// <summary>
/// Extension file name
/// </summary>
public string ExtensionFileName { get; set; }
/// <summary>
/// Platform name
/// </summary>
public ExternalLanguagePlatform PlatformId
{
get
{
return string.IsNullOrWhiteSpace(Platform) ? ExternalLanguagePlatform.None : (ExternalLanguagePlatform)Enum.Parse(typeof(ExternalLanguagePlatform), Platform, true);
}
}
public string Platform { get; set; }
/// <summary>
/// Extension parameters
/// </summary>
public string Parameters { get; set; }
/// <summary>
/// Environment variables
/// </summary>
public string EnvironmentVariables { get; set; }
}
}

View File

@@ -5,7 +5,7 @@
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensions.Contracts
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
{
public class ExternalLanguageStatusRequestParams
{
@@ -38,6 +38,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensions.Contracts
{
public static readonly
RequestType<ExternalLanguageStatusRequestParams, ExternalLanguageStatusResponseParams> Type =
RequestType<ExternalLanguageStatusRequestParams, ExternalLanguageStatusResponseParams>.Create("languageextension/status");
RequestType<ExternalLanguageStatusRequestParams, ExternalLanguageStatusResponseParams>.Create("languageExtension/status");
}
}

View File

@@ -0,0 +1,39 @@
//
// 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;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
{
public class ExternalLanguageUpdateRequestParams
{
/// <summary>
/// Connection uri
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// Language name
/// </summary>
public ExternalLanguage Language { get; set; }
}
/// <summary>
/// Response class for external language update
/// </summary>
public class ExternalLanguageUpdateResponseParams
{
}
/// <summary>
/// Request class for external language status
/// </summary>
public class ExternalLanguageUpdateRequest
{
public static readonly
RequestType<ExternalLanguageUpdateRequestParams, ExternalLanguageUpdateResponseParams> Type =
RequestType<ExternalLanguageUpdateRequestParams, ExternalLanguageUpdateResponseParams>.Create("languageExtension/update");
}
}

View File

@@ -0,0 +1,343 @@
//
// 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.ServiceLayer.LanguageExtensibility.Contracts;
using Microsoft.SqlTools.ServiceLayer.Management;
using Microsoft.SqlTools.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility
{
public enum ModifyType
{
Create,
Alter
}
public enum ContentModifyType
{
Modify,
Add,
Remove
}
public class ExternalLanguageOperations
{
private static string StatusScript = $@"
SELECT is_installed
FROM sys.dm_db_external_language_stats s, sys.external_languages l
WHERE s.external_language_id = l.external_language_id AND language = @{LanguageNameParamName}";
private const string GetAllScript = @"
SELECT l.external_language_id, language, l.create_date, dp.name, content, file_name, platform_desc, parameters, environment_variables
FROM sys.external_languages l
JOIN sys.external_language_files lf on l.external_language_id = lf.external_language_id
JOIN sys.database_principals dp on l.principal_id = dp.principal_id
ORDER BY l.external_language_id, platform";
private static string GetLanguageScript = $@"
SELECT l.external_language_id, language, l.create_date, dp.name, content, file_name, platform_desc, parameters, environment_variables
FROM sys.external_languages l
JOIN sys.external_language_files lf on l.external_language_id = lf.external_language_id
JOIN sys.database_principals dp on l.principal_id = dp.principal_id
WHERE language=@{LanguageNameParamName}
ORDER BY platform";
public const string CreateScript = "CREATE EXTERNAL LANGUAGE";
public const string DropScript = "DROP EXTERNAL LANGUAGE";
public const string AlterScript = "ALTER EXTERNAL LANGUAGE";
public const string SetContentScript = "SET";
public const string AddContentScript = "ADD";
public const string RemoveContentScript = "REMOVE";
private const string ContentParamName = "CONTENT";
private const string FileNameParamName = "FILE_NAME";
private const string PlatformParamName = "PLATFORM";
private const string EnvVariablesParamName = "ENVIRONMENT_VARIABLES";
private const string ParametersParamName = "PARAMETERS";
private const string LanguageNameParamName = "LANGUAGE";
private string GetDropScript(string languageName)
{
return $@"{DropScript} [{CUtils.EscapeStringCBracket(languageName)}]";
}
/// <summary>
/// Returns the status of external languages in a connection
/// </summary>
/// <param name="connection"></param>
/// <param name="languageName"></param>
/// <returns></returns>
public virtual bool GetLanguageStatus(IDbConnection connection, string languageName)
{
bool status = false;
try
{
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = StatusScript;
var parameter = command.CreateParameter();
parameter.ParameterName = $"@{LanguageNameParamName}";
parameter.Value = languageName;
command.Parameters.Add(parameter);
using (IDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
status = (Convert.ToBoolean(reader[0].ToString()));
}
}
}
}
catch (Exception ex)
{
Logger.Write(TraceEventType.Warning, $"Failed to get language status for language: {languageName}, error: {ex.Message}");
status = false;
}
return status;
}
/// <summary>
/// Returns the list of languages
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
public virtual List<ExternalLanguage> GetLanguages(IDbConnection connection)
{
return GetLanguages(connection, null);
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="languageName"></param>
/// <returns></returns>
public virtual ExternalLanguage GetLanguage(IDbConnection connection, string languageName)
{
List<ExternalLanguage> result = GetLanguages(connection, languageName);
if (result != null && result.Any())
{
return result.First();
}
return null;
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="language"></param>
public virtual void UpdateLanguage(IDbConnection connection, ExternalLanguage language)
{
if (string.IsNullOrWhiteSpace(language?.Name))
{
throw new LanguageExtensibilityException($"Failed to update language. language or language name is empty.");
}
Dictionary<string, object> parameters = new Dictionary<string, object>();
ExternalLanguage currentLanguage = GetLanguage(connection, language.Name);
if (currentLanguage == null)
{
ExecuteNonQuery(connection, GetCreateScript(language, parameters), parameters);
}
else
{
foreach (var content in language.Contents)
{
var currentContent = currentLanguage.Contents.FirstOrDefault(x => x.PlatformId == content.PlatformId);
if (currentContent != null)
{
ExecuteNonQuery(connection, GetUpdateScript(language, content, parameters, ContentModifyType.Modify), parameters);
}
else
{
ExecuteNonQuery(connection, GetUpdateScript(language, content, parameters, ContentModifyType.Add), parameters);
}
}
foreach (var currentContent in currentLanguage.Contents)
{
var content = language.Contents.FirstOrDefault(x => x.PlatformId == currentContent.PlatformId);
if (content == null)
{
ExecuteNonQuery(connection, GetUpdateScript(language, currentContent, parameters, ContentModifyType.Remove), parameters);
}
}
}
}
public virtual void DeleteLanguage(IDbConnection connection, string languageName)
{
if (string.IsNullOrWhiteSpace(languageName))
{
throw new LanguageExtensibilityException($"Failed to delete language. language name is empty");
}
Dictionary<string, object> parameters = new Dictionary<string, object>();
ExecuteNonQuery(connection, GetDropScript(languageName), parameters);
}
/// <summary>
/// Returns the status of external languages in a connection
/// </summary>
/// <param name="connection"></param>
/// <param name="languageName"></param>
/// <returns></returns>
private List<ExternalLanguage> GetLanguages(IDbConnection connection, string languageName = null)
{
Dictionary<int, ExternalLanguage> dic = new Dictionary<int, ExternalLanguage>();
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = languageName != null ? GetLanguageScript : GetAllScript;
if (languageName != null)
{
var parameter = command.CreateParameter();
parameter.ParameterName = $"@{LanguageNameParamName}";
parameter.Value = languageName;
command.Parameters.Add(parameter);
}
using (IDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
int id = reader.GetInt32(0);
string name = reader.GetString(1);
string createdDate = reader.IsDBNull(2) ? string.Empty : reader.GetDateTime(2).ToString();
string owner = reader.IsDBNull(3) ? string.Empty : reader.GetString(3);
string extentionFileName = reader.IsDBNull(5) ? string.Empty : reader.GetString(5);
string platform = reader.IsDBNull(6) ? string.Empty : reader.GetString(6);
string parameters = reader.IsDBNull(7) ? string.Empty : reader.GetString(7);
string envVariables = reader.IsDBNull(8) ? string.Empty : reader.GetString(8);
if (!dic.ContainsKey(id))
{
dic.Add(id, new ExternalLanguage
{
Name = name,
Owner = owner,
CreatedDate = createdDate,
Contents = new List<ExternalLanguageContent>()
});
}
ExternalLanguage metadata = dic[id];
metadata.Contents.Add(new ExternalLanguageContent
{
EnvironmentVariables = envVariables,
Parameters = parameters,
Platform = platform,
ExtensionFileName = extentionFileName
});
}
}
}
return new List<ExternalLanguage>(dic.Values);
}
private string GetCreateScript(ExternalLanguage language, Dictionary<string, object> parameters)
{
return GetLanguageModifyScript(language, language.Contents, parameters, ModifyType.Create);
}
private string GetUpdateScript(ExternalLanguage language, ExternalLanguageContent content, Dictionary<string, object> parameters, ContentModifyType contentModifyType)
{
return GetLanguageModifyScript(language, new List<ExternalLanguageContent> { content }, parameters, ModifyType.Alter, contentModifyType);
}
private string GetLanguageModifyScript(ExternalLanguage language, List<ExternalLanguageContent> contents, Dictionary<string, object> parameters, ModifyType modifyType, ContentModifyType contentModifyType = ContentModifyType.Add)
{
string contentScript = string.Empty;
for (int i = 0; i < contents.Count; i++)
{
var content = contents[i];
string seperator = contentScript == string.Empty ? "" : ",";
contentScript = $"{contentScript}{seperator}{GetLanguageContent(content, i, parameters)}";
}
string ownerScript = string.IsNullOrWhiteSpace(language.Owner) ? "" : $"AUTHORIZATION [{CUtils.EscapeStringCBracket(language.Owner)}]";
string scriptAction = modifyType == ModifyType.Create ? CreateScript : AlterScript;
string contentAction = "FROM";
if (modifyType == ModifyType.Alter)
{
switch (contentModifyType)
{
case ContentModifyType.Modify:
contentAction = SetContentScript;
break;
case ContentModifyType.Add:
contentAction = AddContentScript;
break;
case ContentModifyType.Remove:
contentAction = RemoveContentScript;
break;
}
}
return $@"
{scriptAction} [{CUtils.EscapeStringCBracket(language.Name)}]
{ownerScript}
{contentAction} {contentScript}
";
}
private string AddStringParameter(string paramName, string prefix, string paramValue)
{
string value = string.IsNullOrWhiteSpace(paramValue) ? paramValue : CUtils.EscapeStringSQuote(paramValue);
return $"{prefix} {paramName} = N'{value}'";
}
private string GetLanguageContent(ExternalLanguageContent content, int index, Dictionary<string, object> parameters)
{
string postfix = index.ToString();
string prefix = ",";
string contentScript = string.Empty;
if (content.IsLocalFile)
{
byte[] contentBytes;
using (var stream = new FileStream(content.PathToExtension, FileMode.Open, FileAccess.Read))
{
using (var reader = new BinaryReader(stream))
{
contentBytes = reader.ReadBytes((int)stream.Length);
}
}
parameters.Add($"{ContentParamName}{postfix}", contentBytes);
contentScript = $"CONTENT = @{ContentParamName}{postfix}";
}
else if (!string.IsNullOrWhiteSpace(content.PathToExtension))
{
contentScript = $"{AddStringParameter(ContentParamName, string.Empty, content.PathToExtension)}";
}
return $@"(
{contentScript}
{AddStringParameter(FileNameParamName, string.IsNullOrWhiteSpace(contentScript) ? string.Empty : prefix,
content.ExtensionFileName)}
{AddStringParameter(ParametersParamName, prefix, content.Parameters)}
{AddStringParameter(EnvVariablesParamName, prefix, content.EnvironmentVariables)}
)";
}
private void ExecuteNonQuery(IDbConnection connection, string script, Dictionary<string, object> parameters)
{
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = script;
foreach (var item in parameters)
{
var parameter = command.CreateParameter();
parameter.ParameterName = item.Key;
parameter.Value = item.Value;
command.Parameters.Add(parameter);
}
command.ExecuteNonQuery();
}
}
}
}

View File

@@ -0,0 +1,233 @@
//
// 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;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts;
using Microsoft.SqlTools.Utility;
using System;
using System.Data;
using System.Diagnostics;
using System.Threading.Tasks;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility
{
public class ExternalLanguageService
{
private ExternalLanguageOperations serviceOperations = new ExternalLanguageOperations();
private ConnectionService connectionService = null;
private static readonly Lazy<ExternalLanguageService> instance = new Lazy<ExternalLanguageService>(() => new ExternalLanguageService());
/// <summary>
/// Gets the singleton instance object
/// </summary>
public static ExternalLanguageService Instance
{
get { return instance.Value; }
}
/// <summary>
/// Internal for testing purposes only
/// </summary>
internal ConnectionService ConnectionServiceInstance
{
get
{
if (connectionService == null)
{
connectionService = ConnectionService.Instance;
}
return connectionService;
}
set
{
connectionService = value;
}
}
public ExternalLanguageOperations ExternalLanguageOperations
{
get
{
return serviceOperations;
}
set
{
serviceOperations = value;
}
}
public void InitializeService(ServiceHost serviceHost)
{
serviceHost.SetRequestHandler(ExternalLanguageStatusRequest.Type, this.HandleExternalLanguageStatusRequest);
serviceHost.SetRequestHandler(ExternalLanguageListRequest.Type, this.HandleExternalLanguageListRequest);
serviceHost.SetRequestHandler(ExternalLanguageDeleteRequest.Type, this.HandleExternalLanguageDeleteRequest);
serviceHost.SetRequestHandler(ExternalLanguageUpdateRequest.Type, this.HandleExternalLanguageUpdateRequest);
}
/// <summary>
/// Handles external language delete request
/// </summary>
/// <param name="parameters">Request parameters</param>
/// <param name="requestContext">Request Context</param>
/// <returns></returns>
public async Task HandleExternalLanguageDeleteRequest(ExternalLanguageDeleteRequestParams parameters, RequestContext<ExternalLanguageDeleteResponseParams> requestContext)
{
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageDeleteRequest");
try
{
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(
parameters.OwnerUri,
out connInfo);
ExternalLanguageDeleteResponseParams response = new ExternalLanguageDeleteResponseParams
{
};
if (connInfo == null)
{
await requestContext.SendError(new Exception(SR.ConnectionServiceDbErrorDefaultNotConnected(parameters.OwnerUri)));
}
else
{
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
{
ExternalLanguageOperations.DeleteLanguage(dbConnection, parameters.LanguageName);
}
await requestContext.SendResult(response);
}
}
catch (Exception e)
{
// Exception related to run task will be captured here
await requestContext.SendError(e);
}
}
/// <summary>
/// Handles external language delete request
/// </summary>
/// <param name="parameters">Request parameters</param>
/// <param name="requestContext">Request Context</param>
/// <returns></returns>
public async Task HandleExternalLanguageUpdateRequest(ExternalLanguageUpdateRequestParams parameters, RequestContext<ExternalLanguageUpdateResponseParams> requestContext)
{
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageUpdateRequest");
try
{
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(
parameters.OwnerUri,
out connInfo);
ExternalLanguageUpdateResponseParams response = new ExternalLanguageUpdateResponseParams
{
};
if (connInfo == null)
{
await requestContext.SendError(new Exception(SR.ConnectionServiceDbErrorDefaultNotConnected(parameters.OwnerUri)));
}
else
{
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
{
ExternalLanguageOperations.UpdateLanguage(dbConnection, parameters.Language);
}
await requestContext.SendResult(response);
}
}
catch (Exception e)
{
// Exception related to run task will be captured here
await requestContext.SendError(e);
}
}
/// <summary>
/// Handles external language status request
/// </summary>
/// <param name="parameters">Request parameters</param>
/// <param name="requestContext">Request Context</param>
/// <returns></returns>
public async Task HandleExternalLanguageStatusRequest(ExternalLanguageStatusRequestParams parameters, RequestContext<ExternalLanguageStatusResponseParams> requestContext)
{
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageStatusRequest");
try
{
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(
parameters.OwnerUri,
out connInfo);
ExternalLanguageStatusResponseParams response = new ExternalLanguageStatusResponseParams
{
Status = false,
};
if (connInfo == null)
{
await requestContext.SendError(new Exception(SR.ConnectionServiceDbErrorDefaultNotConnected(parameters.OwnerUri)));
}
else
{
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
{
response.Status = ExternalLanguageOperations.GetLanguageStatus(dbConnection, parameters.LanguageName);
}
await requestContext.SendResult(response);
}
}
catch (Exception e)
{
// Exception related to run task will be captured here
await requestContext.SendError(e);
}
}
/// <summary>
/// Handles external language status request
/// </summary>
/// <param name="parameters">Request parameters</param>
/// <param name="requestContext">Request Context</param>
/// <returns></returns>
public async Task HandleExternalLanguageListRequest(ExternalLanguageListRequestParams parameters, RequestContext<ExternalLanguageListResponseParams> requestContext)
{
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageListRequest");
try
{
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(
parameters.OwnerUri,
out connInfo);
ExternalLanguageListResponseParams response = new ExternalLanguageListResponseParams
{
};
if (connInfo == null)
{
await requestContext.SendError(new Exception(SR.ConnectionServiceDbErrorDefaultNotConnected(parameters.OwnerUri)));
}
else
{
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
{
response.Languages = ExternalLanguageOperations.GetLanguages(dbConnection);
}
await requestContext.SendResult(response);
}
}
catch (Exception e)
{
// Exception related to run task will be captured here
await requestContext.SendError(e);
}
}
}
}

View File

@@ -0,0 +1,27 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility
{
/// <summary>
/// Exception raised from machine learning services operations
/// </summary>
public class LanguageExtensibilityException : Exception
{
internal LanguageExtensibilityException() : base()
{
}
internal LanguageExtensibilityException(string m) : base(m)
{
}
internal LanguageExtensibilityException(string m, Exception innerException) : base(m, innerException)
{
}
}
}

View File

@@ -1,51 +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 System.Data;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensions
{
public class LanguageExtensionOperations
{
private const string LanguageStatusScript = @"SELECT is_installed
FROM sys.dm_db_external_language_stats s, sys.external_languages l
WHERE s.external_language_id = l.external_language_id AND language = @LanguageName";
/// <summary>
/// Returns the status of external languages in a connection
/// </summary>
/// <param name="connection"></param>
/// <param name="languageName"></param>
/// <returns></returns>
public bool GetLanguageStatus(IDbConnection connection, string languageName)
{
bool status = false;
try
{
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = LanguageStatusScript;
var parameter = command.CreateParameter();
parameter.ParameterName = "@LanguageName";
parameter.Value = languageName;
command.Parameters.Add(parameter);
using (IDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
status = (reader[0].ToString() == "True");
}
}
}
}
catch
{
status = false;
}
return status;
}
}
}

View File

@@ -1,98 +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;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.LanguageExtensions.Contracts;
using Microsoft.SqlTools.Utility;
using System;
using System.Data;
using System.Diagnostics;
using System.Threading.Tasks;
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensions
{
public class LanguageExtensionsService
{
private LanguageExtensionOperations serviceOperations = new LanguageExtensionOperations();
private ConnectionService connectionService = null;
private static readonly Lazy<LanguageExtensionsService> instance = new Lazy<LanguageExtensionsService>(() => new LanguageExtensionsService());
/// <summary>
/// Gets the singleton instance object
/// </summary>
public static LanguageExtensionsService Instance
{
get { return instance.Value; }
}
/// <summary>
/// Internal for testing purposes only
/// </summary>
internal ConnectionService ConnectionServiceInstance
{
get
{
if (connectionService == null)
{
connectionService = ConnectionService.Instance;
}
return connectionService;
}
set
{
connectionService = value;
}
}
public void InitializeService(ServiceHost serviceHost)
{
serviceHost.SetRequestHandler(ExternalLanguageStatusRequest.Type, this.HandleExternalLanguageStatusRequest);
}
/// <summary>
/// Handles external language status request
/// </summary>
/// <param name="parameters">Request parameters</param>
/// <param name="requestContext">Request Context</param>
/// <returns></returns>
public async Task HandleExternalLanguageStatusRequest(ExternalLanguageStatusRequestParams parameters, RequestContext<ExternalLanguageStatusResponseParams> requestContext)
{
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageStatusRequest");
try
{
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(
parameters.OwnerUri,
out connInfo);
ExternalLanguageStatusResponseParams response = new ExternalLanguageStatusResponseParams
{
Status = false,
};
if (connInfo == null)
{
await requestContext.SendError(new Exception(SR.ProfilerConnectionNotFound));
}
else
{
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
{
response.Status = serviceOperations.GetLanguageStatus(dbConnection, parameters.LanguageName);
}
await requestContext.SendResult(response);
}
}
catch (Exception e)
{
// Exception related to run task will be captured here
await requestContext.SendError(e);
}
}
}
}

View File

@@ -514,6 +514,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Management
/// <returns></returns>
public static String EscapeString(string s, char cEsc)
{
if (string.IsNullOrWhiteSpace(s))
{
return s;
}
StringBuilder sb = new StringBuilder(s.Length * 2);
foreach (char c in s)
{