Added new Kusto ServiceLayer (#1009)

* Copy smoModel some rename

* Copy entire service layer

* Building copy

* Fixing some references

* Launch profile

* Resolve namespace issues

* Compiling tests. Correct manifest.

* Fixing localization resources

* ReliableKustoClient

* Some trimming of extra code and Kusto code

* Kusto client creation in bindingContent

* Removing Smo and new Kusto classes

* More trimming

* Kusto schema hookup

* Solidying DataSource abstraction

* Solidifying further

* Latest refatoring

* More refactoring

* Building and launching Kusto service layer

* Working model which enumerates databases

* Refactoring to pass IDataSource to all tree nodes

* Removing some dependencies on the context

* Working with tables and schema

* Comment checkin

* Refactoring to give out select script

* Query created and sent back to ADS

* Fix query generation

* Fix listing of databases

* Tunneling the query through.

* Successful query execution

* Return only results table

* Deleting Cms

* Delete DacFx

* Delete SchemaCompare and TaskServices

* Change build definition to not stop at launch

* Fix error after merge

* Save Kusto results in different formats (#935)

* save results as csv etc

* some fixes

Co-authored-by: Monica Gupta <mogupt@microsoft.com>

* 2407 Added OrderBy clause in KustoDataSource > GetDatabaseMetaData and GetColumnMetadata (#959)

* 2405 Defaulted Options when setting ServerInfo in ConnectionService > GetConnectionCompleteParams (#965)

* 2747 Fixed IsUnknownType error for Kusto (#989)

* 2747 Removed unused directives in Kusto > DbColumnWrapper. Refactored IsUnknownType to handle null DataTypeName

* 2747 Reverted IsUnknownType change in DbColumnWrapper. Changed DataTypeName to get calue from ColumnType. Refactored SafeGetValue to type check before hard casting to reduce case exceptions.

* Added EmbeddedResourceUseDependentUponConvention to Microsoft.Kusto.ServiceLayer.csproj. Also renamed DACfx to match Microsoft.SqlTools.ServiceLayer. Added to compile Exclude="**/obj/**/*.cs"

* Srahman cleanup sql code (#992)

* Removed Management and Security Service Code.

* Remove FileBrowser service

* Comment why we are using SqlServer library

* Remove SQL specific type definitions

* clean up formatter service (#996)

Co-authored-by: Monica Gupta <mogupt@microsoft.com>

* Code clean up and Kusto intellisense (#994)

* Code clean up and Kusto intellisense

* Addressed few comments

* Addressed few comments

* addressed comments

Co-authored-by: Monica Gupta <mogupt@microsoft.com>

* Return multiple tables for Kusto

* Changes required for Kusto manage dashboard (#1039)

* Changes required for manage dashboard

* Addressed comments

Co-authored-by: Monica Gupta <mogupt@microsoft.com>

* 2728 Kusto function support (#1038)

* loc update (#914)

* loc update

* loc updates

* 2728 moved ColumnInfo and KustoResultsReader to separate files. Added Folder and Function to TreeNode.cs

* 2728 Added FunctionInfo. Added Folder to ColumnInfo. Removed partial class from KustoResultsReader. Set Function.IsAlwaysLeaf=true in TreeNode.cs. In KustoDataSource changed tableMetadata type to TableMetaData. Added folder and function dictionaries. Refactored GetSchema function. Renamed GenerateColumnMetadataKey to GenerateMetadataKey

* 2728 Added FunctionInfo. Added Folder to ColumnInfo. Removed partial class from KustoResultsReader. Set Function.IsAlwaysLeaf=true in TreeNode.cs. In KustoDataSource changed tableMetadata type to TableMetaData. Added folder and function dictionaries. Refactored GetSchema function. Renamed GenerateColumnMetadataKey to GenerateMetadataKey

* 2728 Created new SqlConnection within using block. Refactored KustoDataSource > columnmetadata to sort on get instead of insert.

* 2728 Added GetFunctionInfo function to KustoDataSource.

* 2728 Reverted change to Microsoft.Kusto.ServiceLayer.csproj from merge

* 2728 Reverted change to SqlTools.ServiceLayer\Localization\transXliff

* 2728 Reverted change to sr.de.xlf and sr.zh-hans.xlf

* 2728 Refactored KustoDataSource Function folders to support subfolders

* 2728 Refactored KustoDataSource to use urn for folders, functions, and tables instead of name.

* Merge remote-tracking branch 'origin/main' into feature-ADE

# Conflicts:
#	Packages.props

* 2728 Moved metadata files into Metadata subdirectory. Added GenerateAlterFunction to IDataSource and DataSourceBase.

* 2728 Added summary information to SafeAdd in SystemExtensions. Renamed local variable in SetTableMetadata

* 2728 Moved SafeAdd from SystemExtensions to KustoQueryUtils. Added check when getting database schema to return existing records before querying again. Added AddRange function to KustoQueryUtils. Created SetFolderMetadataForFunctions method.

* 2728 Added DatabaseKeyPrefix to only return tables to a database for the dashboard. Added logic to store all database tables within the tableMetadata dictionary for the dashboard.

* 2728 Created TableInfo and moved info objects into Models directory. Refactored KustoDataSource to lazy load columns for tables. Refactored logic to load tables using cslschema instead of schema.

* 2728 Renamed LoadColumnSchema to GetTableSchema to be consistent.

Co-authored-by: khoiph1 <khoiph@microsoft.com>

* Addressed comments

Co-authored-by: Shafiq Rahman <srahman@microsoft.com>
Co-authored-by: Monica Gupta <mogupt@microsoft.com>
Co-authored-by: Justin M <63619224+JustinMDotNet@users.noreply.github.com>
Co-authored-by: rkselfhost <rkselfhost@outlook.com>
Co-authored-by: khoiph1 <khoiph@microsoft.com>
This commit is contained in:
Monica Gupta
2020-08-12 15:34:38 -07:00
committed by GitHub
parent d2f5bfaa16
commit 148b6e398d
276 changed files with 75983 additions and 1 deletions

23
.vscode/launch.json vendored
View File

@@ -18,6 +18,20 @@
"stopAtEntry": false, "stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart" "internalConsoleOptions": "openOnSessionStart"
}, },
{
"name": "Kusto service Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/src/Microsoft.Kusto.ServiceLayer/bin/Debug/netcoreapp3.1/MicrosoftKustoServiceLayer.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Microsoft.Kusto.ServiceLayer",
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
"console": "externalTerminal",
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart"
},
{ {
"name": ".NET Core Attach", "name": ".NET Core Attach",
"type": "coreclr", "type": "coreclr",
@@ -26,6 +40,15 @@
"requireExactSource": false, "requireExactSource": false,
"justMyCode": false, "justMyCode": false,
"enableStepFiltering": false "enableStepFiltering": false
},
{
"name": "Kusto Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}",
"requireExactSource": false,
"justMyCode": false,
"enableStepFiltering": false
} }
,] ,]
} }

View File

@@ -20,6 +20,8 @@
<PackageReference Update="Microsoft.Data.SqlClient" Version="2.0.0"/> <PackageReference Update="Microsoft.Data.SqlClient" Version="2.0.0"/>
<PackageReference Update="Microsoft.SqlServer.SqlManagementObjects" Version="160.2004021.0" /> <PackageReference Update="Microsoft.SqlServer.SqlManagementObjects" Version="160.2004021.0" />
<PackageReference Update="Microsoft.SqlServer.DACFx" Version="150.4870.3-preview" GeneratePathProperty="true" /> <PackageReference Update="Microsoft.SqlServer.DACFx" Version="150.4870.3-preview" GeneratePathProperty="true" />
<PackageReference Update="Microsoft.Azure.Kusto.Data" Version="8.0.2" />
<PackageReference Update="Microsoft.Azure.Kusto.Language" Version="8.1.2"/>
<PackageReference Update="Moq" Version="4.8.2" /> <PackageReference Update="Moq" Version="4.8.2" />
<PackageReference Update="NUnit" Version="3.12.0" /> <PackageReference Update="NUnit" Version="3.12.0" />

View File

@@ -104,6 +104,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SqlTools.ManagedB
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SqlTools.Test.CompletionExtension", "test\Microsoft.SqlTools.Test.CompletionExtension\Microsoft.SqlTools.Test.CompletionExtension.csproj", "{0EC2B30C-0652-49AE-9594-85B3C3E9CA21}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SqlTools.Test.CompletionExtension", "test\Microsoft.SqlTools.Test.CompletionExtension\Microsoft.SqlTools.Test.CompletionExtension.csproj", "{0EC2B30C-0652-49AE-9594-85B3C3E9CA21}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Kusto.ServiceLayer", "src\Microsoft.Kusto.ServiceLayer\Microsoft.Kusto.ServiceLayer.csproj", "{E0C941C8-91F2-4BE1-8B79-AC88EDB78729}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "azure-pipelines", "azure-pipelines", "{48D5C134-4091-438D-9D35-6EB8CF0D1DCC}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "azure-pipelines", "azure-pipelines", "{48D5C134-4091-438D-9D35-6EB8CF0D1DCC}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
azure-pipelines\build.yml = azure-pipelines\build.yml azure-pipelines\build.yml = azure-pipelines\build.yml
@@ -249,6 +251,12 @@ Global
{0EC2B30C-0652-49AE-9594-85B3C3E9CA21}.Integration|Any CPU.Build.0 = Debug|Any CPU {0EC2B30C-0652-49AE-9594-85B3C3E9CA21}.Integration|Any CPU.Build.0 = Debug|Any CPU
{0EC2B30C-0652-49AE-9594-85B3C3E9CA21}.Release|Any CPU.ActiveCfg = Release|Any CPU {0EC2B30C-0652-49AE-9594-85B3C3E9CA21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0EC2B30C-0652-49AE-9594-85B3C3E9CA21}.Release|Any CPU.Build.0 = Release|Any CPU {0EC2B30C-0652-49AE-9594-85B3C3E9CA21}.Release|Any CPU.Build.0 = Release|Any CPU
{E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Integration|Any CPU.ActiveCfg = Debug|Any CPU
{E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Integration|Any CPU.Build.0 = Debug|Any CPU
{E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -278,6 +286,7 @@ Global
{3F82F298-700A-48DF-8A69-D048DFBA782C} = {2BBD7364-054F-4693-97CD-1C395E3E84A9} {3F82F298-700A-48DF-8A69-D048DFBA782C} = {2BBD7364-054F-4693-97CD-1C395E3E84A9}
{D3696EFA-FB1E-4848-A726-FF7B168AFB96} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {D3696EFA-FB1E-4848-A726-FF7B168AFB96} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4}
{0EC2B30C-0652-49AE-9594-85B3C3E9CA21} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {0EC2B30C-0652-49AE-9594-85B3C3E9CA21} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4}
{E0C941C8-91F2-4BE1-8B79-AC88EDB78729} = {2BBD7364-054F-4693-97CD-1C395E3E84A9}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B31CDF4B-2851-45E5-8C5F-BE97125D9DD8} SolutionGuid = {B31CDF4B-2851-45E5-8C5F-BE97125D9DD8}

View File

@@ -0,0 +1,136 @@
//
// 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.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.Kusto.ServiceLayer.Admin.Contracts;
using Microsoft.Kusto.ServiceLayer.Connection;
using Microsoft.Kusto.ServiceLayer.DataSource;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
using Microsoft.Kusto.ServiceLayer.Hosting;
using Microsoft.Kusto.ServiceLayer.Utility;
namespace Microsoft.Kusto.ServiceLayer.Admin
{
/// <summary>
/// Admin task service class
/// </summary>
public class AdminService
{
private static readonly Lazy<AdminService> instance = new Lazy<AdminService>(() => new AdminService());
private static ConnectionService connectionService = null;
/// <summary>
/// Default, parameterless constructor.
/// </summary>
internal AdminService()
{
}
/// <summary>
/// Internal for testing purposes only
/// </summary>
internal static ConnectionService ConnectionServiceInstance
{
get
{
if (AdminService.connectionService == null)
{
AdminService.connectionService = ConnectionService.Instance;
}
return AdminService.connectionService;
}
set
{
AdminService.connectionService = value;
}
}
/// <summary>
/// Gets the singleton instance object
/// </summary>
public static AdminService Instance
{
get { return instance.Value; }
}
/// <summary>
/// Initializes the service instance
/// </summary>
public void InitializeService(ServiceHost serviceHost)
{
serviceHost.SetRequestHandler(GetDatabaseInfoRequest.Type, HandleGetDatabaseInfoRequest);
}
/// <summary>
/// Handle get database info request
/// </summary>
internal static async Task HandleGetDatabaseInfoRequest(
GetDatabaseInfoParams databaseParams,
RequestContext<GetDatabaseInfoResponse> requestContext)
{
try
{
Func<Task> requestHandler = async () =>
{
ConnectionInfo connInfo;
AdminService.ConnectionServiceInstance.TryFindConnection(
databaseParams.OwnerUri,
out connInfo);
DatabaseInfo info = null;
if (connInfo != null)
{
info = GetDatabaseInfo(connInfo);
}
await requestContext.SendResult(new GetDatabaseInfoResponse()
{
DatabaseInfo = info
});
};
Task task = Task.Run(async () => await requestHandler()).ContinueWithOnFaulted(async t =>
{
await requestContext.SendError(t.Exception.ToString());
});
}
catch (Exception ex)
{
await requestContext.SendError(ex.ToString());
}
}
/// <summary>
/// Return database info for a specific database
/// </summary>
/// <param name="connInfo"></param>
/// <returns></returns>
internal static DatabaseInfo GetDatabaseInfo(ConnectionInfo connInfo)
{
if(!string.IsNullOrEmpty(connInfo.ConnectionDetails.DatabaseName)){
ReliableDataSourceConnection connection;
connInfo.TryGetConnection("Default", out connection);
IDataSource dataSource = connection.GetUnderlyingConnection();
DataSourceObjectMetadata objectMetadata = DataSourceFactory.CreateClusterMetadata(connInfo.ConnectionDetails.ServerName);
List<DataSourceObjectMetadata> metadata = dataSource.GetChildObjects(objectMetadata, true).ToList();
var databaseMetadata = metadata.Where(o => o.Name == connInfo.ConnectionDetails.DatabaseName);
List<DatabaseInfo> databaseInfo = DataSourceFactory.ConvertToDatabaseInfo(databaseMetadata);
return databaseInfo.ElementAtOrDefault(0);
}
return null;
}
}
}

View File

@@ -0,0 +1,23 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
namespace Microsoft.Kusto.ServiceLayer.Admin.Contracts
{
public class DatabaseInfo
{
/// <summary>
/// Gets or sets the options
/// </summary>
public Dictionary<string, object> Options { get; set; }
public DatabaseInfo()
{
Options = new Dictionary<string, object>();
}
}
}

View File

@@ -0,0 +1,41 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
namespace Microsoft.Kusto.ServiceLayer.Admin.Contracts
{
/// <summary>
/// Params for a get database info request
/// </summar>
public class GetDatabaseInfoParams
{
/// <summary>
/// Uri identifier for the connection to get the database info for
/// </summary>
public string OwnerUri { get; set; }
}
/// <summary>
/// Response object for get database info
/// </summary>
public class GetDatabaseInfoResponse
{
/// <summary>
/// The object containing the database info
/// </summary>
public DatabaseInfo DatabaseInfo { get; set; }
}
/// <summary>
/// Get database info request mapping
/// </summary>
public class GetDatabaseInfoRequest
{
public static readonly
RequestType<GetDatabaseInfoParams, GetDatabaseInfoResponse> Type =
RequestType<GetDatabaseInfoParams, GetDatabaseInfoResponse>.Create("admin/getdatabaseinfo");
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
namespace Microsoft.Kusto.ServiceLayer.Connection
{
/// <summary>
/// Used to uniquely identify a CancellationTokenSource associated with both
/// a string URI and a string connection type.
/// </summary>
public class CancelTokenKey : CancelConnectParams, IEquatable<CancelTokenKey>
{
public override bool Equals(object obj)
{
CancelTokenKey other = obj as CancelTokenKey;
if (other == null)
{
return false;
}
return other.OwnerUri == OwnerUri && other.Type == Type;
}
public bool Equals(CancelTokenKey obj)
{
return obj.OwnerUri == OwnerUri && obj.Type == Type;
}
public override int GetHashCode()
{
return OwnerUri.GetHashCode() ^ Type.GetHashCode();
}
}
}

View File

@@ -0,0 +1,162 @@
//
// 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.Concurrent;
using System.Collections.Generic;
using System.Data.Common;
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.Utility;
namespace Microsoft.Kusto.ServiceLayer.Connection
{
/// <summary>
/// Information pertaining to a unique connection instance.
/// </summary>
public class ConnectionInfo
{
/// <summary>
/// Constructor
/// </summary>
public ConnectionInfo(IDataSourceConnectionFactory factory, string ownerUri, ConnectionDetails details)
{
Factory = factory;
OwnerUri = ownerUri;
ConnectionDetails = details;
ConnectionId = Guid.NewGuid();
IntellisenseMetrics = new InteractionMetrics<double>(new int[] {50, 100, 200, 500, 1000, 2000});
}
/// <summary>
/// Unique Id, helpful to identify a connection info object
/// </summary>
public Guid ConnectionId { get; private set; }
/// <summary>
/// URI identifying the owner/user of the connection. Could be a file, service, resource, etc.
/// </summary>
public string OwnerUri { get; private set; }
/// <summary>
/// Factory used for creating the SQL connection associated with the connection info.
/// </summary>
public IDataSourceConnectionFactory Factory { get; private set; }
/// <summary>
/// Properties used for creating/opening the SQL connection.
/// </summary>
public ConnectionDetails ConnectionDetails { get; private set; }
/// <summary>
/// A map containing all connections to the database that are associated with
/// this ConnectionInfo's OwnerUri.
/// This is internal for testing access only
/// </summary>
internal readonly ConcurrentDictionary<string, ReliableDataSourceConnection> ConnectionTypeToConnectionMap =
new ConcurrentDictionary<string, ReliableDataSourceConnection>();
/// <summary>
/// Intellisense Metrics
/// </summary>
public InteractionMetrics<double> IntellisenseMetrics { get; private set; }
/// <summary>
/// Returns true if the db connection is to any cloud instance
/// </summary>
public bool IsCloud { get; set; }
/// <summary>
/// Returns the major version number of the db we are connected to
/// </summary>
public int MajorVersion { get; set; }
/// <summary>
/// All DbConnection instances held by this ConnectionInfo
/// </summary>
public ICollection<ReliableDataSourceConnection> AllConnections
{
get
{
return ConnectionTypeToConnectionMap.Values;
}
}
/// <summary>
/// All connection type strings held by this ConnectionInfo
/// </summary>
/// <returns></returns>
public ICollection<string> AllConnectionTypes
{
get
{
return ConnectionTypeToConnectionMap.Keys;
}
}
public bool HasConnectionType(string connectionType)
{
connectionType = connectionType ?? ConnectionType.Default;
return ConnectionTypeToConnectionMap.ContainsKey(connectionType);
}
/// <summary>
/// The count of DbConnectioninstances held by this ConnectionInfo
/// </summary>
public int CountConnections
{
get
{
return ConnectionTypeToConnectionMap.Count;
}
}
/// <summary>
/// Try to get the DbConnection associated with the given connection type string.
/// </summary>
/// <returns>true if a connection with type connectionType was located and out connection was set,
/// false otherwise </returns>
/// <exception cref="ArgumentException">Thrown when connectionType is null or empty</exception>
public bool TryGetConnection(string connectionType, out ReliableDataSourceConnection connection)
{
Validate.IsNotNullOrEmptyString("Connection Type", connectionType);
return ConnectionTypeToConnectionMap.TryGetValue(connectionType, out connection);
}
/// <summary>
/// Adds a DbConnection to this object and associates it with the given
/// connection type string. If a connection already exists with an identical
/// connection type string, it is not overwritten. Ignores calls where connectionType = null
/// </summary>
/// <exception cref="ArgumentException">Thrown when connectionType is null or empty</exception>
public void AddConnection(string connectionType, ReliableDataSourceConnection connection)
{
Validate.IsNotNullOrEmptyString("Connection Type", connectionType);
ConnectionTypeToConnectionMap.TryAdd(connectionType, connection);
}
/// <summary>
/// Removes the single DbConnection instance associated with string connectionType
/// </summary>
/// <exception cref="ArgumentException">Thrown when connectionType is null or empty</exception>
public void RemoveConnection(string connectionType)
{
Validate.IsNotNullOrEmptyString("Connection Type", connectionType);
ReliableDataSourceConnection connection;
ConnectionTypeToConnectionMap.TryRemove(connectionType, out connection);
}
/// <summary>
/// Removes all DbConnection instances held by this object
/// </summary>
public void RemoveAllConnections()
{
foreach (var type in AllConnectionTypes)
{
ReliableDataSourceConnection connection;
ConnectionTypeToConnectionMap.TryRemove(type, out connection);
}
}
}
}

View File

@@ -0,0 +1,302 @@
//
// 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.Contracts;
namespace Microsoft.Kusto.ServiceLayer.Connection
{
/// <summary>
/// Helper class for providing metadata about connection options
/// </summary>
internal class ConnectionProviderOptionsHelper
{
internal static ConnectionProviderOptions BuildConnectionProviderOptions()
{
return new ConnectionProviderOptions
{
Options = new ConnectionOption[]
{
new ConnectionOption
{
Name = "server",
DisplayName = "Server name",
Description = "Name of the SQL Server instance",
ValueType = ConnectionOption.ValueTypeString,
SpecialValueType = ConnectionOption.SpecialValueServerName,
IsIdentity = true,
IsRequired = true,
GroupName = "Source"
},
new ConnectionOption
{
Name = "database",
DisplayName = "Database name",
Description = "The name of the initial catalog or database int the data source",
ValueType = ConnectionOption.ValueTypeString,
SpecialValueType = ConnectionOption.SpecialValueDatabaseName,
IsIdentity = true,
IsRequired = false,
GroupName = "Source"
},
new ConnectionOption
{
Name = "authenticationType",
DisplayName = "Authentication type",
Description = "Specifies the method of authenticating with SQL Server",
ValueType = ConnectionOption.ValueTypeCategory,
SpecialValueType = ConnectionOption.SpecialValueAuthType,
CategoryValues = new CategoryValue[]
{ new CategoryValue { DisplayName = "SQL Login", Name = "SqlLogin" },
new CategoryValue { DisplayName = "Windows Authentication", Name = "Integrated" },
new CategoryValue { DisplayName = "Azure Active Directory - Universal with MFA support", Name = "AzureMFA" }
},
IsIdentity = true,
IsRequired = true,
GroupName = "Security"
},
new ConnectionOption
{
Name = "user",
DisplayName = "User name",
Description = "Indicates the user ID to be used when connecting to the data source",
ValueType = ConnectionOption.ValueTypeString,
SpecialValueType = ConnectionOption.SpecialValueUserName,
IsIdentity = true,
IsRequired = true,
GroupName = "Security"
},
new ConnectionOption
{
Name = "password",
DisplayName = "Password",
Description = "Indicates the password to be used when connecting to the data source",
ValueType = ConnectionOption.ValueTypePassword,
SpecialValueType = ConnectionOption.SpecialValuePasswordName,
IsIdentity = true,
IsRequired = true,
GroupName = "Security"
},
new ConnectionOption
{
Name = "applicationIntent",
DisplayName = "Application intent",
Description = "Declares the application workload type when connecting to a server",
ValueType = ConnectionOption.ValueTypeCategory,
CategoryValues = new CategoryValue[] {
new CategoryValue { Name = "ReadWrite", DisplayName = "ReadWrite" },
new CategoryValue {Name = "ReadOnly", DisplayName = "ReadOnly" }
},
GroupName = "Initialization"
},
new ConnectionOption
{
Name = "asynchronousProcessing",
DisplayName = "Asynchronous processing enabled",
Description = "When true, enables usage of the Asynchronous functionality in the .Net Framework Data Provider",
ValueType = ConnectionOption.ValueTypeBoolean,
GroupName = "Initialization"
},
new ConnectionOption
{
Name = "connectTimeout",
DisplayName = "Connect timeout",
Description =
"The length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error",
ValueType = ConnectionOption.ValueTypeNumber,
DefaultValue = "15",
GroupName = "Initialization"
},
new ConnectionOption
{
Name = "currentLanguage",
DisplayName = "Current language",
Description = "The SQL Server language record name",
ValueType = ConnectionOption.ValueTypeString,
GroupName = "Initialization"
},
new ConnectionOption
{
Name = "columnEncryptionSetting",
DisplayName = "Column encryption setting",
Description = "Default column encryption setting for all the commands on the connection",
ValueType = ConnectionOption.ValueTypeCategory,
GroupName = "Security",
CategoryValues = new CategoryValue[] {
new CategoryValue { Name = "Disabled" },
new CategoryValue {Name = "Enabled" }
}
},
new ConnectionOption
{
Name = "encrypt",
DisplayName = "Encrypt",
Description =
"When true, SQL Server uses SSL encryption for all data sent between the client and server if the servers has a certificate installed",
GroupName = "Security",
ValueType = ConnectionOption.ValueTypeBoolean
},
new ConnectionOption
{
Name = "persistSecurityInfo",
DisplayName = "Persist security info",
Description = "When false, security-sensitive information, such as the password, is not returned as part of the connection",
GroupName = "Security",
ValueType = ConnectionOption.ValueTypeBoolean
},
new ConnectionOption
{
Name = "trustServerCertificate",
DisplayName = "Trust server certificate",
Description = "When true (and encrypt=true), SQL Server uses SSL encryption for all data sent between the client and server without validating the server certificate",
GroupName = "Security",
ValueType = ConnectionOption.ValueTypeBoolean
},
new ConnectionOption
{
Name = "attachedDBFileName",
DisplayName = "Attached DB file name",
Description = "The name of the primary file, including the full path name, of an attachable database",
ValueType = ConnectionOption.ValueTypeString,
GroupName = "Source"
},
new ConnectionOption
{
Name = "contextConnection",
DisplayName = "Context connection",
Description = "When true, indicates the connection should be from the SQL server context. Available only when running in the SQL Server process",
ValueType = ConnectionOption.ValueTypeBoolean,
GroupName = "Source"
},
new ConnectionOption
{
Name = "port",
DisplayName = "Port",
ValueType = ConnectionOption.ValueTypeNumber
},
new ConnectionOption
{
Name = "connectRetryCount",
DisplayName = "Connect retry count",
Description = "Number of attempts to restore connection",
ValueType = ConnectionOption.ValueTypeNumber,
DefaultValue = "1",
GroupName = "Connection Resiliency"
},
new ConnectionOption
{
Name = "connectRetryInterval",
DisplayName = "Connect retry interval",
Description = "Delay between attempts to restore connection",
ValueType = ConnectionOption.ValueTypeNumber,
DefaultValue = "10",
GroupName = "Connection Resiliency"
},
new ConnectionOption
{
Name = "applicationName",
DisplayName = "Application name",
Description = "The name of the application",
ValueType = ConnectionOption.ValueTypeString,
GroupName = "Context",
SpecialValueType = ConnectionOption.SpecialValueAppName
},
new ConnectionOption
{
Name = "workstationId",
DisplayName = "Workstation Id",
Description = "The name of the workstation connecting to SQL Server",
ValueType = ConnectionOption.ValueTypeString,
GroupName = "Context"
},
new ConnectionOption
{
Name = "pooling",
DisplayName = "Pooling",
Description = "When true, the connection object is drawn from the appropriate pool, or if necessary, is created and added to the appropriate pool",
ValueType = ConnectionOption.ValueTypeBoolean,
GroupName = "Pooling"
},
new ConnectionOption
{
Name = "maxPoolSize",
DisplayName = "Max pool size",
Description = "The maximum number of connections allowed in the pool",
ValueType = ConnectionOption.ValueTypeNumber,
GroupName = "Pooling"
},
new ConnectionOption
{
Name = "minPoolSize",
DisplayName = "Min pool size",
Description = "The minimum number of connections allowed in the pool",
ValueType = ConnectionOption.ValueTypeNumber,
GroupName = "Pooling"
},
new ConnectionOption
{
Name = "loadBalanceTimeout",
DisplayName = "Load balance timeout",
Description = "The minimum amount of time (in seconds) for this connection to live in the pool before being destroyed",
ValueType = ConnectionOption.ValueTypeNumber,
GroupName = "Pooling"
},
new ConnectionOption
{
Name = "replication",
DisplayName = "Replication",
Description = "Used by SQL Server in Replication",
ValueType = ConnectionOption.ValueTypeBoolean,
GroupName = "Replication"
},
new ConnectionOption
{
Name = "attachDbFilename",
DisplayName = "Attach DB filename",
ValueType = ConnectionOption.ValueTypeString
},
new ConnectionOption
{
Name = "failoverPartner",
DisplayName = "Failover partner",
Description = "the name or network address of the instance of SQL Server that acts as a failover partner",
ValueType = ConnectionOption.ValueTypeString,
GroupName = " Source"
},
new ConnectionOption
{
Name = "multiSubnetFailover",
DisplayName = "Multi subnet failover",
ValueType = ConnectionOption.ValueTypeBoolean
},
new ConnectionOption
{
Name = "multipleActiveResultSets",
DisplayName = "Multiple active result sets",
Description = "When true, multiple result sets can be returned and read from one connection",
ValueType = ConnectionOption.ValueTypeBoolean,
GroupName = "Advanced"
},
new ConnectionOption
{
Name = "packetSize",
DisplayName = "Packet size",
Description = "Size in bytes of the network packets used to communicate with an instance of SQL Server",
ValueType = ConnectionOption.ValueTypeNumber,
GroupName = "Advanced"
},
new ConnectionOption
{
Name = "typeSystemVersion",
DisplayName = "Type system version",
Description = "Indicates which server type system then provider will expose through the DataReader",
ValueType = ConnectionOption.ValueTypeString,
GroupName = "Advanced"
}
}
};
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection
{
/// <summary>
/// String constants that represent connection types.
///
/// Default: Connection used by the editor. Opened by the editor upon the initial connection.
/// Query: Connection used for executing queries. Opened when the first query is executed.
/// </summary>
public static class ConnectionType
{
public const string Default = "Default";
public const string Query = "Query";
public const string Edit = "Edit";
public const string ObjectExplorer = "ObjectExplorer";
public const string Dashboard = "Dashboard";
public const string GeneralConnection = "GeneralConnection";
}
}

View File

@@ -0,0 +1,19 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Serialize Connection String request
/// </summary>
public class BuildConnectionInfoRequest
{
public static readonly
RequestType<string, ConnectionDetails> Type =
RequestType<string, ConnectionDetails>.Create("connection/buildconnectioninfo");
}
}

View File

@@ -0,0 +1,24 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Parameters for the Cancel Connect Request.
/// </summary>
public class CancelConnectParams
{
/// <summary>
/// A URI identifying the owner of the connection. This will most commonly be a file in the workspace
/// or a virtual file representing an object in a database.
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// The type of connection we are trying to cancel
/// </summary>
public string Type { get; set; } = ConnectionType.Default;
}
}

View File

@@ -0,0 +1,19 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Cancel connect request mapping entry
/// </summary>
public class CancelConnectRequest
{
public static readonly
RequestType<CancelConnectParams, bool> Type =
RequestType<CancelConnectParams, bool>.Create("connection/cancelconnect");
}
}

View File

@@ -0,0 +1,23 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Parameters for the List Databases Request.
/// </summary>
public class ChangeDatabaseParams
{
/// <summary>
/// URI of the owner of the connection requesting the list of databases.
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// The database to change to
/// </summary>
public string NewDatabase { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// List databases request mapping entry
/// </summary>
public class ChangeDatabaseRequest
{
public static readonly
RequestType<ChangeDatabaseParams, bool> Type =
RequestType<ChangeDatabaseParams, bool>.Create("connection/changedatabase");
}
}

View File

@@ -0,0 +1,37 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Parameters for the Connect Request.
/// </summary>
public class ConnectParams
{
/// <summary>
/// A URI identifying the owner of the connection. This will most commonly be a file in the workspace
/// or a virtual file representing an object in a database.
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// Contains the required parameters to initialize a connection to a database.
/// A connection will identified by its server name, database name and user name.
/// This may be changed in the future to support multiple connections with different
/// connection properties to the same database.
/// </summary>
public ConnectionDetails Connection { get; set; }
/// <summary>
/// The type of this connection. By default, this is set to ConnectionType.Default.
/// </summary>
public string Type { get; set; } = ConnectionType.Default;
/// <summary>
/// The porpose of the connection to keep track of open connections
/// </summary>
public string Purpose { get; set; } = ConnectionType.GeneralConnection;
}
}

View File

@@ -0,0 +1,48 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Extension methods to ConnectParams
/// </summary>
public static class ConnectParamsExtensions
{
/// <summary>
/// Check that the fields in ConnectParams are all valid
/// </summary>
public static bool IsValid(this ConnectParams parameters, out string errorMessage)
{
errorMessage = string.Empty;
if (string.IsNullOrEmpty(parameters.OwnerUri))
{
errorMessage = SR.ConnectionParamsValidateNullOwnerUri;
}
else if (parameters.Connection == null)
{
errorMessage = SR.ConnectionParamsValidateNullConnection;
}
else if (!string.IsNullOrEmpty(parameters.Connection.ConnectionString))
{
// Do not check other connection parameters if a connection string is present
return string.IsNullOrEmpty(errorMessage);
}
else if (string.IsNullOrEmpty(parameters.Connection.ServerName))
{
errorMessage = SR.ConnectionParamsValidateNullServerName;
}
else if (string.IsNullOrEmpty(parameters.Connection.AuthenticationType) || parameters.Connection.AuthenticationType == "SqlLogin")
{
// For SqlLogin, username cannot be empty
if (string.IsNullOrEmpty(parameters.Connection.UserName))
{
errorMessage = SR.ConnectionParamsValidateNullSqlAuth("UserName");
}
}
return string.IsNullOrEmpty(errorMessage);
}
}
}

View File

@@ -0,0 +1,19 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// ConnectionChanged notification mapping entry
/// </summary>
public class ConnectionChangedNotification
{
public static readonly
EventType<ConnectionChangedParams> Type =
EventType<ConnectionChangedParams>.Create("connection/connectionchanged");
}
}

View File

@@ -0,0 +1,23 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Parameters for the ConnectionChanged Notification.
/// </summary>
public class ConnectionChangedParams
{
/// <summary>
/// A URI identifying the owner of the connection. This will most commonly be a file in the workspace
/// or a virtual file representing an object in a database.
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// Contains the high-level properties about the connection, for display to the user.
/// </summary>
public ConnectionSummary Connection { get; set; }
}
}

View File

@@ -0,0 +1,66 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Parameters to be sent back with a connection complete event
/// </summary>
public class ConnectionCompleteParams
{
/// <summary>
/// A URI identifying the owner of the connection. This will most commonly be a file in the workspace
/// or a virtual file representing an object in a database.
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// A GUID representing a unique connection ID
/// </summary>
public string ConnectionId { get; set; }
/// <summary>
/// Gets or sets any detailed connection error messages.
/// </summary>
public string Messages { get; set; }
/// <summary>
/// Error message returned from the engine for a connection failure reason, if any.
/// </summary>
public string ErrorMessage { get; set; }
/// <summary>
/// Error number returned from the engine for connection failure reason, if any.
/// </summary>
public int ErrorNumber { get; set; }
/// <summary>
/// Information about the connected server.
/// </summary>
public ServerInfo ServerInfo { get; set; }
/// <summary>
/// Gets or sets the actual Connection established, including Database Name
/// </summary>
public ConnectionSummary ConnectionSummary { get; set; }
/// <summary>
/// The type of connection that this notification is for
/// </summary>
public string Type { get; set; } = ConnectionType.Default;
}
/// <summary>
/// ConnectionComplete notification mapping entry
/// </summary>
public class ConnectionCompleteNotification
{
public static readonly
EventType<ConnectionCompleteParams> Type =
EventType<ConnectionCompleteParams>.Create("connection/complete");
}
}

View File

@@ -0,0 +1,540 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.Kusto.ServiceLayer.Utility;
using Microsoft.SqlTools.Utility;
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Message format for the initial connection request
/// </summary>
/// <remarks>
/// If this contract is ever changed, be sure to update ConnectionDetailsExtensions methods.
/// </remarks>
public class ConnectionDetails : GeneralRequestDetails, IConnectionSummary
{
public ConnectionDetails() : base()
{
}
/// <summary>
/// Gets or sets the connection password
/// </summary>
public string Password
{
get
{
return GetOptionValue<string>("password");
}
set
{
SetOptionValue("password", value);
}
}
/// <summary>
/// Gets or sets the connection server name
/// </summary>
public string ServerName
{
get
{
return GetOptionValue<string>("server");
}
set
{
SetOptionValue("server", value);
}
}
/// <summary>
/// Gets or sets the connection database name
/// </summary>
public string DatabaseName
{
get
{
return GetOptionValue<string>("database");
}
set
{
SetOptionValue("database", value);
}
}
/// <summary>
/// Gets or sets the connection user name
/// </summary>
public string UserName
{
get
{
return GetOptionValue<string>("user");
}
set
{
SetOptionValue("user", value);
}
}
/// <summary>
/// Gets or sets the authentication to use.
/// </summary>
public string AuthenticationType
{
get
{
return GetOptionValue<string>("authenticationType");
}
set
{
SetOptionValue("authenticationType", value);
}
}
/// <summary>
/// Gets or sets a Boolean value that indicates whether SQL Server uses SSL encryption for all data sent between the client and server if the server has a certificate installed.
/// </summary>
public bool? Encrypt
{
get
{
return GetOptionValue<bool?>("encrypt");
}
set
{
SetOptionValue("encrypt", value);
}
}
/// <summary>
/// Gets or sets a value that indicates whether the channel will be encrypted while bypassing walking the certificate chain to validate trust.
/// </summary>
public bool? TrustServerCertificate
{
get
{
return GetOptionValue<bool?>("trustServerCertificate");
}
set
{
SetOptionValue("trustServerCertificate", value);
}
}
/// <summary>
/// Gets or sets a Boolean value that indicates if security-sensitive information, such as the password, is not returned as part of the connection if the connection is open or has ever been in an open state.
/// </summary>
public bool? PersistSecurityInfo
{
get
{
return GetOptionValue<bool?>("persistSecurityInfo");
}
set
{
SetOptionValue("persistSecurityInfo", value);
}
}
/// <summary>
/// Gets or sets the length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error.
/// </summary>
public int? ConnectTimeout
{
get
{
return GetOptionValue<int?>("connectTimeout");
}
set
{
SetOptionValue("connectTimeout", value);
}
}
/// <summary>
/// The number of reconnections attempted after identifying that there was an idle connection failure.
/// </summary>
public int? ConnectRetryCount
{
get
{
return GetOptionValue<int?>("connectRetryCount");
}
set
{
SetOptionValue("connectRetryCount", value);
}
}
/// <summary>
/// Amount of time (in seconds) between each reconnection attempt after identifying that there was an idle connection failure.
/// </summary>
public int? ConnectRetryInterval
{
get
{
return GetOptionValue<int?>("connectRetryInterval");
}
set
{
SetOptionValue("connectRetryInterval", value);
}
}
/// <summary>
/// Gets or sets the name of the application associated with the connection string.
/// </summary>
public string ApplicationName
{
get
{
return GetOptionValue<string>("applicationName");
}
set
{
SetOptionValue("applicationName", value);
}
}
/// <summary>
/// Gets or sets the name of the workstation connecting to SQL Server.
/// </summary>
public string WorkstationId
{
get
{
return GetOptionValue<string>("workstationId");
}
set
{
SetOptionValue("workstationId", value);
}
}
/// <summary>
/// Declares the application workload type when connecting to a database in an SQL Server Availability Group.
/// </summary>
public string ApplicationIntent
{
get
{
return GetOptionValue<string>("applicationIntent");
}
set
{
SetOptionValue("applicationIntent", value);
}
}
/// <summary>
/// Gets or sets the SQL Server Language record name.
/// </summary>
public string CurrentLanguage
{
get
{
return GetOptionValue<string>("currentLanguage");
}
set
{
SetOptionValue("currentLanguage", value);
}
}
/// <summary>
/// Gets or sets a Boolean value that indicates whether the connection will be pooled or explicitly opened every time that the connection is requested.
/// </summary>
public bool? Pooling
{
get
{
return GetOptionValue<bool?>("pooling");
}
set
{
SetOptionValue("pooling", value);
}
}
/// <summary>
/// Gets or sets the maximum number of connections allowed in the connection pool for this specific connection string.
/// </summary>
public int? MaxPoolSize
{
get
{
return GetOptionValue<int?>("maxPoolSize");
}
set
{
SetOptionValue("maxPoolSize", value);
}
}
/// <summary>
/// Gets or sets the minimum number of connections allowed in the connection pool for this specific connection string.
/// </summary>
public int? MinPoolSize
{
get
{
return GetOptionValue<int?>("minPoolSize");
}
set
{
SetOptionValue("minPoolSize", value);
}
}
/// <summary>
/// Gets or sets the minimum time, in seconds, for the connection to live in the connection pool before being destroyed.
/// </summary>
public int? LoadBalanceTimeout
{
get
{
return GetOptionValue<int?>("loadBalanceTimeout");
}
set
{
SetOptionValue("loadBalanceTimeout", value);
}
}
/// <summary>
/// Gets or sets a Boolean value that indicates whether replication is supported using the connection.
/// </summary>
public bool? Replication
{
get
{
return GetOptionValue<bool?>("replication");
}
set
{
SetOptionValue("replication", value);
}
}
/// <summary>
/// Gets or sets a string that contains the name of the primary data file. This includes the full path name of an attachable database.
/// </summary>
public string AttachDbFilename
{
get
{
return GetOptionValue<string>("attachDbFilename");
}
set
{
SetOptionValue("attachDbFilename", value);
}
}
/// <summary>
/// Gets or sets the name or address of the partner server to connect to if the primary server is down.
/// </summary>
public string FailoverPartner
{
get
{
return GetOptionValue<string>("failoverPartner");
}
set
{
SetOptionValue("failoverPartner", value);
}
}
/// <summary>
/// If your application is connecting to an AlwaysOn availability group (AG) on different subnets, setting MultiSubnetFailover=true provides faster detection of and connection to the (currently) active server.
/// </summary>
public bool? MultiSubnetFailover
{
get
{
return GetOptionValue<bool?>("multiSubnetFailover");
}
set
{
SetOptionValue("multiSubnetFailover", value);
}
}
/// <summary>
/// When true, an application can maintain multiple active result sets (MARS).
/// </summary>
public bool? MultipleActiveResultSets
{
get
{
return GetOptionValue<bool?>("multipleActiveResultSets");
}
set
{
SetOptionValue("multipleActiveResultSets", value);
}
}
/// <summary>
/// Gets or sets the size in bytes of the network packets used to communicate with an instance of SQL Server.
/// </summary>
public int? PacketSize
{
get
{
return GetOptionValue<int?>("packetSize");
}
set
{
SetOptionValue("packetSize", value);
}
}
/// <summary>
/// Gets or sets the port to use for the TCP/IP connection
/// </summary>
public int? Port
{
get
{
return GetOptionValue<int?>("port");
}
set
{
SetOptionValue("port", value);
}
}
/// <summary>
/// Gets or sets a string value that indicates the type system the application expects.
/// </summary>
public string TypeSystemVersion
{
get
{
return GetOptionValue<string>("typeSystemVersion");
}
set
{
SetOptionValue("typeSystemVersion", value);
}
}
/// <summary>
/// Gets or sets a string value to be used as the connection string. If given, all other options will be ignored.
/// </summary>
public string ConnectionString
{
get
{
return GetOptionValue<string>("connectionString");
}
set
{
SetOptionValue("connectionString", value);
}
}
/// <summary>
/// Gets or sets the group ID
/// </summary>
public string GroupId
{
get
{
return GetOptionValue<string>("groupId");
}
set
{
SetOptionValue("groupId", value);
}
}
/// <summary>
/// Gets or sets the database display name
/// </summary>
public string DatabaseDisplayName
{
get
{
return GetOptionValue<string>("databaseDisplayName");
}
set
{
SetOptionValue("databaseDisplayName", value);
}
}
public string AzureAccountToken
{
get
{
return GetOptionValue<string>("azureAccountToken");
}
set
{
SetOptionValue("azureAccountToken", value);
}
}
public bool IsComparableTo(ConnectionDetails other)
{
if (other == null)
{
return false;
}
if (ServerName != other.ServerName
|| AuthenticationType != other.AuthenticationType
|| UserName != other.UserName
|| AzureAccountToken != other.AzureAccountToken)
{
return false;
}
// For database name, only compare if neither is empty. This is important
// Since it allows for handling of connections to the default database, but is
// not a 100% accurate heuristic.
if (!string.IsNullOrEmpty(DatabaseName)
&& !string.IsNullOrEmpty(other.DatabaseName)
&& DatabaseName != other.DatabaseName)
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,52 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Extension methods for the ConnectionDetails contract class
/// </summary>
public static class ConnectionDetailsExtensions
{
/// <summary>
/// Create a copy of a connection details object.
/// </summary>
public static ConnectionDetails Clone(this ConnectionDetails details)
{
return new ConnectionDetails()
{
ServerName = details.ServerName,
DatabaseName = details.DatabaseName,
UserName = details.UserName,
Password = details.Password,
AuthenticationType = details.AuthenticationType,
Encrypt = details.Encrypt,
TrustServerCertificate = details.TrustServerCertificate,
PersistSecurityInfo = details.PersistSecurityInfo,
ConnectTimeout = details.ConnectTimeout,
ConnectRetryCount = details.ConnectRetryCount,
ConnectRetryInterval = details.ConnectRetryInterval,
ApplicationName = details.ApplicationName,
WorkstationId = details.WorkstationId,
ApplicationIntent = details.ApplicationIntent,
CurrentLanguage = details.CurrentLanguage,
Pooling = details.Pooling,
MaxPoolSize = details.MaxPoolSize,
MinPoolSize = details.MinPoolSize,
LoadBalanceTimeout = details.LoadBalanceTimeout,
Replication = details.Replication,
AttachDbFilename = details.AttachDbFilename,
FailoverPartner = details.FailoverPartner,
MultiSubnetFailover = details.MultiSubnetFailover,
MultipleActiveResultSets = details.MultipleActiveResultSets,
PacketSize = details.PacketSize,
TypeSystemVersion = details.TypeSystemVersion,
ConnectionString = details.ConnectionString,
Port = details.Port,
AzureAccountToken = details.AzureAccountToken
};
}
}
}

View File

@@ -0,0 +1,19 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Connect request mapping entry
/// </summary>
public class ConnectionRequest
{
public static readonly
RequestType<ConnectParams, bool> Type =
RequestType<ConnectParams, bool>.Create("connection/connect");
}
}

View File

@@ -0,0 +1,48 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
public interface IConnectionSummary
{
/// <summary>
/// Gets or sets the connection server name
/// </summary>
string ServerName { get; set; }
/// <summary>
/// Gets or sets the connection database name
/// </summary>
string DatabaseName { get; set; }
/// <summary>
/// Gets or sets the connection user name
/// </summary>
string UserName { get; set; }
}
/// <summary>
/// Provides high level information about a connection.
/// </summary>
public class ConnectionSummary : IConnectionSummary
{
/// <summary>
/// Gets or sets the connection server name
/// </summary>
public virtual string ServerName { get; set; }
/// <summary>
/// Gets or sets the connection database name
/// </summary>
public virtual string DatabaseName { get; set; }
/// <summary>
/// Gets or sets the connection user name
/// </summary>
public virtual string UserName { get; set; }
}
}

View File

@@ -0,0 +1,53 @@
//
// 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;
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Treats connections as the same if their server, db and usernames all match
/// </summary>
public class ConnectionSummaryComparer : IEqualityComparer<ConnectionSummary>
{
public bool Equals(ConnectionSummary x, ConnectionSummary y)
{
if(x == y) { return true; }
else if(x != null)
{
if(y == null) { return false; }
// Compare server, db, username. Note: server is case-insensitive in the driver
return string.Compare(x.ServerName, y.ServerName, StringComparison.OrdinalIgnoreCase) == 0
&& string.Compare(x.DatabaseName, y.DatabaseName, StringComparison.Ordinal) == 0
&& string.Compare(x.UserName, y.UserName, StringComparison.Ordinal) == 0;
}
return false;
}
public int GetHashCode(ConnectionSummary obj)
{
int hashcode = 31;
if(obj != null)
{
if(obj.ServerName != null)
{
hashcode ^= obj.ServerName.GetHashCode();
}
if (obj.DatabaseName != null)
{
hashcode ^= obj.DatabaseName.GetHashCode();
}
if (obj.UserName != null)
{
hashcode ^= obj.UserName.GetHashCode();
}
}
return hashcode;
}
}
}

View File

@@ -0,0 +1,26 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Extension methods to ConnectionSummary
/// </summary>
public static class ConnectionSummaryExtensions
{
/// <summary>
/// Create a copy of a ConnectionSummary object
/// </summary>
public static ConnectionSummary Clone(this IConnectionSummary summary)
{
return new ConnectionSummary()
{
ServerName = summary.ServerName,
DatabaseName = summary.DatabaseName,
UserName = summary.UserName
};
}
}
}

