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:
Charles Gagnon
2021-05-13 14:39:19 -07:00
committed by GitHub
parent 6785940f1d
commit 64a6b6a85c

View File

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