Files
sqltoolsservice/src/Microsoft.SqlTools.ServiceLayer/Metadata/MetadataService.cs
Aasim Khan 73c2a75fba Creating a new Sql Core project that stores OE classes. (#2165)
* init

* More fixes

* moving filters from contracts to core OE classes

* Fixing some tests

* More fixes and added doc comments

* Fixing tests

* Quick refactoring

* more cleanups

* cleanup

* Adding stateless OE

* Adding null checks

* Making group by schema independent of settings

* Fixing tests

* Removing node info from core oe code

* Fixing tests and moving OE code to its own project

* moving oe to own project

* Removing changes to Kusto

* Removing azure access token from service layer

* Fixing project description and title

* Fixing file name typo

* Removing unused  strings from service layer

* Fixing localized strings in tests
Adding comments to stateless OE

* Fixing stuff

* Update src/Microsoft.SqlTools.SqlCore/Microsoft.SqlTools.SqlCore.csproj

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

* Fixing project nesting

* Fixing more stuff and removing OE class

* Cleanup

* Code cleanup

* fixing oe service provider

* Fixing test name

* Remove using

* Update src/Microsoft.SqlTools.SqlCore/ObjectExplorer/SmoModel/SmoQueryContext.cs

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

* Fixing syntax error

* Adding project to locproject

* Fixing stuff

* Fixing errors

* sorting usings

---------

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
2023-08-16 22:11:35 -07:00

220 lines
8.0 KiB
C#

//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
#nullable disable
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.Metadata.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Microsoft.SqlTools.SqlCore.Metadata;
namespace Microsoft.SqlTools.ServiceLayer.Metadata
{
/// <summary>
/// Main class for Metadata Service functionality
/// </summary>
public sealed class MetadataService
{
private static readonly Lazy<MetadataService> LazyInstance = new Lazy<MetadataService>(() => new MetadataService());
public static MetadataService Instance => LazyInstance.Value;
private static ConnectionService connectionService = null;
/// <summary>
/// Internal for testing purposes only
/// </summary>
internal static ConnectionService ConnectionServiceInstance
{
get
{
connectionService ??= ConnectionService.Instance;
return connectionService;
}
set
{
connectionService = value;
}
}
/// <summary>
/// Initializes the Metadata Service instance
/// </summary>
/// <param name="serviceHost"></param>
/// <param name="context"></param>
public void InitializeService(ServiceHost serviceHost)
{
serviceHost.SetRequestHandler(MetadataListRequest.Type, HandleMetadataListRequest, true);
serviceHost.SetRequestHandler(TableMetadataRequest.Type, HandleGetTableRequest, true);
serviceHost.SetRequestHandler(ViewMetadataRequest.Type, HandleGetViewRequest, true);
}
/// <summary>
/// Handle a metadata query request
/// </summary>
internal async Task HandleMetadataListRequest(
MetadataQueryParams metadataParams,
RequestContext<MetadataQueryResult> requestContext)
{
Func<Task> requestHandler = async () =>
{
ConnectionInfo connInfo;
MetadataService.ConnectionServiceInstance.TryFindConnection(
metadataParams.OwnerUri,
out connInfo);
var metadata = new List<ObjectMetadata>();
if (connInfo != null)
{
using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connInfo, "Metadata"))
{
ReadMetadata(sqlConn, metadata);
}
}
await requestContext.SendResult(new MetadataQueryResult
{
Metadata = metadata.ToArray()
});
};
Task task = Task.Run(async () => await requestHandler()).ContinueWithOnFaulted(async t =>
{
await requestContext.SendError(t.Exception.ToString());
});
MetadataListTask = task;
}
internal Task MetadataListTask { get; set; }
/// <summary>
/// Handle a table metadata query request
/// </summary>
internal static async Task HandleGetTableRequest(
TableMetadataParams metadataParams,
RequestContext<TableMetadataResult> requestContext)
{
await HandleGetTableOrViewRequest(metadataParams, "table", requestContext);
}
/// <summary>
/// Handle a view metadata query request
/// </summary>
internal static async Task HandleGetViewRequest(
TableMetadataParams metadataParams,
RequestContext<TableMetadataResult> requestContext)
{
await HandleGetTableOrViewRequest(metadataParams, "view", requestContext);
}
/// <summary>
/// Handle a table pr view metadata query request
/// </summary>
private static async Task HandleGetTableOrViewRequest(
TableMetadataParams metadataParams,
string objectType,
RequestContext<TableMetadataResult> requestContext)
{
ConnectionInfo connInfo;
MetadataService.ConnectionServiceInstance.TryFindConnection(
metadataParams.OwnerUri,
out connInfo);
ColumnMetadata[] metadata = null;
if (connInfo != null)
{
using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connInfo, "Metadata"))
{
TableMetadata table = new SmoMetadataFactory().GetObjectMetadata(
sqlConn, metadataParams.Schema,
metadataParams.ObjectName, objectType);
metadata = table.Columns;
}
}
await requestContext.SendResult(new TableMetadataResult
{
Columns = metadata
});
}
internal static bool IsSystemDatabase(string database)
{
// compare against master for now
return string.Compare("master", database, StringComparison.OrdinalIgnoreCase) == 0;
}
/// <summary>
/// Read metadata for the current connection
/// </summary>
internal static void ReadMetadata(SqlConnection sqlConn, List<ObjectMetadata> metadata)
{
string sql =
@"SELECT s.name AS schema_name, o.[name] AS object_name, o.[type] AS object_type
FROM sys.all_objects o
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.[type] IN ('P','V','U','AF','FN','IF','TF') ";
if (!IsSystemDatabase(sqlConn.Database))
{
sql += @"AND o.is_ms_shipped != 1 ";
}
sql += @"ORDER BY object_type, schema_name, object_name";
using (SqlCommand sqlCommand = new SqlCommand(sql, sqlConn))
{
using (var reader = sqlCommand.ExecuteReader())
{
while (reader.Read())
{
var schemaName = reader[0] as string;
var objectName = reader[1] as string;
var objectType = reader[2] as string;
MetadataType metadataType;
string metadataTypeName;
if (objectType.StartsWith("V"))
{
metadataType = MetadataType.View;
metadataTypeName = "View";
}
else if (objectType.StartsWith("P"))
{
metadataType = MetadataType.SProc;
metadataTypeName = "StoredProcedure";
}
else if (objectType == "AF" || objectType == "FN" || objectType == "IF" || objectType == "TF")
{
metadataType = MetadataType.Function;
metadataTypeName = "UserDefinedFunction";
}
else
{
metadataType = MetadataType.Table;
metadataTypeName = "Table";
}
metadata.Add(new ObjectMetadata
{
MetadataType = metadataType,
MetadataTypeName = metadataTypeName,
Schema = schemaName,
Name = objectName
});
}
}
}
}
}
}