View File

@@ -0,0 +1,25 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Parameters for the Disconnect Request.
/// </summary>
public class DisconnectParams
{
/// <summary>
/// A URI identifying the owner of the connection. This will most commonly be a file in the workspace
/// or a virtual file representing an object in a database.
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// The type of connection we are disconnecting. If null, we will disconnect all connections.
/// connections.
/// </summary>
public string Type { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Disconnect request mapping entry
/// </summary>
public class DisconnectRequest
{
public static readonly
RequestType<DisconnectParams, bool> Type =
RequestType<DisconnectParams, bool>.Create("connection/disconnect");
}
}

View File

@@ -0,0 +1,23 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Parameters for the Get Connection String Request.
/// </summary>
public class GetConnectionStringParams
{
/// <summary>
/// URI of the owner of the connection
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// Indicates whether the password should be return in the connection string
/// </summary>
public bool IncludePassword { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Get Connection String request
/// </summary>
public class GetConnectionStringRequest
{
public static readonly
RequestType<GetConnectionStringParams, string> Type =
RequestType<GetConnectionStringParams, string>.Create("connection/getconnectionstring");
}
}

View File

@@ -0,0 +1,42 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Parameters for the Language Flavor Change notification.
/// </summary>
public class LanguageFlavorChangeParams
{
/// <summary>
/// A URI identifying the affected resource
/// </summary>
public string Uri { get; set; }
/// <summary>
/// The primary language
/// </summary>
public string Language { get; set; }
/// <summary>
/// The specific language flavor that is being set
/// </summary>
public string Flavor { get; set; }
}
/// <summary>
/// Defines an event that is sent from the client to notify that
/// the client is exiting and the server should as well.
/// </summary>
public class LanguageFlavorChangeNotification
{
public static readonly
EventType<LanguageFlavorChangeParams> Type =
EventType<LanguageFlavorChangeParams>.Create("connection/languageflavorchanged");
}
}

View File

@@ -0,0 +1,23 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Parameters for the List Databases Request.
/// </summary>
public class ListDatabasesParams
{
/// <summary>
/// URI of the owner of the connection requesting the list of databases.
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// whether to include the details of the databases. Called by manage dashboard
/// </summary>
public bool? IncludeDetails { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
//
// 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.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// List databases request mapping entry
/// </summary>
public class ListDatabasesRequest
{
public static readonly
RequestType<ListDatabasesParams, ListDatabasesResponse> Type =
RequestType<ListDatabasesParams, ListDatabasesResponse>.Create("connection/listdatabases");
}
}

View File

@@ -0,0 +1,24 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.Kusto.ServiceLayer.Admin.Contracts;
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Message format for the list databases response
/// </summary>
public class ListDatabasesResponse
{
/// <summary>
/// Gets or sets the list of database names.
/// </summary>
public string[] DatabaseNames { get; set; }
/// <summary>
/// Gets or sets the databases details.
/// </summary>
public DatabaseInfo[] Databases { get; set; }
}
}

View File

@@ -0,0 +1,75 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts
{
/// <summary>
/// Contract for information on the connected SQL Server instance.
/// </summary>
public class ServerInfo
{
/// <summary>
/// The major version of the SQL Server instance.
/// </summary>
public int ServerMajorVersion { get; set; }
/// <summary>
/// The minor version of the SQL Server instance.
/// </summary>
public int ServerMinorVersion { get; set; }
/// <summary>
/// The build of the SQL Server instance.
/// </summary>
public int ServerReleaseVersion { get; set; }
/// <summary>
/// The ID of the engine edition of the SQL Server instance.
/// </summary>
public int EngineEditionId { get; set; }
/// <summary>
/// String containing the full server version text.
/// </summary>
public string ServerVersion { get; set; }
/// <summary>
/// String describing the product level of the server.
/// </summary>
public string ServerLevel { get; set; }
/// <summary>
/// The edition of the SQL Server instance.
/// </summary>
public string ServerEdition { get; set; }
/// <summary>
/// Whether the SQL Server instance is running in the cloud (Azure) or not.
/// </summary>
public bool IsCloud { get; set; }
/// <summary>
/// The version of Azure that the SQL Server instance is running on, if applicable.
/// </summary>
public int AzureVersion { get; set; }
/// <summary>
/// The Operating System version string of the machine running the SQL Server instance.
/// </summary>
public string OsVersion { get; set; }
/// <summary>
/// The Operating System version string of the machine running the SQL Server instance.
/// </summary>
public string MachineName { get; set; }
/// <summary>
/// Server options
/// </summary>
public Dictionary<string, object> Options { get; set; }
}
}

View File

@@ -0,0 +1,29 @@
//
// 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.Common;
using Microsoft.Kusto.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
namespace Microsoft.Kusto.ServiceLayer.Connection
{
/// <summary>
/// Factory class to create SqlClientConnections
/// The purpose of the factory is to make it easier to mock out the database
/// in 'offline' unit test scenarios.
/// </summary>
public class DataSourceConnectionFactory : IDataSourceConnectionFactory
{
/// <summary>
/// Creates a new SqlConnection object
/// </summary>
public ReliableDataSourceConnection CreateDataSourceConnection(string connectionString, string azureAccountToken)
{
RetryPolicy connectionRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy();
RetryPolicy commandRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy();
return new ReliableDataSourceConnection(connectionString, connectionRetryPolicy, commandRetryPolicy, azureAccountToken);
}
}
}

View File

@@ -0,0 +1,28 @@
//
// 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.Kusto.ServiceLayer.Connection
{
public class DatabaseFullAccessException: Exception
{
public DatabaseFullAccessException()
: base()
{
}
public DatabaseFullAccessException(string message, Exception exception)
: base(message, exception)
{
}
public DatabaseFullAccessException(string message)
: base(message)
{
}
}
}

View File

@@ -0,0 +1,114 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.Kusto.ServiceLayer.LanguageServices;
using System;
using System.Collections.Generic;
using System.Threading;
namespace Microsoft.Kusto.ServiceLayer.Connection
{
public class DatabaseLocksManager: IDisposable
{
internal DatabaseLocksManager(int waitToGetFullAccess)
{
this.waitToGetFullAccess = waitToGetFullAccess;
}
private static DatabaseLocksManager instance = new DatabaseLocksManager(DefaultWaitToGetFullAccess);
public static DatabaseLocksManager Instance
{
get
{
return instance;
}
}
public ConnectionService ConnectionService { get; set; }
private Dictionary<string, ManualResetEvent> databaseAccessEvents = new Dictionary<string, ManualResetEvent>();
private object databaseAccessLock = new object();
public const int DefaultWaitToGetFullAccess = 10000;
public int waitToGetFullAccess = DefaultWaitToGetFullAccess;
private ManualResetEvent GetResetEvent(string serverName, string databaseName)
{
string key = GenerateKey(serverName, databaseName);
ManualResetEvent resetEvent = null;
lock (databaseAccessLock)
{
if (!databaseAccessEvents.TryGetValue(key, out resetEvent))
{
resetEvent = new ManualResetEvent(true);
databaseAccessEvents.Add(key, resetEvent);
}
}
return resetEvent;
}
public bool GainFullAccessToDatabase(string serverName, string databaseName)
{
/*
* TODO: add the lock so not two process can get full access at the same time
ManualResetEvent resetEvent = GetResetEvent(serverName, databaseName);
if (resetEvent.WaitOne(this.waitToGetFullAccess))
{
resetEvent.Reset();
foreach (IConnectedBindingQueue item in ConnectionService.ConnectedQueues)
{
item.CloseConnections(serverName, databaseName);
}
return true;
}
else
{
throw new DatabaseFullAccessException($"Waited more than {waitToGetFullAccess} milli seconds for others to release the lock");
}
*/
foreach (IConnectedBindingQueue item in ConnectionService.ConnectedQueues)
{
item.CloseConnections(serverName, databaseName, DefaultWaitToGetFullAccess);
}
return true;
}
public bool ReleaseAccess(string serverName, string databaseName)
{
/*
ManualResetEvent resetEvent = GetResetEvent(serverName, databaseName);
foreach (IConnectedBindingQueue item in ConnectionService.ConnectedQueues)
{
item.OpenConnections(serverName, databaseName);
}
resetEvent.Set();
*/
foreach (IConnectedBindingQueue item in ConnectionService.ConnectedQueues)
{
item.OpenConnections(serverName, databaseName, DefaultWaitToGetFullAccess);
}
return true;
}
private string GenerateKey(string serverName, string databaseName)
{
return $"{serverName.ToLowerInvariant()}-{databaseName.ToLowerInvariant()}";
}
public void Dispose()
{
foreach (var resetEvent in databaseAccessEvents)
{
resetEvent.Value.Dispose();
}
}
}
}

View File

@@ -0,0 +1,40 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.Kusto.ServiceLayer.Connection
{
/// <summary>
/// Any operation that needs full access to databas should implement this interface.
/// Make sure to call GainAccessToDatabase before the operation and ReleaseAccessToDatabase after
/// </summary>
public interface IFeatureWithFullDbAccess
{
/// <summary>
/// Database Lock Manager
/// </summary>
DatabaseLocksManager LockedDatabaseManager { get; set; }
/// <summary>
/// Makes sure the feature has fill access to the database
/// </summary>
bool GainAccessToDatabase();
/// <summary>
/// Release the access to db
/// </summary>
bool ReleaseAccessToDatabase();
/// <summary>
/// Server name
/// </summary>
string ServerName { get; }
/// <summary>
/// Database name
/// </summary>
string DatabaseName { get; }
}
}

View File

@@ -0,0 +1,20 @@
//
// 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.Common;
namespace Microsoft.Kusto.ServiceLayer.Connection
{
/// <summary>
/// Interface for the SQL Connection factory
/// </summary>
public interface IDataSourceConnectionFactory
{
/// <summary>
/// Create a new SQL Connection object
/// </summary>
ReliableDataSourceConnection CreateDataSourceConnection(string connectionString, string azureAccountToken);
}
}

View File

@@ -0,0 +1,58 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// This code is copied from the source described in the comment below.
// =======================================================================================
// Microsoft Windows Server AppFabric Customer Advisory Team (CAT) Best Practices Series
//
// This sample is supplemental to the technical guidance published on the community
// blog at http://blogs.msdn.com/appfabriccat/ and copied from
// sqlmain ./sql/manageability/mfx/common/
//
// =======================================================================================
// Copyright © 2012 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. YOU BEAR THE RISK OF USING IT.
// =======================================================================================
using System;
namespace Microsoft.Kusto.ServiceLayer.Connection.ReliableConnection
{
/// <summary>
/// Defines a arguments for event handler which will be invoked whenever a retry condition is encountered.
/// </summary>
internal sealed class RetryCallbackEventArgs : EventArgs
{
private readonly int _retryCount;
private readonly Exception _exception;
private readonly TimeSpan _delay;
public RetryCallbackEventArgs(int retryCount, Exception exception, TimeSpan delay)
{
_retryCount = retryCount;
_exception = exception;
_delay = delay;
}
public TimeSpan Delay
{
get { return _delay; }
}
public Exception Exception
{
get { return _exception; }
}
public int RetryCount
{
get { return _retryCount; }
}
}
}

View File

@@ -0,0 +1,59 @@
// <copyright file="KustoQueryUtils.cs" company="Microsoft">
// Copyright (c) Microsoft. All Rights Reserved.
// </copyright>
using System;
using System.Text.RegularExpressions;
using System.Linq;
using System.Data;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
class DataReaderWrapper:IDataReader
{
private readonly IDataReader _inner ;
public DataReaderWrapper(IDataReader inner)
{
_inner = inner;
}
public object this[int i] => _inner[i];
public object this[string name] => _inner[name];
public int Depth => _inner.Depth;
public bool IsClosed => _inner.IsClosed;
public int RecordsAffected => _inner.RecordsAffected;
public int FieldCount => _inner.FieldCount;
public void Close() => _inner.Close();
public void Dispose() => _inner.Dispose();
public bool GetBoolean(int i) => _inner.GetBoolean(i);
public byte GetByte(int i) => _inner.GetByte(i);
public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) => _inner.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
public char GetChar(int i) => _inner.GetChar(i);
public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) => _inner.GetChars(i, fieldoffset, buffer, bufferoffset, length);
public IDataReader GetData(int i) => _inner.GetData(i);
public string GetDataTypeName(int i) => _inner.GetDataTypeName(i);
public DateTime GetDateTime(int i) => _inner.GetDateTime(i);
public decimal GetDecimal(int i) => _inner.GetDecimal(i);
public double GetDouble(int i) => _inner.GetDouble(i);
public Type GetFieldType(int i) => _inner.GetFieldType(i);
public float GetFloat(int i) => _inner.GetFloat(i);
public Guid GetGuid(int i) => _inner.GetGuid(i);
public short GetInt16(int i) => _inner.GetInt16(i);
public int GetInt32(int i) => _inner.GetInt32(i);
public long GetInt64(int i) => _inner.GetInt64(i);
public string GetName(int i) => _inner.GetName(i);
public int GetOrdinal(string name) => _inner.GetOrdinal(name);
public DataTable GetSchemaTable() => _inner.GetSchemaTable();
public string GetString(int i) => _inner.GetString(i);
public object GetValue(int i) => _inner.GetValue(i);
public int GetValues(object[] values) => _inner.GetValues(values);
public bool IsDBNull(int i) => _inner.IsDBNull(i);
public virtual bool NextResult() => _inner.NextResult();
public bool Read() => _inner.Read();
}
}

View File

