mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-21 01:25:42 -05:00
extend the list databases request (#951)
* extend the list databases request * reuse databaseInfo and refactor * fix typo
This commit is contained in:
@@ -910,41 +910,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
|
||||
{
|
||||
throw new Exception(SR.ConnectionServiceListDbErrorNotConnected(owner));
|
||||
}
|
||||
ConnectionDetails connectionDetails = info.ConnectionDetails.Clone();
|
||||
|
||||
// Connect to master and query sys.databases
|
||||
connectionDetails.DatabaseName = "master";
|
||||
var connection = this.ConnectionFactory.CreateSqlConnection(BuildConnectionString(connectionDetails), connectionDetails.AzureAccountToken);
|
||||
connection.Open();
|
||||
|
||||
List<string> results = new List<string>();
|
||||
var systemDatabases = new[] { "master", "model", "msdb", "tempdb" };
|
||||
using (DbCommand command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = @"SELECT name FROM sys.databases WHERE state_desc='ONLINE' ORDER BY name ASC";
|
||||
command.CommandTimeout = 15;
|
||||
command.CommandType = CommandType.Text;
|
||||
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
results.Add(reader[0].ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put system databases at the top of the list
|
||||
results =
|
||||
results.Where(s => systemDatabases.Any(s.Equals)).Concat(
|
||||
results.Where(s => systemDatabases.All(x => !s.Equals(x)))).ToList();
|
||||
|
||||
connection.Close();
|
||||
|
||||
ListDatabasesResponse response = new ListDatabasesResponse();
|
||||
response.DatabaseNames = results.ToArray();
|
||||
|
||||
return response;
|
||||
var handler = ListDatabaseRequestHandlerFactory.getHandler(listDatabasesParams.IncludeDetails.HasTrue(), info.IsSqlDb);
|
||||
return handler.HandleRequest(this.connectionFactory, info);
|
||||
}
|
||||
|
||||
public void InitializeService(IProtocolEndpoint serviceHost)
|
||||
|
||||
@@ -14,5 +14,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public bool? IncludeDetails { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
@@ -14,5 +16,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
|
||||
/// 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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
//
|
||||
// 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;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Connection
|
||||
{
|
||||
public class ListDatabasesRequestDatabaseProperties
|
||||
{
|
||||
public const string Name = "name";
|
||||
public const string SizeInMB = "sizeInMB";
|
||||
public const string State = "state";
|
||||
public const string LastBackup = "lastBackup";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory class for ListDatabasesRequest handler
|
||||
/// </summary>
|
||||
static class ListDatabaseRequestHandlerFactory
|
||||
{
|
||||
public static IListDatabaseRequestHandler getHandler(bool includeDetails, bool isSqlDB)
|
||||
{
|
||||
if (!includeDetails)
|
||||
{
|
||||
return new DatabaseNamesHandler();
|
||||
}
|
||||
else if (isSqlDB)
|
||||
{
|
||||
return new SqlDBDatabaseDetailHandler();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SqlServerDatabaseDetailHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface of ListDatabasesRequest handler
|
||||
/// </summary>
|
||||
interface IListDatabaseRequestHandler
|
||||
{
|
||||
ListDatabasesResponse HandleRequest(ISqlConnectionFactory connectionFactory, ConnectionInfo connectionInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base handler
|
||||
/// </summary>
|
||||
abstract class ListDatabaseRequestHandler<T> : IListDatabaseRequestHandler
|
||||
{
|
||||
private static readonly string[] SystemDatabases = new string[] { "master", "model", "msdb", "tempdb" };
|
||||
|
||||
public abstract string QueryText { get; }
|
||||
|
||||
public ListDatabasesResponse HandleRequest(ISqlConnectionFactory connectionFactory, ConnectionInfo connectionInfo)
|
||||
{
|
||||
ConnectionDetails connectionDetails = connectionInfo.ConnectionDetails.Clone();
|
||||
|
||||
// Connect to master
|
||||
connectionDetails.DatabaseName = "master";
|
||||
using (var connection = connectionFactory.CreateSqlConnection(ConnectionService.BuildConnectionString(connectionDetails), connectionDetails.AzureAccountToken))
|
||||
{
|
||||
connection.Open();
|
||||
ListDatabasesResponse response = new ListDatabasesResponse();
|
||||
using (DbCommand command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = this.QueryText;
|
||||
command.CommandTimeout = 15;
|
||||
command.CommandType = CommandType.Text;
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
List<T> results = new List<T>();
|
||||
while (reader.Read())
|
||||
{
|
||||
results.Add(this.CreateItem(reader));
|
||||
}
|
||||
// Put system databases at the top of the list
|
||||
results = results.Where(s => SystemDatabases.Any(x => this.NameMatches(x, s))).Concat(
|
||||
results.Where(s => SystemDatabases.All(x => !this.NameMatches(x, s)))).ToList();
|
||||
SetResponse(response, results.ToArray());
|
||||
}
|
||||
}
|
||||
connection.Close();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract bool NameMatches(string databaseName, T item);
|
||||
protected abstract T CreateItem(DbDataReader reader);
|
||||
protected abstract void SetResponse(ListDatabasesResponse response, T[] results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// database names handler
|
||||
/// </summary>
|
||||
class DatabaseNamesHandler : ListDatabaseRequestHandler<string>
|
||||
{
|
||||
public override string QueryText
|
||||
{
|
||||
get
|
||||
{
|
||||
return @"SELECT name FROM sys.databases WHERE state_desc='ONLINE' ORDER BY name ASC";
|
||||
}
|
||||
}
|
||||
|
||||
protected override string CreateItem(DbDataReader reader)
|
||||
{
|
||||
return reader[0].ToString();
|
||||
}
|
||||
|
||||
protected override bool NameMatches(string databaseName, string item)
|
||||
{
|
||||
return databaseName == item;
|
||||
}
|
||||
|
||||
protected override void SetResponse(ListDatabasesResponse response, string[] results)
|
||||
{
|
||||
response.DatabaseNames = results;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class BaseDatabaseDetailHandler : ListDatabaseRequestHandler<DatabaseInfo>
|
||||
{
|
||||
protected override bool NameMatches(string databaseName, DatabaseInfo item)
|
||||
{
|
||||
return databaseName == item.Options[ListDatabasesRequestDatabaseProperties.Name].ToString();
|
||||
}
|
||||
|
||||
protected override void SetResponse(ListDatabasesResponse response, DatabaseInfo[] results)
|
||||
{
|
||||
response.Databases = results;
|
||||
}
|
||||
|
||||
protected override DatabaseInfo CreateItem(DbDataReader reader)
|
||||
{
|
||||
DatabaseInfo databaseInfo = new DatabaseInfo();
|
||||
SetProperties(reader, databaseInfo);
|
||||
return databaseInfo;
|
||||
}
|
||||
|
||||
protected virtual void SetProperties(DbDataReader reader, DatabaseInfo databaseInfo)
|
||||
{
|
||||
databaseInfo.Options[ListDatabasesRequestDatabaseProperties.Name] = reader["name"].ToString();
|
||||
databaseInfo.Options[ListDatabasesRequestDatabaseProperties.State] = reader["state"].ToString();
|
||||
databaseInfo.Options[ListDatabasesRequestDatabaseProperties.SizeInMB] = reader["size"].ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Standalone SQL Server database detail handler
|
||||
/// </summary>
|
||||
class SqlServerDatabaseDetailHandler : BaseDatabaseDetailHandler
|
||||
{
|
||||
public override string QueryText
|
||||
{
|
||||
get
|
||||
{
|
||||
return @"
|
||||
WITH
|
||||
db_size
|
||||
AS
|
||||
(
|
||||
SELECT database_id, CAST(SUM(size) * 8.0 / 1024 AS INTEGER) size
|
||||
FROM sys.master_files
|
||||
GROUP BY database_id
|
||||
),
|
||||
db_backup
|
||||
AS
|
||||
(
|
||||
SELECT database_name, MAX(backup_start_date) AS last_backup
|
||||
FROM msdb..backupset
|
||||
GROUP BY database_name
|
||||
)
|
||||
SELECT name, state_desc AS state, db_size.size, db_backup.last_backup
|
||||
FROM sys.databases LEFT JOIN db_size ON sys.databases.database_id = db_size.database_id
|
||||
LEFT JOIN db_backup ON sys.databases.name = db_backup.database_name
|
||||
WHERE state_desc='ONLINE'
|
||||
ORDER BY name ASC";
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetProperties(DbDataReader reader, DatabaseInfo databaseInfo)
|
||||
{
|
||||
base.SetProperties(reader, databaseInfo);
|
||||
databaseInfo.Options[ListDatabasesRequestDatabaseProperties.LastBackup] = reader["last_backup"] == DBNull.Value ? "" : Convert.ToDateTime(reader["last_backup"]).ToString("yyyy-MM-dd hh:mm:ss");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL DB database detail handler
|
||||
/// </summary>
|
||||
class SqlDBDatabaseDetailHandler : BaseDatabaseDetailHandler
|
||||
{
|
||||
public override string QueryText
|
||||
{
|
||||
get
|
||||
{
|
||||
return @"
|
||||
WITH
|
||||
db_size
|
||||
AS
|
||||
(
|
||||
SELECT name, storage_in_megabytes AS size
|
||||
FROM (
|
||||
SELECT database_name name, max(end_time) size_time
|
||||
FROM sys.resource_stats
|
||||
GROUP BY database_name) db_size_time
|
||||
LEFT JOIN sys.resource_stats ON database_name = name AND size_time = end_time
|
||||
)
|
||||
SELECT db.name, state_desc AS state, size
|
||||
FROM sys.databases db LEFT JOIN db_size ON db.name = db_size.name
|
||||
WHERE state_desc='ONLINE'
|
||||
ORDER BY name ASC
|
||||
";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user