diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs index 9f626720..b0080b75 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs @@ -440,7 +440,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection IsCloud = serverInfo.IsCloud, AzureVersion = serverInfo.AzureVersion, OsVersion = serverInfo.OsVersion, - MachineName = serverInfo.MachineName + MachineName = serverInfo.MachineName, + Options = serverInfo.Options, }; connectionInfo.IsCloud = serverInfo.IsCloud; connectionInfo.MajorVersion = serverInfo.ServerMajorVersion; diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ServerInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ServerInfo.cs index 72305180..a62ff495 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ServerInfo.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ServerInfo.cs @@ -3,6 +3,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using System; +using System.Collections.Generic; + namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts { /// @@ -64,5 +67,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts /// The Operating System version string of the machine running the SQL Server instance. /// public string MachineName { get; set; } + + /// + /// Server options + /// + public Dictionary Options { get; set; } } } + +public class ClusterEndpoint +{ + public string ServiceName; + public string IpAddress; + public int Port; +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/ReliableConnectionHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/ReliableConnectionHelper.cs index 77c055e5..18441aa7 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/ReliableConnectionHelper.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/ReliableConnectionHelper.cs @@ -29,7 +29,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection private const string DacFxApplicationName = "DacFx"; private const int SqlDwEngineEditionId = (int)DatabaseEngineEdition.SqlDataWarehouse; - + // See MSDN documentation for "SERVERPROPERTY (SQL Azure Database)" for "EngineEdition" property: // http://msdn.microsoft.com/en-us/library/ee336261.aspx private const int SqlAzureEngineEditionId = 5; @@ -681,6 +681,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection public class ServerInfo { + internal const string OptionIsBigDataCluster = "isBigDataCluster"; + internal const string OptionClusterEndpoints = "clusterEndpoints"; public int ServerMajorVersion; public int ServerMinorVersion; public int ServerReleaseVersion; @@ -699,6 +701,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection public string OsVersion; public string MachineName; + + public Dictionary Options { get; set; } } public static bool TryGetServerVersion(string connectionString, out ServerInfo serverInfo, string azureAccountToken) @@ -754,6 +758,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection delegate (IDataReader reader) { reader.Read(); + int engineEditionId = Int32.Parse(reader[0].ToString(), CultureInfo.InvariantCulture); serverInfo.EngineEditionId = engineEditionId; @@ -770,6 +775,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection serverInfo.IsSelectiveXmlIndexMetadataPresent = reader.GetInt32(5) == 1; } + if (reader.FieldCount > 6) + { + serverInfo.Options = new Dictionary(); + serverInfo.Options.Add(ServerInfo.OptionIsBigDataCluster, reader.GetInt32(6)); + } + // The 'ProductVersion' server property is of the form ##.#[#].####.#, Version serverVersion = new Version(serverInfo.ServerVersion); @@ -806,6 +817,34 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection serverInfo.OsVersion = reader[0].ToString(); }); + // Get BDC endpoints + if (serverInfo != null && serverInfo.Options != null && serverInfo.Options.ContainsKey(ServerInfo.OptionIsBigDataCluster)) + { + int? isBigDataCluster = serverInfo.Options[ServerInfo.OptionIsBigDataCluster] as int?; + List clusterEndpoints = new List(); + try + { + if (isBigDataCluster != null && isBigDataCluster.Value == 1) + { + ExecuteReader( + connection, + SqlConnectionHelperScripts.GetClusterEndpoints, + delegate (IDataReader reader) + { + while (reader.Read()) + { + clusterEndpoints.Add(new ClusterEndpoint { ServiceName = reader.GetString(0), IpAddress = reader.GetString(1), Port = reader.GetInt32(2) }); + } + serverInfo.Options.Add(ServerInfo.OptionClusterEndpoints, clusterEndpoints); + }); + } + } + catch (SqlException) + { + serverInfo.Options.Add(ServerInfo.OptionClusterEndpoints, clusterEndpoints); + } + } + return serverInfo; }; diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/SqlConnectionHelperScripts.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/SqlConnectionHelperScripts.cs index 588b348f..247dd196 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/SqlConnectionHelperScripts.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/SqlConnectionHelperScripts.cs @@ -7,8 +7,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection { static class SqlConnectionHelperScripts { - public const string EngineEdition = "SELECT SERVERPROPERTY('EngineEdition'), SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'), SERVERPROPERTY ('edition'), SERVERPROPERTY ('MachineName'), (SELECT CASE WHEN EXISTS (SELECT TOP 1 1 from [sys].[all_columns] WITH (NOLOCK) WHERE name = N'xml_index_type' AND OBJECT_ID(N'sys.xml_indexes') = object_id) THEN 1 ELSE 0 END AS SXI_PRESENT)"; - public const string EngineEditionWithLock = "SELECT SERVERPROPERTY('EngineEdition'), SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'), SERVERPROPERTY ('edition'), SERVERPROPERTY ('MachineName'), (SELECT CASE WHEN EXISTS (SELECT TOP 1 1 from [sys].[all_columns] WHERE name = N'xml_index_type' AND OBJECT_ID(N'sys.xml_indexes') = object_id) THEN 1 ELSE 0 END AS SXI_PRESENT)"; + public const string EngineEdition = "SELECT SERVERPROPERTY('EngineEdition'), SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'), SERVERPROPERTY ('edition'), SERVERPROPERTY ('MachineName'), (SELECT CASE WHEN EXISTS (SELECT TOP 1 1 from [sys].[all_columns] WITH (NOLOCK) WHERE name = N'xml_index_type' AND OBJECT_ID(N'sys.xml_indexes') = object_id) THEN 1 ELSE 0 END AS SXI_PRESENT), (SELECT CASE WHEN EXISTS (SELECT name FROM model.sys.assemblies WHERE name = 'Microsoft.SqlServer.DataPoolManagement.Assemblies') THEN 1 ELSE 0 END)"; + public const string EngineEditionWithLock = "SELECT SERVERPROPERTY('EngineEdition'), SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'), SERVERPROPERTY ('edition'), SERVERPROPERTY ('MachineName'), (SELECT CASE WHEN EXISTS (SELECT TOP 1 1 from [sys].[all_columns] WHERE name = N'xml_index_type' AND OBJECT_ID(N'sys.xml_indexes') = object_id) THEN 1 ELSE 0 END AS SXI_PRESENT), (SELECT CASE WHEN EXISTS (SELECT name FROM model.sys.assemblies WHERE name = 'Microsoft.SqlServer.DataPoolManagement.Assemblies') THEN 1 ELSE 0 END)"; public const string CheckDatabaseReadonly = @"EXEC sp_dboption '{0}', 'read only'"; @@ -47,5 +47,6 @@ SELECT @filepath AS FilePath "; public const string GetOsVersion = @"SELECT OSVersion = RIGHT(@@version, LEN(@@version)- 3 -charindex (' ON ', @@version))"; + public const string GetClusterEndpoints = @"SELECT [service_name], [ip_address], [port] FROM [master].[dbo].[cluster_endpoint_info]"; } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs index 36776550..4c773fa8 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs @@ -386,7 +386,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer RootNode = session.Root.ToNodeInfo(), SessionId = uri, ErrorMessage = session.ErrorMessage - }; await serviceHost.SendEvent(CreateSessionCompleteNotification.Type, response); return response; @@ -406,7 +405,20 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer { NodeInfo[] nodes = null; TreeNode node = session.Root.FindNodeByPath(nodePath); - ExpandResponse response = new ExpandResponse { Nodes = new NodeInfo[] { }, ErrorMessage = node.ErrorMessage, SessionId = session.Uri, NodePath = nodePath }; + ExpandResponse response = null; + + // This node was likely returned from a different node provider. Ignore expansion and return an empty array + // since we don't need to add any nodes under this section of the tree. + if (node == null) + { + response = new ExpandResponse { Nodes = new NodeInfo[] { }, ErrorMessage = string.Empty, SessionId = session.Uri, NodePath = nodePath }; + response.Nodes = new NodeInfo[0]; + return response; + } + else + { + response = new ExpandResponse { Nodes = new NodeInfo[] { }, ErrorMessage = node.ErrorMessage, SessionId = session.Uri, NodePath = nodePath }; + } if (node != null && Monitor.TryEnter(node.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout)) {