@@ -0,0 +1,132 @@
// <copyright file="DataSourceUtils.cs" company="Microsoft">
// Copyright (c) Microsoft. All Rights Reserved.
// </copyright>
using System;
using System.Collections.Generic;
using System.Threading;
using System.Data;
using System.Threading.Tasks;
using Microsoft.Kusto.ServiceLayer.Utility;
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
/// <inheritdoc cref="IDataSource"/>
public abstract class DataSourceBase : IDataSource
{
protected Object dataSourceLock = new Object();
private string _database;
#region IDisposable
/// <summary>
/// Finalizes an instance of the <see cref="DataSourceBase"/> class.
/// </summary>
~DataSourceBase()
{
Dispose(false);
}
/// <summary>
/// Disposes resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes resources.
/// </summary>
/// <param name="disposing">true if disposing; false if finalizing.</param>
protected virtual void Dispose(bool disposing)
{
}
#endregion
#region IDataSource
/// <inheritdoc/>
public abstract Task<IDataReader> ExecuteQueryAsync(string query, CancellationToken cancellationToken, string databaseName = null);
/// <inheritdoc/>
public async Task<T> ExecuteScalarQueryAsync<T>(string query, CancellationToken cancellationToken, string databaseName = null)
{
ValidationUtils.IsArgumentNotNullOrWhiteSpace(query, nameof(query));
using (var records = await ExecuteQueryAsync(query, cancellationToken, databaseName))
{
return records.ToScalar<T>();
}
}
public abstract Task<IEnumerable<T>> ExecuteControlCommandAsync<T>(string command, bool throwOnError, CancellationToken cancellationToken);
/// <inheritdoc/>
public abstract DiagnosticsInfo GetDiagnostics(DataSourceObjectMetadata parentMetadata);
/// <inheritdoc/>
public abstract IEnumerable<DataSourceObjectMetadata> GetChildObjects(DataSourceObjectMetadata parentMetadata, bool includeSizeDetails = false);
/// <inheritdoc/>
public abstract void Refresh();
/// <inheritdoc/>
public abstract void Refresh(DataSourceObjectMetadata objectMetadata);
/// <inheritdoc/>
public abstract void UpdateDatabase(string databaseName);
/// <inheritdoc/>
public abstract CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo queryText, Position index, bool throwOnError = false);
/// <inheritdoc/>
public abstract Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false);
/// <inheritdoc/>
public abstract DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false);
/// <inheritdoc/>
public abstract ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText);
/// <inheritdoc/>
public abstract Task<bool> Exists();
/// <inheritdoc/>
public abstract bool Exists(DataSourceObjectMetadata objectMetadata);
public abstract string GenerateAlterFunctionScript(string functionName);
/// <inheritdoc/>
public DataSourceType DataSourceType { get; protected set; }
/// <inheritdoc/>
public string ClusterName { get; protected set; }
/// <inheritdoc/>
public string DatabaseName {
get
{
return _database;
}
set
{
lock(dataSourceLock)
{
_database = value;
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Kusto.ServiceLayer.Utility;
using Microsoft.Kusto.ServiceLayer.Admin.Contracts;
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
using Microsoft.Kusto.ServiceLayer.Metadata.Contracts;
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
/// <summary>
/// Data source factory.
/// </summary>
public static class DataSourceFactory
{
public static IDataSource Create(DataSourceType dataSourceType, string connectionString, string azureAccountToken)
{
ValidationUtils.IsArgumentNotNullOrWhiteSpace(connectionString, nameof(connectionString));
ValidationUtils.IsArgumentNotNullOrWhiteSpace(azureAccountToken, nameof(azureAccountToken));
switch (dataSourceType)
{
case DataSourceType.Kusto:
{
return new KustoDataSource(connectionString, azureAccountToken);
}
default:
throw new ArgumentException($"Unsupported data source type \"{dataSourceType}\"", nameof(dataSourceType));
}
}
public static DataSourceObjectMetadata CreateClusterMetadata(string clusterName)
{
ValidationUtils.IsArgumentNotNullOrWhiteSpace(clusterName, nameof(clusterName));
return new DataSourceObjectMetadata{
MetadataType = DataSourceMetadataType.Cluster,
MetadataTypeName = DataSourceMetadataType.Cluster.ToString(),
Name = clusterName,
PrettyName = clusterName,
Urn = $"{clusterName}"
};
}
public static DataSourceObjectMetadata CreateDatabaseMetadata(DataSourceObjectMetadata clusterMetadata, string databaseName)
{
ValidationUtils.IsTrue<ArgumentException>(clusterMetadata.MetadataType == DataSourceMetadataType.Cluster, nameof(clusterMetadata));
ValidationUtils.IsArgumentNotNullOrWhiteSpace(databaseName, nameof(databaseName));
return new DatabaseMetadata{
ClusterName = clusterMetadata.Name,
MetadataType = DataSourceMetadataType.Database,
MetadataTypeName = DataSourceMetadataType.Database.ToString(),
Name = databaseName,
PrettyName = databaseName,
Urn = $"{clusterMetadata.Urn}.{databaseName}"
};
}
public static FolderMetadata CreateFolderMetadata(DataSourceObjectMetadata parentMetadata, string path, string name)
{
ValidationUtils.IsNotNull(parentMetadata, nameof(parentMetadata));
return new FolderMetadata{
MetadataType = DataSourceMetadataType.Folder,
MetadataTypeName = DataSourceMetadataType.Folder.ToString(),
Name = name,
PrettyName = name,
ParentMetadata = parentMetadata,
Urn = $"{path}.{name}"
};
}
// Gets default keywords for intellisense when there is no connection.
public static CompletionItem[] GetDefaultAutoComplete(DataSourceType dataSourceType, ScriptDocumentInfo scriptDocumentInfo, Position textDocumentPosition){
switch (dataSourceType)
{
case DataSourceType.Kusto:
{
return KustoIntellisenseHelper.GetDefaultKeywords(scriptDocumentInfo, textDocumentPosition);
}
default:
throw new ArgumentException($"Unsupported data source type \"{dataSourceType}\"", nameof(dataSourceType));
}
}
// Gets default keywords errors related to intellisense when there is no connection.
public static ScriptFileMarker[] GetDefaultSemanticMarkers(DataSourceType dataSourceType, ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText){
switch (dataSourceType)
{
case DataSourceType.Kusto:
{
return KustoIntellisenseHelper.GetDefaultDiagnostics(parseInfo, scriptFile, queryText);
}
default:
throw new ArgumentException($"Unsupported data source type \"{dataSourceType}\"", nameof(dataSourceType));
}
}
// Converts database details shown on cluster manage dashboard to DatabaseInfo type. Add DataSourceType as param if required to show different properties
public static List<DatabaseInfo> ConvertToDatabaseInfo(IEnumerable<DataSourceObjectMetadata> clusterDBDetails)
{
var databaseDetails = new List<DatabaseInfo>();
if(typeof(DatabaseMetadata) == clusterDBDetails.FirstOrDefault().GetType()){
foreach(var dbDetail in clusterDBDetails)
{
DatabaseInfo databaseInfo = new DatabaseInfo();
Int64.TryParse(dbDetail.SizeInMB.ToString(), out long sum_OriginalSize);
databaseInfo.Options["name"] = dbDetail.Name;
databaseInfo.Options["sizeInMB"] = (sum_OriginalSize /(1024 * 1024)).ToString();
databaseDetails.Add(databaseInfo);
}
}
return databaseDetails;
}
// Converts tables details shown on database manage dashboard to ObjectMetadata type. Add DataSourceType as param if required to show different properties
public static List<ObjectMetadata> ConvertToObjectMetadata(IEnumerable<DataSourceObjectMetadata> dbChildDetails)
{
var databaseChildDetails = new List<ObjectMetadata>();
foreach(var childDetail in dbChildDetails)
{
ObjectMetadata dbChildInfo = new ObjectMetadata();
dbChildInfo.Name = childDetail.PrettyName;
dbChildInfo.MetadataTypeName = childDetail.MetadataTypeName;
dbChildInfo.MetadataType = MetadataType.Table; // Add mapping here.
databaseChildDetails.Add(dbChildInfo);
}
return databaseChildDetails;
}
public static ReliableConnectionHelper.ServerInfo ConvertToServerinfoFormat(DataSourceType dataSourceType, DiagnosticsInfo clusterDiagnostics)
{
switch (dataSourceType)
{
case DataSourceType.Kusto:
{
ReliableConnectionHelper.ServerInfo serverInfo = new ReliableConnectionHelper.ServerInfo();
serverInfo.Options = new Dictionary<string, object>(clusterDiagnostics.Options);
return serverInfo;
}
default:
throw new ArgumentException($"Unsupported data source type \"{dataSourceType}\"", nameof(dataSourceType));
}
}
}
}

View File

@@ -0,0 +1,329 @@
//
// 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.Threading;
using System.Threading.Tasks;
using System.Linq;
using Kusto.Language;
using Kusto.Language.Editor;
using Kusto.Language.Syntax;
using Kusto.Language.Symbols;
using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
{
/// <summary>
/// Kusto specific class for intellisense helper functions.
/// </summary>
public static class KustoIntellisenseHelper
{
public class ShowDatabasesResult
{
public string DatabaseName;
public string PersistentStorage;
public string Version;
public bool IsCurrent;
public string DatabaseAccessMode;
public string PrettyName;
public bool CurrentUserIsUnrestrictedViewer;
public string DatabaseId;
}
public class ShowDatabaseSchemaResult
{
public string DatabaseName;
public string TableName;
public string ColumnName;
public string ColumnType;
public bool IsDefaultTable;
public bool IsDefaultColumn;
public string PrettyName;
public string Version;
public string Folder;
public string DocName;
}
public class ShowFunctionsResult
{
public string Name;
public string Parameters;
public string Body;
public string Folder;
public string DocString;
}
/// <summary>
/// Convert CLR type name into a Kusto scalar type.
/// </summary>
private static ScalarSymbol GetKustoType(string clrTypeName)
{
switch (clrTypeName)
{
case "System.Byte":
case "Byte":
case "byte":
case "System.SByte":
case "SByte":
case "sbyte":
case "System.Int16":
case "Int16":
case "short":
case "System.UInt16":
case "UInt16":
case "ushort":
case "System.Int32":
case "System.Single":
case "Int32":
case "int":
return ScalarTypes.Int;
case "System.UInt32": // unsigned ints don't fit into int, use long
case "UInt32":
case "uint":
case "System.Int64":
case "Int64":
case "long":
return ScalarTypes.Long;
case "System.Double":
case "Double":
case "double":
case "float":
return ScalarTypes.Real;
case "System.UInt64": // unsigned longs do not fit into long, use decimal
case "UInt64":
case "ulong":
case "System.Decimal":
case "Decimal":
case "decimal":
case "System.Data.SqlTypes.SqlDecimal":
case "SqlDecimal":
return ScalarTypes.Decimal;
case "System.Guid":
case "Guid":
return ScalarTypes.Guid;
case "System.DateTime":
case "DateTime":
return ScalarTypes.DateTime;
case "System.TimeSpan":
case "TimeSpan":
return ScalarTypes.TimeSpan;
case "System.String":
case "String":
case "string":
return ScalarTypes.String;
case "System.Boolean":
case "Boolean":
case "bool":
return ScalarTypes.Bool;
case "System.Object":
case "Object":
case "object":
return ScalarTypes.Dynamic;
case "System.Type":
case "Type":
return ScalarTypes.Type;
default:
throw new InvalidOperationException($"Unhandled clr type: {clrTypeName}");
}
}
private static IReadOnlyList<Parameter> NoParameters = new Parameter[0];
/// <summary>
/// Translate Kusto parameter list declaration into into list of <see cref="Parameter"/> instances.
/// </summary>
private static IReadOnlyList<Parameter> TranslateParameters(string parameters)
{
parameters = parameters.Trim();
if (string.IsNullOrEmpty(parameters) || parameters == "()")
return NoParameters;
if (parameters[0] != '(')
parameters = "(" + parameters;
if (parameters[parameters.Length - 1] != ')')
parameters = parameters + ")";
var query = "let fn = " + parameters + " { };";
var code = KustoCode.ParseAndAnalyze(query);
var let = code.Syntax.GetFirstDescendant<LetStatement>();
var variable = let.Name.ReferencedSymbol as VariableSymbol;
var function = variable.Type as FunctionSymbol;
return function.Signatures[0].Parameters;
}
/// <summary>
/// Loads the schema for the specified databasea into a a <see cref="DatabaseSymbol"/>.
/// </summary>
public static async Task<DatabaseSymbol> LoadDatabaseAsync(IDataSource dataSource, string databaseName, bool throwOnError = false)
{
var members = new List<Symbol>();
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken cancellationToken = source.Token;
var tableSchemas = await dataSource.ExecuteControlCommandAsync<ShowDatabaseSchemaResult>($".show database {databaseName} schema", throwOnError, cancellationToken).ConfigureAwait(false);
if (tableSchemas == null)
return null;
tableSchemas = tableSchemas
.Where(r => !string.IsNullOrEmpty(r.TableName) && !string.IsNullOrEmpty(r.ColumnName))
.ToArray();
foreach (var table in tableSchemas.GroupBy(s => s.TableName))
{
var columns = table.Select(s => new ColumnSymbol(s.ColumnName, GetKustoType(s.ColumnType))).ToList();
var tableSymbol = new TableSymbol(table.Key, columns);
members.Add(tableSymbol);
}
var functionSchemas = await dataSource.ExecuteControlCommandAsync<ShowFunctionsResult>(".show functions", throwOnError, cancellationToken).ConfigureAwait(false);
if (functionSchemas == null)
return null;
foreach (var fun in functionSchemas)
{
var parameters = TranslateParameters(fun.Parameters);
var functionSymbol = new FunctionSymbol(fun.Name, fun.Body, parameters);
members.Add(functionSymbol);
}
var databaseSymbol = new DatabaseSymbol(databaseName, members);
return databaseSymbol;
}
public static CompletionItemKind CreateCompletionItemKind(CompletionKind kustoKind)
{
CompletionItemKind kind = CompletionItemKind.Variable;
switch (kustoKind)
{
case CompletionKind.Syntax:
kind = CompletionItemKind.Module;
break;
case CompletionKind.Column:
kind = CompletionItemKind.Field;
break;
case CompletionKind.Variable:
kind = CompletionItemKind.Variable;
break;
case CompletionKind.Table:
kind = CompletionItemKind.File;
break;
case CompletionKind.Database:
kind = CompletionItemKind.Method;
break;
case CompletionKind.LocalFunction:
case CompletionKind.DatabaseFunction:
case CompletionKind.BuiltInFunction:
case CompletionKind.AggregateFunction:
kind = CompletionItemKind.Function;
break;
default:
kind = CompletionItemKind.Keyword;
break;
}
return kind;
}
/// <summary>
/// Gets default keyword when user if not connected to any Kusto cluster.
/// </summary>
public static LanguageServices.Contracts.CompletionItem[] GetDefaultKeywords(ScriptDocumentInfo scriptDocumentInfo, Position textDocumentPosition){
var kustoCodeService = new KustoCodeService(scriptDocumentInfo.Contents, GlobalState.Default);
var script = CodeScript.From(scriptDocumentInfo.Contents, GlobalState.Default);
script.TryGetTextPosition(textDocumentPosition.Line + 1, textDocumentPosition.Character, out int position); // Gets the actual offset based on line and local offset
var completion = kustoCodeService.GetCompletionItems(position);
List<LanguageServices.Contracts.CompletionItem> completions = new List<LanguageServices.Contracts.CompletionItem>();
foreach (var autoCompleteItem in completion.Items)
{
var label = autoCompleteItem.DisplayText;
// convert the completion item candidates into vscode format CompletionItems
completions.Add(AutoCompleteHelper.CreateCompletionItem(label, label + " keyword", label, CompletionItemKind.Keyword, scriptDocumentInfo.StartLine, scriptDocumentInfo.StartColumn, textDocumentPosition.Character));
}
return completions.ToArray();
}
/// <summary>
/// Gets default diagnostics when user if not connected to any Kusto cluster.
/// </summary>
public static ScriptFileMarker[] GetDefaultDiagnostics(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText){
var kustoCodeService = new KustoCodeService(queryText, GlobalState.Default);
var script = CodeScript.From(queryText, GlobalState.Default);
var parseResult = kustoCodeService.GetDiagnostics();
parseInfo.ParseResult = parseResult;
// build a list of Kusto script file markers from the errors.
List<ScriptFileMarker> markers = new List<ScriptFileMarker>();
if (parseResult != null && parseResult.Count() > 0)
{
foreach (var error in parseResult)
{
script.TryGetLineAndOffset(error.Start, out var startLine, out var startOffset);
script.TryGetLineAndOffset(error.End, out var endLine, out var endOffset);
// vscode specific format for error markers.
markers.Add(new ScriptFileMarker()
{
Message = error.Message,
Level = ScriptFileMarkerLevel.Error,
ScriptRegion = new ScriptRegion()
{
File = scriptFile.FilePath,
StartLineNumber = startLine,
StartColumnNumber = startOffset,
StartOffset = 0,
EndLineNumber = endLine,
EndColumnNumber = endOffset,
EndOffset = 0
}
});
}
}
return markers.ToArray();
}
/// <summary>
/// Loads the schema for the specified database and returns a new <see cref="GlobalState"/> with the database added or updated.
/// </summary>
public static async Task<GlobalState> AddOrUpdateDatabaseAsync(IDataSource dataSource, GlobalState globals, string databaseName, string clusterName, bool throwOnError)
{ // try and show error from here.
DatabaseSymbol databaseSymbol = null;
if(databaseName != null){
databaseSymbol = await LoadDatabaseAsync(dataSource, databaseName, throwOnError).ConfigureAwait(false);
}
if(databaseSymbol == null){
return globals;
}
var cluster = globals.GetCluster(clusterName);
if (cluster == null)
{
cluster = new ClusterSymbol(clusterName, new[] { databaseSymbol }, isOpen: true);
globals = globals.AddOrUpdateCluster(cluster);
}
else
{
cluster = cluster.AddOrUpdateDatabase(databaseSymbol);
globals = globals.AddOrUpdateCluster(cluster);
}
globals = globals.WithCluster(cluster).WithDatabase(databaseSymbol);
return globals;
}
}
}

View File

@@ -0,0 +1,48 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using Kusto.Language;
using Kusto.Language.Editor;
namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
{
/// <summary>
/// Data Source specific class for storing cached metadata regarding a parsed KQL file.
/// </summary>
public class ScriptParseInfo
{
private object buildingMetadataLock = new object();
/// <summary>
/// Event which tells if MetadataProvider is built fully or not
/// </summary>
public object BuildingMetadataLock
{
get { return this.buildingMetadataLock; }
}
/// <summary>
/// Gets or sets a flag determining is the LanguageService is connected
/// </summary>
public bool IsConnected { get; set; }
/// <summary>
/// Gets or sets the binding queue connection context key
/// </summary>
public string ConnectionKey { get; set; }
/// <summary>
/// Gets or sets the previous Kusto diagnostics result. TODOKusto: Check exact usage.
/// </summary>
public IReadOnlyList<Diagnostic> ParseResult { get; set; }
/// <summary>
/// Gets or sets the current autocomplete suggestion list retrieved from the Kusto language library.
/// So that other details like documentation can be later retrieved in ResolveCompletionItem.
/// </summary>
public IEnumerable<CompletionItem > CurrentSuggestions { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
/// <summary>
/// Represents the type of a data source.
/// </summary>
public enum DataSourceType
{
/// <summary>
/// Unknown.
/// </summary>
None,
/// <summary>
/// A Kusto cluster.
/// </summary>
Kusto,
/// <summary>
/// An Application Insights subscription.
/// </summary>
ApplicationInsights,
/// <summary>
/// An Operations Management Suite (OMS) Log Analytics workspace.
/// </summary>
OmsLogAnalytics
}
}

View File

@@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
public class DiagnosticsInfo
{
/// <summary>
/// Gets or sets the options
/// </summary>
public Dictionary<string, object> Options { get; set; }
public DiagnosticsInfo()
{
Options = new Dictionary<string, object>();
}
}
}

View File

@@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
/// <summary>
/// Represents data source utilities.
/// </summary>
public interface IDataSource : IDisposable
{
/// <summary>
/// The data source type.
/// </summary>
DataSourceType DataSourceType { get; }
/// <summary>
/// The cluster/server name.
/// </summary>
string ClusterName { get; }
/// <summary>
/// The current database name, if there is one.
/// </summary>
string DatabaseName { get; set; }
/// <summary>
/// Executes a query.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>The results.</returns>
Task<IDataReader> ExecuteQueryAsync(string query, CancellationToken cancellationToken, string databaseName = null);
/// <summary>
/// Executes a Kusto query that returns a scalar value.
/// </summary>
/// <typeparam name="T">The type of the result.</typeparam>
/// <param name="query">The query.</param>
/// <returns>The result.</returns>
Task<T> ExecuteScalarQueryAsync<T>(string query, CancellationToken cancellationToken, string databaseName = null);
/// <summary>
/// Executes a Kusto query that returns a scalar value.
/// </summary>
/// <typeparam name="T">The type of the result.</typeparam>
/// <param name="query">The query.</param>
/// <returns>The result.</returns>
Task<IEnumerable<T>> ExecuteControlCommandAsync<T>(string command, bool throwOnError, CancellationToken cancellationToken);
/// <summary>
/// Get children of the given parent
/// </summary>
/// <param name="parentMetadata">Parent object metadata.</param>
/// <returns>Metadata for all children.</returns>
DiagnosticsInfo GetDiagnostics(DataSourceObjectMetadata parentMetadata);
/// <summary>
/// Get children of the given parent
/// </summary>
/// <param name="parentMetadata">Parent object metadata.</param>
/// <param name="includeSizeDetails"></param>
/// <returns>Metadata for all children.</returns>
IEnumerable<DataSourceObjectMetadata> GetChildObjects(DataSourceObjectMetadata parentMetadata, bool includeSizeDetails = false);
/// <summary>
/// Refresh object list for entire cluster.
/// </summary>
void Refresh();
/// <summary>
/// Refresh object list for given object.
/// </summary>
/// <param name="objectMetadata">Object metadata.</param>
void Refresh(DataSourceObjectMetadata objectMetadata);
/// <summary>
/// Updates database and affected variables like GlobalState for given object.
/// </summary>
/// <param name="updateDatabase">Object metadata.</param>
void UpdateDatabase(string databaseName);
/// <summary>
/// Gets autocomplete suggestions at given position.
/// </summary>
/// <param name="GetAutoCompleteSuggestions">Object metadata.</param>
CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo queryText, Position index, bool throwOnError = false);
/// <summary>
/// Gets quick info hover tooltips for the current position.
/// </summary>
/// <param name="GetHoverHelp">Object metadata.</param>
Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false);
/// <summary>
/// Gets definition for a selected query text.
/// </summary>
/// <param name="GetDefinition">Object metadata.</param>
DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false);
/// <summary>
/// Gets a list of semantic diagnostic marks for the provided script file
/// </summary>
/// <param name="GetSemanticMarkers">Object metadata.</param>
ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText);
/// <summary>
/// Tells whether the data source exists.
/// </summary>
/// <returns>true if it exists; false otherwise.</returns>
Task<bool> Exists();
/// <summary>
/// Tells whether the object exists.
/// </summary>
/// <returns>true if it exists; false otherwise.</returns>
bool Exists(DataSourceObjectMetadata objectMetadata);
/// <summary>
/// Gets FunctionInfo object for a function
/// </summary>
/// <param name="functionName"></param>
/// <returns></returns>
string GenerateAlterFunctionScript(string functionName);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,115 @@
// <copyright file="KustoQueryUtils.cs" company="Microsoft">
// Copyright (c) Microsoft. All Rights Reserved.
// </copyright>
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
public static class KustoQueryUtils
{
public const string StatementSeparator = "\n | "; // Start each statement on a new line. Not required by Kusto, but doing this for readability of scripts generated from here.
/// <summary>
/// Escape table/column/database names for a Kusto query.
/// </summary>
/// <param name="name">The name to be escaped</param>
/// <param name="alwaysEscape">Always escape if this flag is set</param>
/// <returns>The escaped string</returns>
public static string EscapeName(string name, bool alwaysEscape = false)
{
if (name.StartsWith("[@") || name == "*") // Field already escaped. No escaping required for '*' operand
{
return name;
}
string result = name;
Regex rx = new Regex("[^_a-zA-Z0-9]");
string [] kustoKeywordList = {"and", "anomalychart", "areachart", "asc", "barchart", "between", "bool", "boolean", "by",
"columnchart", "consume", "contains", "containscs", "count", "date", "datetime", "default", "desc", "distinct",
"double", "dynamic", "endswith", "evaluate", "extend", "false", "filter", "find", "first", "flags", "float",
"getschema", "has", "hasprefix", "hassuffix", "in", "int", "join", "journal", "kind", "ladderchart", "last",
"like", "limit", "linechart", "long", "materialize", "mvexpand", "notcontains", "notlike", "of", "or", "order",
"parse", "piechart", "pivotchart", "print", "project", "queries", "real", "regex", "sample", "scatterchart",
"search", "set", "sort", "stacked", "stacked100", "stackedareachart", "startswith", "string", "summarize",
"take", "time", "timechart", "timeline", "timepivot", "timespan", "to", "top", "toscalar", "true", "union",
"unstacked", "viewers", "where", "withsource"}; // add more keywords here
var escapeName = rx.IsMatch(name) || kustoKeywordList.Any(name.Contains) || alwaysEscape;
if (escapeName)
{
if (name.IndexOf('"') > -1)
{
result = "[@'" + name + "']";
}
else
{
result = "[@\"" + name + "\"]";
}
}
return result;
}
public static bool IsClusterLevelQuery(string query)
{
string [] clusterLevelQueryPrefixes = {
".show databases",
".show schema"
};
return clusterLevelQueryPrefixes.Any(query.StartsWith);
}
/// <summary>
/// Adds an object of type DataSourceObjectMetadata to a dictionary<string, Dictionary<string, T>>. If the key exists then the item is added
/// to the list. If not then the key is created and then added.
/// </summary>
/// <param name="dictionary">The dictionary of the dictionary that the list should be added to.</param>
/// <param name="key">The key to be added.</param>
/// <param name="metadata">The metadata to be added to the list.</param>
/// <typeparam name="T"></typeparam>
public static void SafeAdd<T>(this Dictionary<string, Dictionary<string, T>> dictionary, string key,
T metadata) where T : DataSourceObjectMetadata
{
if (dictionary.ContainsKey(key))
{
if (dictionary[key].ContainsKey(metadata.Name))
{
return;
}
dictionary[key].Add(metadata.Name, metadata);
}
else
{
dictionary[key] = new Dictionary<string, T> {{metadata.Name, metadata}};
}
}
/// <summary>
/// Add a range to a dictionary of ConcurrentDictionary. Adds range to existing IEnumerable within dictionary
/// at the same key.
/// </summary>
/// <param name="dictionary"></param>
/// <param name="key"></param>
/// <param name="metadatas"></param>
/// <typeparam name="T"></typeparam>
public static void AddRange<T>(this ConcurrentDictionary<string, IEnumerable<T>> dictionary, string key,
List<T> metadatas) where T : DataSourceObjectMetadata
{
if (dictionary.ContainsKey(key))
{
metadatas.AddRange(dictionary[key]);
}
dictionary[key] = metadatas.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase).ToList();
}
}
}

View File

@@ -0,0 +1,22 @@
using System.Data;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
internal class KustoResultsReader : DataReaderWrapper
{
public KustoResultsReader(IDataReader reader)
: base(reader)
{
}
/// <summary>
/// Kusto returns 3 results tables - QueryResults, QueryProperties, QueryStatus. When returning query results
/// we want the caller to only read the first table. We override the NextResult function here to only return one table
/// from the IDataReader.
/// </summary>
/*public override bool NextResult()
{
return false;
}*/
}
}

View File

