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

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; }
}
}
}