mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 18:47:57 -05:00
Fix intellisense parsing for Azure and MI connections (#1211)
* Fix intellisense parsing for Azure connections * formatting * Refactor to use compat level * update logic * Update log message * spelling
This commit is contained in:
@@ -6,11 +6,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.SqlServer.Management.Common;
|
using Microsoft.SqlServer.Management.Common;
|
||||||
|
using SMO = Microsoft.SqlServer.Management.Smo;
|
||||||
using Microsoft.SqlServer.Management.SmoMetadataProvider;
|
using Microsoft.SqlServer.Management.SmoMetadataProvider;
|
||||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||||
using Microsoft.SqlServer.Management.SqlParser.Common;
|
using Microsoft.SqlServer.Management.SqlParser.Common;
|
||||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||||
|
using Microsoft.SqlTools.Utility;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||||
{
|
{
|
||||||
@@ -25,6 +28,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
private ServerConnection serverConnection;
|
private ServerConnection serverConnection;
|
||||||
|
|
||||||
|
private SMO.Server server;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connected binding context constructor
|
/// Connected binding context constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -55,7 +60,19 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
// reset the parse options so the get recreated for the current connection
|
// reset the parse options so the get recreated for the current connection
|
||||||
this.parseOptions = null;
|
this.parseOptions = null;
|
||||||
}
|
// Set up a SMO Server to query when determing parse options and we don't have a metadataprovider
|
||||||
|
this.server = new SMO.Server(this.serverConnection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SMO.Server Server
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// Use the Server from the SmoMetadataProvider if we have it to avoid
|
||||||
|
// unnecessary overhead of querying a new object
|
||||||
|
return this.SmoMetadataProvider?.SmoServer ?? this.server;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -92,26 +109,30 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Language Service ServerVersion
|
/// Gets the Language Service ServerVersion
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ServerVersion ServerVersion
|
public ServerVersion ServerVersion
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this.ServerConnection != null
|
return this.ServerConnection?.ServerVersion;
|
||||||
? this.ServerConnection.ServerVersion
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current DataEngineType
|
/// Gets the current DataEngineType
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DatabaseEngineType DatabaseEngineType
|
public DatabaseEngineType DatabaseEngineType
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this.ServerConnection != null
|
return this.ServerConnection?.DatabaseEngineType ?? DatabaseEngineType.Standalone;
|
||||||
? this.ServerConnection.DatabaseEngineType
|
}
|
||||||
: DatabaseEngineType.Standalone;
|
}
|
||||||
|
|
||||||
|
public DatabaseEngineEdition DatabaseEngineEdition
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.ServerConnection?.DatabaseEngineEdition ?? DatabaseEngineEdition.Standard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,12 +143,12 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this.IsConnected
|
return this.IsConnected
|
||||||
? GetTransactSqlVersion(this.ServerVersion)
|
? GetTransactSqlVersion(this.Server)
|
||||||
: TransactSqlVersion.Current;
|
: TransactSqlVersion.Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current DatabaseCompatibilityLevel
|
/// Gets the current DatabaseCompatibilityLevel
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -136,7 +157,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this.IsConnected
|
return this.IsConnected
|
||||||
? GetDatabaseCompatibilityLevel(this.ServerVersion)
|
? GetDatabaseCompatibilityLevel(this.Server)
|
||||||
: DatabaseCompatibilityLevel.Current;
|
: DatabaseCompatibilityLevel.Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,55 +183,111 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the database compatibility level from a server version
|
/// Gets the database compatibility level for a given server connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serverVersion"></param>
|
/// <param name="server"></param>
|
||||||
private static DatabaseCompatibilityLevel GetDatabaseCompatibilityLevel(ServerVersion serverVersion)
|
private static DatabaseCompatibilityLevel GetDatabaseCompatibilityLevel(SMO.Server server)
|
||||||
{
|
{
|
||||||
int versionMajor = Math.Max(serverVersion.Major, 8);
|
if (server.DatabaseEngineType == DatabaseEngineType.SqlAzureDatabase)
|
||||||
|
|
||||||
switch (versionMajor)
|
|
||||||
{
|
{
|
||||||
case 8:
|
return DatabaseCompatibilityLevel.Azure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the actual compat level of the database we're connected to
|
||||||
|
switch (GetServerCompatibilityLevel(server))
|
||||||
|
{
|
||||||
|
case SMO.CompatibilityLevel.Version80:
|
||||||
return DatabaseCompatibilityLevel.Version80;
|
return DatabaseCompatibilityLevel.Version80;
|
||||||
case 9:
|
case SMO.CompatibilityLevel.Version90:
|
||||||
return DatabaseCompatibilityLevel.Version90;
|
return DatabaseCompatibilityLevel.Version90;
|
||||||
case 10:
|
case SMO.CompatibilityLevel.Version100:
|
||||||
return DatabaseCompatibilityLevel.Version100;
|
return DatabaseCompatibilityLevel.Version100;
|
||||||
case 11:
|
case SMO.CompatibilityLevel.Version110:
|
||||||
return DatabaseCompatibilityLevel.Version110;
|
return DatabaseCompatibilityLevel.Version110;
|
||||||
case 12:
|
case SMO.CompatibilityLevel.Version120:
|
||||||
return DatabaseCompatibilityLevel.Version120;
|
return DatabaseCompatibilityLevel.Version120;
|
||||||
case 13:
|
case SMO.CompatibilityLevel.Version130:
|
||||||
return DatabaseCompatibilityLevel.Version130;
|
return DatabaseCompatibilityLevel.Version130;
|
||||||
|
case SMO.CompatibilityLevel.Version140:
|
||||||
|
return DatabaseCompatibilityLevel.Version140;
|
||||||
|
case SMO.CompatibilityLevel.Version150:
|
||||||
|
return DatabaseCompatibilityLevel.Version150;
|
||||||
default:
|
default:
|
||||||
return DatabaseCompatibilityLevel.Current;
|
return DatabaseCompatibilityLevel.Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the transaction sql version from a server version
|
/// Gets the transaction sql version for a given server connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serverVersion"></param>
|
/// <param name="server"></param>
|
||||||
private static TransactSqlVersion GetTransactSqlVersion(ServerVersion serverVersion)
|
private static TransactSqlVersion GetTransactSqlVersion(SMO.Server server)
|
||||||
{
|
{
|
||||||
int versionMajor = Math.Max(serverVersion.Major, 9);
|
if (server.DatabaseEngineType == DatabaseEngineType.SqlAzureDatabase)
|
||||||
|
|
||||||
switch (versionMajor)
|
|
||||||
{
|
{
|
||||||
case 9:
|
return TransactSqlVersion.Azure;
|
||||||
case 10:
|
}
|
||||||
|
|
||||||
|
// Determine the language version to use - we can't just use VersionMajor directly because there are engine versions (such as MI)
|
||||||
|
// whose language version they support is higher than the actual server version. So we choose the highest compat level from
|
||||||
|
// between the server version and compat level
|
||||||
|
var compatLevel = Math.Max(server.VersionMajor * 10, (int)GetServerCompatibilityLevel(server));
|
||||||
|
switch (compatLevel)
|
||||||
|
{
|
||||||
|
case 90:
|
||||||
|
case 100:
|
||||||
// In case of 10.0 we still use Version 10.5 as it is the closest available.
|
// In case of 10.0 we still use Version 10.5 as it is the closest available.
|
||||||
return TransactSqlVersion.Version105;
|
return TransactSqlVersion.Version105;
|
||||||
case 11:
|
case 110:
|
||||||
return TransactSqlVersion.Version110;
|
return TransactSqlVersion.Version110;
|
||||||
case 12:
|
case 120:
|
||||||
return TransactSqlVersion.Version120;
|
return TransactSqlVersion.Version120;
|
||||||
case 13:
|
case 130:
|
||||||
return TransactSqlVersion.Version130;
|
return TransactSqlVersion.Version130;
|
||||||
|
case 140:
|
||||||
|
return TransactSqlVersion.Version140;
|
||||||
|
case 150:
|
||||||
|
return TransactSqlVersion.Version150;
|
||||||
default:
|
default:
|
||||||
return TransactSqlVersion.Current;
|
return TransactSqlVersion.Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the SMO compatibility level for the given server, defaulting to the highest available level if an
|
||||||
|
/// error occurs while querying.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="server">The server object to get the compat level of</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static SMO.CompatibilityLevel GetServerCompatibilityLevel(SMO.Server server)
|
||||||
|
{
|
||||||
|
// Set the default fields so that we avoid the overhead of querying for properties we don't need right now
|
||||||
|
server.SetDefaultInitFields(typeof(SMO.Database), nameof(SMO.Database.CompatibilityLevel));
|
||||||
|
|
||||||
|
SMO.CompatibilityLevel compatLevel;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// First try the master DB since it will have the highest compat level for that instance
|
||||||
|
compatLevel = server.Databases["master"].CompatibilityLevel;
|
||||||
|
Logger.Write(System.Diagnostics.TraceEventType.Information, $"Got compat level for binding context {compatLevel} after querying master");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// If we can't get it from master then fall back to the current database
|
||||||
|
try
|
||||||
|
{
|
||||||
|
compatLevel = server.Databases[server.ConnectionContext.DatabaseName].CompatibilityLevel;
|
||||||
|
Logger.Write(System.Diagnostics.TraceEventType.Information, $"Got compat level for binding context {compatLevel} after querying connection DB");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// There's nothing else we can do so just default to the highest available version
|
||||||
|
compatLevel = Enum.GetValues(typeof(SMO.CompatibilityLevel)).Cast<SMO.CompatibilityLevel>().Max();
|
||||||
|
Logger.Write(System.Diagnostics.TraceEventType.Information, $"Failed to get compat level for binding context from querying server - using default of {compatLevel}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return compatLevel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user