@@ -0,0 +1,11 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata
{
/// <summary>
/// Column metadata information
/// </summary>
public class ColumnMetadata : TableMetadata
{
public string TableName { get; set; }
public string DataType { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata
{
/// <summary>
/// Metadata type enumeration
/// </summary>
public enum DataSourceMetadataType
{
Cluster = 0,
Database = 1,
Table = 2,
Column = 3,
Function = 4,
Folder = 5
}
}

View File

@@ -0,0 +1,20 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata
{
/// <summary>
/// Object metadata information
/// </summary>
public class DataSourceObjectMetadata
{
public DataSourceMetadataType MetadataType { get; set; }
public string MetadataTypeName { get; set; }
public string Name { get; set; }
public string PrettyName { get; set; }
public string Urn { get; set; }
public string SizeInMB { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata
{
/// <summary>
/// Database metadata information
/// </summary>
public class DatabaseMetadata : DataSourceObjectMetadata
{
public string ClusterName { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata
{
/// <summary>
/// Folder metadata information
/// </summary>
public class FolderMetadata : DataSourceObjectMetadata
{
public DataSourceObjectMetadata ParentMetadata { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata
{
public class FunctionMetadata : DatabaseMetadata
{
public string DatabaseName { get; set; }
public string Parameters { get; set; }
public string Body { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata
{
/// <summary>
/// Database metadata information
/// </summary>
public class TableMetadata : DatabaseMetadata
{
public string DatabaseName { get; set; }
public string Folder { get; set; }
}
}

View File

@@ -0,0 +1,26 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Models
{
public class ColumnInfo
{
/// <summary>
/// The table name.
/// </summary>
public string Table { get; set; }
/// <summary>
/// The column name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// The data type.
/// </summary>
public string DataType { get; set; }
/// <summary>
/// The folder name.
/// </summary>
public string Folder { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Models
{
public class FunctionInfo
{
public string Name { get; set; }
public string Parameters { get; set; }
public string Body { get; set; }
public string Folder { get; set; }
public string DocString { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
namespace Microsoft.Kusto.ServiceLayer.DataSource.Models
{
public class TableInfo
{
public string TableName { get; set; }
public string Folder { get; set; }
}
}

View File

@@ -0,0 +1,258 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// This code is copied from the source described in the comment below.
// =======================================================================================
// Microsoft Windows Server AppFabric Customer Advisory Team (CAT) Best Practices Series
//
// This sample is supplemental to the technical guidance published on the community
// blog at http://blogs.msdn.com/appfabriccat/ and copied from
// sqlmain ./sql/manageability/mfx/common/
//
// =======================================================================================
// Copyright © 2012 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. YOU BEAR THE RISK OF USING IT.
// =======================================================================================
using System;
using System.Collections.Generic;
using System.Data;
using System.Collections;
using System.Data.Common;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Threading;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.SqlTools.Utility;
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
using Microsoft.Kusto.ServiceLayer.DataSource;
namespace Microsoft.Kusto.ServiceLayer.Connection
{
/// <summary>
/// Provides a reliable way of opening connections to and executing commands
/// taking into account potential network unreliability and a requirement for connection retry.
/// </summary>
public sealed partial class ReliableDataSourceConnection : IDisposable
{
private IDataSource _dataSource;
private readonly RetryPolicy _connectionRetryPolicy;
private RetryPolicy _commandRetryPolicy;
private Guid _azureSessionId = Guid.NewGuid();
private string _connectionString;
private string _azureAccountToken;
/// <summary>
/// Initializes a new instance of the ReliableKustoClient class with a given connection string
/// and a policy defining whether to retry a request if the connection fails to be opened or a command
/// fails to be successfully executed.
/// </summary>
/// <param name="connectionString">The connection string used to open the SQL Azure database.</param>
/// <param name="connectionRetryPolicy">The retry policy defining whether to retry a request if a connection fails to be established.</param>
/// <param name="commandRetryPolicy">The retry policy defining whether to retry a request if a command fails to be executed.</param>
public ReliableDataSourceConnection(string connectionString, RetryPolicy connectionRetryPolicy, RetryPolicy commandRetryPolicy, string azureAccountToken)
{
_connectionString = connectionString;
_azureAccountToken = azureAccountToken;
_dataSource = DataSourceFactory.Create(DataSourceType.Kusto, connectionString, azureAccountToken);
_connectionRetryPolicy = connectionRetryPolicy ?? RetryPolicyFactory.CreateNoRetryPolicy();
_commandRetryPolicy = commandRetryPolicy ?? RetryPolicyFactory.CreateNoRetryPolicy();
_connectionRetryPolicy.RetryOccurred += RetryConnectionCallback;
_commandRetryPolicy.RetryOccurred += RetryCommandCallback;
}
private void RetryCommandCallback(RetryState retryState)
{
RetryPolicyUtils.RaiseSchemaAmbientRetryMessage(retryState, SqlSchemaModelErrorCodes.ServiceActions.CommandRetry, _azureSessionId);
}
private void RetryConnectionCallback(RetryState retryState)
{
RetryPolicyUtils.RaiseSchemaAmbientRetryMessage(retryState, SqlSchemaModelErrorCodes.ServiceActions.ConnectionRetry, _azureSessionId);
}
/// <summary>
/// Disposes resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or
/// resetting managed and unmanaged resources.
/// </summary>
/// <param name="disposing">A flag indicating that managed resources must be released.</param>
public void Dispose(bool disposing)
{
if (disposing)
{
if (_connectionRetryPolicy != null)
{
_connectionRetryPolicy.RetryOccurred -= RetryConnectionCallback;
}
if (_commandRetryPolicy != null)
{
_commandRetryPolicy.RetryOccurred -= RetryCommandCallback;
}
_dataSource.Dispose();
}
}
/// <summary>
/// Gets or sets the connection string for opening a connection to the SQL Azure database.
/// </summary>
public string ConnectionString { get; set; }
/// <summary>
/// Gets the policy which decides whether to retry a connection request, based on how many
/// times the request has been made and the reason for the last failure.
/// </summary>
public RetryPolicy ConnectionRetryPolicy
{
get { return _connectionRetryPolicy; }
}
/// <summary>
/// Gets the policy which decides whether to retry a command, based on how many
/// times the request has been made and the reason for the last failure.
/// </summary>
public RetryPolicy CommandRetryPolicy
{
get { return _commandRetryPolicy; }
set
{
Validate.IsNotNull(nameof(value), value);
if (_commandRetryPolicy != null)
{
_commandRetryPolicy.RetryOccurred -= RetryCommandCallback;
}
_commandRetryPolicy = value;
_commandRetryPolicy.RetryOccurred += RetryCommandCallback;
}
}
/// <summary>
/// Gets the server name from the underlying connection.
/// </summary>
public string ClusterName
{
get { return _dataSource.ClusterName; }
}
/// <summary>
/// If the underlying SqlConnection absolutely has to be accessed, for instance
/// to pass to external APIs that require this type of connection, then this
/// can be used.
/// </summary>
/// <returns><see cref="SqlConnection"/></returns>
public IDataSource GetUnderlyingConnection()
{
return _dataSource;
}
/// <summary>
/// Changes the current database for an open Connection object.
/// </summary>
/// <param name="databaseName">The name of the database to use in place of the current database.</param>
public void ChangeDatabase(string databaseName)
{
_dataSource.UpdateDatabase(databaseName);
}
/// <summary>
/// Opens a database connection with the settings specified by the ConnectionString
/// property of the provider-specific Connection object.
/// </summary>
public void Open()
{
// TODOKusto: Should we initialize in the constructor or here. Set a breapoint and check.
// Check if retry policy was specified, if not, disable retries by executing the Open method using RetryPolicy.NoRetry.
if(_dataSource == null)
{
_connectionRetryPolicy.ExecuteAction(() =>
{
_dataSource = DataSourceFactory.Create(DataSourceType.Kusto, _connectionString, _azureAccountToken);
});
}
}
/// <summary>
/// Opens a database connection with the settings specified by the ConnectionString
/// property of the provider-specific Connection object.
/// </summary>
public Task OpenAsync(CancellationToken token)
{
// Make sure that the token isn't cancelled before we try
if (token.IsCancellationRequested)
{
return Task.FromCanceled(token);
}
// Check if retry policy was specified, if not, disable retries by executing the Open method using RetryPolicy.NoRetry.
try
{
return _connectionRetryPolicy.ExecuteAction(async () =>
{
await Task.Run(() => Open());
});
}
catch (Exception e)
{
return Task.FromException(e);
}
}
/// <summary>
/// Closes the connection to the database.
/// </summary>
public void Close()
{
}
/// <summary>
/// Gets the time to wait while trying to establish a connection before terminating
/// the attempt and generating an error.
/// </summary>
public int ConnectionTimeout
{
get { return 30; }
}
/// <summary>
/// Gets the name of the current database or the database to be used after a
/// connection is opened.
/// </summary>
public string Database
{
get { return _dataSource.DatabaseName; }
}
private void VerifyConnectionOpen(ReliableDataSourceConnection conn)
{
if(conn.GetUnderlyingConnection() == null)
{
conn.Open();
}
}
}
}

View File

@@ -0,0 +1,113 @@
//
// 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.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.Formatter.Contracts
{
/// <summary>
/// A formatting request to process an entire document
/// </summary>
public class DocumentFormattingRequest
{
public static readonly
RequestType<DocumentFormattingParams, TextEdit[]> Type =
RequestType<DocumentFormattingParams, TextEdit[]>.Create("textDocument/formatting");
}
/// <summary>
/// A formatting request to process a specific range inside a document
/// </summary>
public class DocumentRangeFormattingRequest
{
public static readonly
RequestType<DocumentRangeFormattingParams, TextEdit[]> Type =
RequestType<DocumentRangeFormattingParams, TextEdit[]>.Create("textDocument/rangeFormatting");
}
/// <summary>
/// A formatting request to handle a user typing, giving a chance to update the text based on this
/// </summary>
public class DocumentOnTypeFormattingRequest
{
public static readonly
RequestType<DocumentOnTypeFormattingParams, TextEdit[]> Type =
RequestType<DocumentOnTypeFormattingParams, TextEdit[]>.Create("textDocument/onTypeFormatting");
}
/// <summary>
/// Params for the <see cref="DocumentFormattingRequest"/>
/// </summary>
public class DocumentFormattingParams
{
/// <summary>
/// The document to format.
/// </summary>
public TextDocumentIdentifier TextDocument { get; set; }
/// <summary>
/// The formatting options
/// </summary>
public FormattingOptions Options { get; set; }
}
/// <summary>
/// Params for the <see cref="DocumentRangeFormattingRequest"/>
/// </summary>
public class DocumentRangeFormattingParams : DocumentFormattingParams
{
/// <summary>
/// The range to format
/// </summary>
public Range Range { get; set; }
}
/// <summary>
/// Params for the <see cref="DocumentOnTypeFormattingRequest"/>
/// </summary>
public class DocumentOnTypeFormattingParams : DocumentFormattingParams
{
/// <summary>
/// The position at which this request was sent.
/// </summary>
Position Position { get; set; }
/// <summary>
/// The character that has been typed.
/// </summary>
string Ch { get; set; }
}
/// <summary>
/// Value-object describing what options formatting should use.
/// </summary>
public class FormattingOptions
{
/// <summary>
/// Size of a tab in spaces
/// </summary>
public int TabSize { get; set; }
/// <summary>
/// Prefer spaces over tabs.
/// </summary>
public bool InsertSpaces { get; set; }
// TODO there may be other options passed by VSCode - format is
// [key: string]: boolean | number | string;
// Determine how these might be passed and add them here
}
}

View File

@@ -0,0 +1,171 @@
//
// 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.ComponentModel;
namespace Microsoft.Kusto.ServiceLayer.Formatter
{
public enum CasingOptions { None, Uppercase, Lowercase };
/// <summary>
/// The supported options to use when formatting text
/// </summary>
public class FormatOptions : INotifyPropertyChanged
{
private int spacesPerIndent;
private bool useTabs = false;
private bool encloseIdentifiersInSquareBrackets;
private bool placeCommasBeforeNextStatement;
private bool placeEachReferenceOnNewLineInQueryStatements;
private CasingOptions keywordCasing;
private CasingOptions datatypeCasing;
private bool alignColumnDefinitionsInColumns;
internal FormatOptions()
{
SpacesPerIndent = 4;
UseTabs = false;
PlaceCommasBeforeNextStatement = false;
EncloseIdentifiersInSquareBrackets = false;
PlaceEachReferenceOnNewLineInQueryStatements = false;
}
public int SpacesPerIndent
{
get { return spacesPerIndent; }
set { spacesPerIndent = value;
RaisePropertyChanged("SpacesPerIndent"); }
}
public bool UseTabs
{
get { return useTabs; }
set
{
useTabs = value;
// raise UseTabs & UseSpaces property changed events
RaisePropertyChanged("UseTabs");
RaisePropertyChanged("UseSpaces");
}
}
public bool UseSpaces
{
get { return !UseTabs; }
set { UseTabs = !value; }
}
public bool EncloseIdentifiersInSquareBrackets
{
get { return encloseIdentifiersInSquareBrackets; }
set
{
encloseIdentifiersInSquareBrackets = value;
RaisePropertyChanged("EncloseIdentifiersInSquareBrackets");
}
}
public bool PlaceCommasBeforeNextStatement
{
get { return placeCommasBeforeNextStatement; }
set
{
placeCommasBeforeNextStatement = value;
RaisePropertyChanged("PlaceCommasBeforeNextStatement");
}
}
public bool PlaceEachReferenceOnNewLineInQueryStatements
{
get { return placeEachReferenceOnNewLineInQueryStatements; }
set
{
placeEachReferenceOnNewLineInQueryStatements = value;
RaisePropertyChanged("PlaceEachReferenceOnNewLineInQueryStatements");
}
}
public CasingOptions KeywordCasing
{
get { return keywordCasing; }
set
{
keywordCasing = value;
RaisePropertyChanged("KeywordCasing");
}
}
public bool UppercaseKeywords
{
get { return KeywordCasing == CasingOptions.Uppercase; }
}
public bool LowercaseKeywords
{
get { return KeywordCasing == CasingOptions.Lowercase; }
}
public bool DoNotFormatKeywords
{
get { return KeywordCasing == CasingOptions.None; }
}
public CasingOptions DatatypeCasing
{
get { return datatypeCasing; }
set
{
datatypeCasing = value;
RaisePropertyChanged("DatatypeCasing");
}
}
public bool UppercaseDataTypes
{
get { return DatatypeCasing == CasingOptions.Uppercase; }
}
public bool LowercaseDataTypes
{
get { return DatatypeCasing == CasingOptions.Lowercase; }
}
public bool DoNotFormatDataTypes
{
get { return DatatypeCasing == CasingOptions.None; }
}
public bool AlignColumnDefinitionsInColumns
{
get { return alignColumnDefinitionsInColumns; }
set
{
alignColumnDefinitionsInColumns = value;
RaisePropertyChanged("AlignColumnDefinitionsInColumns");
}
}
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
public static void Copy(FormatOptions target, FormatOptions source)
{
target.AlignColumnDefinitionsInColumns = source.AlignColumnDefinitionsInColumns;
target.DatatypeCasing = source.DatatypeCasing;
target.EncloseIdentifiersInSquareBrackets = source.EncloseIdentifiersInSquareBrackets;
target.KeywordCasing = source.KeywordCasing;
target.PlaceCommasBeforeNextStatement = source.PlaceCommasBeforeNextStatement;
target.PlaceEachReferenceOnNewLineInQueryStatements = source.PlaceEachReferenceOnNewLineInQueryStatements;
target.SpacesPerIndent = source.SpacesPerIndent;
target.UseSpaces = source.UseSpaces;
target.UseTabs = source.UseTabs;
}
}
}

View File

@@ -0,0 +1,320 @@
//
// 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.Composition;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
//using Kusto.Language;
//using Kusto.Language.Editor;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.Hosting;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.Kusto.ServiceLayer.Formatter.Contracts;
using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.SqlContext;
using Microsoft.Kusto.ServiceLayer.Workspace;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
using Microsoft.SqlTools.Utility;
using Range = Microsoft.Kusto.ServiceLayer.Workspace.Contracts.Range;
namespace Microsoft.Kusto.ServiceLayer.Formatter
{
[Export(typeof(IHostedService))]
public class TSqlFormatterService : HostedService<TSqlFormatterService>, IComposableService
{
private FormatterSettings settings;
/// <summary>
/// The default constructor is required for MEF-based composable services
/// </summary>
public TSqlFormatterService()
{
settings = new FormatterSettings();
}
public override void InitializeService(IProtocolEndpoint serviceHost)
{
Logger.Write(TraceEventType.Verbose, "TSqlFormatter initialized");
serviceHost.SetRequestHandler(DocumentFormattingRequest.Type, HandleDocFormatRequest);
serviceHost.SetRequestHandler(DocumentRangeFormattingRequest.Type, HandleDocRangeFormatRequest);
WorkspaceService?.RegisterConfigChangeCallback(HandleDidChangeConfigurationNotification);
}
/// <summary>
/// Gets the workspace service. Note: should handle case where this is null in cases where unit tests do not set this up
/// </summary>
private WorkspaceService<SqlToolsSettings> WorkspaceService
{
get { return ServiceProvider.GetService<WorkspaceService<SqlToolsSettings>>(); }
}
/// <summary>
/// Gets the language service. Note: should handle case where this is null in cases where unit tests do not set this up
/// </summary>
private LanguageService LanguageService
{
get { return ServiceProvider.GetService<LanguageService>(); }
}
/// <summary>
/// Ensure formatter settings are always up to date
/// </summary>
public Task HandleDidChangeConfigurationNotification(
SqlToolsSettings newSettings,
SqlToolsSettings oldSettings,
EventContext eventContext)
{
// update the current settings to reflect any changes (assuming formatter settings exist)
settings = newSettings?.SqlTools?.Format ?? settings;
return Task.FromResult(true);
}
public async Task HandleDocFormatRequest(DocumentFormattingParams docFormatParams, RequestContext<TextEdit[]> requestContext)
{
Func<Task<TextEdit[]>> requestHandler = () =>
{
return FormatAndReturnEdits(docFormatParams);
};
await HandleRequest(requestHandler, requestContext, "HandleDocFormatRequest");
DocumentStatusHelper.SendTelemetryEvent(requestContext, CreateTelemetryProps(isDocFormat: true));
}
public async Task HandleDocRangeFormatRequest(DocumentRangeFormattingParams docRangeFormatParams, RequestContext<TextEdit[]> requestContext)
{
Func<Task<TextEdit[]>> requestHandler = () =>
{
return FormatRangeAndReturnEdits(docRangeFormatParams);
};
await HandleRequest(requestHandler, requestContext, "HandleDocRangeFormatRequest");
DocumentStatusHelper.SendTelemetryEvent(requestContext, CreateTelemetryProps(isDocFormat: false));
}
private static TelemetryProperties CreateTelemetryProps(bool isDocFormat)
{
return new TelemetryProperties
{
Properties = new Dictionary<string, string>
{
{ TelemetryPropertyNames.FormatType,
isDocFormat ? TelemetryPropertyNames.DocumentFormatType : TelemetryPropertyNames.RangeFormatType }
},
EventName = TelemetryEventNames.FormatCode
};
}
private async Task<TextEdit[]> FormatRangeAndReturnEdits(DocumentRangeFormattingParams docFormatParams)
{
return await Task.Factory.StartNew(() =>
{
if (ShouldSkipFormatting(docFormatParams))
{
return Array.Empty<TextEdit>();
}
var range = docFormatParams.Range;
ScriptFile scriptFile = GetFile(docFormatParams);
if (scriptFile == null)
{
return new TextEdit[0];
}
TextEdit textEdit = new TextEdit { Range = range };
string text = scriptFile.GetTextInRange(range.ToBufferRange());
return DoFormat(docFormatParams, textEdit, text);
});
}
private bool ShouldSkipFormatting(DocumentFormattingParams docFormatParams)
{
if (docFormatParams == null
|| docFormatParams.TextDocument == null
|| docFormatParams.TextDocument.Uri == null)
{
return true;
}
return (LanguageService != null && LanguageService.ShouldSkipNonMssqlFile(docFormatParams.TextDocument.Uri));
}
private async Task<TextEdit[]> FormatAndReturnEdits(DocumentFormattingParams docFormatParams)
{
return await Task.Factory.StartNew(() =>
{
if (ShouldSkipFormatting(docFormatParams))
{
return Array.Empty<TextEdit>();
}
var scriptFile = GetFile(docFormatParams);
if (scriptFile == null
|| scriptFile.FileLines.Count == 0)
{
return new TextEdit[0];
}
TextEdit textEdit = PrepareEdit(scriptFile);
string text = scriptFile.Contents;
return DoFormat(docFormatParams, textEdit, text);
});
}
private TextEdit[] DoFormat(DocumentFormattingParams docFormatParams, TextEdit edit, string text)
{
Validate.IsNotNull(nameof(docFormatParams), docFormatParams);
FormatOptions options = GetOptions(docFormatParams);
List<TextEdit> edits = new List<TextEdit>();
edit.NewText = Format(text, options, false);
// TODO do not add if no formatting needed?
edits.Add(edit);
return edits.ToArray();
}
private FormatOptions GetOptions(DocumentFormattingParams docFormatParams)
{
return MergeFormatOptions(docFormatParams.Options, settings);
}
internal static FormatOptions MergeFormatOptions(FormattingOptions formatRequestOptions, FormatterSettings settings)
{
FormatOptions options = new FormatOptions();
if (formatRequestOptions != null)
{
options.UseSpaces = formatRequestOptions.InsertSpaces;
options.SpacesPerIndent = formatRequestOptions.TabSize;
}
UpdateFormatOptionsFromSettings(options, settings);
return options;
}
internal static void UpdateFormatOptionsFromSettings(FormatOptions options, FormatterSettings settings)
{
Validate.IsNotNull(nameof(options), options);
if (settings != null)
{
if (settings.AlignColumnDefinitionsInColumns.HasValue) { options.AlignColumnDefinitionsInColumns = settings.AlignColumnDefinitionsInColumns.Value; }
if (settings.PlaceCommasBeforeNextStatement.HasValue) { options.PlaceCommasBeforeNextStatement = settings.PlaceCommasBeforeNextStatement.Value; }
if (settings.PlaceSelectStatementReferencesOnNewLine.HasValue) { options.PlaceEachReferenceOnNewLineInQueryStatements = settings.PlaceSelectStatementReferencesOnNewLine.Value; }
if (settings.UseBracketForIdentifiers.HasValue) { options.EncloseIdentifiersInSquareBrackets = settings.UseBracketForIdentifiers.Value; }
options.DatatypeCasing = settings.DatatypeCasing;
options.KeywordCasing = settings.KeywordCasing;
}
}
private ScriptFile GetFile(DocumentFormattingParams docFormatParams)
{
return WorkspaceService.Workspace.GetFile(docFormatParams.TextDocument.Uri);
}
private static TextEdit PrepareEdit(ScriptFile scriptFile)
{
int fileLines = scriptFile.FileLines.Count;
Position start = new Position { Line = 0, Character = 0 };
int lastChar = scriptFile.FileLines[scriptFile.FileLines.Count - 1].Length;
Position end = new Position { Line = scriptFile.FileLines.Count - 1, Character = lastChar };
TextEdit edit = new TextEdit
{
Range = new Range { Start = start, End = end }
};
return edit;
}
private async Task HandleRequest<T>(Func<Task<T>> handler, RequestContext<T> requestContext, string requestType)
{
Logger.Write(TraceEventType.Verbose, requestType);
try
{
T result = await handler();
await requestContext.SendResult(result);
}
catch (Exception ex)
{
await requestContext.SendError(ex.ToString());
}
}
public string Format(TextReader input)
{
string originalSql = input.ReadToEnd();
return Format(originalSql, new FormatOptions());
}
public string Format(string input, FormatOptions options)
{
return Format(input, options, true);
}
public string Format(string input, FormatOptions options, bool verifyOutput)
{
string result = null;
//TODOKusto: Implement formatting for Kusto generically here.
//var kustoCodeService = new KustoCodeService(input, GlobalState.Default);
//var formattedText = kustoCodeService.GetFormattedText();
//DoFormat(input, options, verifyOutput, visitor =>
//{
//result = formattedText.Text;
//});
return result;
}
/*public void Format(string input, FormatOptions options, bool verifyOutput, Replacement.OnReplace replace)
{
DoFormat(input, options, verifyOutput, visitor =>
{
foreach (Replacement r in visitor.Context.Replacements)
{
r.Apply(replace);
}
});
}
private void DoFormat(string input, FormatOptions options, bool verifyOutput, Action<FormatterVisitor> postFormatAction)
{
Validate.IsNotNull(nameof(input), input);
Validate.IsNotNull(nameof(options), options);
ParseResult result = Parser.Parse(input);
FormatContext context = new FormatContext(result.Script, options);
FormatterVisitor visitor = new FormatterVisitor(context, ServiceProvider);
result.Script.Accept(visitor);
if (verifyOutput)
{
visitor.VerifyFormat();
}
postFormatAction?.Invoke(visitor);
}*/
}
internal static class RangeExtensions
{
public static BufferRange ToBufferRange(this Range range)
{
// It turns out that VSCode sends Range objects as 0-indexed lines, while
// our BufferPosition and BufferRange logic assumes 1-indexed. Therefore
// need to increment all ranges by 1 when copying internally and reduce
// when returning to the caller
return new BufferRange(
new BufferPosition(range.Start.Line + 1, range.Start.Character + 1),
new BufferPosition(range.End.Line + 1, range.End.Character + 1)
);
}
}
}

View File

@@ -0,0 +1,136 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Threading.Tasks;
using Microsoft.SqlTools.Credentials;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.Hosting;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.Kusto.ServiceLayer.Admin;
using Microsoft.Kusto.ServiceLayer.Metadata;
using Microsoft.Kusto.ServiceLayer.Connection;
using Microsoft.Kusto.ServiceLayer.Hosting;
using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.QueryExecution;
using Microsoft.Kusto.ServiceLayer.Scripting;
using Microsoft.Kusto.ServiceLayer.SqlContext;
using Microsoft.Kusto.ServiceLayer.Workspace;
using SqlToolsContext = Microsoft.SqlTools.ServiceLayer.SqlContext.SqlToolsContext;
namespace Microsoft.Kusto.ServiceLayer
{
/// <summary>
/// Provides support for starting up a service host. This is a common responsibility
/// for both the main service program and test driver that interacts with it
/// </summary>
public static class HostLoader
{
private static object lockObject = new object();
private static bool isLoaded;
private static readonly string[] inclusionList =
{
"microsofsqltoolscredentials.dll",
"microsoft.sqltools.hosting.dll",
"microsoftkustoservicelayer.dll"
};
internal static ServiceHost CreateAndStartServiceHost(SqlToolsContext sqlToolsContext)
{
ServiceHost serviceHost = ServiceHost.Instance;
lock (lockObject)
{
if (!isLoaded)
{
// Grab the instance of the service host
serviceHost.Initialize();
InitializeRequestHandlersAndServices(serviceHost, sqlToolsContext);
// Start the service only after all request handlers are setup. This is vital
// as otherwise the Initialize event can be lost - it's processed and discarded before the handler
// is hooked up to receive the message
serviceHost.Start().Wait();
isLoaded = true;
}
}
return serviceHost;
}
private static void InitializeRequestHandlersAndServices(ServiceHost serviceHost, SqlToolsContext sqlToolsContext)
{
// Load extension provider, which currently finds all exports in current DLL. Can be changed to find based
// on directory or assembly list quite easily in the future
ExtensionServiceProvider serviceProvider = ExtensionServiceProvider.CreateDefaultServiceProvider(inclusionList);
serviceProvider.RegisterSingleService(sqlToolsContext);
serviceProvider.RegisterSingleService(serviceHost);
// Initialize and register singleton services so they're accessible for any MEF service. In the future, these
// could be updated to be IComposableServices, which would avoid the requirement to define a singleton instance
// and instead have MEF handle discovery & loading
WorkspaceService<SqlToolsSettings>.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(WorkspaceService<SqlToolsSettings>.Instance);
LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext);
serviceProvider.RegisterSingleService(LanguageService.Instance);
ConnectionService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(ConnectionService.Instance);
CredentialService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(CredentialService.Instance);
QueryExecutionService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(QueryExecutionService.Instance);
ScriptingService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(ScriptingService.Instance);
AdminService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(AdminService.Instance);
MetadataService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(MetadataService.Instance);
InitializeHostedServices(serviceProvider, serviceHost);
serviceHost.ServiceProvider = serviceProvider;
serviceHost.InitializeRequestHandlers();
}
/// <summary>
/// Internal to support testing. Initializes <see cref="IHostedService"/> instances in the service,
/// and registers them for their preferred service type
/// </summary>
internal static void InitializeHostedServices(RegisteredServiceProvider provider, IProtocolEndpoint host)
{
// Pre-register all services before initializing. This ensures that if one service wishes to reference
// another one during initialization, it will be able to safely do so
foreach (IHostedService service in provider.GetServices<IHostedService>())
{
provider.RegisterSingleService(service.ServiceType, service);
}
ServiceHost serviceHost = host as ServiceHost;
foreach (IHostedService service in provider.GetServices<IHostedService>())
{
// Initialize all hosted services, and register them in the service provider for their requested
// service type. This ensures that when searching for the ConnectionService you can get it without
// searching for an IHostedService of type ConnectionService
service.InitializeService(host);
IDisposable disposable = service as IDisposable;
if (serviceHost != null && disposable != null)
{
serviceHost.RegisterShutdownTask(async (shutdownParams, shutdownRequestContext) =>
{
disposable.Dispose();
await Task.FromResult(0);
});
}
}
}
}
}

View File

@@ -0,0 +1,112 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Range = Microsoft.Kusto.ServiceLayer.Workspace.Contracts.Range;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
/// <summary>
/// All the conversion of intellisense info to vscode format is done in this class.
/// </summary>
public static class AutoCompleteHelper
{
/// <summary>
/// Create a completion item from the default item text since VS Code expects CompletionItems
/// </summary>
/// <param name="label"></param>
/// <param name="detail"></param>
/// <param name="insertText"></param>
/// <param name="kind"></param>
/// <param name="row"></param>
/// <param name="startColumn"></param>
/// <param name="endColumn"></param>
public static CompletionItem CreateCompletionItem(
string label,
string detail,
string insertText,
CompletionItemKind kind,
int row,
int startColumn,
int endColumn)
{
CompletionItem item = new CompletionItem
{
Label = label,
Kind = kind,
Detail = detail,
InsertText = insertText,
TextEdit = new TextEdit
{
NewText = insertText,
Range = new Range
{
Start = new Position
{
Line = row,
Character = startColumn
},
End = new Position
{
Line = row,
Character = endColumn
}
}
}
};
return item;
}
/// <summary>
/// Converts QuickInfo object into a VS Code Hover object
/// </summary>
/// <param name="quickInfo"></param>
/// <param name="language"></param>
/// <param name="row"></param>
/// <param name="startColumn"></param>
/// <param name="endColumn"></param>
public static Hover ConvertQuickInfoToHover(
string quickInfoText,
string language,
int row,
int startColumn,
int endColumn)
{
// convert from the parser format to the VS Code wire format
var markedStrings = new MarkedString[1];
if (quickInfoText != null)
{
markedStrings[0] = new MarkedString()
{
Language = language,
Value = quickInfoText
};
return new Hover()
{
Contents = markedStrings,
Range = new Range
{
Start = new Position
{
Line = row,
Character = startColumn
},
End = new Position
{
Line = row,
Character = endColumn
}
}
};
}
else
{
return null;
}
}
}
}

View File

@@ -0,0 +1,502 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Kusto.ServiceLayer.Utility;
using Microsoft.SqlTools.Utility;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
/// <summary>
/// Main class for the Binding Queue
/// </summary>
public class BindingQueue<T> : IDisposable where T : IBindingContext, new()
{
internal const int QueueThreadStackSize = 5 * 1024 * 1024;
private CancellationTokenSource processQueueCancelToken = null;
private ManualResetEvent itemQueuedEvent = new ManualResetEvent(initialState: false);
private object bindingQueueLock = new object();
private LinkedList<QueueItem> bindingQueue = new LinkedList<QueueItem>();
private object bindingContextLock = new object();
private Task queueProcessorTask;
public delegate void UnhandledExceptionDelegate(string connectionKey, Exception ex);
public event UnhandledExceptionDelegate OnUnhandledException;
/// <summary>
/// Map from context keys to binding context instances
/// Internal for testing purposes only
/// </summary>
internal Dictionary<string, IBindingContext> BindingContextMap { get; set; }
internal Dictionary<IBindingContext, Task> BindingContextTasks { get; set; } = new Dictionary<IBindingContext, Task>();
/// <summary>
/// Constructor for a binding queue instance
/// </summary>
public BindingQueue()
{
this.BindingContextMap = new Dictionary<string, IBindingContext>();
this.StartQueueProcessor();
}
public void StartQueueProcessor()
{
this.queueProcessorTask = StartQueueProcessorAsync();
}
/// <summary>
/// Stops the binding queue by sending cancellation request
/// </summary>
/// <param name="timeout"></param>
public bool StopQueueProcessor(int timeout)
{
this.processQueueCancelToken.Cancel();
return this.queueProcessorTask.Wait(timeout);
}
/// <summary>
/// Returns true if cancellation is requested
/// </summary>
/// <returns></returns>
public bool IsCancelRequested
{
get
{
return this.processQueueCancelToken.IsCancellationRequested;
}
}
/// <summary>
/// Queue a binding request item
/// </summary>
public virtual QueueItem QueueBindingOperation(
string key,
Func<IBindingContext, CancellationToken, object> bindOperation,
Func<IBindingContext, object> timeoutOperation = null,
Func<Exception, object> errorHandler = null,
int? bindingTimeout = null,
int? waitForLockTimeout = null)
{
// don't add null operations to the binding queue
if (bindOperation == null)
{
return null;
}
QueueItem queueItem = new QueueItem()
{
Key = key,
BindOperation = bindOperation,
TimeoutOperation = timeoutOperation,
ErrorHandler = errorHandler,
BindingTimeout = bindingTimeout,
WaitForLockTimeout = waitForLockTimeout
};
lock (this.bindingQueueLock)
{
this.bindingQueue.AddLast(queueItem);
}
this.itemQueuedEvent.Set();
return queueItem;
}
/// <summary>
/// Checks if a particular binding context is connected or not
/// </summary>
/// <param name="key"></param>
public bool IsBindingContextConnected(string key)
{
lock (this.bindingContextLock)
{
IBindingContext context;
if (this.BindingContextMap.TryGetValue(key, out context))
{
return context.IsConnected;
}
return false;
}
}
/// <summary>
/// Gets or creates a binding context for the provided context key
/// </summary>
/// <param name="key"></param>
protected IBindingContext GetOrCreateBindingContext(string key)
{
// use a default binding context for disconnected requests
if (string.IsNullOrWhiteSpace(key))
{
key = "disconnected_binding_context";
}
lock (this.bindingContextLock)
{
if (!this.BindingContextMap.ContainsKey(key))
{
var bindingContext = new T();
this.BindingContextMap.Add(key, bindingContext);
this.BindingContextTasks.Add(bindingContext, Task.Run(() => null));
}
return this.BindingContextMap[key];
}
}
protected IEnumerable<IBindingContext> GetBindingContexts(string keyPrefix)
{
// use a default binding context for disconnected requests
if (string.IsNullOrWhiteSpace(keyPrefix))
{
keyPrefix = "disconnected_binding_context";
}
lock (this.bindingContextLock)
{
return this.BindingContextMap.Where(x => x.Key.StartsWith(keyPrefix)).Select(v => v.Value);
}
}
/// <summary>
/// Checks if a binding context already exists for the provided context key
/// </summary>
protected bool BindingContextExists(string key)
{
lock (this.bindingContextLock)
{
return this.BindingContextMap.ContainsKey(key);
}
}
/// <summary>
/// Remove the binding queue entry
/// </summary>
protected void RemoveBindingContext(string key)
{
lock (this.bindingContextLock)
{
if (this.BindingContextMap.ContainsKey(key))
{
// disconnect existing connection
var bindingContext = this.BindingContextMap[key];
if (bindingContext.ServerConnection != null && bindingContext.ServerConnection.IsOpen)
{
// Disconnecting can take some time so run it in a separate task so that it doesn't block removal
Task.Run(() =>
{
bindingContext.ServerConnection.Cancel();
bindingContext.ServerConnection.Disconnect();
});
}
// remove key from the map
this.BindingContextMap.Remove(key);
this.BindingContextTasks.Remove(bindingContext);
}
}
}
public bool HasPendingQueueItems
{
get
{
lock (this.bindingQueueLock)
{
return this.bindingQueue.Count > 0;
}
}
}
/// <summary>
/// Gets the next pending queue item
/// </summary>
private QueueItem GetNextQueueItem()
{
lock (this.bindingQueueLock)
{
if (this.bindingQueue.Count == 0)
{
return null;
}
QueueItem queueItem = this.bindingQueue.First.Value;
this.bindingQueue.RemoveFirst();
return queueItem;
}
}
/// <summary>
/// Starts the queue processing thread
/// </summary>
private Task StartQueueProcessorAsync()
{
if (this.processQueueCancelToken != null)
{
this.processQueueCancelToken.Dispose();
}
this.processQueueCancelToken = new CancellationTokenSource();
return Task.Factory.StartNew(
ProcessQueue,
this.processQueueCancelToken.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
/// <summary>
/// The core queue processing method
/// </summary>
/// <param name="state"></param>
private void ProcessQueue()
{
CancellationToken token = this.processQueueCancelToken.Token;
WaitHandle[] waitHandles = new WaitHandle[2]
{
this.itemQueuedEvent,
token.WaitHandle
};
while (true)
{
// wait for with an item to be queued or the a cancellation request
WaitHandle.WaitAny(waitHandles);
if (token.IsCancellationRequested)
{
break;
}
try
{
// dispatch all pending queue items
while (this.HasPendingQueueItems)
{
QueueItem queueItem = GetNextQueueItem();
if (queueItem == null)
{
continue;
}
IBindingContext bindingContext = GetOrCreateBindingContext(queueItem.Key);
if (bindingContext == null)
{
queueItem.ItemProcessed.Set();
continue;
}
var bindingContextTask = this.BindingContextTasks[bindingContext];
// Run in the binding context task in case this task has to wait for a previous binding operation
this.BindingContextTasks[bindingContext] = bindingContextTask.ContinueWith((task) =>
{
bool lockTaken = false;
try
{
// prefer the queue item binding item, otherwise use the context default timeout
int bindTimeout = queueItem.BindingTimeout ?? bindingContext.BindingTimeout;
// handle the case a previous binding operation is still running
if (!bindingContext.BindingLock.WaitOne(queueItem.WaitForLockTimeout ?? 0))
{
try
{
Logger.Write(TraceEventType.Warning, "Binding queue operation timed out waiting for previous operation to finish");
queueItem.Result = queueItem.TimeoutOperation != null
? queueItem.TimeoutOperation(bindingContext)
: null;
}
catch (Exception ex)
{
Logger.Write(TraceEventType.Error, "Exception running binding queue lock timeout handler: " + ex.ToString());
}
finally
{
queueItem.ItemProcessed.Set();
}
return;
}
bindingContext.BindingLock.Reset();
lockTaken = true;
// execute the binding operation
object result = null;
CancellationTokenSource cancelToken = new CancellationTokenSource();
// run the operation in a separate thread
var bindTask = Task.Run(() =>
{
try
{
result = queueItem.BindOperation(
bindingContext,
cancelToken.Token);
}
catch (Exception ex)
{
Logger.Write(TraceEventType.Error, "Unexpected exception on the binding queue: " + ex.ToString());
if (queueItem.ErrorHandler != null)
{
try
{
result = queueItem.ErrorHandler(ex);
}
catch (Exception ex2)
{
Logger.Write(TraceEventType.Error, "Unexpected exception in binding queue error handler: " + ex2.ToString());
}
}
if (IsExceptionOfType(ex, typeof(SqlException)) || IsExceptionOfType(ex, typeof(SocketException)))
{
if (this.OnUnhandledException != null)
{
this.OnUnhandledException(queueItem.Key, ex);
}
RemoveBindingContext(queueItem.Key);
}
}
});
Task.Run(() =>
{
try
{
// check if the binding tasks completed within the binding timeout
if (bindTask.Wait(bindTimeout))
{
queueItem.Result = result;
}
else
{
cancelToken.Cancel();
// if the task didn't complete then call the timeout callback
if (queueItem.TimeoutOperation != null)
{
queueItem.Result = queueItem.TimeoutOperation(bindingContext);
}
bindTask.ContinueWithOnFaulted(t => Logger.Write(TraceEventType.Error, "Binding queue threw exception " + t.Exception.ToString()));
// Give the task a chance to complete before moving on to the next operation
bindTask.Wait();
}
}
catch (Exception ex)
{
Logger.Write(TraceEventType.Error, "Binding queue task completion threw exception " + ex.ToString());
}
finally
{
// set item processed to avoid deadlocks
if (lockTaken)
{
bindingContext.BindingLock.Set();
}
queueItem.ItemProcessed.Set();
}
});
}
catch (Exception ex)
{
// catch and log any exceptions raised in the binding calls
// set item processed to avoid deadlocks
Logger.Write(TraceEventType.Error, "Binding queue threw exception " + ex.ToString());
// set item processed to avoid deadlocks
if (lockTaken)
{
bindingContext.BindingLock.Set();
}
queueItem.ItemProcessed.Set();
}
}, TaskContinuationOptions.None);
// if a queue processing cancellation was requested then exit the loop
if (token.IsCancellationRequested)
{
break;
}
}
}
finally
{
lock (this.bindingQueueLock)
{
// verify the binding queue is still empty
if (this.bindingQueue.Count == 0)
{
// reset the item queued event since we've processed all the pending items
this.itemQueuedEvent.Reset();
}
}
}
}
}
/// <summary>
/// Clear queued items
/// </summary>
public void ClearQueuedItems()
{
lock (this.bindingQueueLock)
{
if (this.bindingQueue.Count > 0)
{
this.bindingQueue.Clear();
}
}
}
public void Dispose()
{
if (this.processQueueCancelToken != null)
{
this.processQueueCancelToken.Dispose();
}
if (itemQueuedEvent != null)
{
itemQueuedEvent.Dispose();
}
if (this.BindingContextMap != null)
{
foreach (var item in this.BindingContextMap)
{
if (item.Value != null && item.Value.ServerConnection != null && item.Value.ServerConnection.SqlConnectionObject != null)
{
item.Value.ServerConnection.SqlConnectionObject.Close();
}
}
}
}
private bool IsExceptionOfType(Exception ex, Type t)
{
return ex.GetType() == t || (ex.InnerException != null && ex.InnerException.GetType() == t);
}
}
}

View File

@@ -0,0 +1,223 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SmoMetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.Common;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Parser;
using Kusto.Data.Net.Client;
using Kusto.Data.Common;
using Kusto.Data;
using Microsoft.Kusto.ServiceLayer.DataSource;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
/// <summary>
/// Class for the binding context for connected sessions
/// </summary>
public class ConnectedBindingContext : IBindingContext
{
private ParseOptions parseOptions;
private ManualResetEvent bindingLock;
private ServerConnection serverConnection;
/// <inheritdoc/>
public IDataSource DataSource { get; set; }
/// <summary>
/// Connected binding context constructor
/// </summary>
public ConnectedBindingContext()
{
this.bindingLock = new ManualResetEvent(initialState: true);
this.BindingTimeout = ConnectedBindingQueue.DefaultBindingTimeout;
this.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider();
}
/// <summary>
/// Gets or sets a flag indicating if the binder is connected
/// </summary>
public bool IsConnected { get; set; }
/// <summary>
/// Gets or sets the binding server connection
/// </summary>
public ServerConnection ServerConnection
{
get
{
return this.serverConnection;
}
set
{
this.serverConnection = value;
// reset the parse options so the get recreated for the current connection
this.parseOptions = null;
}
}
/// <summary>
/// Gets or sets the metadata display info provider
/// </summary>
public MetadataDisplayInfoProvider MetadataDisplayInfoProvider { get; set; }
/// <summary>
/// Gets or sets the SMO metadata provider
/// </summary>
public SmoMetadataProvider SmoMetadataProvider { get; set; }
/// <summary>
/// Gets or sets the binder
/// </summary>
public IBinder Binder { get; set; }
/// <summary>
/// Gets the binding lock object
/// </summary>
public ManualResetEvent BindingLock
{
get
{
return this.bindingLock;
}
}
/// <summary>
/// Gets or sets the binding operation timeout in milliseconds
/// </summary>
public int BindingTimeout { get; set; }
/// <summary>
/// Gets the Language Service ServerVersion
/// </summary>
public ServerVersion ServerVersion
{
get
{
return this.ServerConnection != null
? this.ServerConnection.ServerVersion
: null;
}
}
/// <summary>
/// Gets the current DataEngineType
/// </summary>
public DatabaseEngineType DatabaseEngineType
{
get
{
return this.ServerConnection != null
? this.ServerConnection.DatabaseEngineType
: DatabaseEngineType.Standalone;
}
}
/// <summary>
/// Gets the current connections TransactSqlVersion
/// </summary>
public TransactSqlVersion TransactSqlVersion
{
get
{
return this.IsConnected
? GetTransactSqlVersion(this.ServerVersion)
: TransactSqlVersion.Current;
}
}
/// <summary>
/// Gets the current DatabaseCompatibilityLevel
/// </summary>
public DatabaseCompatibilityLevel DatabaseCompatibilityLevel
{
get
{
return this.IsConnected
? GetDatabaseCompatibilityLevel(this.ServerVersion)
: DatabaseCompatibilityLevel.Current;
}
}
/// <summary>
/// Gets the current ParseOptions
/// </summary>
public ParseOptions ParseOptions
{
get
{
if (this.parseOptions == null)
{
this.parseOptions = new ParseOptions(
batchSeparator: LanguageService.DefaultBatchSeperator,
isQuotedIdentifierSet: true,
compatibilityLevel: DatabaseCompatibilityLevel,
transactSqlVersion: TransactSqlVersion);
}
return this.parseOptions;
}
}
/// <summary>
/// Gets the database compatibility level from a server version
/// </summary>
/// <param name="serverVersion"></param>
private static DatabaseCompatibilityLevel GetDatabaseCompatibilityLevel(ServerVersion serverVersion)
{
int versionMajor = Math.Max(serverVersion.Major, 8);
switch (versionMajor)
{
case 8:
return DatabaseCompatibilityLevel.Version80;
case 9:
return DatabaseCompatibilityLevel.Version90;
case 10:
return DatabaseCompatibilityLevel.Version100;
case 11:
return DatabaseCompatibilityLevel.Version110;
case 12:
return DatabaseCompatibilityLevel.Version120;
case 13:
return DatabaseCompatibilityLevel.Version130;
default:
return DatabaseCompatibilityLevel.Current;
}
}
/// <summary>
/// Gets the transaction sql version from a server version
/// </summary>
/// <param name="serverVersion"></param>
private static TransactSqlVersion GetTransactSqlVersion(ServerVersion serverVersion)
{
int versionMajor = Math.Max(serverVersion.Major, 9);
switch (versionMajor)
{
case 9:
case 10:
// In case of 10.0 we still use Version 10.5 as it is the closest available.
return TransactSqlVersion.Version105;
case 11:
return TransactSqlVersion.Version110;
case 12:
return TransactSqlVersion.Version120;
case 13:
return TransactSqlVersion.Version130;
default:
return TransactSqlVersion.Current;
}
}
}
}

View File

@@ -0,0 +1,234 @@
//
// 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.Data.SqlClient;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SmoMetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.Kusto.ServiceLayer.Connection;
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
using Microsoft.Kusto.ServiceLayer.SqlContext;
using Microsoft.Kusto.ServiceLayer.Workspace;
using Microsoft.Kusto.ServiceLayer.DataSource;
using System.Threading;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
public interface IConnectedBindingQueue
{
void CloseConnections(string serverName, string databaseName, int millisecondsTimeout);
void OpenConnections(string serverName, string databaseName, int millisecondsTimeout);
string AddConnectionContext(ConnectionInfo connInfo, string featureName = null, bool overwrite = false);
void Dispose();
QueueItem QueueBindingOperation(
string key,
Func<IBindingContext, CancellationToken, object> bindOperation,
Func<IBindingContext, object> timeoutOperation = null,
Func<Exception, object> errorHandler = null,
int? bindingTimeout = null,
int? waitForLockTimeout = null);
}
public class SqlConnectionOpener
{
/// <summary>
/// Virtual method used to support mocking and testing
/// </summary>
public virtual ServerConnection OpenServerConnection(ConnectionInfo connInfo, string featureName)
{
return ConnectionService.OpenServerConnection(connInfo, featureName);
}
}
/// <summary>
/// ConnectedBindingQueue class for processing online binding requests
/// </summary>
public class ConnectedBindingQueue : BindingQueue<ConnectedBindingContext>, IConnectedBindingQueue
{
internal const int DefaultBindingTimeout = 500;
internal const int DefaultMinimumConnectionTimeout = 30;
/// <summary>
/// flag determing if the connection queue requires online metadata objects
/// it's much cheaper to not construct these objects if not needed
/// </summary>
private bool needsMetadata;
private SqlConnectionOpener connectionOpener;
/// <summary>
/// Gets the current settings
/// </summary>
internal SqlToolsSettings CurrentSettings
{
get { return WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings; }
}
public ConnectedBindingQueue()
: this(true)
{
}
public ConnectedBindingQueue(bool needsMetadata)
{
this.needsMetadata = needsMetadata;
this.connectionOpener = new SqlConnectionOpener();
}
// For testing purposes only
internal void SetConnectionOpener(SqlConnectionOpener opener)
{
this.connectionOpener = opener;
}
/// <summary>
/// Generate a unique key based on the ConnectionInfo object
/// </summary>
/// <param name="connInfo"></param>
internal static string GetConnectionContextKey(ConnectionDetails details)
{
string key = string.Format("{0}_{1}_{2}_{3}",
details.ServerName ?? "NULL",
details.DatabaseName ?? "NULL",
details.UserName ?? "NULL",
details.AuthenticationType ?? "NULL"
);
if (!string.IsNullOrEmpty(details.DatabaseDisplayName))
{
key += "_" + details.DatabaseDisplayName;
}
if (!string.IsNullOrEmpty(details.GroupId))
{
key += "_" + details.GroupId;
}
return Uri.EscapeUriString(key);
}
/// <summary>
/// Generate a unique key based on the ConnectionInfo object
/// </summary>
/// <param name="connInfo"></param>
private string GetConnectionContextKey(string serverName, string databaseName)
{
return string.Format("{0}_{1}",
serverName ?? "NULL",
databaseName ?? "NULL");
}
public void CloseConnections(string serverName, string databaseName, int millisecondsTimeout)
{
string connectionKey = GetConnectionContextKey(serverName, databaseName);
var contexts = GetBindingContexts(connectionKey);
foreach (var bindingContext in contexts)
{
if (bindingContext.BindingLock.WaitOne(millisecondsTimeout))
{
bindingContext.ServerConnection.Disconnect();
}
}
}
public void OpenConnections(string serverName, string databaseName, int millisecondsTimeout)
{
string connectionKey = GetConnectionContextKey(serverName, databaseName);
var contexts = GetBindingContexts(connectionKey);
foreach (var bindingContext in contexts)
{
if (bindingContext.BindingLock.WaitOne(millisecondsTimeout))
{
try
{
bindingContext.ServerConnection.Connect();
}
catch
{
//TODO: remove the binding context?
}
}
}
}
public void RemoveBindigContext(ConnectionInfo connInfo)
{
string connectionKey = GetConnectionContextKey(connInfo.ConnectionDetails);
if (BindingContextExists(connectionKey))
{
RemoveBindingContext(connectionKey);
}
}
/// <summary>
/// Use a ConnectionInfo item to create a connected binding context
/// </summary>
/// <param name="connInfo">Connection info used to create binding context</param>
/// <param name="overwrite">Overwrite existing context</param>
public virtual string AddConnectionContext(ConnectionInfo connInfo, string featureName = null, bool overwrite = false)
{
if (connInfo == null)
{
return string.Empty;
}
// lookup the current binding contextna
string connectionKey = GetConnectionContextKey(connInfo.ConnectionDetails);
if (BindingContextExists(connectionKey))
{
if (overwrite)
{
RemoveBindingContext(connectionKey);
}
else
{
// no need to populate the context again since the context already exists
return connectionKey;
}
}
IBindingContext bindingContext = this.GetOrCreateBindingContext(connectionKey);
if (bindingContext.BindingLock.WaitOne())
{
try
{
bindingContext.BindingLock.Reset();
// populate the binding context to work with the SMO metadata provider
bindingContext.ServerConnection = connectionOpener.OpenServerConnection(connInfo, featureName);
string connectionString = ConnectionService.BuildConnectionString(connInfo.ConnectionDetails);
bindingContext.DataSource = DataSourceFactory.Create(DataSourceType.Kusto, connectionString, connInfo.ConnectionDetails.AzureAccountToken);
if (this.needsMetadata)
{
bindingContext.SmoMetadataProvider = SmoMetadataProvider.CreateConnectedProvider(bindingContext.ServerConnection);
bindingContext.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider();
bindingContext.MetadataDisplayInfoProvider.BuiltInCasing =
this.CurrentSettings.SqlTools.IntelliSense.LowerCaseSuggestions.Value
? CasingStyle.Lowercase : CasingStyle.Uppercase;
bindingContext.Binder = BinderProvider.CreateBinder(bindingContext.SmoMetadataProvider);
}
bindingContext.BindingTimeout = ConnectedBindingQueue.DefaultBindingTimeout;
bindingContext.IsConnected = true;
}
catch (Exception)
{
bindingContext.IsConnected = false;
}
finally
{
bindingContext.BindingLock.Set();
}
}
return connectionKey;
}
}
}

View File

@@ -0,0 +1,111 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Diagnostics;
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class CompletionRequest
{
public static readonly
RequestType<TextDocumentPosition, CompletionItem[]> Type =
RequestType<TextDocumentPosition, CompletionItem[]>.Create("textDocument/completion");
}
public class CompletionResolveRequest
{
public static readonly
RequestType<CompletionItem, CompletionItem> Type =
RequestType<CompletionItem, CompletionItem>.Create("completionItem/resolve");
}
public enum CompletionItemKind
{
Text = 1,
Method = 2,
Function = 3,
Constructor = 4,
Field = 5,
Variable = 6,
Class = 7,
Interface = 8,
Module = 9,
Property = 10,
Unit = 11,
Value = 12,
Enum = 13,
Keyword = 14,
Snippet = 15,
Color = 16,
File = 17,
Reference = 18
}
public class Command
{
/// <summary>
/// Title of the command.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The identifier of the actual command handler, like `vsintellicode.completionItemSelected`.
/// </summary>
public string command { get; set; }
/// <summary>
/// A tooltip for the command, when represented in the UI.
/// </summary>
public string Tooltip { get; set; }
/// <summary>
/// Arguments that the command handler should be invoked with.
/// </summary>
public object[] Arguments { get; set; }
}
[DebuggerDisplay("Kind = {Kind.ToString()}, Label = {Label}, Detail = {Detail}")]
public class CompletionItem
{
public string Label { get; set; }
public CompletionItemKind? Kind { get; set; }
public string Detail { get; set; }
/// <summary>
/// Gets or sets the documentation string for the completion item.
/// </summary>
public string Documentation { get; set; }
public string SortText { get; set; }
public string FilterText { get; set; }
public string InsertText { get; set; }
public TextEdit TextEdit { get; set; }
/// <summary>
/// Gets or sets a custom data field that allows the server to mark
/// each completion item with an identifier that will help correlate
/// the item to the previous completion request during a completion
/// resolve request.
/// </summary>
public object Data { get; set; }
/// <summary>
/// Exposing a command field for a completion item for passing telemetry
/// </summary>
public Command Command { get; set; }
/// <summary>
/// Whether this completion item is preselected or not
/// </summary>
public bool? Preselect { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
//
// 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.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class DefinitionRequest
{
public static readonly
RequestType<TextDocumentPosition, Location[]> Type =
RequestType<TextDocumentPosition, Location[]>.Create("textDocument/definition");
}
}

View File

@@ -0,0 +1,72 @@
//
// 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.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class PublishDiagnosticsNotification
{
public static readonly
EventType<PublishDiagnosticsNotification> Type =
EventType<PublishDiagnosticsNotification>.Create("textDocument/publishDiagnostics");
/// <summary>
/// Gets or sets the URI for which diagnostic information is reported.
/// </summary>
public string Uri { get; set; }
/// <summary>
/// Gets or sets the array of diagnostic information items.
/// </summary>
public Diagnostic[] Diagnostics { get; set; }
}
public enum DiagnosticSeverity
{
/// <summary>
/// Indicates that the diagnostic represents an error.
/// </summary>
Error = 1,
/// <summary>
/// Indicates that the diagnostic represents a warning.
/// </summary>
Warning = 2,
/// <summary>
/// Indicates that the diagnostic represents an informational message.
/// </summary>
Information = 3,
/// <summary>
/// Indicates that the diagnostic represents a hint.
/// </summary>
Hint = 4
}
public class Diagnostic
{
public Range Range { get; set; }
/// <summary>
/// Gets or sets the severity of the diagnostic. If omitted, the
/// client should interpret the severity.
/// </summary>
public DiagnosticSeverity? Severity { get; set; }
/// <summary>
/// Gets or sets the diagnostic's code (optional).
/// </summary>
public string Code { get; set; }
/// <summary>
/// Gets or sets the diagnostic message.
/// </summary>
public string Message { get; set; }
}
}

View File

@@ -0,0 +1,32 @@
//
// 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.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public enum DocumentHighlightKind
{
Text = 1,
Read = 2,
Write = 3
}
public class DocumentHighlight
{
public Range Range { get; set; }
public DocumentHighlightKind Kind { get; set; }
}
public class DocumentHighlightRequest
{
public static readonly
RequestType<TextDocumentPosition, DocumentHighlight[]> Type =
RequestType<TextDocumentPosition, DocumentHighlight[]>.Create("textDocument/documentHighlight");
}
}

View File

@@ -0,0 +1,16 @@
//
// 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.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class ExpandAliasRequest
{
public static readonly
RequestType<string, string> Type =
RequestType<string, string>.Create("SqlTools/expandAlias");
}
}

View File

@@ -0,0 +1,24 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class FindModuleRequest
{
public static readonly
RequestType<List<PSModuleMessage>, object> Type =
RequestType<List<PSModuleMessage>, object>.Create("SqlTools/findModule");
}
public class PSModuleMessage
{
public string Name { get; set; }
public string Description { get; set; }
}
}

View File

@@ -0,0 +1,33 @@
//
// 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.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class MarkedString
{
public string Language { get; set; }
public string Value { get; set; }
}
public class Hover
{
public MarkedString[] Contents { get; set; }
public Range? Range { get; set; }
}
public class HoverRequest
{
public static readonly
RequestType<TextDocumentPosition, Hover> Type =
RequestType<TextDocumentPosition, Hover>.Create("textDocument/hover");
}
}

View File

@@ -0,0 +1,16 @@
//
// 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.Kusto.ServiceLayer.LanguageServices.Contracts
{
class InstallModuleRequest
{
public static readonly
RequestType<string, object> Type =
RequestType<string, object>.Create("SqlTools/installModule");
}
}

View File

@@ -0,0 +1,30 @@
//
// 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.Kusto.ServiceLayer.LanguageServices.Contracts
{
/// <summary>
/// Parameters sent back with an IntelliSense ready event
/// </summary>
public class IntelliSenseReadyParams
{
/// <summary>
/// URI identifying the text document
/// </summary>
public string OwnerUri { get; set; }
}
/// <summary>
/// Event sent when the language service is finished updating after a connection
/// </summary>
public class IntelliSenseReadyNotification
{
public static readonly
EventType<IntelliSenseReadyParams> Type =
EventType<IntelliSenseReadyParams>.Create("textDocument/intelliSenseReady");
}
}

View File

@@ -0,0 +1,30 @@
//
// 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.Kusto.ServiceLayer.LanguageServices.Contracts
{
/// <summary>
/// Parameters to be sent back with a rebuild IntelliSense event
/// </summary>
public class RebuildIntelliSenseParams
{
/// <summary>
/// URI identifying the file that should have its IntelliSense cache rebuilt
/// </summary>
public string OwnerUri { get; set; }
}
/// <summary>
/// RebuildIntelliSenseNotification notification mapping entry
/// </summary>
public class RebuildIntelliSenseNotification
{
public static readonly
EventType<RebuildIntelliSenseParams> Type =
EventType<RebuildIntelliSenseParams>.Create("textDocument/rebuildIntelliSense");
}
}

View File

@@ -0,0 +1,28 @@
//
// 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.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class ReferencesRequest
{
public static readonly
RequestType<ReferencesParams, Location[]> Type =
RequestType<ReferencesParams, Location[]>.Create("textDocument/references");
}
public class ReferencesParams : TextDocumentPosition
{
public ReferencesContext Context { get; set; }
}
public class ReferencesContext
{
public bool IncludeDeclaration { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
//
// 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.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class ShowOnlineHelpRequest
{
public static readonly
RequestType<string, object> Type =
RequestType<string, object>.Create("SqlTools/showOnlineHelp");
}
}

View File

@@ -0,0 +1,43 @@
//
// 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.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class SignatureHelpRequest
{
public static readonly
RequestType<TextDocumentPosition, SignatureHelp> Type =
RequestType<TextDocumentPosition, SignatureHelp>.Create("textDocument/signatureHelp");
}
public class ParameterInformation
{
public string Label { get; set; }
public string Documentation { get; set; }
}
public class SignatureInformation
{
public string Label { get; set; }
public string Documentation { get; set; }
public ParameterInformation[] Parameters { get; set; }
}
public class SignatureHelp
{
public SignatureInformation[] Signatures { get; set; }
public int? ActiveSignature { get; set; }
public int? ActiveParameter { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
//
// 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.Kusto.ServiceLayer.LanguageServices.Contracts
{
/// <summary>
/// Parameters sent back with an status change event
/// </summary>
public class StatusChangeParams
{
/// <summary>
/// URI identifying the text document
/// </summary>
public string OwnerUri { get; set; }
/// <summary>
/// The new status for the document
/// </summary>
public string Status { get; set; }
}
/// <summary>
/// Event sent for language service status change notification
/// </summary>
public class StatusChangedNotification
{
public static readonly
EventType<StatusChangeParams> Type =
EventType<StatusChangeParams>.Create("textDocument/statusChanged");
}
}

View File

@@ -0,0 +1,31 @@
//
// 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.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class SyntaxParseParams
{
public string OwnerUri { get; set; }
public string Query { get; set; }
}
public class SyntaxParseResult
{
public bool Parseable { get; set; }
public string[] Errors { get; set; }
}
public class SyntaxParseRequest
{
public static readonly
RequestType<SyntaxParseParams, SyntaxParseResult> Type =
RequestType<SyntaxParseParams, SyntaxParseResult>.Create("query/syntaxparse");
}
}

View File

@@ -0,0 +1,100 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
public class TelemetryProperties
{
public string EventName { get; set; }
/// <summary>
/// Telemetry properties
/// </summary>
public Dictionary<string, string> Properties { get; set; }
/// <summary>
/// Telemetry measures
/// </summary>
public Dictionary<string, double> Measures { get; set; }
}
/// <summary>
/// Parameters sent back with an IntelliSense ready event
/// </summary>
public class TelemetryParams
{
public TelemetryProperties Params { get; set; }
}
/// <summary>
/// Event sent when the language service needs to add a telemetry event
/// </summary>
public class TelemetryNotification
{
public static readonly
EventType<TelemetryParams> Type =
EventType<TelemetryParams>.Create("telemetry/sqlevent");
}
/// <summary>
/// List of telemetry events
/// </summary>
public static class TelemetryEventNames
{
/// <summary>
/// telemetry event name for auto complete response time
/// </summary>
public const string IntellisenseQuantile = "IntellisenseQuantile";
/// <summary>
/// telemetry event name for when definition is requested
/// </summary>
public const string PeekDefinitionRequested = "PeekDefinitionRequested";
/// <summary>
/// telemetry event name for when definition is requested
/// </summary>
public const string FormatCode = "FormatCode";
}
/// <summary>
/// List of properties used in telemetry events
/// </summary>
public static class TelemetryPropertyNames
{
/// <summary>
/// Is a connection to an Azure database or not
/// </summary>
public const string IsAzure = "IsAzure";
/// <summary>
/// Did an event succeed or not
/// </summary>
public const string Succeeded = "Succeeded";
/// <summary>
/// Was the action against a connected file or similar resource, or not
/// </summary>
public const string Connected = "Connected";
/// <summary>
/// Format type property - should be one of <see cref="DocumentFormatType"/> or <see cref="RangeFormatType"/>
/// </summary>
public const string FormatType = "FormatType";
/// <summary>
/// A full document format
/// </summary>
public const string DocumentFormatType = "Document";
/// <summary>
/// A document range format
/// </summary>
public const string RangeFormatType = "Range";
}
}

View File

@@ -0,0 +1,20 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Diagnostics;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts
{
[DebuggerDisplay("NewText = {NewText}, Range = {Range.Start.Line}:{Range.Start.Character} - {Range.End.Line}:{Range.End.Character}")]
public class TextEdit
{
public Range Range { get; set; }
public string NewText { get; set; }
}
}

View File

@@ -0,0 +1,124 @@
//
// 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.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
using Microsoft.SqlTools.Utility;
using Range = Microsoft.Kusto.ServiceLayer.Workspace.Contracts.Range;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
/// <summary>
/// Main class for Language Service functionality including anything that reqires knowledge of
/// the language to perfom, such as definitions, intellisense, etc.
/// </summary>
public static class DiagnosticsHelper
{
/// <summary>
/// Send the diagnostic results back to the host application
/// </summary>
/// <param name="scriptFile"></param>
/// <param name="semanticMarkers"></param>
/// <param name="eventContext"></param>
internal static async Task PublishScriptDiagnostics(
ScriptFile scriptFile,
ScriptFileMarker[] semanticMarkers,
EventContext eventContext)
{
var allMarkers = scriptFile.SyntaxMarkers != null
? scriptFile.SyntaxMarkers.Concat(semanticMarkers)
: semanticMarkers;
// Always send syntax and semantic errors. We want to
// make sure no out-of-date markers are being displayed.
await eventContext.SendEvent(
PublishDiagnosticsNotification.Type,
new PublishDiagnosticsNotification
{
Uri = scriptFile.ClientUri,
Diagnostics =
allMarkers
.Select(GetDiagnosticFromMarker)
.ToArray()
});
}
/// <summary>
/// Send the diagnostic results back to the host application
/// </summary>
/// <param name="scriptFile"></param>
/// <param name="semanticMarkers"></param>
/// <param name="eventContext"></param>
internal static async Task ClearScriptDiagnostics(
string uri,
EventContext eventContext)
{
Validate.IsNotNullOrEmptyString(nameof(uri), uri);
Validate.IsNotNull(nameof(eventContext), eventContext);
// Always send syntax and semantic errors. We want to
// make sure no out-of-date markers are being displayed.
await eventContext.SendEvent(
PublishDiagnosticsNotification.Type,
new PublishDiagnosticsNotification
{
Uri = uri,
Diagnostics = Array.Empty<Diagnostic>()
});
}
/// <summary>
/// Convert a ScriptFileMarker to a Diagnostic that is Language Service compatible
/// </summary>
/// <param name="scriptFileMarker"></param>
/// <returns></returns>
internal static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker)
{
return new Diagnostic
{
Severity = MapDiagnosticSeverity(scriptFileMarker.Level),
Message = scriptFileMarker.Message,
Range = new Range
{
Start = new Position
{
Line = scriptFileMarker.ScriptRegion.StartLineNumber - 1,
Character = scriptFileMarker.ScriptRegion.StartColumnNumber - 1
},
End = new Position
{
Line = scriptFileMarker.ScriptRegion.EndLineNumber - 1,
Character = scriptFileMarker.ScriptRegion.EndColumnNumber - 1
}
}
};
}
/// <summary>
/// Map ScriptFileMarker severity to Diagnostic severity
/// </summary>
/// <param name="markerLevel"></param>
internal static DiagnosticSeverity MapDiagnosticSeverity(ScriptFileMarkerLevel markerLevel)
{
switch (markerLevel)
{
case ScriptFileMarkerLevel.Error:
return DiagnosticSeverity.Error;
case ScriptFileMarkerLevel.Warning:
return DiagnosticSeverity.Warning;
case ScriptFileMarkerLevel.Information:
return DiagnosticSeverity.Information;
default:
return DiagnosticSeverity.Error;
}
}
}
}

View File

@@ -0,0 +1,77 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.SqlTools.Utility;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
/// <summary>
/// Helper class to send events to the client
/// </summary>
public class DocumentStatusHelper
{
public const string DefinitionRequested = "DefinitionRequested";
public const string DefinitionRequestCompleted = "DefinitionRequestCompleted";
/// <summary>
/// Sends an event for specific document using the existing request context
/// </summary>
public static void SendStatusChange<T>(RequestContext<T> requestContext, TextDocumentPosition textDocumentPosition, string status)
{
Task.Factory.StartNew(async () =>
{
if (requestContext != null)
{
string ownerUri = textDocumentPosition != null && textDocumentPosition.TextDocument != null ? textDocumentPosition.TextDocument.Uri : "";
await requestContext.SendEvent(StatusChangedNotification.Type, new StatusChangeParams()
{
OwnerUri = ownerUri,
Status = status
});
}
});
}
/// <summary>
/// Sends a telemetry event for specific document using the existing request context
/// </summary>
public static void SendTelemetryEvent<T>(RequestContext<T> requestContext, string telemetryEvent)
{
Validate.IsNotNull(nameof(requestContext), requestContext);
Validate.IsNotNullOrWhitespaceString(nameof(telemetryEvent), telemetryEvent);
Task.Factory.StartNew(async () =>
{
await requestContext.SendEvent(TelemetryNotification.Type, new TelemetryParams()
{
Params = new TelemetryProperties
{
EventName = telemetryEvent
}
});
});
}
/// <summary>
/// Sends a telemetry event for specific document using the existing request context
/// </summary>
public static void SendTelemetryEvent<T>(RequestContext<T> requestContext, TelemetryProperties telemetryProps)
{
Validate.IsNotNull(nameof(requestContext), requestContext);
Validate.IsNotNull(nameof(telemetryProps), telemetryProps);
Validate.IsNotNullOrWhitespaceString("telemetryProps.EventName", telemetryProps.EventName);
Task.Factory.StartNew(async () =>
{
await requestContext.SendEvent(TelemetryNotification.Type, new TelemetryParams()
{
Params = telemetryProps
});
});
}
}
}

View File

@@ -0,0 +1,88 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SmoMetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.Common;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Parser;
using Microsoft.Kusto.ServiceLayer.DataSource;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
/// <summary>
/// The context used for binding requests
/// </summary>
public interface IBindingContext
{
/// <summary>
/// Gets or sets a flag indicating if the context is connected
/// </summary>
bool IsConnected { get; set; }
/// <summary>
/// Gets or sets the binding server connection
/// </summary>
ServerConnection ServerConnection { get; set; }
/// <summary>
/// Gets or sets data source interface
/// </summary>
IDataSource DataSource { get; set; }
/// <summary>
/// Gets or sets the metadata display info provider
/// </summary>
MetadataDisplayInfoProvider MetadataDisplayInfoProvider { get; set; }
/// <summary>
/// Gets or sets the SMO metadata provider
/// </summary>
SmoMetadataProvider SmoMetadataProvider { get; set; }
/// <summary>
/// Gets or sets the binder
/// </summary>
IBinder Binder { get; set; }
/// <summary>
/// Gets the binding lock object
/// </summary>
ManualResetEvent BindingLock { get; }
/// <summary>
/// Gets or sets the binding operation timeout in milliseconds
/// </summary>
int BindingTimeout { get; set; }
/// <summary>
/// Gets or sets the current connection parse options
/// </summary>
ParseOptions ParseOptions { get; }
/// <summary>
/// Gets or sets the current connection server version
/// </summary>
ServerVersion ServerVersion { get; }
/// <summary>
/// Gets or sets the database engine type
/// </summary>
DatabaseEngineType DatabaseEngineType { get; }
/// <summary>
/// Gets or sets the T-SQL version
/// </summary>
TransactSqlVersion TransactSqlVersion { get; }
/// <summary>
/// Gets or sets the database compatibility level
/// </summary>
DatabaseCompatibilityLevel DatabaseCompatibilityLevel { get; }
}
}

View File

@@ -0,0 +1,98 @@
//
// 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.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.Utility;
namespace Microsoft.Kusto.ServiceLayer
{
/// <summary>
/// A class to calculate the value for the metrics using the given bucket
/// </summary>
public class InteractionMetrics<T>
{
/// <summary>
/// Creates new instance given a bucket of metrics
/// </summary>
public InteractionMetrics(int[] metrics)
{
Validate.IsNotNull("metrics", metrics);
if(metrics.Length == 0)
{
throw new ArgumentOutOfRangeException("metrics");
}
Counters = new ConcurrentDictionary<string, T>();
if (!IsSorted(metrics))
{
Array.Sort(metrics);
}
Metrics = metrics;
}
private ConcurrentDictionary<string, T> Counters { get; }
private object perfCountersLock = new object();
/// <summary>
/// The metrics bucket
/// </summary>
public int[] Metrics { get; private set; }
/// <summary>
/// Returns true if the given list is sorted
/// </summary>
private bool IsSorted(int[] metrics)
{
if (metrics.Length > 1)
{
int previous = metrics[0];
for (int i = 1; i < metrics.Length; i++)
{
if(metrics[i] < previous)
{
return false;
}
previous = metrics[i];
}
}
return true;
}
/// <summary>
/// Update metric value given new number
/// </summary>
public void UpdateMetrics(double duration, T newValue, Func<string, T, T> updateValueFactory)
{
int metric = Metrics[Metrics.Length - 1];
for (int i = 0; i < Metrics.Length; i++)
{
if (duration <= Metrics[i])
{
metric = Metrics[i];
break;
}
}
string key = metric.ToString();
Counters.AddOrUpdate(key, newValue, updateValueFactory);
}
/// <summary>
/// Returns the quantile
/// </summary>
public Dictionary<string, T> Quantile
{
get
{
return Counters.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
/// <summary>
/// /// Result object for PeekDefinition
/// </summary>
public class DefinitionResult
{
/// <summary>
/// True, if definition error occured
/// </summary>
public bool IsErrorResult;
/// <summary>
/// Error message, if any
/// </summary>
public string Message { get; set; }
/// <summary>
/// Location object representing the definition script file
/// </summary>
public Location[] Locations;
}
}

View File

@@ -0,0 +1,77 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Threading;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
/// <summary>
/// Class that stores the state of a binding queue request item
/// </summary>
public class QueueItem
{
/// <summary>
/// QueueItem constructor
/// </summary>
public QueueItem()
{
this.ItemProcessed = new ManualResetEvent(initialState: false);
}
/// <summary>
/// Gets or sets the queue item key
/// </summary>
public string Key { get; set; }
/// <summary>
/// Gets or sets the bind operation callback method
/// </summary>
public Func<IBindingContext, CancellationToken, object> BindOperation { get; set; }
/// <summary>
/// Gets or sets the timeout operation to call if the bind operation doesn't finish within timeout period
/// </summary>
public Func<IBindingContext, object> TimeoutOperation { get; set; }
/// <summary>
/// Gets or sets the operation to call if the bind operation encounters an unexpected exception.
/// Supports returning an object in case of the exception occurring since in some cases we need to be
/// tolerant of error cases and still return some value
/// </summary>
public Func<Exception, object> ErrorHandler { get; set; }
/// <summary>
/// Gets or sets an event to signal when this queue item has been processed
/// </summary>
public virtual ManualResetEvent ItemProcessed { get; set; }
/// <summary>
/// Gets or sets the result of the queued task
/// </summary>
public object Result { get; set; }
/// <summary>
/// Gets or sets the binding operation timeout in milliseconds
/// </summary>
public int? BindingTimeout { get; set; }
/// <summary>
/// Gets or sets the timeout for how long to wait for the binding lock
/// </summary>
public int? WaitForLockTimeout { get; set; }
/// <summary>
/// Converts the result of the execution to type T
/// </summary>
public T GetResultAsT<T>() where T : class
{
//var task = this.ResultsTask;
return (this.Result != null)
? this.Result as T
: null;
}
}
}

View File

@@ -0,0 +1,107 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlServer.Management.SqlParser.Parser;
using Microsoft.SqlTools.Utility;
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Completion
{
/// <summary>
/// A class to calculate the numbers used by SQL parser using the text positions and content
/// </summary>
public class ScriptDocumentInfo
{
/// <summary>
/// Create new instance
/// </summary>
public ScriptDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile, ScriptParseInfo scriptParseInfo)
: this(textDocumentPosition, scriptFile)
{
Validate.IsNotNull(nameof(scriptParseInfo), scriptParseInfo);
ScriptParseInfo = scriptParseInfo;
}
private ScriptDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile)
{
StartLine = textDocumentPosition.Position.Line;
ParserLine = textDocumentPosition.Position.Line + 1;
StartColumn = TextUtilities.PositionOfPrevDelimeter(
scriptFile.Contents,
textDocumentPosition.Position.Line,
textDocumentPosition.Position.Character);
EndColumn = TextUtilities.PositionOfNextDelimeter(
scriptFile.Contents,
textDocumentPosition.Position.Line,
textDocumentPosition.Position.Character);
ParserColumn = textDocumentPosition.Position.Character + 1;
Contents = scriptFile.Contents;
}
/// <summary>
/// Creates a new <see cref="ScriptDocumentInfo"/> with no backing <see cref="ScriptParseInfo"/> defined
/// </summary>
/// <param name="textDocumentPosition">A <see cref="TextDocumentPosition"/></param>
/// <param name="scriptFile">A <see cref="ScriptFile"/> to process</param>
/// <returns></returns>
public static ScriptDocumentInfo CreateDefaultDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile)
{
return new ScriptDocumentInfo(textDocumentPosition, scriptFile);
}
/// <summary>
/// Gets a string containing the full contents of the file.
/// </summary>
public string Contents { get; private set; }
/// <summary>
/// Script Parse Info Instance
/// </summary>
public ScriptParseInfo ScriptParseInfo { get; private set; }
/// <summary>
/// Start Line
/// </summary>
public int StartLine { get; private set; }
/// <summary>
/// Parser Line
/// </summary>
public int ParserLine { get; private set; }
/// <summary>
/// Start Column
/// </summary>
public int StartColumn { get; private set; }
/// <summary>
/// end Column
/// </summary>
public int EndColumn { get; private set; }
/// <summary>
/// Parser Column
/// </summary>
public int ParserColumn { get; private set; }
/// <summary>
/// The token text in the file content used for completion list
/// </summary>
public virtual string TokenText
{
get
{
return Token != null ? Token.Text : null;
}
}
/// <summary>
/// The token in the file content used for completion list
/// </summary>
public Token Token { get; private set; }
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,490 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype"><value>text/microsoft-resx</value></resheader><resheader name="version"><value>1.3</value></resheader><resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><data name="ConnectionServiceConnectErrorNullParams"><value>Verbindungsparameter dürfen nicht null sein.</value></data>
<data name="ConnectionServiceListDbErrorNullOwnerUri"><value>OwnerUri darf nicht null oder leer sein.</value></data>
<data name="ConnectionServiceListDbErrorNotConnected"><value>SpecifiedUri '{0}' hat keine gültige Verbindung</value></data>
<data name="ConnectionServiceConnStringInvalidAuthType"><value>Ungültiger Wert '{0}' für AuthenticationType. Gültige Werte sind 'Integrated' und 'SqlLogin'.</value></data>
<data name="ConnectionServiceConnStringInvalidIntent"><value>Ungültiger Wert '{0}' für ApplicationIntent. Gültige Werte sind 'ReadWrite' und 'ReadOnly'.</value></data>
<data name="ConnectionServiceConnectionCanceled"><value>Verbindung wurde abgebrochen.</value></data>
<data name="ConnectionParamsValidateNullOwnerUri"><value>OwnerUri darf nicht null oder leer sein.</value></data>
<data name="ConnectionParamsValidateNullConnection"><value>Verbindungsdetails-Objekt darf nicht null sein.</value></data>
<data name="ConnectionParamsValidateNullServerName"><value>ServerName darf nicht null oder leer sein.</value></data>
<data name="ConnectionParamsValidateNullSqlAuth"><value>{0} darf bei Verwendung der SqlLogin-Authentifizierung nicht null oder leer sein</value></data>
<data name="QueryServiceCancelAlreadyCompleted"><value>Die Abfrage wurde bereits abgeschlossen und kann nicht abgebrochen werden</value></data>
<data name="QueryServiceCancelDisposeFailed"><value>Abfrage wurde erfolgreich abgebrochen, Fehler beim Abfrage verfügen. Benutzer-URI nicht gefunden.</value></data>
<data name="QueryServiceQueryCancelled"><value>Die Abfrage wurde vom Benutzer abgebrochen.</value></data>
<data name="QueryServiceSubsetBatchNotCompleted"><value>Die Stapelverarbeitung ist noch nicht abgeschlossen</value></data>
<data name="QueryServiceSubsetBatchOutOfRange"><value>Batch-Index darf nicht kleiner als 0 oder größer als die Anzahl der Batches sein.</value></data>
<data name="QueryServiceSubsetResultSetOutOfRange"><value>Der Index der Ergebnismenge darf nicht kleiner als 0 oder größer als die Anzahl der Ergebnismengen sein</value></data>
<data name="QueryServiceDataReaderByteCountInvalid"><value>Die maximale Anzahl an Bytes die zurückgeben wird, muss größer als 0 sein.</value></data>
<data name="QueryServiceDataReaderCharCountInvalid"><value>Die maximale Anzahl an Zeichen die zurückgeben werden, muss größer als 0 sein.</value></data>
<data name="QueryServiceDataReaderXmlCountInvalid"><value>Die maximale Anzahl an XML Bytes die zurückgeben wird, muss größer als 0 sein.</value></data>
<data name="QueryServiceFileWrapperWriteOnly"><value>Die Zugriffsmethode kann nicht write-only sein.</value></data>
<data name="QueryServiceFileWrapperNotInitialized"><value>FileStreamWrapper muss initialisiert werden, bevor Operationen ausführt werden können</value></data>
<data name="QueryServiceFileWrapperReadOnly"><value>Diese FileStreamWrapper kann nicht zum Schreiben verwendet werden</value></data>
<data name="QueryServiceAffectedOneRow"><value>(1 Zeile betroffen)</value></data>
<data name="QueryServiceAffectedRows"><value>({0} Zeilen betroffen)</value></data>
<data name="QueryServiceCompletedSuccessfully"><value>Die Befehle wurden erfolgreich ausgeführt.</value></data>
<data name="QueryServiceErrorFormat"><value>Zeile MSG {0} auf {1} Status {2}, {3} {4} {5}</value></data>
<data name="QueryServiceQueryFailed"><value>Fehler bei Abfrage: {0}</value></data>
<data name="QueryServiceColumnNull"><value>(Kein Spaltenname)</value></data>
<data name="QueryServiceRequestsNoQuery"><value>Die angeforderte Abfrage ist nicht vorhanden.</value></data>
<data name="QueryServiceQueryInvalidOwnerUri"><value>Dieser Editor ist nicht mit einer Datenbank verbunden.</value></data>
<data name="QueryServiceQueryInProgress"><value>Eine Abfrage wird für diese Sitzung bereits ausgeführt. Brechen Sie diese Abfrage ab, oder warten Sie auf Beendigung.</value></data>
<data name="QueryServiceMessageSenderNotSql"><value>Das sender Objekt für OnInfoMessage muss vom Typ SqlConnection sein</value></data>
<data name="QueryServiceSaveAsResultSetNotComplete"><value>Das Ergebnis kann nicht gespeichert werden, solange die Abfrageausführung nicht abgeschlossen ist.</value></data>
<data name="QueryServiceSaveAsMiscStartingError"><value>Beim Speichern ist ein interner Fehler aufgetreten</value></data>
<data name="QueryServiceSaveAsInProgress"><value>Eine Speicheranforderung mit demselben Pfad wird bereits ausgeführt.</value></data>
<data name="QueryServiceSaveAsFail"><value>Fehler beim Speichern von {0}: {1}</value></data>
<data name="QueryServiceResultSetNotRead"><value>Der Teil kann nicht gelesen werden solange die Ergebnisse nicht vom Server gelesen wurden</value></data>
<data name="QueryServiceResultSetStartRowOutOfRange"><value>Index der Startzeile kann nicht kleiner als 0 oder größer als die Anzahl der Zeilen der Ergebnismenge sein</value></data>
<data name="QueryServiceResultSetRowCountOutOfRange"><value>Zeilenanzahl muss eine positive ganze Zahl sein.</value></data>
<data name="QueryServiceResultSetNoColumnSchema"><value>Es konnten keine Schemainformationen der Spalte abgerufen werden</value></data>
<data name="QueryServiceExecutionPlanNotFound"><value>Es konnten kein Ausführungsplan für die Ergebnismenge abgerufen werden</value></data>
<data name="PeekDefinitionAzureError"><value>Diese Funktionalität wird derzeit nicht in Azure SQL DB ud Data Warehouse unterstützt: {0}</value></data>
<data name="PeekDefinitionError"><value>Ein unerwarteter Fehler trat beim Einsehen der Definitionen auf: {0}</value></data>
<data name="PeekDefinitionNoResultsError"><value>Es wurden keine Ergebnisse gefunden.</value></data>
<data name="PeekDefinitionDatabaseError"><value>Es wurde kein Datenbankobjekt abgerufen</value></data>
<data name="PeekDefinitionNotConnectedError"><value>Verbinden Sie Sich mit einem Server.</value></data>
<data name="PeekDefinitionTimedoutError"><value>Zeitüberschreitung bei der Ausführung</value></data>
<data name="PeekDefinitionTypeNotSupportedError"><value>Dieser Objekttyp wird aktuell von dieser Funktionalität nicht unterstützt</value></data>
<data name="WorkspaceServicePositionLineOutOfRange"><value>Die Position befindet sich außerhalb der Zeile</value></data>
<data name="WorkspaceServicePositionColumnOutOfRange"><value>Die Position befindet sich außerhalb der Spalte in Zeile {0}</value></data>
<data name="WorkspaceServiceBufferPositionOutOfOrder"><value>Startposition ({0}, {1}) muss vor oder gleich der Endposition ({2}, {3}) sein</value></data>
<data name="EE_BatchSqlMessageNoProcedureInfo"><value>Meldung {0}, Ebene {1}, Status {2}, Zeile {3}</value></data>
<data name="EE_BatchSqlMessageWithProcedureInfo"><value>Meldung {0}, Ebene {1}, Status {2}, Prozedur {3}, Zeile {4}</value></data>
<data name="EE_BatchSqlMessageNoLineInfo"><value>Meldung {0}, Ebene {1}, Status {2}</value></data>
<data name="EE_BatchError_Exception"><value>Fehler beim Ausführen des Batches. Fehlermeldung: {0}</value></data>
<data name="EE_BatchExecutionInfo_RowsAffected"><value>({0} Zeile(n) betroffen)</value></data>
<data name="EE_ExecutionNotYetCompleteError"><value>Die vorherige Ausführung ist noch nicht abgeschlossen.</value></data>
<data name="EE_ScriptError_Error"><value>Ein Skriptfehler ist aufgetreten.</value></data>
<data name="EE_ScriptError_ParsingSyntax"><value>Ein Syntaxfehler ist aufgetreten der bei Analyse von {0}</value></data>
<data name="EE_ScriptError_FatalError"><value>Ein schwerwiegender Fehler ist aufgetreten.</value></data>
<data name="EE_ExecutionInfo_FinalizingLoop"><value>{0}-mal ausgeführt...</value></data>
<data name="EE_ExecutionInfo_QueryCancelledbyUser"><value>Sie haben die Abfrage abgebrochen.</value></data>
<data name="EE_BatchExecutionError_Halting"><value>Fehler während der Batchausführung.</value></data>
<data name="EE_BatchExecutionError_Ignoring"><value>Fehler während der Batchausführung, aber des Fehlers wurde ignoriert.</value></data>
<data name="EE_ExecutionInfo_InitializingLoop"><value>Beginning execution loop</value></data>
<data name="EE_ExecutionError_CommandNotSupported"><value>Befehl {0} wird nicht unterstützt.</value></data>
<data name="EE_ExecutionError_VariableNotFound"><value>Die Variable {0} konnte nicht gefunden werden.</value></data>
<data name="BatchParserWrapperExecutionEngineError"><value>Fehler bei der SQL-Ausführung: {0}</value></data>
<data name="BatchParserWrapperExecutionError"><value>Batch-Ausführung des Batchanalysewrappers: {0} in Zeile {1} gefunden...: {2} Beschreibung: {3}</value></data>
<data name="BatchParserWrapperExecutionEngineBatchMessage"><value>Batch Parser Wrapper Execution Engine Meldung empfangen: Meldung: {0} Ausführliche Meldung: {1}</value></data>
<data name="BatchParserWrapperExecutionEngineBatchResultSetProcessing"><value>Stapelverarbeitung Parser Wrapper Execution Engine Stapel ResultSet: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1}</value></data>
<data name="BatchParserWrapperExecutionEngineBatchResultSetFinished"><value>Batch-Parser Wrapper Execution Engine wurde beendet ResultSet.</value></data>
<data name="BatchParserWrapperExecutionEngineBatchCancelling"><value>Ausführung des Batchanalysewrappers Batch abgebrochen.</value></data>
<data name="EE_ScriptError_Warning"><value>Scripting-Warnung.</value></data>
<data name="TroubleshootingAssistanceMessage"><value>Weitere Informationen zu diesem Fehler finden Sie in den entsprechenden Abschnitten der Produktdokumentation.</value></data>
<data name="BatchParser_CircularReference"><value>Die Datei '{0}' ist rekursiv eingeschlossen.</value></data>
<data name="BatchParser_CommentNotTerminated"><value>Fehlender End Kommentarzeichen "* /".</value></data>
<data name="BatchParser_StringNotTerminated"><value>Fehlendes schließendes Anführungszeichen nach der Zeichenfolge</value></data>
<data name="BatchParser_IncorrectSyntax"><value>Syntaxfehler aufgetreten beim Analysieren von '{0}'.</value></data>
<data name="BatchParser_VariableNotDefined"><value>Variable {0} ist nicht definiert.</value></data>
<data name="TestLocalizationConstant"><value>Test</value></data>
<data name="ErrorEmptyStringReplacement"><value>Ersatz einer leeren Zeichenfolge durch eine leere Zeichenfolge.</value></data>
<data name="EditDataSessionNotFound"><value>Die Sitzung "{0}" ist nicht vorhanden.</value></data>
<data name="EditDataQueryNotCompleted"><value>Die Abfrage wurde nicht abgeschlossen</value></data>
<data name="EditDataQueryImproperResultSets"><value>Die Abfrage erzeugte mehr als eine Ergebnismenge</value></data>
<data name="EditDataFailedAddRow"><value>Fehler beim Hinzufügen einer neuen Zeile zum Aktualisierungscache</value></data>
<data name="EditDataRowOutOfRange"><value>Die angegebene Zeilen-ID ist außerhalb des Bereiches des Bearbeitungscaches</value></data>
<data name="EditDataUpdatePending"><value>Für diese Zeile steht eine Aktualisierung an, die erst zurückgenommen werden muß</value></data>
<data name="EditDataUpdateNotPending"><value>Die angegebene Zeilen-ID hat keine ausstehenden Aktualisierungen</value></data>
<data name="EditDataObjectMetadataNotFound"><value>Tabellen oder Sicht Metadaten konnten nicht gefunden werden</value></data>
<data name="EditDataInvalidFormatBinary"><value>Ungültiges Format für eine binäre Spalte</value></data>
<data name="EditDataInvalidFormatBoolean"><value>Spalten vom Typ Boolean müssen entweder der Zahl 0 oder 1 oder der Zeichenkette true oder false entsprechen</value></data>
<data name="EditDataCreateScriptMissingValue"><value>Ein Pflichtfeld hat keinen Wert.</value></data>
<data name="EditDataDeleteSetCell"><value>Für diese Zeile steht ein Löschbefehl aus, die Aktualisierung von Feldern kann nicht durchgeführt werden.</value></data>
<data name="EditDataColumnIdOutOfRange"><value>Die ID der Spalte muss innerhalb des Bereichs der Spalten der Abfrage sein</value></data>
<data name="EditDataColumnCannotBeEdited"><value>Die Spalte kann nicht editiert werden</value></data>
<data name="EditDataColumnNoKeyColumns"><value>Keine Schlüsselspalten gefunden</value></data>
<data name="EditDataScriptFilePathNull"><value>Der Name der Ausgabedatei muss angegeben werden</value></data>
<data name="EditDataUnsupportedObjectType"><value>Das Datenbankobjekt {0} kan nicht editiert werden</value></data>
<data name="ConnectionServiceDbErrorDefaultNotConnected"><value>Spezifizierte URI '{0}' hat keine Standardverbindung</value></data>
<data name="EditDataCommitInProgress"><value>Eine Commit-Anweisung wird ausgeführt. Bitte warten Sie bis zur Fertigstellung</value></data>
<data name="SqlScriptFormatterDecimalMissingPrecision"><value>Für die Decimal-Spalte fehlt die Angabe der Genauigkeit und Dezimalstellenanzahl</value></data>
<data name="EditDataComputedColumnPlaceholder"><value>&lt;TBD&gt;</value></data>
<data name="QueryServiceResultSetAddNoRows"><value>Kann Zeile nicht an Ergebnisbuffer anhängen, da keine Zeilen im Datareader enthalten sind.</value></data>
<data name="EditDataTimeOver24Hrs"><value>Der Wert für eine Spalte vom Typ TIME muss zwischen 00:00:00.0000000 und 23:59:59.9999999 liegen</value></data>
<data name="EditDataNullNotAllowed"><value>NULL ist für diese Spalte nicht erlaubt</value></data>
<data name="EditDataSessionAlreadyExists"><value>Es gibt bereits eine Session</value></data>
<data name="EditDataSessionNotInitialized"><value>Eine Session wurde nocht nicht initialisiert</value></data>
<data name="EditDataSessionAlreadyInitialized"><value>Eine Session wurde bereits initialisiert</value></data>
<data name="EditDataSessionAlreadyInitializing"><value>Eine Session wurde bereits initialisiert oder befindet sich im Prozess der Initialisierung.</value></data>
<data name="EditDataQueryFailed"><value>Fehler beim Ausführen der Abfrage. Weitere Informationen finden SIe in der Ausgabe</value></data>
<data name="EditDataFilteringNegativeLimit"><value>Die Ergebnismengengrenze darf nicht negativ sein</value></data>
<data name="QueryServiceCellNull"><value>NULL</value></data>
<data name="EditDataMetadataObjectNameRequired"><value>Der Name des Objekts muss angegeben werden</value></data>
<data name="EditDataMetadataTooManyIdentifiers"><value>Einen bestimmten Server oder Datenbank auszuwählen wird nicht unterstützt.</value></data>
<data name="EditDataMetadataNotExtended"><value>Die Metadaten der Tabelle enthält keine erweiterten EIgenschaften.</value></data>
<data name="EditDataObjectNotFound"><value>Tabelle oder Sicht zur Bearbeitung konnte nicht gefunden werden</value></data>
<data name="TreeNodeError"><value>Fehler beim Erweitern von: {0}</value></data>
<data name="ServerNodeConnectionError"><value>Fehler bei der Verbindung zu {0}</value></data>
<data name="SchemaHierarchy_Aggregates"><value>Aggregate</value></data>
<data name="SchemaHierarchy_ServerRoles"><value>Serverrollen</value></data>
<data name="SchemaHierarchy_ApplicationRoles"><value>Anwendungsrollen</value></data>
<data name="SchemaHierarchy_Assemblies"><value>Assemblys</value></data>
<data name="SchemaHierarchy_AssemblyFiles"><value>Assemblydateien</value></data>
<data name="SchemaHierarchy_AsymmetricKeys"><value>Asymmetrische Schlüssel</value></data>
<data name="SchemaHierarchy_DatabaseAsymmetricKeys"><value>Asymmetrische Schlüssel</value></data>
<data name="SchemaHierarchy_DataCompressionOptions"><value>Datenkomprimierungsoptionen</value></data>
<data name="SchemaHierarchy_Certificates"><value>Zertifikate</value></data>
<data name="SchemaHierarchy_FileTables"><value>FileTables</value></data>
<data name="SchemaHierarchy_DatabaseCertificates"><value>Zertifikate</value></data>
<data name="SchemaHierarchy_CheckConstraints"><value>Einschränkungen überprüfen</value></data>
<data name="SchemaHierarchy_Columns"><value>Spalten</value></data>
<data name="SchemaHierarchy_Constraints"><value>Einschränkungen</value></data>
<data name="SchemaHierarchy_Contracts"><value>Verträge</value></data>
<data name="SchemaHierarchy_Credentials"><value>Anmeldeinformationen</value></data>
<data name="SchemaHierarchy_ErrorMessages"><value>Fehlermeldungen</value></data>
<data name="SchemaHierarchy_ServerRoleMembership"><value>Serverrollenmitgliedschaft</value></data>
<data name="SchemaHierarchy_DatabaseOptions"><value>Datenbankoptionen</value></data>
<data name="SchemaHierarchy_DatabaseRoles"><value>Datenbankrollen</value></data>
<data name="SchemaHierarchy_RoleMemberships"><value>Rollenmitgliedschaften</value></data>
<data name="SchemaHierarchy_DatabaseTriggers"><value>Datenbanktrigger</value></data>
<data name="SchemaHierarchy_DefaultConstraints"><value>DEFAULT-Einschränkungen</value></data>
<data name="SchemaHierarchy_Defaults"><value>Standardwerte</value></data>
<data name="SchemaHierarchy_Sequences"><value>Sequenzen</value></data>
<data name="SchemaHierarchy_Endpoints"><value>Endpunkte</value></data>
<data name="SchemaHierarchy_EventNotifications"><value>Ereignisbenachrichtigungen</value></data>
<data name="SchemaHierarchy_ServerEventNotifications"><value>Serverbenachrichtigungsereignisse</value></data>
<data name="SchemaHierarchy_ExtendedProperties"><value>Erweiterte Eigenschaften</value></data>
<data name="SchemaHierarchy_FileGroups"><value>Dateigruppen</value></data>
<data name="SchemaHierarchy_ForeignKeys"><value>Fremdschlüssel</value></data>
<data name="SchemaHierarchy_FullTextCatalogs"><value>Volltextkataloge</value></data>
<data name="SchemaHierarchy_FullTextIndexes"><value>Volltextindizes</value></data>
<data name="SchemaHierarchy_Functions"><value>Funktionen</value></data>
<data name="SchemaHierarchy_Indexes"><value>Indizes</value></data>
<data name="SchemaHierarchy_InlineFunctions"><value>Inlinefunktionen</value></data>
<data name="SchemaHierarchy_Keys"><value>Schlüssel</value></data>
<data name="SchemaHierarchy_LinkedServers"><value>Verbindungsserver</value></data>
<data name="SchemaHierarchy_LinkedServerLogins"><value>Anmeldungen für Verbindungsserver</value></data>
<data name="SchemaHierarchy_Logins"><value>Anmeldungen</value></data>
<data name="SchemaHierarchy_MasterKey"><value>Hauptschlüssel</value></data>
<data name="SchemaHierarchy_MasterKeys"><value>Hauptschlüssel</value></data>
<data name="SchemaHierarchy_MessageTypes"><value>Meldungstypen</value></data>
<data name="SchemaHierarchy_MultiSelectFunctions"><value>Tabellenwertfunktionen</value></data>
<data name="SchemaHierarchy_Parameters"><value>Parameter</value></data>
<data name="SchemaHierarchy_PartitionFunctions"><value>Partitionsfunktionen</value></data>
<data name="SchemaHierarchy_PartitionSchemes"><value>Partitionsschemas</value></data>
<data name="SchemaHierarchy_Permissions"><value>Berechtigungen</value></data>
<data name="SchemaHierarchy_PrimaryKeys"><value>Primärschlüssel</value></data>
<data name="SchemaHierarchy_Programmability"><value>Programmierbarkeit</value></data>
<data name="SchemaHierarchy_Queues"><value>Warteschlangen</value></data>
<data name="SchemaHierarchy_RemoteServiceBindings"><value>Remotedienstbindungen</value></data>
<data name="SchemaHierarchy_ReturnedColumns"><value>Zurückgegebene Spalten</value></data>
<data name="SchemaHierarchy_Roles"><value>Rollen</value></data>
<data name="SchemaHierarchy_Routes"><value>Routen</value></data>
<data name="SchemaHierarchy_Rules"><value>Regeln</value></data>
<data name="SchemaHierarchy_Schemas"><value>Schemas</value></data>
<data name="SchemaHierarchy_Security"><value>Sicherheit</value></data>
<data name="SchemaHierarchy_ServerObjects"><value>Serverobjekte</value></data>
<data name="SchemaHierarchy_Management"><value>Verwaltung</value></data>
<data name="SchemaHierarchy_ServerTriggers"><value>Trigger</value></data>
<data name="SchemaHierarchy_ServiceBroker"><value>Service Broker</value></data>
<data name="SchemaHierarchy_Services"><value>Dienste</value></data>
<data name="SchemaHierarchy_Signatures"><value>Signaturen</value></data>
<data name="SchemaHierarchy_LogFiles"><value>Protokolldateien</value></data>
<data name="SchemaHierarchy_Statistics"><value>Statistik</value></data>
<data name="SchemaHierarchy_Storage"><value>Speicher</value></data>
<data name="SchemaHierarchy_StoredProcedures"><value>Gespeicherte Prozeduren</value></data>
<data name="SchemaHierarchy_SymmetricKeys"><value>Symmetrische Schlüssel</value></data>
<data name="SchemaHierarchy_Synonyms"><value>Synonyme</value></data>
<data name="SchemaHierarchy_Tables"><value>Tabellen</value></data>
<data name="SchemaHierarchy_Triggers"><value>Trigger</value></data>
<data name="SchemaHierarchy_Types"><value>Typen</value></data>
<data name="SchemaHierarchy_UniqueKeys"><value>Eindeutige Schlüssel</value></data>
<data name="SchemaHierarchy_UserDefinedDataTypes"><value>Benutzerdefinierte Datentypen</value></data>
<data name="SchemaHierarchy_UserDefinedTypes"><value>Benutzerdefinierte Typen (CLR)</value></data>
<data name="SchemaHierarchy_Users"><value>Benutzer</value></data>
<data name="SchemaHierarchy_Views"><value>Sichten</value></data>
<data name="SchemaHierarchy_XmlIndexes"><value>XML-Indizes</value></data>
<data name="SchemaHierarchy_XMLSchemaCollections"><value>XML-Schemaauflistungen</value></data>
<data name="SchemaHierarchy_UserDefinedTableTypes"><value>Benutzerdefinierte Tabellentypen</value></data>
<data name="SchemaHierarchy_FilegroupFiles"><value>Dateien</value></data>
<data name="MissingCaption"><value>Fehlende Beschriftung</value></data>
<data name="SchemaHierarchy_BrokerPriorities"><value>Brokerprioritäten</value></data>
<data name="SchemaHierarchy_CryptographicProviders"><value>Kryptografieanbieter</value></data>
<data name="SchemaHierarchy_DatabaseAuditSpecifications"><value>Datenbank-Überwachungsspezifikationen</value></data>
<data name="SchemaHierarchy_DatabaseEncryptionKeys"><value>Verschlüsselungsschlüssel für Datenbank</value></data>
<data name="SchemaHierarchy_EventSessions"><value>Ereignissitzungen</value></data>
<data name="SchemaHierarchy_FullTextStopLists"><value>Volltext-Stopplisten</value></data>
<data name="SchemaHierarchy_ResourcePools"><value>Ressourcenpools</value></data>
<data name="SchemaHierarchy_ServerAudits"><value>Überwachungen</value></data>
<data name="SchemaHierarchy_ServerAuditSpecifications"><value>Serverüberwachungsspezifikationen</value></data>
<data name="SchemaHierarchy_SpatialIndexes"><value>Räumliche Indizes</value></data>
<data name="SchemaHierarchy_WorkloadGroups"><value>Arbeitsauslastungsgruppen</value></data>
<data name="SchemaHierarchy_SqlFiles"><value>SQL-Dateien</value></data>
<data name="SchemaHierarchy_ServerFunctions"><value>Serverfunktionen</value></data>
<data name="SchemaHierarchy_SqlType"><value>SQL-Typ</value></data>
<data name="SchemaHierarchy_ServerOptions"><value>Serveroptionen</value></data>
<data name="SchemaHierarchy_DatabaseDiagrams"><value>Datenbankdiagramme</value></data>
<data name="SchemaHierarchy_SystemTables"><value>Systemtabellen</value></data>
<data name="SchemaHierarchy_Databases"><value>Datenbanken</value></data>
<data name="SchemaHierarchy_SystemContracts"><value>Systemverträge</value></data>
<data name="SchemaHierarchy_SystemDatabases"><value>Systemdatenbanken</value></data>
<data name="SchemaHierarchy_SystemMessageTypes"><value>Systemmeldungstypen</value></data>
<data name="SchemaHierarchy_SystemQueues"><value>Systemwarteschlangen</value></data>
<data name="SchemaHierarchy_SystemServices"><value>Systemdienste</value></data>
<data name="SchemaHierarchy_SystemStoredProcedures"><value>Gespeicherte Systemprozeduren</value></data>
<data name="SchemaHierarchy_SystemViews"><value>Systemsichten</value></data>
<data name="SchemaHierarchy_DataTierApplications"><value>Datenebenenanwendungen</value></data>
<data name="SchemaHierarchy_ExtendedStoredProcedures"><value>Erweiterte gespeicherte Prozeduren</value></data>
<data name="SchemaHierarchy_SystemAggregateFunctions"><value>Aggregatfunktionen</value></data>
<data name="SchemaHierarchy_SystemApproximateNumerics"><value>Ungefähre numerische Ausdrücke</value></data>
<data name="SchemaHierarchy_SystemBinaryStrings"><value>Binärzeichenfolgen</value></data>
<data name="SchemaHierarchy_SystemCharacterStrings"><value>Zeichenfolgen</value></data>
<data name="SchemaHierarchy_SystemCLRDataTypes"><value>CLR-Datentypen</value></data>
<data name="SchemaHierarchy_SystemConfigurationFunctions"><value>Konfigurationsfunktionen</value></data>
<data name="SchemaHierarchy_SystemCursorFunctions"><value>Cursorfunktionen</value></data>
<data name="SchemaHierarchy_SystemDataTypes"><value>Systemdatentypen</value></data>
<data name="SchemaHierarchy_SystemDateAndTime"><value>Datum und Uhrzeit</value></data>
<data name="SchemaHierarchy_SystemDateAndTimeFunctions"><value>Datums- und Uhrzeitfunktionen</value></data>
<data name="SchemaHierarchy_SystemExactNumerics"><value>Genaue numerische Ausdrücke</value></data>
<data name="SchemaHierarchy_SystemFunctions"><value>Systemfunktionen</value></data>
<data name="SchemaHierarchy_SystemHierarchyIdFunctions"><value>Hierarchie-ID-Funktionen</value></data>
<data name="SchemaHierarchy_SystemMathematicalFunctions"><value>Mathematische Funktionen</value></data>
<data name="SchemaHierarchy_SystemMetadataFunctions"><value>Metadatenfunktionen</value></data>
<data name="SchemaHierarchy_SystemOtherDataTypes"><value>Andere Datentypen</value></data>
<data name="SchemaHierarchy_SystemOtherFunctions"><value>Andere Funktionen</value></data>
<data name="SchemaHierarchy_SystemRowsetFunctions"><value>Rowsetfunktionen</value></data>
<data name="SchemaHierarchy_SystemSecurityFunctions"><value>Sicherheitsfunktionen</value></data>
<data name="SchemaHierarchy_SystemSpatialDataTypes"><value>Räumliche Datentypen</value></data>
<data name="SchemaHierarchy_SystemStringFunctions"><value>Zeichenfolgenfunktionen</value></data>
<data name="SchemaHierarchy_SystemSystemStatisticalFunctions"><value>Statistische Systemfunktionen</value></data>
<data name="SchemaHierarchy_SystemTextAndImageFunctions"><value>Text- und Bildfunktionen</value></data>
<data name="SchemaHierarchy_SystemUnicodeCharacterStrings"><value>Unicode-Zeichenfolgen</value></data>
<data name="SchemaHierarchy_AggregateFunctions"><value>Aggregatfunktionen</value></data>
<data name="SchemaHierarchy_ScalarValuedFunctions"><value>Skalarwertfunktionen</value></data>
<data name="SchemaHierarchy_TableValuedFunctions"><value>Tabellenwertfunktionen</value></data>
<data name="SchemaHierarchy_SystemExtendedStoredProcedures"><value>Erweiterte gespeicherte Systemprozeduren</value></data>
<data name="SchemaHierarchy_BuiltInType"><value>Integrierte Typen</value></data>
<data name="SchemaHierarchy_BuiltInServerRole"><value>Integrierte Serverrollen</value></data>
<data name="SchemaHierarchy_UserWithPassword"><value>Benutzer mit Kennwort</value></data>
<data name="SchemaHierarchy_SearchPropertyList"><value>Sucheigenschaftenliste</value></data>
<data name="SchemaHierarchy_SecurityPolicies"><value>Sicherheitsrichtlinien</value></data>
<data name="SchemaHierarchy_SecurityPredicates"><value>Sicherheitsprädikate</value></data>
<data name="SchemaHierarchy_ServerRole"><value>Serverrolle</value></data>
<data name="SchemaHierarchy_SearchPropertyLists"><value>Sucheigenschaftenlisten</value></data>
<data name="SchemaHierarchy_ColumnStoreIndexes"><value>Spaltenspeicherindizes</value></data>
<data name="SchemaHierarchy_TableTypeIndexes"><value>Tabellentypindex</value></data>
<data name="SchemaHierarchy_SelectiveXmlIndexes"><value>Selektive XML-Indexe</value></data>
<data name="SchemaHierarchy_XmlNamespaces"><value>XML-Namespaces</value></data>
<data name="SchemaHierarchy_XmlTypedPromotedPaths"><value>XML-typisierte höher gestufte Pfade</value></data>
<data name="SchemaHierarchy_SqlTypedPromotedPaths"><value>T-SQL-typisierte höher gestufte Pfade</value></data>
<data name="SchemaHierarchy_DatabaseScopedCredentials"><value>Datenbankweit gültige Anmeldeinformationen</value></data>
<data name="SchemaHierarchy_ExternalDataSources"><value>Externe Datenquellen</value></data>
<data name="SchemaHierarchy_ExternalFileFormats"><value>Externe Dateiformate</value></data>
<data name="SchemaHierarchy_ExternalResources"><value>Externe Ressourcen</value></data>
<data name="SchemaHierarchy_ExternalTables"><value>Externe Tabellen</value></data>
<data name="SchemaHierarchy_AlwaysEncryptedKeys"><value>Immer verschlüsselte Schlüssel</value></data>
<data name="SchemaHierarchy_ColumnMasterKeys"><value>Spaltenhauptschlüssel</value></data>
<data name="SchemaHierarchy_ColumnEncryptionKeys"><value>Spaltenverschlüsselungsschlüssel</value></data>
<data name="SchemaHierarchy_Server"><value>Server</value></data>
<data name="ScriptingParams_ConnectionString_Property_Invalid"><value>Fehler beim Analysieren der Eigenschaft ScriptingParams.ConnectionString.</value></data>
<data name="ScriptingParams_FilePath_Property_Invalid"><value>Ungültiges Verzeichnis angeben in der Eigenschaft ScriptingParams.FilePath.</value></data>
<data name="ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid"><value>Fehler beim Analysieren der Eigenschaft ScriptingListObjectsCompleteParams.ConnectionString</value></data>
<data name="SchemaHierarchy_SubroutineParameterLabelFormatString"><value>{0} ({1}, {2}, {3})</value></data>
<data name="SchemaHierarchy_SubroutineParameterNoDefaultLabel"><value>Kein Standard</value></data>
<data name="SchemaHierarchy_SubroutineParameterInputLabel"><value>Eingabe</value></data>
<data name="SchemaHierarchy_SubroutineParameterInputOutputLabel"><value>Eingabe/Ausgabe</value></data>
<data name="SchemaHierarchy_SubroutineParameterInputReadOnlyLabel"><value>Eingabe/schreibgeschützt</value></data>
<data name="SchemaHierarchy_SubroutineParameterInputOutputReadOnlyLabel"><value>Eingabe/Ausgabe/schreibgeschützt</value></data>
<data name="SchemaHierarchy_SubroutineParameterDefaultLabel"><value>Standard</value></data>
<data name="SchemaHierarchy_NullColumn_Label"><value>NULL</value></data>
<data name="SchemaHierarchy_NotNullColumn_Label"><value>nicht NULL</value></data>
<data name="SchemaHierarchy_UDDTLabelWithType"><value>{0} ({1}, {2})</value></data>
<data name="SchemaHierarchy_UDDTLabelWithoutType"><value>{0} ({1})</value></data>
<data name="SchemaHierarchy_ComputedColumnLabelWithType"><value>{0} ({1}berechnet, {2}, {3})</value></data>
<data name="SchemaHierarchy_ComputedColumnLabelWithoutType"><value>{0} ({1}berechnet)</value></data>
<data name="SchemaHierarchy_ColumnSetLabelWithoutType"><value>{0} (Spaltensatz, {1})</value></data>
<data name="SchemaHierarchy_ColumnSetLabelWithType"><value>{0} (Spaltensatz, {1} {2}, {3})</value></data>
<data name="SchemaHierarchy_ColumnSetLabelWithTypeAndKeyString"><value>{0} (Spaltensatz, {1}, {2}, {3})</value></data>
<data name="UniqueIndex_LabelPart"><value>Eindeutig</value></data>
<data name="NonUniqueIndex_LabelPart"><value>Nicht eindeutig</value></data>
<data name="ClusteredIndex_LabelPart"><value>Gruppiert</value></data>
<data name="NonClusteredIndex_LabelPart"><value>Nicht gruppiert</value></data>
<data name="History_LabelPart"><value>Verlauf</value></data>
<data name="SystemVersioned_LabelPart"><value>System-Mit Versionsangabe</value></data>
<data name="unavailable"><value>Nicht verfügbar</value></data>
<data name="filegroup_dialog_defaultFilegroup"><value>Aktuelle Standarddateigruppe: {0}</value></data>
<data name="filegroup_dialog_title"><value>Neue Dateigruppe für "{0}"</value></data>
<data name="filegroups_default"><value>Standard</value></data>
<data name="filegroups_files"><value>Dateien</value></data>
<data name="filegroups_name"><value>Name</value></data>
<data name="filegroups_readonly"><value>Schreibgeschützt</value></data>
<data name="general_autogrowth"><value>Automatische Vergrößerung/Maximale Größe</value></data>
<data name="general_builderText"><value>...</value></data>
<data name="general_default"><value>&lt;Standard&gt;</value></data>
<data name="general_fileGroup"><value>Dateigruppe</value></data>
<data name="general_fileName"><value>Logischer Name</value></data>
<data name="general_fileType"><value>Dateityp</value></data>
<data name="general_initialSize"><value>Anfangsgröße (MB)</value></data>
<data name="general_newFilegroup"><value>&lt;neue Dateigruppe&gt;</value></data>
<data name="general_path"><value>Pfad</value></data>
<data name="general_physicalFileName"><value>Dateiname</value></data>
<data name="general_rawDevice"><value>&lt;unformatiertes Medium&gt;</value></data>
<data name="general_recoveryModel_bulkLogged"><value>Massenprotokolliert</value></data>
<data name="general_recoveryModel_full"><value>Vollständig</value></data>
<data name="general_recoveryModel_simple"><value>Einfach</value></data>
<data name="general_titleSearchOwner"><value>Datenbankbesitzer auswählen</value></data>
<data name="prototype_autogrowth_disabled"><value>Kein(e)</value></data>
<data name="prototype_autogrowth_restrictedGrowthByMB"><value>Um {0} MB, auf {1} MB beschränkt</value></data>
<data name="prototype_autogrowth_restrictedGrowthByPercent"><value>Um {0} Prozent, auf {1} MB beschränkt </value></data>
<data name="prototype_autogrowth_unrestrictedGrowthByMB"><value>Um {0} MB, unbegrenzt</value></data>
<data name="prototype_autogrowth_unrestrictedGrowthByPercent"><value>Um {0} Prozent, unbegrenzt</value></data>
<data name="prototype_autogrowth_unlimitedfilestream"><value>Unbegrenzt</value></data>
<data name="prototype_autogrowth_limitedfilestream"><value>Auf {0} MB beschränkt</value></data>
<data name="prototype_db_category_automatic"><value>Automatisch</value></data>
<data name="prototype_db_category_servicebroker"><value>Service Broker</value></data>
<data name="prototype_db_category_collation"><value>Sortierung</value></data>
<data name="prototype_db_category_cursor"><value>Cursor</value></data>
<data name="prototype_db_category_misc"><value>Verschiedenes</value></data>
<data name="prototype_db_category_recovery"><value>Wiederherstellung</value></data>
<data name="prototype_db_category_state"><value>Status</value></data>
<data name="prototype_db_prop_ansiNullDefault"><value>ANSI NULL Default</value></data>
<data name="prototype_db_prop_ansiNulls"><value>ANSI NULLS aktiviert</value></data>
<data name="prototype_db_prop_ansiPadding"><value>ANSI-Auffüllung aktiviert </value></data>
<data name="prototype_db_prop_ansiWarnings"><value>ANSI Warnings aktiviert</value></data>
<data name="prototype_db_prop_arithabort"><value>Abbruch bei arithmetischem Fehler aktiviert </value></data>
<data name="prototype_db_prop_autoClose"><value>Automatisch schließen</value></data>
<data name="prototype_db_prop_autoCreateStatistics"><value>Statistik automatisch erstellen</value></data>
<data name="prototype_db_prop_autoShrink"><value>Automatisch verkleinern</value></data>
<data name="prototype_db_prop_autoUpdateStatistics"><value>Statistiken automatisch aktualisieren </value></data>
<data name="prototype_db_prop_autoUpdateStatisticsAsync"><value>Statistik automatisch asynchron aktualisieren</value></data>
<data name="prototype_db_prop_caseSensitive"><value>Unterscheidung nach Groß-/Kleinschreibung</value></data>
<data name="prototype_db_prop_closeCursorOnCommit"><value>Schließen des Cursors nach Commit aktiviert </value></data>
<data name="prototype_db_prop_collation"><value>Sortierung</value></data>
<data name="prototype_db_prop_concatNullYieldsNull"><value>Verketten von NULL-Werten ergibt NULL </value></data>
<data name="prototype_db_prop_databaseCompatibilityLevel"><value>Datenbank-Kompatibilitätsgrad </value></data>
<data name="prototype_db_prop_databaseState"><value>Datenbankstatus </value></data>
<data name="prototype_db_prop_defaultCursor"><value>Standardcursor</value></data>
<data name="prototype_db_prop_fullTextIndexing"><value>Volltextindizierung aktiviert </value></data>
<data name="prototype_db_prop_numericRoundAbort"><value>Abbruch bei numerischem Runden </value></data>
<data name="prototype_db_prop_pageVerify"><value>Seitenüberprüfung </value></data>
<data name="prototype_db_prop_quotedIdentifier"><value>Bezeichner in Anführungszeichen aktiviert </value></data>
<data name="prototype_db_prop_readOnly"><value>Datenbank schreibgeschützt</value></data>
<data name="prototype_db_prop_recursiveTriggers"><value>Rekursive Trigger aktiviert </value></data>
<data name="prototype_db_prop_restrictAccess"><value>Zugriff beschränken</value></data>
<data name="prototype_db_prop_selectIntoBulkCopy"><value>Select Into/Bulk Copy</value></data>
<data name="prototype_db_prop_honorBrokerPriority"><value>Brokerpriorität berücksichtigen</value></data>
<data name="prototype_db_prop_serviceBrokerGuid"><value>Service Broker-Bezeichner</value></data>
<data name="prototype_db_prop_brokerEnabled"><value>Broker aktiviert</value></data>
<data name="prototype_db_prop_truncateLogOnCheckpoint"><value>Protokoll bei Prüfpunkt abschneiden </value></data>
<data name="prototype_db_prop_dbChaining"><value>Datenbankübergreifende Besitzverkettung aktiviert</value></data>
<data name="prototype_db_prop_trustworthy"><value>Vertrauenswürdig</value></data>
<data name="prototype_db_prop_dateCorrelationOptimization"><value>Optimierung der Datumskorrelation aktiviert:
prototype_db_prop_parameterization = Parameterization</value></data>
<data name="prototype_db_prop_parameterization_value_forced"><value>Erzwungen</value></data>
<data name="prototype_db_prop_parameterization_value_simple"><value>Einfach</value></data>
<data name="prototype_file_dataFile"><value>ROWS (Daten)</value></data>
<data name="prototype_file_logFile"><value>LOG</value></data>
<data name="prototype_file_filestreamFile"><value>FILESTREAM-Daten</value></data>
<data name="prototype_file_noFileGroup"><value>Nicht zutreffend</value></data>
<data name="prototype_file_defaultpathstring"><value>&lt;Standardpfad&gt;</value></data>
<data name="title_openConnectionsMustBeClosed"><value>Geöffnete Verbindungen</value></data>
<data name="warning_openConnectionsMustBeClosed"><value>Zum Ändern der Datenbankeigenschaften muss SQL Server alle anderen Verbindungen mit der Datenbank schließen. Möchten Sie wirklich die Eigenschaften ändern und alle anderen Verbindungen schließen?</value></data>
<data name="prototype_db_prop_databaseState_value_autoClosed"><value>AUTO_CLOSED</value></data>
<data name="prototype_db_prop_databaseState_value_emergency"><value>EMERGENCY</value></data>
<data name="prototype_db_prop_databaseState_value_inaccessible"><value>INACCESSIBLE</value></data>
<data name="prototype_db_prop_databaseState_value_normal"><value>NORMAL</value></data>
<data name="prototype_db_prop_databaseState_value_offline"><value>OFFLINE</value></data>
<data name="prototype_db_prop_databaseState_value_recovering"><value>RECOVERING</value></data>
<data name="prototype_db_prop_databaseState_value_recoveryPending"><value>RECOVERY PENDING</value></data>
<data name="prototype_db_prop_databaseState_value_restoring"><value>RESTORING</value></data>
<data name="prototype_db_prop_databaseState_value_shutdown"><value>SHUTDOWN</value></data>
<data name="prototype_db_prop_databaseState_value_standby"><value>STANDBY</value></data>
<data name="prototype_db_prop_databaseState_value_suspect"><value>SUSPECT</value></data>
<data name="prototype_db_prop_defaultCursor_value_global"><value>GLOBAL</value></data>
<data name="prototype_db_prop_defaultCursor_value_local"><value>LOCAL</value></data>
<data name="prototype_db_prop_restrictAccess_value_multiple"><value>MULTI_USER</value></data>
<data name="prototype_db_prop_restrictAccess_value_restricted"><value>RESTRICTED_USER</value></data>
<data name="prototype_db_prop_restrictAccess_value_single"><value>SINGLE_USER</value></data>
<data name="prototype_db_prop_pageVerify_value_checksum"><value>CHECKSUM</value></data>
<data name="prototype_db_prop_pageVerify_value_none"><value>NONE</value></data>
<data name="prototype_db_prop_pageVerify_value_tornPageDetection"><value>TORN_PAGE_DETECTION</value></data>
<data name="prototype_db_prop_varDecimalEnabled"><value>VarDecimal-Speicherformat aktiviert</value></data>
<data name="compatibilityLevel_katmai"><value>SQL Server 2008 (100)</value></data>
<data name="prototype_db_prop_encryptionEnabled"><value>Verschlüsselung aktiviert</value></data>
<data name="prototype_db_prop_databasescopedconfig_value_off"><value>AUS</value></data>
<data name="prototype_db_prop_databasescopedconfig_value_on"><value>EIN</value></data>
<data name="prototype_db_prop_databasescopedconfig_value_primary"><value>PRIMÄR</value></data>
<data name="error_db_prop_invalidleadingColumns"><value>Die Anzahl führender Hashspalten ist bei der HASH-Verteilungsrichtlinie optional, sollte aber zwischen 1 und 16 Spalten liegen.</value></data>
<data name="compatibilityLevel_denali"><value>SQL Server 2012 (110)</value></data>
<data name="compatibilityLevel_sql14"><value>SQL Server 2014 (120)</value></data>
<data name="compatibilityLevel_sql15"><value>SQL Server 2016 (130)</value></data>
<data name="compatibilityLevel_sqlvNext"><value>SQL Server vNext (140)</value></data>
<data name="general_containmentType_None"><value>Kein(e)</value></data>
<data name="general_containmentType_Partial"><value>Teilweise</value></data>
<data name="filegroups_filestreamFiles"><value>FILESTREAM-Dateien</value></data>
<data name="prototype_file_noApplicableFileGroup"><value>Keine anwendbare Dateigruppe</value></data>
<data name="DatabaseNotAccessible"><value>Auf die Datenbank "{0}" kann nicht zugegriffen werden.</value></data>
<data name="QueryServiceResultSetHasNoResults"><value>Abfrage hat keine Ergebnis zum Zurückgeben</value></data>
<data name="QueryServiceResultSetTooLarge"><value>Ergebnismenge ist zu groß, um sicher geladen zu werden</value></data>
<data name="prototype_db_prop_parameterization"><value>Parametrisierung</value></data>
<data name="ConflictWithNoRecovery"><value>Diese Option darf nicht angegeben werden, wenn eine Sicherung mit der NORECOVERY-Option wiederhergestellt wird.</value></data>
<data name="InvalidPathForDatabaseFile"><value>Ungültiger Pfad für Datenbankdatei: {0}</value></data>
<data name="Log"><value>Protokoll</value></data>
<data name="RestorePlanFailed"><value>Fehler beim Erstellen des Wiederherstellungsplan</value></data>
<data name="RestoreNotSupported"><value>Wiederherstellen der Datenbank wird nicht unterstützt.</value></data>
<data name="RestoreTaskName"><value>Datenbank wiederherstellen</value></data>
<data name="RestoreCopyOnly"><value>(nur kopieren)</value></data>
<data name="RestoreBackupSetComponent"><value>Komponente</value></data>
<data name="RestoreBackupSetType"><value>Typ</value></data>
<data name="RestoreBackupSetServer"><value>Server</value></data>
<data name="RestoreBackupSetDatabase"><value>Datenbank</value></data>
<data name="RestoreBackupSetPosition"><value>Position</value></data>
<data name="RestoreBackupSetFirstLsn"><value>Erste LSN</value></data>
<data name="RestoreBackupSetLastLsn"><value>Letzte LSN</value></data>
<data name="RestoreBackupSetCheckpointLsn"><value>Prüfpunkt-LSN</value></data>
<data name="RestoreBackupSetFullLsn"><value>Vollständige LSN</value></data>
<data name="RestoreBackupSetStartDate"><value>Startdatum</value></data>
<data name="RestoreBackupSetFinishDate"><value>Beendigungsdatum</value></data>
<data name="RestoreBackupSetSize"><value>Größe</value></data>
<data name="RestoreBackupSetUserName"><value>Benutzername</value></data>
<data name="RestoreBackupSetExpiration"><value>Ablaufdatum</value></data>
<data name="RestoreBackupSetName"><value>Name</value></data>
<data name="TheLastBackupTaken"><value>Letzte Sicherung ({0})</value></data>
<data name="BackupTaskName"><value>Datenbank sichern</value></data>
<data name="TaskInProgress"><value>In Bearbeitung</value></data>
<data name="TaskCompleted"><value>Abgeschlossen</value></data>
<data name="ScriptTaskName"><value>Skripterstellung</value></data>
<data name="ProfilerConnectionNotFound"><value>Verbindung nicht gefunden</value></data>
<data name="BackupPathIsFolderError"><value>Der angegebene Dateiname ist zugleich ein Verzeichnisname: {0}</value></data>
<data name="InvalidBackupPathError"><value>Es kann nicht überprüft werden, ob der Speicherort der Sicherungsdatei vorhanden ist: {0}</value></data>
<data name="InvalidPathError"><value>Auf den angegebenen Pfad auf dem Server kann nicht zugegriffen werden: {0}</value></data>
<data name="NoBackupsetsToRestore"><value>Kein Sicherungssatz zur Wiederherstellung ausgewählt</value></data>
<data name="NeverBackedUp"><value>Nie</value></data>
<data name="AzureSqlDbEdition"><value>Azure SQL DB</value></data>
<data name="AzureSqlDwEdition"><value>Azure SQL Data Warehouse</value></data>
<data name="AzureSqlStretchEdition"><value>Azure SQL Stretch Database</value></data>
<data name="Error_InvalidDirectoryName"><value>Der Pfad {0} ist kein gültiges Verzeichnis</value></data>
<data name="Error_ExistingDirectoryName"><value>Die Datei {1} im Verzeichnis {0} existiert bereits.</value></data>
<data name="EditDataValueTooLarge"><value>Der Wert {0} ist zu groß für eine Spalte mit dem Datentyp {1}</value></data>
</root>

View File

@@ -0,0 +1,489 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype"><value>text/microsoft-resx</value></resheader><resheader name="version"><value>1.3</value></resheader><resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><data name="ConnectionServiceConnectErrorNullParams"><value>Los parámetros de conexión no pueden ser nulos</value></data>
<data name="ConnectionServiceListDbErrorNullOwnerUri"><value>OwnerUri no puede ser nulo ni estar vacío</value></data>
<data name="ConnectionServiceListDbErrorNotConnected"><value>SpecifiedUri '{0}' no tiene una conexión existente</value></data>
<data name="ConnectionServiceConnStringInvalidAuthType"><value>El valor '{0}' no es válido para AuthenticationType. Los valores válidos son 'Integrated' y 'SqlLogin'.</value></data>
<data name="ConnectionServiceConnStringInvalidIntent"><value>El valor '{0}' no es válido para ApplicationIntent. Los valores válidos son 'ReadWrite' y 'ReadOnly'.</value></data>
<data name="ConnectionServiceConnectionCanceled"><value>Conexión cancelada</value></data>
<data name="ConnectionParamsValidateNullOwnerUri"><value>OwnerUri no puede ser nulo ni estar vacío</value></data>
<data name="ConnectionParamsValidateNullConnection"><value>El objeto de detalles de conexión no puede ser nulo</value></data>
<data name="ConnectionParamsValidateNullServerName"><value>ServerName no puede ser nulo ni estar vacío</value></data>
<data name="ConnectionParamsValidateNullSqlAuth"><value>{0} no puede ser nulo ni estar vacío cuando se utiliza autenticación SqlLogin</value></data>
<data name="QueryServiceCancelAlreadyCompleted"><value>Ya se ha completado la consulta, no se puede cancelar</value></data>
<data name="QueryServiceCancelDisposeFailed"><value>La consulta fue cancelada con éxito, pero no se ha podido desechar. No se encontró el URI del propietario.</value></data>
<data name="QueryServiceQueryCancelled"><value>Consulta cancelada por el usuario</value></data>
<data name="QueryServiceSubsetBatchNotCompleted"><value>El lote aún no ha finalizado,</value></data>
<data name="QueryServiceSubsetBatchOutOfRange"><value>Índice de lote no puede ser menor que 0 o mayor que el número de lotes</value></data>
<data name="QueryServiceSubsetResultSetOutOfRange"><value>Índice del conjunto de resultados no puede ser menor que 0 o mayor que el número de conjuntos de resultados</value></data>
<data name="QueryServiceDataReaderByteCountInvalid"><value>El número máximo de bytes a devolver debe ser mayor que cero</value></data>
<data name="QueryServiceDataReaderCharCountInvalid"><value>El número máximo de caracteres a devolver debe ser mayor que cero</value></data>
<data name="QueryServiceDataReaderXmlCountInvalid"><value>El número máximo de bytes XML a devolver debe ser mayor que cero</value></data>
<data name="QueryServiceFileWrapperWriteOnly"><value>El método de acceso no puede ser de sólo escritura</value></data>
<data name="QueryServiceFileWrapperNotInitialized"><value>FileStreamWrapper debe inicializarse antes de realizar operaciones</value></data>
<data name="QueryServiceFileWrapperReadOnly"><value>Este FileStreamWrapper no se puede utilizar para escritura.</value></data>
<data name="QueryServiceAffectedOneRow"><value>(1 fila afectada)</value></data>
<data name="QueryServiceAffectedRows"><value>({0} filas afectadas)</value></data>
<data name="QueryServiceCompletedSuccessfully"><value>Comandos finalizados correctamente.</value></data>
<data name="QueryServiceErrorFormat"><value>Msg {0}, nivel {1} estado {2}, línea {3} {4} {5}</value></data>
<data name="QueryServiceQueryFailed"><value>Error en la consulta: {0}</value></data>
<data name="QueryServiceColumnNull"><value>(Ningún nombre de columna)</value></data>
<data name="QueryServiceRequestsNoQuery"><value>La consulta solicitada no existe</value></data>
<data name="QueryServiceQueryInvalidOwnerUri"><value>Este editor no está conectado a una base de datos</value></data>
<data name="QueryServiceQueryInProgress"><value>Una consulta ya está en curso para esta sesión de editor. Por favor, cancelar esta consulta o esperar su finalización.</value></data>
<data name="QueryServiceMessageSenderNotSql"><value>Remitente de eventos de OnInfoMessage debe ser un objeto SqlConnection</value></data>
<data name="QueryServiceSaveAsResultSetNotComplete"><value>No se puede guardar el resultado hasta que haya finalizado la ejecución de la consulta</value></data>
<data name="QueryServiceSaveAsMiscStartingError"><value>Error interno al iniciar el guardado de la tarea</value></data>
<data name="QueryServiceSaveAsInProgress"><value>Una operacion de guardado en la misma ruta se encuentra en curso</value></data>
<data name="QueryServiceSaveAsFail"><value>Error al guardar {0}: {1}</value></data>
<data name="QueryServiceResultSetNotRead"><value>No se puede leer el subconjunto, a menos que los resultados se han leído desde el servidor</value></data>
<data name="QueryServiceResultSetStartRowOutOfRange"><value>Fila de inicio no puede ser menor que 0 o mayor que el número de filas en el conjunto de resultados</value></data>
<data name="QueryServiceResultSetRowCountOutOfRange"><value>La cantidad de filas debe ser un entero positivo</value></data>
<data name="QueryServiceResultSetNoColumnSchema"><value>No se pudo recuperar el esquema de columna para el conjunto de resultados</value></data>
<data name="QueryServiceExecutionPlanNotFound"><value>No se pudo recuperar un plan de ejecución del conjunto de resultados</value></data>
<data name="PeekDefinitionAzureError"><value>Esta característica actualmente no se admite en la base de datos de SQL Azure y almacén de datos: {0}</value></data>
<data name="PeekDefinitionError"><value>Se ha producido un error inesperado durante la ejecución de la definición de Peek: {0}</value></data>
<data name="PeekDefinitionNoResultsError"><value>No se encontraron resultados.</value></data>
<data name="PeekDefinitionDatabaseError"><value>No se pudo obtener ningún objeto asociado a la base de datos.</value></data>
<data name="PeekDefinitionNotConnectedError"><value>Por favor, conéctese a un servidor</value></data>
<data name="PeekDefinitionTimedoutError"><value>Tiempo de espera agotado para esta operación.</value></data>
<data name="PeekDefinitionTypeNotSupportedError"><value>Esta característica no admite actualmente este tipo de objeto.</value></data>
<data name="WorkspaceServicePositionLineOutOfRange"><value>Posición está fuera del intervalo de la línea de archivo</value></data>
<data name="WorkspaceServicePositionColumnOutOfRange"><value>Posición está fuera del intervalo de la columna de la línea {0}</value></data>
<data name="WorkspaceServiceBufferPositionOutOfOrder"><value>Posición de inicio ({0}, {1}) debe preceder o ser igual a la posición final ({2}, {3})</value></data>
<data name="EE_BatchSqlMessageNoProcedureInfo"><value>Msg {0}, {1}, nivel de estado {2}, línea {3}</value></data>
<data name="EE_BatchSqlMessageWithProcedureInfo"><value>Msj {0}, {1}, nivel de estado {2}, procedimiento {3}, línea {4}</value></data>
<data name="EE_BatchSqlMessageNoLineInfo"><value>Msg {0}, nivel {1}, {2} de estado</value></data>
<data name="EE_BatchError_Exception"><value>Se produjo un error al procesar el lote. Mensaje de error: {0}</value></data>
<data name="EE_BatchExecutionInfo_RowsAffected"><value>({0} filas afectadas)</value></data>
<data name="EE_ExecutionNotYetCompleteError"><value>La ejecución anterior aún no está completa.</value></data>
<data name="EE_ScriptError_Error"><value>Se ha producido un error de secuencias de comandos.</value></data>
<data name="EE_ScriptError_ParsingSyntax"><value>Se encontró sintaxis incorrecta mientras se estaba analizando {0}.</value></data>
<data name="EE_ScriptError_FatalError"><value>Se ha producido un error grave.</value></data>
<data name="EE_ExecutionInfo_FinalizingLoop"><value>La ejecución se completó {0} veces...</value></data>
<data name="EE_ExecutionInfo_QueryCancelledbyUser"><value>Se canceló la consulta.</value></data>
<data name="EE_BatchExecutionError_Halting"><value>Se produjo un error mientras se ejecutaba el lote.</value></data>
<data name="EE_BatchExecutionError_Ignoring"><value>Se produjo un error mientras se ejecutaba el lote, pero se ha omitido el error.</value></data>
<data name="EE_ExecutionInfo_InitializingLoop"><value>Beginning execution loop</value></data>
<data name="EE_ExecutionError_CommandNotSupported"><value>No se admite el comando {0}.</value></data>
<data name="EE_ExecutionError_VariableNotFound"><value>La variable {0} no se encontró.</value></data>
<data name="BatchParserWrapperExecutionEngineError"><value>Error de ejecución de SQL: {0}</value></data>
<data name="BatchParserWrapperExecutionError"><value>Ejecución de contenedor del analizador por lotes: {0} se encuentra... en la línea {1}: {2} Descripción: {3}</value></data>
<data name="BatchParserWrapperExecutionEngineBatchMessage"><value>Lote analizador contenedor ejecución motor lote mensaje recibido: mensaje: {0} mensaje detallado: {1}</value></data>
<data name="BatchParserWrapperExecutionEngineBatchResultSetProcessing"><value>Motor de ejecución de analizador contenedor lote ResultSet procesamiento por lotes: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1}</value></data>
<data name="BatchParserWrapperExecutionEngineBatchResultSetFinished"><value>Finalizó el elemento ResultSet analizador contenedor ejecución motor los lotes.</value></data>
<data name="BatchParserWrapperExecutionEngineBatchCancelling"><value>Cancelando la ejecución por lotes del contenedor del analizador por lotes.</value></data>
<data name="EE_ScriptError_Warning"><value>Advertencia de scripting.</value></data>
<data name="TroubleshootingAssistanceMessage"><value>Para obtener más información acerca de este error, vea los temas de solución de problemas en la documentación del producto.</value></data>
<data name="BatchParser_CircularReference"><value>El archivo '{0}' se incluyó recursivamente.</value></data>
<data name="BatchParser_CommentNotTerminated"><value>Falta la marca de final de comentario ' * /'.</value></data>
<data name="BatchParser_StringNotTerminated"><value>Sin comilla de cierre después de la cadena de caracteres.</value></data>
<data name="BatchParser_IncorrectSyntax"><value>Se encontró sintaxis incorrecta al analizar '{0}'.</value></data>
<data name="BatchParser_VariableNotDefined"><value>La variable {0} no está definida.</value></data>
<data name="TestLocalizationConstant"><value>prueba</value></data>
<data name="ErrorEmptyStringReplacement"><value>Sustitución de una cadena vacía por una cadena vacía.</value></data>
<data name="EditDataSessionNotFound"><value>Sesión de edición no existe,</value></data>
<data name="EditDataQueryNotCompleted"><value>La consulta no ha finalizado.</value></data>
<data name="EditDataQueryImproperResultSets"><value>La consulta no generó un único set de resultados</value></data>
<data name="EditDataFailedAddRow"><value>Falló al agregar una nueva fila a la caché de actualización</value></data>
<data name="EditDataRowOutOfRange"><value>El ID de la fila ingresado, se encuentra fuera del rango de filas de la caché de edición</value></data>
<data name="EditDataUpdatePending"><value>Una actualización está pendiente para esta fila y debe de revertirse primero</value></data>
<data name="EditDataUpdateNotPending"><value>El ID de la fila ingresado no tiene actualizaciones pendientes</value></data>
<data name="EditDataObjectMetadataNotFound"><value>La metadata de la tabla o vista no pudo ser encontrada</value></data>
<data name="EditDataInvalidFormatBinary"><value>Formato inválido para columna binaria</value></data>
<data name="EditDataInvalidFormatBoolean"><value>Columnas del tipo boolean deben de ser numéricos 1 o 0, o tipo string true o false</value></data>
<data name="EditDataCreateScriptMissingValue"><value>Falta un valor requerido de la celda</value></data>
<data name="EditDataDeleteSetCell"><value>Existe una eliminación pendiente para esta fila, una actualización de celda no puede ser realizada.</value></data>
<data name="EditDataColumnIdOutOfRange"><value>El ID de la columna debe de estar en el rango de columnas de la consulta.</value></data>
<data name="EditDataColumnCannotBeEdited"><value>La columna no puede ser editada</value></data>
<data name="EditDataColumnNoKeyColumns"><value>No se encontró ninguna columna clave</value></data>
<data name="EditDataScriptFilePathNull"><value>Proporcione un nombre de archivo de salida</value></data>
<data name="EditDataUnsupportedObjectType"><value>Objeto de base de datos {0} no puede ser usado para modificación.</value></data>
<data name="ConnectionServiceDbErrorDefaultNotConnected"><value>SpecifiedUri '{0}' no tiene alguna conexión por defecto</value></data>
<data name="EditDataCommitInProgress"><value>Una tarea de confirmación se encuentra en progreso. Por favor espere que la operación termine.</value></data>
<data name="SqlScriptFormatterDecimalMissingPrecision"><value>Columna del tipo decimal no tiene precisión o escala numérica</value></data>
<data name="EditDataComputedColumnPlaceholder"><value>&lt;TBD&gt;</value></data>
<data name="QueryServiceResultSetAddNoRows"><value>No se pueden agregar filas al buffer de resultados, el lector de datos no contiene filas</value></data>
<data name="EditDataTimeOver24Hrs"><value>Los valores en la columna TIME deben estar incluidos en el rango desde 00:00:00:000000 hasta 23:59:59.999999</value></data>
<data name="EditDataNullNotAllowed"><value>No se permite un valor NULL en esta columna</value></data>
<data name="EditDataSessionAlreadyExists"><value>La sesión de edición ya existe.</value></data>
<data name="EditDataSessionNotInitialized"><value>La sesión de edición no se inicializó</value></data>
<data name="EditDataSessionAlreadyInitialized"><value>La sesión de edición ya se inicializó</value></data>
<data name="EditDataSessionAlreadyInitializing"><value>La sesión de edición ya se inicializo o se encuentra en proceso de inicialización</value></data>
<data name="EditDataQueryFailed"><value>La ejecución de la consulta falló, ver los mensajes para obtener mas detalle</value></data>
<data name="EditDataFilteringNegativeLimit"><value>El límite del resultado no puede ser negativo</value></data>
<data name="QueryServiceCellNull"><value>NULL</value></data>
<data name="EditDataMetadataObjectNameRequired"><value>Se debe proveer un nombre de objeto</value></data>
<data name="EditDataMetadataTooManyIdentifiers"><value>No se permite especificar explícitamente el servidor o la base de datos</value></data>
<data name="EditDataMetadataNotExtended"><value>Los metadatos de la tabla no tienen propiedades extendidas</value></data>
<data name="EditDataObjectNotFound"><value>La tabla o vista solicitada para edición no se encuentra</value></data>
<data name="TreeNodeError"><value>Error en expansión: {0}</value></data>
<data name="ServerNodeConnectionError"><value>Error conectando a {0}</value></data>
<data name="SchemaHierarchy_Aggregates"><value>Agregados</value></data>
<data name="SchemaHierarchy_ServerRoles"><value>Roles de servidor</value></data>
<data name="SchemaHierarchy_ApplicationRoles"><value>Roles de aplicación</value></data>
<data name="SchemaHierarchy_Assemblies"><value>Ensamblados</value></data>
<data name="SchemaHierarchy_AssemblyFiles"><value>Archivos de ensamblado</value></data>
<data name="SchemaHierarchy_AsymmetricKeys"><value>Claves asimétricas</value></data>
<data name="SchemaHierarchy_DatabaseAsymmetricKeys"><value>Claves asimétricas</value></data>
<data name="SchemaHierarchy_DataCompressionOptions"><value>Opciones de compresión de datos</value></data>
<data name="SchemaHierarchy_Certificates"><value>Certificados</value></data>
<data name="SchemaHierarchy_FileTables"><value>Tablas de archivos</value></data>
<data name="SchemaHierarchy_DatabaseCertificates"><value>Certificados</value></data>
<data name="SchemaHierarchy_CheckConstraints"><value>Restricciones CHECK</value></data>
<data name="SchemaHierarchy_Columns"><value>Columnas</value></data>
<data name="SchemaHierarchy_Constraints"><value>Restricciones</value></data>
<data name="SchemaHierarchy_Contracts"><value>Contratos</value></data>
<data name="SchemaHierarchy_Credentials"><value>Credenciales</value></data>
<data name="SchemaHierarchy_ErrorMessages"><value>Mensajes de error</value></data>
<data name="SchemaHierarchy_ServerRoleMembership"><value>Pertenencia a roles de servidor</value></data>
<data name="SchemaHierarchy_DatabaseOptions"><value>Opciones de base de datos</value></data>
<data name="SchemaHierarchy_DatabaseRoles"><value>Roles de base de datos</value></data>
<data name="SchemaHierarchy_RoleMemberships"><value>Pertenencias a roles</value></data>
<data name="SchemaHierarchy_DatabaseTriggers"><value>Desencadenadores de base de datos</value></data>
<data name="SchemaHierarchy_DefaultConstraints"><value>Restricciones DEFAULT</value></data>
<data name="SchemaHierarchy_Defaults"><value>Valores predeterminados</value></data>
<data name="SchemaHierarchy_Sequences"><value>Secuencias</value></data>
<data name="SchemaHierarchy_Endpoints"><value>Extremos</value></data>
<data name="SchemaHierarchy_EventNotifications"><value>Notificaciones de eventos</value></data>
<data name="SchemaHierarchy_ServerEventNotifications"><value>Notificaciones de eventos de servidor</value></data>
<data name="SchemaHierarchy_ExtendedProperties"><value>Propiedades extendidas</value></data>
<data name="SchemaHierarchy_FileGroups"><value>Grupos de archivos</value></data>
<data name="SchemaHierarchy_ForeignKeys"><value>Claves externas</value></data>
<data name="SchemaHierarchy_FullTextCatalogs"><value>Catálogos de texto completo</value></data>
<data name="SchemaHierarchy_FullTextIndexes"><value>Índices de texto completo</value></data>
<data name="SchemaHierarchy_Functions"><value>Funciones</value></data>
<data name="SchemaHierarchy_Indexes"><value>Índices</value></data>
<data name="SchemaHierarchy_InlineFunctions"><value>Funciones Inline</value></data>
<data name="SchemaHierarchy_Keys"><value>Claves</value></data>
<data name="SchemaHierarchy_LinkedServers"><value>Servidores vinculados</value></data>
<data name="SchemaHierarchy_LinkedServerLogins"><value>Inicios de sesión de servidor vinculado</value></data>
<data name="SchemaHierarchy_Logins"><value>Inicios de sesión</value></data>
<data name="SchemaHierarchy_MasterKey"><value>Clave maestra</value></data>
<data name="SchemaHierarchy_MasterKeys"><value>Claves maestras</value></data>
<data name="SchemaHierarchy_MessageTypes"><value>Tipos de mensaje</value></data>
<data name="SchemaHierarchy_MultiSelectFunctions"><value>Funciones con valores de tabla</value></data>
<data name="SchemaHierarchy_Parameters"><value>Parámetros</value></data>
<data name="SchemaHierarchy_PartitionFunctions"><value>Funciones de partición</value></data>
<data name="SchemaHierarchy_PartitionSchemes"><value>Esquemas de partición</value></data>
<data name="SchemaHierarchy_Permissions"><value>Permisos</value></data>
<data name="SchemaHierarchy_PrimaryKeys"><value>Claves principales</value></data>
<data name="SchemaHierarchy_Programmability"><value>Programación</value></data>
<data name="SchemaHierarchy_Queues"><value>Colas</value></data>
<data name="SchemaHierarchy_RemoteServiceBindings"><value>Enlaces de servicio remoto</value></data>
<data name="SchemaHierarchy_ReturnedColumns"><value>Columnas devueltos</value></data>
<data name="SchemaHierarchy_Roles"><value>Roles</value></data>
<data name="SchemaHierarchy_Routes"><value>Rutas</value></data>
<data name="SchemaHierarchy_Rules"><value>Reglas</value></data>
<data name="SchemaHierarchy_Schemas"><value>Esquemas</value></data>
<data name="SchemaHierarchy_Security"><value>Seguridad</value></data>
<data name="SchemaHierarchy_ServerObjects"><value>Objetos de servidor</value></data>
<data name="SchemaHierarchy_Management"><value>Administración</value></data>
<data name="SchemaHierarchy_ServerTriggers"><value>Desencadenadores</value></data>
<data name="SchemaHierarchy_ServiceBroker"><value>Service Broker</value></data>
<data name="SchemaHierarchy_Services"><value>Servicios</value></data>
<data name="SchemaHierarchy_Signatures"><value>Firmas</value></data>
<data name="SchemaHierarchy_LogFiles"><value>Archivos de registro</value></data>
<data name="SchemaHierarchy_Statistics"><value>Estadísticas</value></data>
<data name="SchemaHierarchy_Storage"><value>Almacenamiento</value></data>
<data name="SchemaHierarchy_StoredProcedures"><value>Procedimientos almacenados</value></data>
<data name="SchemaHierarchy_SymmetricKeys"><value>Claves simétricas</value></data>
<data name="SchemaHierarchy_Synonyms"><value>Sinónimos</value></data>
<data name="SchemaHierarchy_Tables"><value>Tablas</value></data>
<data name="SchemaHierarchy_Triggers"><value>Desencadenadores</value></data>
<data name="SchemaHierarchy_Types"><value>Tipos</value></data>
<data name="SchemaHierarchy_UniqueKeys"><value>Claves únicas</value></data>
<data name="SchemaHierarchy_UserDefinedDataTypes"><value>Tipos de datos definidos por el usuario</value></data>
<data name="SchemaHierarchy_UserDefinedTypes"><value>Tipos definidos por el usuario (CLR)</value></data>
<data name="SchemaHierarchy_Users"><value>Usuarios</value></data>
<data name="SchemaHierarchy_Views"><value>Vistas</value></data>
<data name="SchemaHierarchy_XmlIndexes"><value>Índices XML</value></data>
<data name="SchemaHierarchy_XMLSchemaCollections"><value>Colecciones de esquemas XML</value></data>
<data name="SchemaHierarchy_UserDefinedTableTypes"><value>Tipos de tablas definidos por el usuario</value></data>
<data name="SchemaHierarchy_FilegroupFiles"><value>Archivos</value></data>
<data name="MissingCaption"><value>Falta el título</value></data>
<data name="SchemaHierarchy_BrokerPriorities"><value>Prioridades de Broker</value></data>
<data name="SchemaHierarchy_CryptographicProviders"><value>Proveedores de servicios criptográficos</value></data>
<data name="SchemaHierarchy_DatabaseAuditSpecifications"><value>Especificaciones de auditoría de base de datos</value></data>
<data name="SchemaHierarchy_DatabaseEncryptionKeys"><value>Claves de cifrado de base de datos</value></data>
<data name="SchemaHierarchy_EventSessions"><value>Sesiones de eventos</value></data>
<data name="SchemaHierarchy_FullTextStopLists"><value>Listas de palabras irrelevantes de texto completo</value></data>
<data name="SchemaHierarchy_ResourcePools"><value>Grupos de recursos de servidor</value></data>
<data name="SchemaHierarchy_ServerAudits"><value>Auditorías</value></data>
<data name="SchemaHierarchy_ServerAuditSpecifications"><value>Especificaciones de auditoría de servidor</value></data>
<data name="SchemaHierarchy_SpatialIndexes"><value>Índices espaciales</value></data>
<data name="SchemaHierarchy_WorkloadGroups"><value>Grupos de cargas de trabajo</value></data>
<data name="SchemaHierarchy_SqlFiles"><value>Archivos SQL</value></data>
<data name="SchemaHierarchy_ServerFunctions"><value>Funciones de servidor</value></data>
<data name="SchemaHierarchy_SqlType"><value>Tipo SQL</value></data>
<data name="SchemaHierarchy_ServerOptions"><value>Opciones de servidor</value></data>
<data name="SchemaHierarchy_DatabaseDiagrams"><value>Diagramas de base de datos</value></data>
<data name="SchemaHierarchy_SystemTables"><value>Tablas del sistema</value></data>
<data name="SchemaHierarchy_Databases"><value>Bases de datos</value></data>
<data name="SchemaHierarchy_SystemContracts"><value>Contratos del sistema</value></data>
<data name="SchemaHierarchy_SystemDatabases"><value>Bases de datos del sistema</value></data>
<data name="SchemaHierarchy_SystemMessageTypes"><value>Tipos de mensaje del sistema</value></data>
<data name="SchemaHierarchy_SystemQueues"><value>Colas del sistema</value></data>
<data name="SchemaHierarchy_SystemServices"><value>Servicios del sistema</value></data>
<data name="SchemaHierarchy_SystemStoredProcedures"><value>Procedimientos almacenados del sistema</value></data>
<data name="SchemaHierarchy_SystemViews"><value>Vistas del sistema</value></data>
<data name="SchemaHierarchy_DataTierApplications"><value>Aplicaciones de capa de datos</value></data>
<data name="SchemaHierarchy_ExtendedStoredProcedures"><value>Procedimientos almacenados extendidos</value></data>
<data name="SchemaHierarchy_SystemAggregateFunctions"><value>Funciones de agregado</value></data>
<data name="SchemaHierarchy_SystemApproximateNumerics"><value>Valores numéricos aproximados</value></data>
<data name="SchemaHierarchy_SystemBinaryStrings"><value>Cadenas binarias</value></data>
<data name="SchemaHierarchy_SystemCharacterStrings"><value>Cadenas de caracteres</value></data>
<data name="SchemaHierarchy_SystemCLRDataTypes"><value>Tipos de datos CLR</value></data>
<data name="SchemaHierarchy_SystemConfigurationFunctions"><value>Funciones de configuración</value></data>
<data name="SchemaHierarchy_SystemCursorFunctions"><value>Funciones del cursor</value></data>
<data name="SchemaHierarchy_SystemDataTypes"><value>Tipos de datos del sistema</value></data>
<data name="SchemaHierarchy_SystemDateAndTime"><value>Fecha y hora</value></data>
<data name="SchemaHierarchy_SystemDateAndTimeFunctions"><value>Funciones de fecha y hora</value></data>
<data name="SchemaHierarchy_SystemExactNumerics"><value>Valores numéricos exactos</value></data>
<data name="SchemaHierarchy_SystemFunctions"><value>Funciones del sistema</value></data>
<data name="SchemaHierarchy_SystemHierarchyIdFunctions"><value>Funciones de id. de jerarquía</value></data>
<data name="SchemaHierarchy_SystemMathematicalFunctions"><value>Funciones matemáticas</value></data>
<data name="SchemaHierarchy_SystemMetadataFunctions"><value>Funciones de metadatos</value></data>
<data name="SchemaHierarchy_SystemOtherDataTypes"><value>Otros tipos de datos</value></data>
<data name="SchemaHierarchy_SystemOtherFunctions"><value>Otras funciones</value></data>
<data name="SchemaHierarchy_SystemRowsetFunctions"><value>Funciones de conjunto de filas</value></data>
<data name="SchemaHierarchy_SystemSecurityFunctions"><value>Funciones de seguridad</value></data>
<data name="SchemaHierarchy_SystemSpatialDataTypes"><value>Tipos de datos espaciales</value></data>
<data name="SchemaHierarchy_SystemStringFunctions"><value>Funciones de cadena</value></data>
<data name="SchemaHierarchy_SystemSystemStatisticalFunctions"><value>Funciones estadísticas del sistema</value></data>
<data name="SchemaHierarchy_SystemTextAndImageFunctions"><value>Funciones de texto y de imagen</value></data>
<data name="SchemaHierarchy_SystemUnicodeCharacterStrings"><value>Cadenas de caracteres Unicode</value></data>
<data name="SchemaHierarchy_AggregateFunctions"><value>Funciones de agregado</value></data>
<data name="SchemaHierarchy_ScalarValuedFunctions"><value>Funciones escalares</value></data>
<data name="SchemaHierarchy_TableValuedFunctions"><value>Funciones con valores de tabla</value></data>
<data name="SchemaHierarchy_SystemExtendedStoredProcedures"><value>Procedimientos almacenados extendidos del sistema</value></data>
<data name="SchemaHierarchy_BuiltInType"><value>Tipos integrados</value></data>
<data name="SchemaHierarchy_BuiltInServerRole"><value>Roles de servidor integrados</value></data>
<data name="SchemaHierarchy_UserWithPassword"><value>Usuario con contraseña</value></data>
<data name="SchemaHierarchy_SearchPropertyList"><value>Lista de propiedades de búsqueda</value></data>
<data name="SchemaHierarchy_SecurityPolicies"><value>Directivas de seguridad</value></data>
<data name="SchemaHierarchy_SecurityPredicates"><value>Predicados de seguridad</value></data>
<data name="SchemaHierarchy_ServerRole"><value>Rol de servidor</value></data>
<data name="SchemaHierarchy_SearchPropertyLists"><value>Listas de propiedades de búsqueda</value></data>
<data name="SchemaHierarchy_ColumnStoreIndexes"><value>Índices de almacenamiento de columnas</value></data>
<data name="SchemaHierarchy_TableTypeIndexes"><value>Índices de tipo de tabla</value></data>
<data name="SchemaHierarchy_SelectiveXmlIndexes"><value>Índices XML selectivos</value></data>
<data name="SchemaHierarchy_XmlNamespaces"><value>Espacios de nombres XML</value></data>
<data name="SchemaHierarchy_XmlTypedPromotedPaths"><value>Rutas de acceso promovidas de tipo XML</value></data>
<data name="SchemaHierarchy_SqlTypedPromotedPaths"><value>Rutas de acceso promovidas de tipo T-SQL</value></data>
<data name="SchemaHierarchy_DatabaseScopedCredentials"><value>Credenciales de ámbito de base de datos</value></data>
<data name="SchemaHierarchy_ExternalDataSources"><value>Orígenes de datos externos</value></data>
<data name="SchemaHierarchy_ExternalFileFormats"><value>Formatos de archivo externo</value></data>
<data name="SchemaHierarchy_ExternalResources"><value>Recursos externos</value></data>
<data name="SchemaHierarchy_ExternalTables"><value>Tablas externas</value></data>
<data name="SchemaHierarchy_AlwaysEncryptedKeys"><value>Siempre claves cifradas</value></data>
<data name="SchemaHierarchy_ColumnMasterKeys"><value>Claves maestras de columna</value></data>
<data name="SchemaHierarchy_ColumnEncryptionKeys"><value>Claves de cifrado de columna</value></data>
<data name="SchemaHierarchy_Server"><value>Servidor</value></data>
<data name="ScriptingParams_ConnectionString_Property_Invalid"><value>Error interpretando la propiedad ScriptingParams.ConnectionString</value></data>
<data name="ScriptingParams_FilePath_Property_Invalid"><value>El directorio especificado en la propiedad ScriptingParams.FilePath no es válido</value></data>
<data name="ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid"><value>Error interpretando la propiedad ScriptingListObjectsCompleteParams.ConnectionString</value></data>
<data name="SchemaHierarchy_SubroutineParameterLabelFormatString"><value>{0} ({1}, {2}, {3})</value></data>
<data name="SchemaHierarchy_SubroutineParameterNoDefaultLabel"><value>Sin valores predeterminados</value></data>
<data name="SchemaHierarchy_SubroutineParameterInputLabel"><value>Entrada</value></data>
<data name="SchemaHierarchy_SubroutineParameterInputOutputLabel"><value>Entrada/salida</value></data>
<data name="SchemaHierarchy_SubroutineParameterInputReadOnlyLabel"><value>Entrada/solo lectura</value></data>
<data name="SchemaHierarchy_SubroutineParameterInputOutputReadOnlyLabel"><value>Entrada/salida/solo lectura</value></data>
<data name="SchemaHierarchy_SubroutineParameterDefaultLabel"><value>Predeterminado</value></data>
<data name="SchemaHierarchy_NullColumn_Label"><value>NULL</value></data>
<data name="SchemaHierarchy_NotNullColumn_Label"><value>no es NULL</value></data>
<data name="SchemaHierarchy_UDDTLabelWithType"><value>{0} ({1}, {2})</value></data>
<data name="SchemaHierarchy_UDDTLabelWithoutType"><value>{0} ({1})</value></data>
<data name="SchemaHierarchy_ComputedColumnLabelWithType"><value>{0} ({1}calculado, {2}, {3})</value></data>
<data name="SchemaHierarchy_ComputedColumnLabelWithoutType"><value>{0} ({1}calculado)</value></data>
<data name="SchemaHierarchy_ColumnSetLabelWithoutType"><value>{0} (Conjunto de columnas, {1})</value></data>
<data name="SchemaHierarchy_ColumnSetLabelWithType"><value>{0} (Conjunto de columnas, {1}{2}, {3})</value></data>
<data name="SchemaHierarchy_ColumnSetLabelWithTypeAndKeyString"><value>{0} (Conjunto de columnas, {1}, {2}, {3})</value></data>
<data name="UniqueIndex_LabelPart"><value>Único</value></data>
<data name="NonUniqueIndex_LabelPart"><value>No único</value></data>
<data name="ClusteredIndex_LabelPart"><value>Clúster</value></data>
<data name="NonClusteredIndex_LabelPart"><value>No en clúster</value></data>
<data name="History_LabelPart"><value>Historial</value></data>
<data name="SystemVersioned_LabelPart"><value>Con versión del sistema</value></data>
<data name="unavailable"><value>No disponible</value></data>
<data name="filegroup_dialog_defaultFilegroup"><value>Grupo de archivos predeterminado: {0}</value></data>
<data name="filegroup_dialog_title"><value>Grupo de archivos nuevo para: {0}</value></data>
<data name="filegroups_default"><value>Predeterminado</value></data>
<data name="filegroups_files"><value>Archivos</value></data>
<data name="filegroups_name"><value>Nombre</value></data>
<data name="filegroups_readonly"><value>Solo lectura</value></data>
<data name="general_autogrowth"><value>Crecimiento automático / tamaño máximo</value></data>
<data name="general_builderText"><value>...</value></data>
<data name="general_default"><value>&lt;predeterminado&gt;</value></data>
<data name="general_fileGroup"><value>Grupo de archivos</value></data>
<data name="general_fileName"><value>Nombre lógico</value></data>
<data name="general_fileType"><value>Tipo de archivo</value></data>
<data name="general_initialSize"><value>Tamaño inicial (MB)</value></data>
<data name="general_newFilegroup"><value>&lt;nuevo grupo de archivos&gt;</value></data>
<data name="general_path"><value>Ruta de acceso</value></data>
<data name="general_physicalFileName"><value>Nombre de archivo</value></data>
<data name="general_rawDevice"><value>&lt;dispositivo sin formato&gt;</value></data>
<data name="general_recoveryModel_bulkLogged"><value>Registro masivo</value></data>
<data name="general_recoveryModel_full"><value>Completo</value></data>
<data name="general_recoveryModel_simple"><value>Simple</value></data>
<data name="general_titleSearchOwner"><value>Seleccionar propietario de base de datos</value></data>
<data name="prototype_autogrowth_disabled"><value>Ninguno</value></data>
<data name="prototype_autogrowth_restrictedGrowthByMB"><value>Por {0} MB, limitado a {1} MB</value></data>
<data name="prototype_autogrowth_restrictedGrowthByPercent"><value>Por {0} porciento, limitado a {1} MB</value></data>
<data name="prototype_autogrowth_unrestrictedGrowthByMB"><value>Por {0} MB, sin límite</value></data>
<data name="prototype_autogrowth_unrestrictedGrowthByPercent"><value>Por {0} porciento, sin límite</value></data>
<data name="prototype_autogrowth_unlimitedfilestream"><value>Sin límite</value></data>
<data name="prototype_autogrowth_limitedfilestream"><value>Limitado a {0} MB</value></data>
<data name="prototype_db_category_automatic"><value>Automático</value></data>
<data name="prototype_db_category_servicebroker"><value>Service Broker</value></data>
<data name="prototype_db_category_collation"><value>Intercalación</value></data>
<data name="prototype_db_category_cursor"><value>Cursor</value></data>
<data name="prototype_db_category_misc"><value>Varios</value></data>
<data name="prototype_db_category_recovery"><value>Recuperación</value></data>
<data name="prototype_db_category_state"><value>Estado</value></data>
<data name="prototype_db_prop_ansiNullDefault"><value>ANSI NULL predeterminado</value></data>
<data name="prototype_db_prop_ansiNulls"><value>ANSI NULLS habilitados</value></data>
<data name="prototype_db_prop_ansiPadding"><value>Relleno ANSI habilitado</value></data>
<data name="prototype_db_prop_ansiWarnings"><value>Advertencias ANSI habilitadas</value></data>
<data name="prototype_db_prop_arithabort"><value>Anulación aritmética habilitada</value></data>
<data name="prototype_db_prop_autoClose"><value>Cierre automático</value></data>
<data name="prototype_db_prop_autoCreateStatistics"><value>Crear estadísticas automáticamente</value></data>
<data name="prototype_db_prop_autoShrink"><value>Reducir automáticamente</value></data>
<data name="prototype_db_prop_autoUpdateStatistics"><value>Actualizar estadísticas automáticamente</value></data>
<data name="prototype_db_prop_autoUpdateStatisticsAsync"><value>Actualizar estadísticas automáticamente de forma asincrónica</value></data>
<data name="prototype_db_prop_caseSensitive"><value>Sensible a mayúsculas y minúsculas</value></data>
<data name="prototype_db_prop_closeCursorOnCommit"><value>Cierre del cursor al confirmar habilitado</value></data>
<data name="prototype_db_prop_collation"><value>Intercalación</value></data>
<data name="prototype_db_prop_concatNullYieldsNull"><value>Concatenar valores NULL produce NULL</value></data>
<data name="prototype_db_prop_databaseCompatibilityLevel"><value>Nivel de compatibilidad de base de datos</value></data>
<data name="prototype_db_prop_databaseState"><value>Estado de la base de datos</value></data>
<data name="prototype_db_prop_defaultCursor"><value>Cursor predeterminado</value></data>
<data name="prototype_db_prop_fullTextIndexing"><value>Índice de texto completo habilitado</value></data>
<data name="prototype_db_prop_numericRoundAbort"><value>Anular redondeo numérico</value></data>
<data name="prototype_db_prop_pageVerify"><value>Comprobación de página</value></data>
<data name="prototype_db_prop_quotedIdentifier"><value>Identificadores entre comillas habilitados</value></data>
<data name="prototype_db_prop_readOnly"><value>Base de datos de solo lectura</value></data>
<data name="prototype_db_prop_recursiveTriggers"><value>Desencadenadores recursivos habilitados</value></data>
<data name="prototype_db_prop_restrictAccess"><value>Restringir acceso</value></data>
<data name="prototype_db_prop_selectIntoBulkCopy"><value>Select Into/Bulk Copy</value></data>
<data name="prototype_db_prop_honorBrokerPriority"><value>Asignar prioridad de agente</value></data>
<data name="prototype_db_prop_serviceBrokerGuid"><value>Identificador de Service Broker</value></data>
<data name="prototype_db_prop_brokerEnabled"><value>Broker habilitado</value></data>
<data name="prototype_db_prop_truncateLogOnCheckpoint"><value>Truncar registro en el punto de control</value></data>
<data name="prototype_db_prop_dbChaining"><value>Encadenamiento de propiedad entre bases de datos habilitado</value></data>
<data name="prototype_db_prop_trustworthy"><value>De confianza</value></data>
<data name="prototype_db_prop_dateCorrelationOptimization"><value>Optimización de correlación de fechas Enabledprototype_db_prop_parameterization = Parameterization</value></data>
<data name="prototype_db_prop_parameterization_value_forced"><value>Forzado</value></data>
<data name="prototype_db_prop_parameterization_value_simple"><value>Simple</value></data>
<data name="prototype_file_dataFile"><value>Datos de ROWS</value></data>
<data name="prototype_file_logFile"><value>LOG</value></data>
<data name="prototype_file_filestreamFile"><value>Datos de FILESTREAM</value></data>
<data name="prototype_file_noFileGroup"><value>No aplicable</value></data>
<data name="prototype_file_defaultpathstring"><value>&lt;ruta predeterminada&gt;</value></data>
<data name="title_openConnectionsMustBeClosed"><value>Conexiones abiertas</value></data>
<data name="warning_openConnectionsMustBeClosed"><value>Para cambiar las propiedades de la base de datos, SQL Server debe cerrar todas las otras conexiones a la base de datos. ¿Seguro que desea cambiar las propiedades y cerrar todas las otras conexiones?</value></data>
<data name="prototype_db_prop_databaseState_value_autoClosed"><value>AUTO_CLOSED</value></data>
<data name="prototype_db_prop_databaseState_value_emergency"><value>EMERGENCY</value></data>
<data name="prototype_db_prop_databaseState_value_inaccessible"><value>INACCESSIBLE</value></data>
<data name="prototype_db_prop_databaseState_value_normal"><value>NORMAL</value></data>
<data name="prototype_db_prop_databaseState_value_offline"><value>OFFLINE</value></data>
<data name="prototype_db_prop_databaseState_value_recovering"><value>RECOVERING</value></data>
<data name="prototype_db_prop_databaseState_value_recoveryPending"><value>RECOVERY PENDING</value></data>
<data name="prototype_db_prop_databaseState_value_restoring"><value>RESTORING</value></data>
<data name="prototype_db_prop_databaseState_value_shutdown"><value>SHUTDOWN</value></data>
<data name="prototype_db_prop_databaseState_value_standby"><value>STANDBY</value></data>
<data name="prototype_db_prop_databaseState_value_suspect"><value>SUSPECT</value></data>
<data name="prototype_db_prop_defaultCursor_value_global"><value>GLOBAL</value></data>
<data name="prototype_db_prop_defaultCursor_value_local"><value>LOCAL</value></data>
<data name="prototype_db_prop_restrictAccess_value_multiple"><value>MULTI_USER</value></data>
<data name="prototype_db_prop_restrictAccess_value_restricted"><value>RESTRICTED_USER</value></data>
<data name="prototype_db_prop_restrictAccess_value_single"><value>SINGLE_USER</value></data>
<data name="prototype_db_prop_pageVerify_value_checksum"><value>CHECKSUM</value></data>
<data name="prototype_db_prop_pageVerify_value_none"><value>NONE</value></data>
<data name="prototype_db_prop_pageVerify_value_tornPageDetection"><value>TORN_PAGE_DETECTION</value></data>
<data name="prototype_db_prop_varDecimalEnabled"><value>Formato de almacenamiento VarDecimal habilitado</value></data>
<data name="compatibilityLevel_katmai"><value>SQL Server 2008 (100)</value></data>
<data name="prototype_db_prop_encryptionEnabled"><value>Cifrado habilitado</value></data>
<data name="prototype_db_prop_databasescopedconfig_value_off"><value>OFF</value></data>
<data name="prototype_db_prop_databasescopedconfig_value_on"><value>ON</value></data>
<data name="prototype_db_prop_databasescopedconfig_value_primary"><value>PRIMARY</value></data>
<data name="error_db_prop_invalidleadingColumns"><value>Para la directiva de distribución HASH, el número de columnas iniciales hash es opcional pero debe de ser entre 1 y 16 columnas</value></data>
<data name="compatibilityLevel_denali"><value>SQL Server 2012 (110)</value></data>
<data name="compatibilityLevel_sql14"><value>SQL Server 2014 (120)</value></data>
<data name="compatibilityLevel_sql15"><value>SQL Server 2016 (130)</value></data>
<data name="compatibilityLevel_sqlvNext"><value>SQL Server vNext (140)</value></data>
<data name="general_containmentType_None"><value>Ninguno</value></data>
<data name="general_containmentType_Partial"><value>Parcial</value></data>
<data name="filegroups_filestreamFiles"><value>Archivos FILESTREAM</value></data>
<data name="prototype_file_noApplicableFileGroup"><value>Grupo de archivos no aplicable</value></data>
<data name="DatabaseNotAccessible"><value>La base de datos {0} no es accesible.</value></data>
<data name="QueryServiceResultSetHasNoResults"><value>La consulta no devolvió resultados</value></data>
<data name="QueryServiceResultSetTooLarge"><value>El conjunto de resultados contiene demasiada filas para cargarlo de forma segura</value></data>
<data name="prototype_db_prop_parameterization"><value>Parametrización</value></data>
<data name="ConflictWithNoRecovery"><value>No se permite restaurar una copia de seguridad con la opción NORECOVERY</value></data>
<data name="InvalidPathForDatabaseFile"><value>Ruta de archivo no válida: '{0}'</value></data>
<data name="Log"><value>Registro</value></data>
<data name="RestorePlanFailed"><value>No se pudo crear un plan de restauraciones</value></data>
<data name="RestoreNotSupported"><value>No se admite restaurar la base de datos</value></data>
<data name="RestoreTaskName"><value>Restaurar base de datos</value></data>
<data name="RestoreCopyOnly"><value>(Copiar solamente)</value></data>
<data name="RestoreBackupSetComponent"><value>Componente</value></data>
<data name="RestoreBackupSetType"><value>Tipo</value></data>
<data name="RestoreBackupSetServer"><value>Servidor</value></data>
<data name="RestoreBackupSetDatabase"><value>Base de datos</value></data>
<data name="RestoreBackupSetPosition"><value>Posición</value></data>
<data name="RestoreBackupSetFirstLsn"><value>Primer LSN</value></data>
<data name="RestoreBackupSetLastLsn"><value>Último LSN</value></data>
<data name="RestoreBackupSetCheckpointLsn"><value>Checkpoint LSN</value></data>
<data name="RestoreBackupSetFullLsn"><value>LSN completo</value></data>
<data name="RestoreBackupSetStartDate"><value>Fecha de inicio</value></data>
<data name="RestoreBackupSetFinishDate"><value>Fecha de finalización</value></data>
<data name="RestoreBackupSetSize"><value>Tamaño</value></data>
<data name="RestoreBackupSetUserName"><value>Nombre del usuario</value></data>
<data name="RestoreBackupSetExpiration"><value>Expiración</value></data>
<data name="RestoreBackupSetName"><value>Nombre</value></data>
<data name="TheLastBackupTaken"><value>La última copia de seguridad tomada ({0})</value></data>
<data name="BackupTaskName"><value>Copia de seguridad de la base de datos</value></data>
<data name="TaskInProgress"><value>En curso</value></data>
<data name="TaskCompleted"><value>Completado</value></data>
<data name="ScriptTaskName"><value>scripting </value></data>
<data name="ProfilerConnectionNotFound"><value>Conexión no encontrada</value></data>
<data name="BackupPathIsFolderError"><value>El nombre del archivo especificado es un nombre de directorio: {0}</value></data>
<data name="InvalidBackupPathError"><value>No se puede verificar la existencia de la ubicación del archivo de copia de seguridad: {0}</value></data>
<data name="InvalidPathError"><value>No se puede acceder a la ruta de acceso especificada en el servidor: {0}</value></data>
<data name="NoBackupsetsToRestore"><value>Ningún backupset seleccionado para ser restaurado</value></data>
<data name="NeverBackedUp"><value>Nunca</value></data>
<data name="AzureSqlDbEdition"><value>Azure SQL Database </value></data>
<data name="AzureSqlDwEdition"><value>Azure SQL Data Warehouse</value></data>
<data name="AzureSqlStretchEdition"><value>Azure SQL Stretch Database</value></data>
<data name="Error_InvalidDirectoryName"><value>La ruta de acceso [{0}] no es un directorio válido</value></data>
<data name="Error_ExistingDirectoryName"><value>Ya existe un archivo {1} en el directorio '{0}'</value></data>
<data name="EditDataValueTooLarge"><value>El valor {0} es muy grande para el tipo de columna {1} </value></data>
</root>

Some files were not shown because too many files have changed in this diff Show More