Feature/peek def code gen (#215)

* Add codeGen for existing types

* Modify code gen logic to match current code

* Extend logic for new smo objects

* Add logic to retrieve token type from QuickInfo

* Remove duplicate types

* Add tests for new types

* Modify GetScript logic to use suggestions first

* Add more tests

* Modify codeGen to include quickInfo logic

* Cake build changes to run CodeGen

* CodeGen replace indentation

* Refactor GetScript and add more tests

* Refactor Resolver calls

* Fix TestDriver test for Definition

* Change quickInfo string case

* Revert change sto .sln file

* Fix typos in comments

* change String to string

* Rename test sql objects
This commit is contained in:
Sharon Ravindran
2017-01-19 13:24:58 -08:00
committed by GitHub
parent c055c459a0
commit 5464e4e63a
11 changed files with 1336 additions and 314 deletions

View File

@@ -3,11 +3,13 @@
#load "scripts/runhelpers.cake" #load "scripts/runhelpers.cake"
#load "scripts/archiving.cake" #load "scripts/archiving.cake"
#load "scripts/artifacts.cake" #load "scripts/artifacts.cake"
#tool "nuget:?package=Mono.TextTransform"
using System.ComponentModel; using System.ComponentModel;
using System.Net; using System.Net;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Cake.Common.IO
// Basic arguments // Basic arguments
var target = Argument("target", "Default"); var target = Argument("target", "Default");
@@ -258,6 +260,7 @@ Task("TestCore")
Task("Test") Task("Test")
.IsDependentOn("Setup") .IsDependentOn("Setup")
.IsDependentOn("SRGen") .IsDependentOn("SRGen")
.IsDependentOn("CodeGen")
.IsDependentOn("BuildTest") .IsDependentOn("BuildTest")
.Does(() => .Does(() =>
{ {
@@ -306,6 +309,7 @@ Task("Test")
Task("OnlyPublish") Task("OnlyPublish")
.IsDependentOn("Setup") .IsDependentOn("Setup")
.IsDependentOn("SRGen") .IsDependentOn("SRGen")
.IsDependentOn("CodeGen")
.Does(() => .Does(() =>
{ {
var project = buildPlan.MainProject; var project = buildPlan.MainProject;
@@ -541,6 +545,20 @@ Task("SRGen")
} }
}); });
/// <summary>
/// Executes T4Template-based code generators
/// </summary>
Task("CodeGen")
.Does(() =>
{
var t4Files = GetFiles(sourceFolder + "/**/*.tt");
foreach(var t4Template in t4Files)
{
TransformTemplate(t4Template, new TextTransformSettings {});
}
});
/// <summary> /// <summary>
/// Default Task aliases to Local. /// Default Task aliases to Local.
/// </summary> /// </summary>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Cake" version="0.10.1" /> <package id="Cake" version="0.17.0" />
<package id="Newtonsoft.Json" version="8.0.3" /> <package id="Newtonsoft.Json" version="8.0.3" />
<package id="Microsoft.DataTools.SrGen" version="1.0.2" /> <package id="Microsoft.DataTools.SrGen" version="1.0.2" />
</packages> <package id="Mono.TextTransform" version="1.0.0" />
</packages>

View File

@@ -123,4 +123,4 @@ Global
{B6F4BECE-82EE-4AB6-99AC-108AEE466274} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {B6F4BECE-82EE-4AB6-99AC-108AEE466274} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4}
{E7CF630E-E084-4DA4-BF69-F61BF0A8F5BE} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {E7CF630E-E084-4DA4-BF69-F61BF0A8F5BE} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -61,8 +61,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
private ParseOptions defaultParseOptions = new ParseOptions( private ParseOptions defaultParseOptions = new ParseOptions(
batchSeparator: LanguageService.DefaultBatchSeperator, batchSeparator: LanguageService.DefaultBatchSeperator,
isQuotedIdentifierSet: true, isQuotedIdentifierSet: true,
compatibilityLevel: DatabaseCompatibilityLevel.Current, compatibilityLevel: DatabaseCompatibilityLevel.Current,
transactSqlVersion: TransactSqlVersion.Current); transactSqlVersion: TransactSqlVersion.Current);
/// <summary> /// <summary>
@@ -105,13 +105,13 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
private static readonly Lazy<LanguageService> instance = new Lazy<LanguageService>(() => new LanguageService()); private static readonly Lazy<LanguageService> instance = new Lazy<LanguageService>(() => new LanguageService());
private Lazy<Dictionary<string, ScriptParseInfo>> scriptParseInfoMap private Lazy<Dictionary<string, ScriptParseInfo>> scriptParseInfoMap
= new Lazy<Dictionary<string, ScriptParseInfo>>(() => new Dictionary<string, ScriptParseInfo>()); = new Lazy<Dictionary<string, ScriptParseInfo>>(() => new Dictionary<string, ScriptParseInfo>());
/// <summary> /// <summary>
/// Gets a mapping dictionary for SQL file URIs to ScriptParseInfo objects /// Gets a mapping dictionary for SQL file URIs to ScriptParseInfo objects
/// </summary> /// </summary>
internal Dictionary<string, ScriptParseInfo> ScriptParseInfoMap internal Dictionary<string, ScriptParseInfo> ScriptParseInfoMap
{ {
get get
{ {
@@ -262,20 +262,20 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
else else
{ {
// get the current list of completion items and return to client // get the current list of completion items and return to client
var scriptFile = LanguageService.WorkspaceServiceInstance.Workspace.GetFile( var scriptFile = LanguageService.WorkspaceServiceInstance.Workspace.GetFile(
textDocumentPosition.TextDocument.Uri); textDocumentPosition.TextDocument.Uri);
ConnectionInfo connInfo; ConnectionInfo connInfo;
LanguageService.ConnectionServiceInstance.TryFindConnection( LanguageService.ConnectionServiceInstance.TryFindConnection(
scriptFile.ClientFilePath, scriptFile.ClientFilePath,
out connInfo); out connInfo);
var completionItems = Instance.GetCompletionItems( var completionItems = Instance.GetCompletionItems(
textDocumentPosition, scriptFile, connInfo); textDocumentPosition, scriptFile, connInfo);
await requestContext.SendResult(completionItems); await requestContext.SendResult(completionItems);
} }
} }
/// <summary> /// <summary>
@@ -322,7 +322,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
LanguageService.ConnectionServiceInstance.TryFindConnection(scriptFile.ClientFilePath, out connInfo); LanguageService.ConnectionServiceInstance.TryFindConnection(scriptFile.ClientFilePath, out connInfo);
DefinitionResult definitionResult = LanguageService.Instance.GetDefinition(textDocumentPosition, scriptFile, connInfo); DefinitionResult definitionResult = LanguageService.Instance.GetDefinition(textDocumentPosition, scriptFile, connInfo);
if (definitionResult != null) if (definitionResult != null)
{ {
if (definitionResult.IsErrorResult) if (definitionResult.IsErrorResult)
{ {
await requestContext.SendError( new DefinitionError { message = definitionResult.Message }); await requestContext.SendError( new DefinitionError { message = definitionResult.Message });
@@ -330,7 +330,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
else else
{ {
await requestContext.SendResult(definitionResult.Locations); await requestContext.SendResult(definitionResult.Locations);
} }
} }
} }
DocumentStatusHelper.SendStatusChange(requestContext, textDocumentPosition, DocumentStatusHelper.DefinitionRequestCompleted); DocumentStatusHelper.SendStatusChange(requestContext, textDocumentPosition, DocumentStatusHelper.DefinitionRequestCompleted);
@@ -382,10 +382,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
private static async Task HandleHoverRequest( private static async Task HandleHoverRequest(
TextDocumentPosition textDocumentPosition, TextDocumentPosition textDocumentPosition,
RequestContext<Hover> requestContext) RequestContext<Hover> requestContext)
{ {
// check if Quick Info hover tooltips are enabled // check if Quick Info hover tooltips are enabled
if (WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsQuickInfoEnabled) if (WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsQuickInfoEnabled)
{ {
var scriptFile = WorkspaceService<SqlToolsSettings>.Instance.Workspace.GetFile( var scriptFile = WorkspaceService<SqlToolsSettings>.Instance.Workspace.GetFile(
textDocumentPosition.TextDocument.Uri); textDocumentPosition.TextDocument.Uri);
@@ -396,7 +396,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
} }
await requestContext.SendResult(new Hover()); await requestContext.SendResult(new Hover());
} }
#endregion #endregion
@@ -404,42 +404,42 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
#region Handlers for Events from Other Services #region Handlers for Events from Other Services
/// <summary> /// <summary>
/// Handle the file open notification /// Handle the file open notification
/// </summary> /// </summary>
/// <param name="scriptFile"></param> /// <param name="scriptFile"></param>
/// <param name="eventContext"></param> /// <param name="eventContext"></param>
/// <returns></returns> /// <returns></returns>
public async Task HandleDidOpenTextDocumentNotification( public async Task HandleDidOpenTextDocumentNotification(
ScriptFile scriptFile, ScriptFile scriptFile,
EventContext eventContext) EventContext eventContext)
{ {
// if not in the preview window and diagnostics are enabled then run diagnostics // if not in the preview window and diagnostics are enabled then run diagnostics
if (!IsPreviewWindow(scriptFile) if (!IsPreviewWindow(scriptFile)
&& WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsDiagnositicsEnabled) && WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsDiagnositicsEnabled)
{ {
await RunScriptDiagnostics( await RunScriptDiagnostics(
new ScriptFile[] { scriptFile }, new ScriptFile[] { scriptFile },
eventContext); eventContext);
} }
await Task.FromResult(true); await Task.FromResult(true);
} }
/// <summary> /// <summary>
/// Handles text document change events /// Handles text document change events
/// </summary> /// </summary>
/// <param name="textChangeParams"></param> /// <param name="textChangeParams"></param>
/// <param name="eventContext"></param> /// <param name="eventContext"></param>
public async Task HandleDidChangeTextDocumentNotification(ScriptFile[] changedFiles, EventContext eventContext) public async Task HandleDidChangeTextDocumentNotification(ScriptFile[] changedFiles, EventContext eventContext)
{ {
if (WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsDiagnositicsEnabled) if (WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsDiagnositicsEnabled)
{ {
await this.RunScriptDiagnostics( await this.RunScriptDiagnostics(
changedFiles.ToArray(), changedFiles.ToArray(),
eventContext); eventContext);
} }
await Task.FromResult(true); await Task.FromResult(true);
} }
/// <summary> /// <summary>
@@ -449,8 +449,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// <param name="oldSettings"></param> /// <param name="oldSettings"></param>
/// <param name="eventContext"></param> /// <param name="eventContext"></param>
public async Task HandleDidChangeConfigurationNotification( public async Task HandleDidChangeConfigurationNotification(
SqlToolsSettings newSettings, SqlToolsSettings newSettings,
SqlToolsSettings oldSettings, SqlToolsSettings oldSettings,
EventContext eventContext) EventContext eventContext)
{ {
bool oldEnableIntelliSense = oldSettings.SqlTools.IntelliSense.EnableIntellisense; bool oldEnableIntelliSense = oldSettings.SqlTools.IntelliSense.EnableIntellisense;
@@ -480,7 +480,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
} }
} }
#endregion #endregion
@@ -495,13 +495,13 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{ {
RemoveScriptParseInfo(ownerUri); RemoveScriptParseInfo(ownerUri);
// currently this method is disabled, but we need to reimplement now that the // currently this method is disabled, but we need to reimplement now that the
// implementation of the 'cache' has changed. // implementation of the 'cache' has changed.
await Task.FromResult(0); await Task.FromResult(0);
} }
/// <summary> /// <summary>
/// Parses the SQL text and binds it to the SMO metadata provider if connected /// Parses the SQL text and binds it to the SMO metadata provider if connected
/// </summary> /// </summary>
/// <param name="filePath"></param> /// <param name="filePath"></param>
/// <param name="sqlText"></param> /// <param name="sqlText"></param>
@@ -531,7 +531,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
key: parseInfo.ConnectionKey, key: parseInfo.ConnectionKey,
bindingTimeout: LanguageService.BindingTimeout, bindingTimeout: LanguageService.BindingTimeout,
bindOperation: (bindingContext, cancelToken) => bindOperation: (bindingContext, cancelToken) =>
{ {
try try
{ {
ParseResult parseResult = Parser.IncrementalParse( ParseResult parseResult = Parser.IncrementalParse(
@@ -544,8 +544,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
List<ParseResult> parseResults = new List<ParseResult>(); List<ParseResult> parseResults = new List<ParseResult>();
parseResults.Add(parseResult); parseResults.Add(parseResult);
bindingContext.Binder.Bind( bindingContext.Binder.Bind(
parseResults, parseResults,
connInfo.ConnectionDetails.DatabaseName, connInfo.ConnectionDetails.DatabaseName,
BindMode.Batch); BindMode.Batch);
} }
catch (ConnectionException) catch (ConnectionException)
@@ -562,9 +562,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
return null; return null;
}); });
queueItem.ItemProcessed.WaitOne(); queueItem.ItemProcessed.WaitOne();
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -580,9 +580,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
else else
{ {
Logger.Write(LogLevel.Warning, "Binding metadata lock timeout in ParseAndBind"); Logger.Write(LogLevel.Warning, "Binding metadata lock timeout in ParseAndBind");
} }
return parseInfo.ParseResult; return parseInfo.ParseResult;
} }
@@ -592,16 +592,16 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// <param name="info"></param> /// <param name="info"></param>
public async Task UpdateLanguageServiceOnConnection(ConnectionInfo info) public async Task UpdateLanguageServiceOnConnection(ConnectionInfo info)
{ {
await Task.Run(() => await Task.Run(() =>
{ {
ScriptParseInfo scriptInfo = GetScriptParseInfo(info.OwnerUri, createIfNotExists: true); ScriptParseInfo scriptInfo = GetScriptParseInfo(info.OwnerUri, createIfNotExists: true);
if (Monitor.TryEnter(scriptInfo.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout)) if (Monitor.TryEnter(scriptInfo.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout))
{ {
try try
{ {
scriptInfo.ConnectionKey = this.BindingQueue.AddConnectionContext(info); scriptInfo.ConnectionKey = this.BindingQueue.AddConnectionContext(info);
scriptInfo.IsConnected = true; scriptInfo.IsConnected = true;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -614,7 +614,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
// (Tell Language Service that I am ready with Metadata Provider Object) // (Tell Language Service that I am ready with Metadata Provider Object)
Monitor.Exit(scriptInfo.BuildingMetadataLock); Monitor.Exit(scriptInfo.BuildingMetadataLock);
} }
} }
AutoCompleteHelper.PrepopulateCommonMetadata(info, scriptInfo, this.BindingQueue); AutoCompleteHelper.PrepopulateCommonMetadata(info, scriptInfo, this.BindingQueue);
@@ -658,7 +658,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
key: scriptParseInfo.ConnectionKey, key: scriptParseInfo.ConnectionKey,
bindingTimeout: LanguageService.BindingTimeout, bindingTimeout: LanguageService.BindingTimeout,
bindOperation: (bindingContext, cancelToken) => bindOperation: (bindingContext, cancelToken) =>
{ {
foreach (var suggestion in scriptParseInfo.CurrentSuggestions) foreach (var suggestion in scriptParseInfo.CurrentSuggestions)
{ {
if (string.Equals(suggestion.Title, completionItem.Label)) if (string.Equals(suggestion.Title, completionItem.Label))
@@ -667,25 +667,25 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
completionItem.Documentation = suggestion.Description; completionItem.Documentation = suggestion.Description;
break; break;
} }
} }
return completionItem; return completionItem;
}); });
queueItem.ItemProcessed.WaitOne(); queueItem.ItemProcessed.WaitOne();
} }
catch (Exception ex) catch (Exception ex)
{ {
// if any exceptions are raised looking up extended completion metadata // if any exceptions are raised looking up extended completion metadata
// then just return the original completion item // then just return the original completion item
Logger.Write(LogLevel.Error, "Exeception in ResolveCompletionItem " + ex.ToString()); Logger.Write(LogLevel.Error, "Exception in ResolveCompletionItem " + ex.ToString());
} }
finally finally
{ {
Monitor.Exit(scriptParseInfo.BuildingMetadataLock); Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
} }
} }
} }
return completionItem; return completionItem;
} }
@@ -725,25 +725,21 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{ {
try try
{ {
// Queue the task with the binding queue // Queue the task with the binding queue
QueueItem queueItem = this.BindingQueue.QueueBindingOperation( QueueItem queueItem = this.BindingQueue.QueueBindingOperation(
key: scriptParseInfo.ConnectionKey, key: scriptParseInfo.ConnectionKey,
bindingTimeout: LanguageService.PeekDefinitionTimeout, bindingTimeout: LanguageService.PeekDefinitionTimeout,
bindOperation: (bindingContext, cancelToken) => bindOperation: (bindingContext, cancelToken) =>
{ {
// Get suggestions for the token
int parserLine = textDocumentPosition.Position.Line + 1;
int parserColumn = textDocumentPosition.Position.Character + 1;
IEnumerable<Declaration> declarationItems = Resolver.FindCompletions(
scriptParseInfo.ParseResult,
parserLine, parserColumn,
bindingContext.MetadataDisplayInfoProvider);
// Match token with the suggestions(declaration items) returned
string schemaName = this.GetSchemaName(scriptParseInfo, textDocumentPosition.Position, scriptFile); string schemaName = this.GetSchemaName(scriptParseInfo, textDocumentPosition.Position, scriptFile);
// Script object using SMO
PeekDefinition peekDefinition = new PeekDefinition(bindingContext.ServerConnection, connInfo); PeekDefinition peekDefinition = new PeekDefinition(bindingContext.ServerConnection, connInfo);
return peekDefinition.GetScript(declarationItems, tokenText, schemaName); return peekDefinition.GetScript(
scriptParseInfo.ParseResult,
textDocumentPosition.Position,
bindingContext.MetadataDisplayInfoProvider,
tokenText,
schemaName);
}, },
timeoutOperation: (bindingContext) => timeoutOperation: (bindingContext) =>
{ {
@@ -813,7 +809,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
Token schemaToken = scriptParseInfo.ParseResult.Script.TokenManager.GetToken(schemaTokenIndex); Token schemaToken = scriptParseInfo.ParseResult.Script.TokenManager.GetToken(schemaTokenIndex);
return TextUtilities.RemoveSquareBracketSyntax(schemaToken.Text); return TextUtilities.RemoveSquareBracketSyntax(schemaToken.Text);
} }
} }
// if no schema name, returns null // if no schema name, returns null
return null; return null;
} }
@@ -827,10 +823,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{ {
int startLine = textDocumentPosition.Position.Line; int startLine = textDocumentPosition.Position.Line;
int startColumn = TextUtilities.PositionOfPrevDelimeter( int startColumn = TextUtilities.PositionOfPrevDelimeter(
scriptFile.Contents, scriptFile.Contents,
textDocumentPosition.Position.Line, textDocumentPosition.Position.Line,
textDocumentPosition.Position.Character); textDocumentPosition.Position.Character);
int endColumn = textDocumentPosition.Position.Character; int endColumn = textDocumentPosition.Position.Character;
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri); ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
if (scriptParseInfo != null && scriptParseInfo.ParseResult != null) if (scriptParseInfo != null && scriptParseInfo.ParseResult != null)
@@ -843,29 +839,29 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
key: scriptParseInfo.ConnectionKey, key: scriptParseInfo.ConnectionKey,
bindingTimeout: LanguageService.HoverTimeout, bindingTimeout: LanguageService.HoverTimeout,
bindOperation: (bindingContext, cancelToken) => bindOperation: (bindingContext, cancelToken) =>
{ {
// get the current quick info text // get the current quick info text
Babel.CodeObjectQuickInfo quickInfo = Resolver.GetQuickInfo( Babel.CodeObjectQuickInfo quickInfo = Resolver.GetQuickInfo(
scriptParseInfo.ParseResult, scriptParseInfo.ParseResult,
startLine + 1, startLine + 1,
endColumn + 1, endColumn + 1,
bindingContext.MetadataDisplayInfoProvider); bindingContext.MetadataDisplayInfoProvider);
// convert from the parser format to the VS Code wire format // convert from the parser format to the VS Code wire format
return AutoCompleteHelper.ConvertQuickInfoToHover( return AutoCompleteHelper.ConvertQuickInfoToHover(
quickInfo, quickInfo,
startLine, startLine,
startColumn, startColumn,
endColumn); endColumn);
}); });
queueItem.ItemProcessed.WaitOne(); queueItem.ItemProcessed.WaitOne();
return queueItem.GetResultAsT<Hover>(); return queueItem.GetResultAsT<Hover>();
} }
finally finally
{ {
Monitor.Exit(scriptParseInfo.BuildingMetadataLock); Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
} }
} }
} }
@@ -880,7 +876,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{ {
int startLine = textDocumentPosition.Position.Line; int startLine = textDocumentPosition.Position.Line;
int startColumn = TextUtilities.PositionOfPrevDelimeter( int startColumn = TextUtilities.PositionOfPrevDelimeter(
scriptFile.Contents, scriptFile.Contents,
textDocumentPosition.Position.Line, textDocumentPosition.Position.Line,
textDocumentPosition.Position.Character); textDocumentPosition.Position.Character);
int endColumn = textDocumentPosition.Position.Character; int endColumn = textDocumentPosition.Position.Character;
@@ -895,12 +891,12 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
ConnectionInfo connInfo; ConnectionInfo connInfo;
LanguageService.ConnectionServiceInstance.TryFindConnection( LanguageService.ConnectionServiceInstance.TryFindConnection(
scriptFile.ClientFilePath, scriptFile.ClientFilePath,
out connInfo); out connInfo);
// reparse and bind the SQL statement if needed // reparse and bind the SQL statement if needed
if (RequiresReparse(scriptParseInfo, scriptFile)) if (RequiresReparse(scriptParseInfo, scriptFile))
{ {
ParseAndBind(scriptFile, connInfo); ParseAndBind(scriptFile, connInfo);
} }
@@ -914,14 +910,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
key: scriptParseInfo.ConnectionKey, key: scriptParseInfo.ConnectionKey,
bindingTimeout: LanguageService.BindingTimeout, bindingTimeout: LanguageService.BindingTimeout,
bindOperation: (bindingContext, cancelToken) => bindOperation: (bindingContext, cancelToken) =>
{ {
// get the list of possible current methods for signature help // get the list of possible current methods for signature help
var methods = Resolver.FindMethods( var methods = Resolver.FindMethods(
scriptParseInfo.ParseResult, scriptParseInfo.ParseResult,
startLine + 1, startLine + 1,
endColumn + 1, endColumn + 1,
bindingContext.MetadataDisplayInfoProvider); bindingContext.MetadataDisplayInfoProvider);
// get positional information on the current method // get positional information on the current method
var methodLocations = Resolver.GetMethodNameAndParams(scriptParseInfo.ParseResult, var methodLocations = Resolver.GetMethodNameAndParams(scriptParseInfo.ParseResult,
startLine + 1, startLine + 1,
@@ -941,14 +937,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
return null; return null;
} }
}); });
queueItem.ItemProcessed.WaitOne(); queueItem.ItemProcessed.WaitOne();
return queueItem.GetResultAsT<SignatureHelp>(); return queueItem.GetResultAsT<SignatureHelp>();
} }
finally finally
{ {
Monitor.Exit(scriptParseInfo.BuildingMetadataLock); Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
} }
} }
} }
@@ -974,14 +970,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
// get the current script parse info object // get the current script parse info object
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri); ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
if (scriptParseInfo == null) if (scriptParseInfo == null)
{ {
return AutoCompleteHelper.GetDefaultCompletionItems(ScriptDocumentInfo.CreateDefaultDocumentInfo(textDocumentPosition, scriptFile), useLowerCaseSuggestions); return AutoCompleteHelper.GetDefaultCompletionItems(ScriptDocumentInfo.CreateDefaultDocumentInfo(textDocumentPosition, scriptFile), useLowerCaseSuggestions);
} }
ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo); ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
// reparse and bind the SQL statement if needed // reparse and bind the SQL statement if needed
if (RequiresReparse(scriptParseInfo, scriptFile)) if (RequiresReparse(scriptParseInfo, scriptFile))
{ {
@@ -1019,9 +1015,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{ {
ConnectionInfo connInfo; ConnectionInfo connInfo;
ConnectionService.Instance.TryFindConnection( ConnectionService.Instance.TryFindConnection(
scriptFile.ClientFilePath, scriptFile.ClientFilePath,
out connInfo); out connInfo);
var parseResult = ParseAndBind(scriptFile, connInfo); var parseResult = ParseAndBind(scriptFile, connInfo);
// build a list of SQL script file markers from the errors // build a list of SQL script file markers from the errors
@@ -1181,7 +1177,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// Internal for testing purposes only /// Internal for testing purposes only
/// </summary> /// </summary>
/// <param name="uri"></param> /// <param name="uri"></param>
/// <param name="createIfNotExists">Creates a new instance if one doesn't exist</param> /// <param name="createIfNotExists">Creates a new instance if one doesn't exist</param>
internal ScriptParseInfo GetScriptParseInfo(string uri, bool createIfNotExists = false) internal ScriptParseInfo GetScriptParseInfo(string uri, bool createIfNotExists = false)
{ {
lock (this.parseMapLock) lock (this.parseMapLock)
@@ -1209,7 +1205,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
lock (this.parseMapLock) lock (this.parseMapLock)
{ {
if (this.ScriptParseInfoMap.ContainsKey(uri)) if (this.ScriptParseInfoMap.ContainsKey(uri))
{ {
return this.ScriptParseInfoMap.Remove(uri); return this.ScriptParseInfoMap.Remove(uri);
} }
else else

View File

@@ -4,17 +4,21 @@
// //
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Data.SqlClient; using System.Data.SqlClient;
using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common; using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SqlParser.Intellisense; using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlServer.Management.SqlParser.Parser;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.QueryExecution; using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.Utility; using Microsoft.SqlTools.ServiceLayer.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{ {
@@ -22,7 +26,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// Peek Definition/ Go to definition implementation /// Peek Definition/ Go to definition implementation
/// Script sql objects and write create scripts to file /// Script sql objects and write create scripts to file
/// </summary> /// </summary>
internal class PeekDefinition internal partial class PeekDefinition
{ {
private bool error; private bool error;
private string errorMessage; private string errorMessage;
@@ -37,9 +41,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
private Dictionary<DeclarationType, ScriptGetter> sqlScriptGetters = private Dictionary<DeclarationType, ScriptGetter> sqlScriptGetters =
new Dictionary<DeclarationType, ScriptGetter>(); new Dictionary<DeclarationType, ScriptGetter>();
private Dictionary<string, ScriptGetter> sqlScriptGettersFromQuickInfo =
new Dictionary<string, ScriptGetter>();
// Dictionary that holds the object name (as appears on the TSQL create statement) // Dictionary that holds the object name (as appears on the TSQL create statement)
private Dictionary<DeclarationType, string> sqlObjectTypes = new Dictionary<DeclarationType, string>(); private Dictionary<DeclarationType, string> sqlObjectTypes = new Dictionary<DeclarationType, string>();
private Dictionary<string, string> sqlObjectTypesFromQuickInfo = new Dictionary<string, string>();
/// <summary> /// <summary>
/// Initialize a Peek Definition helper object /// Initialize a Peek Definition helper object
/// </summary> /// </summary>
@@ -48,7 +57,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{ {
this.serverConnection = serverConnection; this.serverConnection = serverConnection;
this.connectionInfo = connInfo; this.connectionInfo = connInfo;
this.tempPath = FileUtils.GetPeekDefinitionTempFolder(); this.tempPath = FileUtils.GetPeekDefinitionTempFolder();
Initialize(); Initialize();
} }
@@ -70,7 +79,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{ {
Logger.Write(LogLevel.Error, "Exception at PeekDefinition Database.get() : " + cfe.Message); Logger.Write(LogLevel.Error, "Exception at PeekDefinition Database.get() : " + cfe.Message);
this.error = true; this.error = true;
this.errorMessage = (connectionInfo != null && connectionInfo.IsAzure)? SR.PeekDefinitionAzureError(cfe.Message) : SR.PeekDefinitionError(cfe.Message); this.errorMessage = (connectionInfo != null && connectionInfo.IsAzure) ? SR.PeekDefinitionAzureError(cfe.Message) : SR.PeekDefinitionError(cfe.Message);
return null; return null;
} }
catch (Exception ex) catch (Exception ex)
@@ -81,78 +90,23 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
return null; return null;
} }
} }
} }
return this.database; return this.database;
} }
} }
/// <summary>
/// Add getters for each sql object supported by peek definition
/// </summary>
private void Initialize()
{
//Add script getters for each sql object
//Add tables to supported types
AddSupportedType(DeclarationType.Table, GetTableScripts, "Table");
//Add views to supported types
AddSupportedType(DeclarationType.View, GetViewScripts, "view");
//Add stored procedures to supported types
AddSupportedType(DeclarationType.StoredProcedure, GetStoredProcedureScripts, "Procedure");
}
/// <summary> /// <summary>
/// Add the given type, scriptgetter and the typeName string to the respective dictionaries /// Add the given type, scriptgetter and the typeName string to the respective dictionaries
/// </summary> /// </summary>
private void AddSupportedType(DeclarationType type, ScriptGetter scriptGetter, string typeName) private void AddSupportedType(DeclarationType type, ScriptGetter scriptGetter, string typeName, string quickInfoType)
{ {
sqlScriptGetters.Add(type, scriptGetter); sqlScriptGetters.Add(type, scriptGetter);
sqlObjectTypes.Add(type, typeName); sqlObjectTypes.Add(type, typeName);
if (!string.IsNullOrEmpty(quickInfoType))
}
/// <summary>
/// Convert a file to a location array containing a location object as expected by the extension
/// </summary>
internal Location[] GetLocationFromFile(string tempFileName, int lineNumber)
{
if (Path.DirectorySeparatorChar.Equals('/'))
{ {
tempFileName = "file:" + tempFileName; sqlScriptGettersFromQuickInfo.Add(quickInfoType.ToLowerInvariant(), scriptGetter);
sqlObjectTypesFromQuickInfo.Add(quickInfoType.ToLowerInvariant(), typeName);
} }
else
{
tempFileName = new Uri(tempFileName).AbsoluteUri;
}
Location[] locations = new[] {
new Location {
Uri = tempFileName,
Range = new Range {
Start = new Position { Line = lineNumber, Character = 1},
End = new Position { Line = lineNumber + 1, Character = 1}
}
}
};
return locations;
}
/// <summary>
/// Get line number for the create statement
/// </summary>
private int GetStartOfCreate(string script, string createString)
{
string[] lines = script.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
for (int lineNumber = 0; lineNumber < lines.Length; lineNumber++)
{
if (lines[lineNumber].IndexOf(createString, StringComparison.OrdinalIgnoreCase) >= 0)
{
return lineNumber;
}
}
return 0;
} }
/// <summary> /// <summary>
@@ -162,45 +116,77 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// <param name="tokenText"></param> /// <param name="tokenText"></param>
/// <param name="schemaName"></param> /// <param name="schemaName"></param>
/// <returns>Location object of the script file</returns> /// <returns>Location object of the script file</returns>
internal DefinitionResult GetScript(IEnumerable<Declaration> declarationItems, string tokenText, string schemaName) internal DefinitionResult GetScript(ParseResult parseResult, Position position, IMetadataDisplayInfoProvider metadataDisplayInfoProvider, string tokenText, string schemaName)
{ {
foreach (Declaration declarationItem in declarationItems) int parserLine = position.Line + 1;
int parserColumn = position.Character + 1;
// Get DeclarationItems from The Intellisense Resolver for the selected token. The type of the selected token is extracted from the declarationItem.
IEnumerable<Declaration> declarationItems = GetCompletionsForToken(parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
if (declarationItems != null && declarationItems.Count() > 0)
{ {
if (declarationItem.Title == null) foreach (Declaration declarationItem in declarationItems)
{ {
continue; if (declarationItem.Title == null)
}
if (declarationItem.Title.Equals(tokenText))
{
// Script object using SMO based on type
DeclarationType type = declarationItem.Type;
if (sqlScriptGetters.ContainsKey(type) && sqlObjectTypes.ContainsKey(type))
{ {
// On *nix and mac systems, the defaultSchema property throws an Exception when accessed. continue;
// This workaround ensures that a schema name is present by attempting
// to get the schema name from the declaration item
// If all fails, the default schema name is assumed to be "dbo"
if ((connectionInfo != null && connectionInfo.ConnectionDetails.AuthenticationType.Equals(Constants.SqlLoginAuthenticationType)) && string.IsNullOrEmpty(schemaName))
{
string fullObjectName = declarationItem.DatabaseQualifiedName;
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
}
Location[] locations = GetSqlObjectDefinition(
sqlScriptGetters[type],
tokenText,
schemaName,
sqlObjectTypes[type]
);
DefinitionResult result = new DefinitionResult
{
IsErrorResult = this.error,
Message = this.errorMessage,
Locations = locations
};
return result;
} }
// sql object type is currently not supported // if declarartionItem matches the selected token, script SMO using that type
if (declarationItem.Title.Equals(tokenText))
{
return GetDefinitionUsingDeclarationType(declarationItem.Type, declarationItem.DatabaseQualifiedName, tokenText, schemaName);
}
}
}
else
{
// if no declarationItem matched the selected token, we try to find the type of the token using QuickInfo.Text
string quickInfoText = GetQuickInfoForToken(parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
return GetDefinitionUsingQuickInfoText(quickInfoText, tokenText, schemaName);
}
// no definition found
return GetDefinitionErrorResult(SR.PeekDefinitionNoResultsError);
}
/// <summary>
/// Script an object using the type extracted from quickInfo Text
/// </summary>
/// <param name="quickInfoText">the text from the quickInfo for the selected token</param>
/// <param name="tokenText">The text of the selected token</param>
/// <param name="schemaName">Schema name</param>
/// <returns></returns>
internal DefinitionResult GetDefinitionUsingQuickInfoText(string quickInfoText, string tokenText, string schemaName)
{
string tokenType = GetTokenTypeFromQuickInfo(quickInfoText, tokenText);
if (tokenType != null)
{
if (sqlScriptGettersFromQuickInfo.ContainsKey(tokenType.ToLowerInvariant()))
{
// With SqlLogin authentication, the defaultSchema property throws an Exception when accessed.
// This workaround ensures that a schema name is present by attempting
// to get the schema name from the declaration item.
// If all fails, the default schema name is assumed to be "dbo"
if ((connectionInfo != null && connectionInfo.ConnectionDetails.AuthenticationType.Equals(Constants.SqlLoginAuthenticationType)) && string.IsNullOrEmpty(schemaName))
{
string fullObjectName = this.GetFullObjectNameFromQuickInfo(quickInfoText, tokenText);
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
}
Location[] locations = GetSqlObjectDefinition(
sqlScriptGettersFromQuickInfo[tokenType.ToLowerInvariant()],
tokenText,
schemaName,
sqlObjectTypesFromQuickInfo[tokenType.ToLowerInvariant()]
);
DefinitionResult result = new DefinitionResult
{
IsErrorResult = this.error,
Message = this.errorMessage,
Locations = locations
};
return result;
}
else
{
// If a type was found but is not in sqlScriptGettersFromQuickInfo, then the type is not supported
return GetDefinitionErrorResult(SR.PeekDefinitionTypeNotSupportedError); return GetDefinitionErrorResult(SR.PeekDefinitionTypeNotSupportedError);
} }
} }
@@ -209,97 +195,41 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
/// <summary> /// <summary>
/// Return schema name from the full name of the database. If schema is missing return dbo as schema name. /// Script a object using the type extracted from declarationItem
/// </summary> /// </summary>
/// <param name="fullObjectName"> The full database qualified name(database.schema.object)</param> /// <param name="declarationItem">The Declarartion object that matched with the selected token</param>
/// <param name="objectName"> Object name</param> /// <param name="tokenText">The text of the selected token</param>
/// <returns>Schema name</returns>
internal string GetSchemaFromDatabaseQualifiedName(string fullObjectName, string objectName)
{
string[] tokens = fullObjectName.Split('.');
for (int i = tokens.Length - 1; i > 0; i--)
{
if (tokens[i].Equals(objectName))
{
return tokens[i - 1];
}
}
return "dbo";
}
/// <summary>
/// Script a table using SMO
/// </summary>
/// <param name="tableName">Table name</param>
/// <param name="schemaName">Schema name</param> /// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns> /// <returns></returns>
internal StringCollection GetTableScripts(string tableName, string schemaName) internal DefinitionResult GetDefinitionUsingDeclarationType(DeclarationType type, string databaseQualifiedName, string tokenText, string schemaName)
{ {
try if (sqlScriptGetters.ContainsKey(type) && sqlObjectTypes.ContainsKey(type))
{ {
Table table = string.IsNullOrEmpty(schemaName) // With SqlLogin authentication, the defaultSchema property throws an Exception when accessed.
? new Table(this.Database, tableName) // This workaround ensures that a schema name is present by attempting
: new Table(this.Database, tableName, schemaName); // to get the schema name from the declaration item.
// If all fails, the default schema name is assumed to be "dbo"
table.Refresh(); if ((connectionInfo != null && connectionInfo.ConnectionDetails.AuthenticationType.Equals(Constants.SqlLoginAuthenticationType)) && string.IsNullOrEmpty(schemaName))
{
return table.Script(); string fullObjectName = databaseQualifiedName;
} schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
catch (Exception ex) }
{ Location[] locations = GetSqlObjectDefinition(
Logger.Write(LogLevel.Error, "Exception at PeekDefinition GetTableScripts : " + ex.Message); sqlScriptGetters[type],
return null; tokenText,
} schemaName,
} sqlObjectTypes[type]
);
/// <summary> DefinitionResult result = new DefinitionResult
/// Script a view using SMO {
/// </summary> IsErrorResult = this.error,
/// <param name="viewName">View name</param> Message = this.errorMessage,
/// <param name="schemaName">Schema name </param> Locations = locations
/// <returns>String collection of scripts</returns> };
internal StringCollection GetViewScripts(string viewName, string schemaName) return result;
{
try
{
View view = string.IsNullOrEmpty(schemaName)
? new View(this.Database, viewName)
: new View(this.Database, viewName, schemaName);
view.Refresh();
return view.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error, "Exception at PeekDefinition GetViewScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a stored procedure using SMO
/// </summary>
/// <param name="storedProcedureName">Stored Procedure name</param>
/// <param name="schemaName">Schema Name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetStoredProcedureScripts(string sprocName, string schemaName)
{
try
{
StoredProcedure sproc = string.IsNullOrEmpty(schemaName)
? new StoredProcedure(this.Database, sprocName)
: new StoredProcedure(this.Database, sprocName, schemaName);
sproc.Refresh();
return sproc.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error, "Exception at PeekDefinition GetStoredProcedureScripts : " + ex.Message);
return null;
} }
// If a type was found but is not in sqlScriptGetters, then the type is not supported
return GetDefinitionErrorResult(SR.PeekDefinitionTypeNotSupportedError);
} }
/// <summary> /// <summary>
@@ -346,6 +276,71 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
} }
#region Helper Methods
/// <summary>
/// Return schema name from the full name of the database. If schema is missing return dbo as schema name.
/// </summary>
/// <param name="fullObjectName"> The full database qualified name(database.schema.object)</param>
/// <param name="objectName"> Object name</param>
/// <returns>Schema name</returns>
internal string GetSchemaFromDatabaseQualifiedName(string fullObjectName, string objectName)
{
if(!string.IsNullOrEmpty(fullObjectName))
{
string[] tokens = fullObjectName.Split('.');
for (int i = tokens.Length - 1; i > 0; i--)
{
if (tokens[i].Equals(objectName))
{
return tokens[i - 1];
}
}
}
return "dbo";
}
/// <summary>
/// Convert a file to a location array containing a location object as expected by the extension
/// </summary>
internal Location[] GetLocationFromFile(string tempFileName, int lineNumber)
{
// Get absolute Uri based on uri format. This works around a dotnetcore URI bug for linux paths.
if (Path.DirectorySeparatorChar.Equals('/'))
{
tempFileName = "file:" + tempFileName;
}
else
{
tempFileName = new Uri(tempFileName).AbsoluteUri;
}
// Create a location array containing the tempFile Uri, as expected by VSCode.
Location[] locations = new[] {
new Location {
Uri = tempFileName,
Range = new Range {
Start = new Position { Line = lineNumber, Character = 1},
End = new Position { Line = lineNumber + 1, Character = 1}
}
}
};
return locations;
}
/// <summary>
/// Get line number for the create statement
/// </summary>
private int GetStartOfCreate(string script, string createString)
{
string[] lines = script.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
for (int lineNumber = 0; lineNumber < lines.Length; lineNumber++)
{
if (lines[lineNumber].IndexOf(createString, StringComparison.OrdinalIgnoreCase) >= 0)
{
return lineNumber;
}
}
return 0;
}
/// <summary> /// <summary>
/// Helper method to create definition error result object /// Helper method to create definition error result object
/// </summary> /// </summary>
@@ -360,5 +355,75 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
Locations = null Locations = null
}; };
} }
/// <summary>
/// Return full object name(database.schema.objectName) from the quickInfo text("type database.schema.objectName")
/// </summary>
/// <param name="quickInfoText">QuickInfo Text for this token</param>
/// <param name="tokenText">Token Text</param>
/// <returns></returns>
internal string GetFullObjectNameFromQuickInfo(string quickInfoText, string tokenText)
{
if (string.IsNullOrEmpty(quickInfoText) || string.IsNullOrEmpty(tokenText))
{
return null;
}
// extract full object name from quickInfo text
string[] tokens = quickInfoText.Split(' ');
List<string> tokenList = tokens.Where(el => el.Contains(tokenText)).ToList();
return (tokenList?.Count() > 0) ? tokenList[0] : null;
}
/// <summary>
/// Return token type from the quickInfo text("type database.schema.objectName")
/// </summary>
/// <param name="quickInfoText">QuickInfo Text for this token</param>
/// <param name="tokenText"Token Text></param>
/// <returns></returns>
internal string GetTokenTypeFromQuickInfo(string quickInfoText, string tokenText)
{
if (string.IsNullOrEmpty(quickInfoText) || string.IsNullOrEmpty(tokenText))
{
return null;
}
// extract string denoting the token type from quickInfo text
string[] tokens = quickInfoText.Split(' ');
List<int> indexList = tokens.Select((s, i) => new { i, s }).Where(el => (el.s).Contains(tokenText)).Select(el => el.i).ToList();
return (indexList?.Count() > 0) ? String.Join(" ", tokens.Take(indexList[0])) : null;
}
/// <summary>
/// Wrapper method that calls Resolver.GetQuickInfo
/// </summary>
internal string GetQuickInfoForToken(ParseResult parseResult, int parserLine, int parserColumn, IMetadataDisplayInfoProvider metadataDisplayInfoProvider)
{
if (parseResult == null || metadataDisplayInfoProvider == null)
{
return null;
}
Babel.CodeObjectQuickInfo quickInfo = Resolver.GetQuickInfo(
parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
return quickInfo?.Text;
}
/// <summary>
/// Wrapper method that calls Resolver.FindCompletions
/// </summary>
/// <param name="parseResult"></param>
/// <param name="parserLine"></param>
/// <param name="parserColumn"></param>
/// <param name="metadataDisplayInfoProvider"></param>
/// <returns></returns>
internal IEnumerable<Declaration> GetCompletionsForToken(ParseResult parseResult, int parserLine, int parserColumn, IMetadataDisplayInfoProvider metadataDisplayInfoProvider)
{
if (parseResult == null || metadataDisplayInfoProvider == null)
{
return null;
}
return Resolver.FindCompletions(
parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
}
#endregion
} }
} }

View File

@@ -0,0 +1,199 @@
//
// 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.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
internal partial class PeekDefinition
{
private void Initialize()
{
AddSupportedType(DeclarationType.Table, GetTableScripts, "Table", "table");
AddSupportedType(DeclarationType.View, GetViewScripts, "View", "view");
AddSupportedType(DeclarationType.StoredProcedure, GetStoredProcedureScripts, "Procedure", "stored procedure");
AddSupportedType(DeclarationType.UserDefinedDataType, GetUserDefinedDataTypeScripts, "Type", "user-defined data type");
AddSupportedType(DeclarationType.UserDefinedTableType, GetUserDefinedTableTypeScripts, "Type", "user-defined table type");
AddSupportedType(DeclarationType.Synonym, GetSynonymScripts, "Synonym", "");
AddSupportedType(DeclarationType.ScalarValuedFunction, GetScalarValuedFunctionScripts, "Function", "scalar-valued function");
AddSupportedType(DeclarationType.TableValuedFunction, GetTableValuedFunctionScripts, "Function", "table-valued function");
}
/// <summary>
/// Script a Table using SMO
/// </summary>
/// <param name="objectName">Table name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetTableScripts(string objectName, string schemaName)
{
try
{
Table smoObject = string.IsNullOrEmpty(schemaName) ? new Table(this.Database, objectName) : new Table(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a View using SMO
/// </summary>
/// <param name="objectName">View name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetViewScripts(string objectName, string schemaName)
{
try
{
View smoObject = string.IsNullOrEmpty(schemaName) ? new View(this.Database, objectName) : new View(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetViewScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a StoredProcedure using SMO
/// </summary>
/// <param name="objectName">StoredProcedure name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetStoredProcedureScripts(string objectName, string schemaName)
{
try
{
StoredProcedure smoObject = string.IsNullOrEmpty(schemaName) ? new StoredProcedure(this.Database, objectName) : new StoredProcedure(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetStoredProcedureScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a UserDefinedDataType using SMO
/// </summary>
/// <param name="objectName">UserDefinedDataType name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetUserDefinedDataTypeScripts(string objectName, string schemaName)
{
try
{
UserDefinedDataType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedDataType(this.Database, objectName) : new UserDefinedDataType(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedDataTypeScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a UserDefinedTableType using SMO
/// </summary>
/// <param name="objectName">UserDefinedTableType name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetUserDefinedTableTypeScripts(string objectName, string schemaName)
{
try
{
UserDefinedTableType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedTableType(this.Database, objectName) : new UserDefinedTableType(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedTableTypeScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a Synonym using SMO
/// </summary>
/// <param name="objectName">Synonym name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetSynonymScripts(string objectName, string schemaName)
{
try
{
Synonym smoObject = string.IsNullOrEmpty(schemaName) ? new Synonym(this.Database, objectName) : new Synonym(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetSynonymScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a ScalarValuedFunction using SMO
/// </summary>
/// <param name="objectName">ScalarValuedFunction name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetScalarValuedFunctionScripts(string objectName, string schemaName)
{
try
{
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetScalarValuedFunctionScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a TableValuedFunction using SMO
/// </summary>
/// <param name="objectName">TableValuedFunction name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetTableValuedFunctionScripts(string objectName, string schemaName)
{
try
{
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableValuedFunctionScripts : " + ex.Message);
return null;
}
}
}
}

View File

@@ -0,0 +1,144 @@
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
//
// 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.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
internal partial class PeekDefinition
{
<#
///
/// Generate Initialize method
///
var indent = " ";
var directory = Path.GetDirectoryName(Host.TemplateFile);
string xmlFile = Path.Combine(directory, "PeekDefinitionSupportedTypes.xml");
var supportedTypes = GetSupportedTypes(xmlFile);
if (supportedTypes != null && supportedTypes.Count > 0)
{
WriteLine("private void Initialize()");
PushIndent(indent);
PushIndent(indent);
WriteLine("{");
PushIndent(indent);
foreach(var typeProperty in supportedTypes)
{
string functionCall = string.Format("AddSupportedType(DeclarationType.{0}, Get{0}Scripts, \"{1}\", \"{2}\");", typeProperty["Name"], typeProperty["CreateSyntax"], typeProperty["QuickInfoType"]);
WriteLine(functionCall);
}
PopIndent();
WriteLine("}\n");
///
/// Generate scriptGetters for each type
///
foreach(var typeProperty in supportedTypes)
{
string statement;
// Write comments
WriteLine("/// <summary>");
WriteLine(string.Format("/// Script a {0} using SMO", typeProperty["Name"]));
WriteLine("/// </summary>");
WriteLine(string.Format("/// <param name=\"objectName\">{0} name</param>", typeProperty["Name"]));
WriteLine(string.Format("/// <param name=\"schemaName\">Schema name</param>"));
WriteLine("/// <returns>String collection of scripts</returns>");
WriteLine(string.Format("internal StringCollection Get{0}Scripts(string objectName, string schemaName)", typeProperty["Name"]));
WriteLine("{");
PushIndent(indent);
// Write try block to retrieve object and return script
WriteLine("try");
WriteLine("{");
if(typeProperty["SupportsSchemaQuery"].IndexOf("true", StringComparison.OrdinalIgnoreCase) >= 0)
{
statement = string.Format("{0} smoObject = string.IsNullOrEmpty(schemaName) ? new {0}(this.Database, objectName) : new {0}(this.Database, objectName, schemaName);", typeProperty["AccessClass"]);
}
else
{
statement = string.Format("{0} smoObject = new {0}(this.Database, objectName);", typeProperty["Name"]);
}
PushIndent(indent);
WriteLine(statement);
WriteLine("smoObject.Refresh();");
WriteLine("return smoObject.Script();");
PopIndent();
WriteLine("}");
// Write catch block to catch and log exceptions
WriteLine("catch (Exception ex)");
WriteLine("{");
PushIndent(indent);
statement = string.Format("LogLevel.Error,\"Exception at PeekDefinition Get{0}Scripts : \" + ex.Message", typeProperty["Name"]);
WriteLine("Logger.Write(" + statement + ");");
WriteLine("return null;");
PopIndent();
WriteLine("}");
PopIndent();
WriteLine("}\n");
}
}
PopIndent();
PopIndent();
#>
}
}
<#+
///
/// Get the supported types from the xml file
///
public static List<Dictionary<string, string>> GetSupportedTypes(string xmlFile)
{
List<Dictionary<string, string>> typeList = null;
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
XmlNodeList supportedTypes = doc.SelectNodes("/SupportedTypes/Type");
if (supportedTypes != null)
{
typeList = new List<Dictionary<string, string>>();
foreach (var type in supportedTypes)
{
XmlElement node = type as XmlElement;
if (node != null)
{
string typeName = (node["Name"] != null) ? node["Name"].InnerText : null;
string createSyntax = (node["CreateSyntax"] != null) ? node["CreateSyntax"].InnerText : null;
string accessClass = (node["AccessClass"] != null) ? node["AccessClass"].InnerText : null;
string supportsSchemaQuery = (node["SupportsSchemaQuery"] != null) ? node["SupportsSchemaQuery"].InnerText : null;
string quickInfoType = (node["QuickInfoType"] != null) ? node["QuickInfoType"].InnerText : null;
if (typeName != null && createSyntax != null && accessClass != null && supportsSchemaQuery!= null)
{
Dictionary<string, string> typeProperties = new Dictionary<string, string>();
typeProperties.Add("Name", typeName);
typeProperties.Add("CreateSyntax", createSyntax);
typeProperties.Add("AccessClass", accessClass);
typeProperties.Add("SupportsSchemaQuery", supportsSchemaQuery);
typeProperties.Add("QuickInfoType", quickInfoType);
typeList.Add(typeProperties);
}
}
}
}
return typeList;
}
#>

View File

@@ -0,0 +1,66 @@
<!--
For each supported type
Name - As denoted in the Microsoft.SqlServer.Management.SqlParser.Intellisense.DeclarationType Enumeration for the object
Create Syntax - The keyword used in the create t-sql statement for the object - e.g create TABLE, create PROCEDURE etc.
AccessClass - The SMO class denoting the object e.g. Table, UserDefinedTableType etc.
QuickInfoType - The type of the object as displayed in the Babel.CodeObjectQuickInfo.Text string (optional)
SupportsSchemaQuery - Boolean denoting if the object can be queried/accessed using the schema name
-->
<SupportedTypes>
<Type>
<Name>Table</Name>
<CreateSyntax>Table</CreateSyntax>
<AccessClass>Table</AccessClass>
<QuickInfoType>table</QuickInfoType>
<SupportsSchemaQuery>true</SupportsSchemaQuery>
</Type>
<Type>
<Name>View</Name>
<CreateSyntax>View</CreateSyntax>
<AccessClass>View</AccessClass>
<QuickInfoType>view</QuickInfoType>
<SupportsSchemaQuery>true</SupportsSchemaQuery>
</Type>
<Type>
<Name>StoredProcedure</Name>
<CreateSyntax>Procedure</CreateSyntax>
<AccessClass>StoredProcedure</AccessClass>
<QuickInfoType>stored procedure</QuickInfoType>
<SupportsSchemaQuery>true</SupportsSchemaQuery>
</Type>
<Type>
<Name>UserDefinedDataType</Name>
<CreateSyntax>Type</CreateSyntax>
<AccessClass>UserDefinedDataType</AccessClass>
<QuickInfoType>user-defined data type</QuickInfoType>
<SupportsSchemaQuery>true</SupportsSchemaQuery>
</Type>
<Type>
<Name>UserDefinedTableType</Name>
<CreateSyntax>Type</CreateSyntax>
<AccessClass>UserDefinedTableType</AccessClass>
<QuickInfoType>user-defined table type</QuickInfoType>
<SupportsSchemaQuery>true</SupportsSchemaQuery>
</Type>
<Type>
<Name>Synonym</Name>
<CreateSyntax>Synonym</CreateSyntax>
<AccessClass>Synonym</AccessClass>
<QuickInfoType></QuickInfoType>
<SupportsSchemaQuery>true</SupportsSchemaQuery>
</Type>
<Type>
<Name>ScalarValuedFunction</Name>
<CreateSyntax>Function</CreateSyntax>
<AccessClass>UserDefinedFunction</AccessClass>
<QuickInfoType>scalar-valued function</QuickInfoType>
<SupportsSchemaQuery>true</SupportsSchemaQuery>
</Type>
<Type>
<Name>TableValuedFunction</Name>
<CreateSyntax>Function</CreateSyntax>
<AccessClass>UserDefinedFunction</AccessClass>
<QuickInfoType>table-valued function</QuickInfoType>
<SupportsSchemaQuery>true</SupportsSchemaQuery>
</Type>
</SupportedTypes>

View File

@@ -4,29 +4,23 @@
// //
using System; using System;
using System.IO; using System.IO;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Microsoft.SqlServer.Management.Common; using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SqlParser.Binder; using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Parser;
using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.LanguageServices; using Microsoft.SqlTools.ServiceLayer.LanguageServices;
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts; using Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion;
using Microsoft.SqlTools.ServiceLayer.SqlContext; using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.Test.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.Workspace; using Microsoft.SqlTools.ServiceLayer.Workspace;
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
using Microsoft.SqlTools.Test.Utility; using Microsoft.SqlTools.Test.Utility;
using Moq; using Moq;
using Xunit; using Xunit;
using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location; using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
{ {
@@ -114,9 +108,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
{ {
Line = 0, Line = 0,
// test for 'dbo' // test for 'dbo'
Character = 16 Character = 15
} }
}; };
TestConnectionResult connectionResult = await TestObjects.InitLiveConnectionInfo(); TestConnectionResult connectionResult = await TestObjects.InitLiveConnectionInfo();
connectionResult.ScriptFile.Contents = "select * from dbo.func ()"; connectionResult.ScriptFile.Contents = "select * from dbo.func ()";
var languageService = new LanguageService(); var languageService = new LanguageService();
@@ -142,15 +137,20 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "from"; string objectName = "from";
Position position = new Position()
List<Declaration> declarations = new List<Declaration>(); {
DefinitionResult result = peekDefinition.GetScript(declarations, objectName, null); Line = 1,
Character = 14
};
ScriptParseInfo scriptParseInfo = new ScriptParseInfo() { IsConnected = true };
Mock<IBindingContext> bindingContextMock = new Mock<IBindingContext>();
DefinitionResult result = peekDefinition.GetScript(scriptParseInfo.ParseResult, position, bindingContextMock.Object.MetadataDisplayInfoProvider, objectName, null);
Assert.NotNull(result); Assert.NotNull(result);
Assert.True(result.IsErrorResult); Assert.True(result.IsErrorResult);
Assert.Equal(SR.PeekDefinitionNoResultsError, result.Message); Assert.Equal(SR.PeekDefinitionNoResultsError, result.Message);
} }
/// <summary> /// <summary>
/// Test GetDefinition with a forced timeout. Expect a error result. /// Test GetDefinition with a forced timeout. Expect a error result.
/// </summary> /// </summary>
@@ -164,9 +164,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
ManualResetEvent mre = new ManualResetEvent(true); // Do not block ManualResetEvent mre = new ManualResetEvent(true); // Do not block
Mock<QueueItem> itemMock = new Mock<QueueItem>(); Mock<QueueItem> itemMock = new Mock<QueueItem>();
itemMock.Setup(i => i.ItemProcessed).Returns(mre); itemMock.Setup(i => i.ItemProcessed).Returns(mre);
DefinitionResult timeoutResult = null; DefinitionResult timeoutResult = null;
queueMock.Setup(q => q.QueueBindingOperation( queueMock.Setup(q => q.QueueBindingOperation(
It.IsAny<string>(), It.IsAny<string>(),
It.IsAny<Func<IBindingContext, CancellationToken, object>>(), It.IsAny<Func<IBindingContext, CancellationToken, object>>(),
@@ -174,7 +174,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
It.IsAny<int?>(), It.IsAny<int?>(),
It.IsAny<int?>())) It.IsAny<int?>()))
.Callback<string, Func<IBindingContext, CancellationToken, object>, Func<IBindingContext, object>, int?, int?>( .Callback<string, Func<IBindingContext, CancellationToken, object>, Func<IBindingContext, object>, int?, int?>(
(key, bindOperation, timeoutOperation, blah, blah2) => (key, bindOperation, timeoutOperation, t1, t2) =>
{ {
timeoutResult = (DefinitionResult) timeoutOperation((IBindingContext)null); timeoutResult = (DefinitionResult) timeoutOperation((IBindingContext)null);
itemMock.Object.Result = timeoutResult; itemMock.Object.Result = timeoutResult;
@@ -306,6 +306,387 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
Cleanup(locations); Cleanup(locations);
} }
/// <summary>
/// Test get definition for a scalar valued function object with active connection and explicit schema name. Expect non-null locations
/// </summary>
[Fact]
public async Task GetScalarValuedFunctionDefinitionWithSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_addTwo";
string schemaName = "dbo";
string objectType = "FUNCTION";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetScalarValuedFunctionScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a table valued function object with active connection and explicit schema name. Expect non-null locations
/// </summary>
[Fact]
public async Task GetTableValuedFunctionDefinitionWithSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_returnTable";
string schemaName = "dbo";
string objectType = "FUNCTION";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableValuedFunctionScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a scalar valued function object that doesn't exist with active connection. Expect null locations
/// </summary>
[Fact]
public async Task GetScalarValuedFunctionDefinitionWithNonExistentFailureTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "doesNotExist";
string schemaName = "dbo";
string objectType = "FUNCTION";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetScalarValuedFunctionScripts, objectName, schemaName, objectType);
Assert.Null(locations);
}
/// <summary>
/// Test get definition for a table valued function object that doesn't exist with active connection. Expect null locations
/// </summary>
[Fact]
public async Task GetTableValuedFunctionDefinitionWithNonExistentObjectFailureTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "doesNotExist";
string schemaName = "dbo";
string objectType = "FUNCTION";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableValuedFunctionScripts, objectName, schemaName, objectType);
Assert.Null(locations);
}
/// <summary>
/// Test get definition for a scalar valued function object with active connection. Expect non-null locations
/// </summary>
[Fact]
public async Task GetScalarValuedFunctionDefinitionWithoutSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_addTwo";
string schemaName = null;
string objectType = "FUNCTION";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetScalarValuedFunctionScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a table valued function object with active connection. Expect non-null locations
/// </summary>
[Fact]
public async Task GetTableValuedFunctionDefinitionWithoutSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_returnTable";
string schemaName = null;
string objectType = "FUNCTION";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableValuedFunctionScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a user defined data type object with active connection and explicit schema name. Expect non-null locations
/// </summary>
[Fact]
public async Task GetUserDefinedDataTypeDefinitionWithSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_ssn";
string schemaName = "dbo";
string objectType = "Type";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedDataTypeScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a user defined data type object with active connection. Expect non-null locations
/// </summary>
[Fact]
public async Task GetUserDefinedDataTypeDefinitionWithoutSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_ssn";
string schemaName = null;
string objectType = "Type";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedDataTypeScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a user defined data type object that doesn't exist with active connection. Expect null locations
/// </summary>
[Fact]
public async Task GetUserDefinedDataTypeDefinitionWithNonExistentFailureTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "doesNotExist";
string schemaName = "dbo";
string objectType = "Type";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedDataTypeScripts, objectName, schemaName, objectType);
Assert.Null(locations);
}
/// <summary>
/// Test get definition for a user defined table type object with active connection and explicit schema name. Expect non-null locations
/// </summary>
[Fact]
public async Task GetUserDefinedTableTypeDefinitionWithSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_locationTableType";
string schemaName = "dbo";
string objectType = "Type";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedTableTypeScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a user defined table type object with active connection. Expect non-null locations
/// </summary>
[Fact]
public async Task GetUserDefinedTableTypeDefinitionWithoutSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_locationTableType";
string schemaName = null;
string objectType = "Type";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedTableTypeScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a user defined table type object that doesn't exist with active connection. Expect null locations
/// </summary>
[Fact]
public async Task GetUserDefinedTableTypeDefinitionWithNonExistentFailureTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "doesNotExist";
string schemaName = "dbo";
string objectType = "Type";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedTableTypeScripts, objectName, schemaName, objectType);
Assert.Null(locations);
}
/// <summary>
/// Test get definition for a synonym object with active connection and explicit schema name. Expect non-null locations
/// </summary>
[Fact]
public async Task GetSynonymDefinitionWithSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_testTable";
string schemaName = "dbo";
string objectType = "Synonym";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetSynonymScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a Synonym object with active connection. Expect non-null locations
/// </summary>
[Fact]
public async Task GetSynonymDefinitionWithoutSchemaNameSuccessTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "pd_testTable";
string schemaName = null;
string objectType = "Synonym";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetSynonymScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a Synonym object that doesn't exist with active connection. Expect null locations
/// </summary>
[Fact]
public async Task GetSynonymDefinitionWithNonExistentFailureTest()
{
// Get live connectionInfo and serverConnection
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "doesNotExist";
string schemaName = "dbo";
string objectType = "Synonym";
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetSynonymScripts, objectName, schemaName, objectType);
Assert.Null(locations);
}
/// <summary>
/// Test get definition using declaration type for a view object with active connection
/// Expect a non-null result with location
/// </summary>
[Fact]
public async Task GetDefinitionUsingDeclarationTypeWithValidObjectTest()
{
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "objects";
string schemaName = "sys";
DefinitionResult result = peekDefinition.GetDefinitionUsingDeclarationType(DeclarationType.View, "master.sys.objects", objectName, schemaName);
Assert.NotNull(result);
Assert.NotNull(result.Locations);
Assert.False(result.IsErrorResult);
Cleanup(result.Locations);
}
/// <summary>
/// Test get definition using declaration type for a non existent view object with active connection
/// Expect a non-null result with location
/// </summary>
[Fact]
public async Task GetDefinitionUsingDeclarationTypeWithNonexistentObjectTest()
{
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "doesNotExist";
string schemaName = "sys";
DefinitionResult result = peekDefinition.GetDefinitionUsingDeclarationType(DeclarationType.View, "master.sys.objects", objectName, schemaName);
Assert.NotNull(result);
Assert.True(result.IsErrorResult);
}
/// <summary>
/// Test get definition using quickInfo text for a view object with active connection
/// Expect a non-null result with location
/// </summary>
[Fact]
public async Task GetDefinitionUsingQuickInfoTextWithValidObjectTest()
{
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "objects";
string schemaName = "sys";
string quickInfoText = "view master.sys.objects";
DefinitionResult result = peekDefinition.GetDefinitionUsingQuickInfoText(quickInfoText, objectName, schemaName);
Assert.NotNull(result);
Assert.NotNull(result.Locations);
Assert.False(result.IsErrorResult);
Cleanup(result.Locations);
}
/// <summary>
/// Test get definition using quickInfo text for a view object with active connection
/// Expect a non-null result with location
/// </summary>
[Fact]
public async Task GetDefinitionUsingQuickInfoTextWithNonexistentObjectTest()
{
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
string objectName = "doesNotExist";
string schemaName = "sys";
string quickInfoText = "view master.sys.objects";
DefinitionResult result = peekDefinition.GetDefinitionUsingQuickInfoText(quickInfoText, objectName, schemaName);
Assert.NotNull(result);
Assert.True(result.IsErrorResult);
}
/// <summary> /// <summary>
/// Helper method to clean up script files /// Helper method to clean up script files
/// </summary> /// </summary>

View File

@@ -220,7 +220,155 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
FileUtils.SafeDirectoryDelete(FileUtils.PeekDefinitionTempFolder, true); FileUtils.SafeDirectoryDelete(FileUtils.PeekDefinitionTempFolder, true);
Assert.False(Directory.Exists(FileUtils.PeekDefinitionTempFolder)); Assert.False(Directory.Exists(FileUtils.PeekDefinitionTempFolder));
// Expected not to throw any exception // Expected not to throw any exception
languageService.DeletePeekDefinitionScripts(); languageService.DeletePeekDefinitionScripts();
}
/// <summary>
/// Test Extracting the full object name from quickInfoText.
/// Given a valid object name string and a vaild quickInfo string containing the object name
/// Expect the full object name (database.schema.objectName)
/// </summary>
[Fact]
public void GetFullObjectNameFromQuickInfoWithValidStringsTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null, null);
string objectName = "testTable";
string quickInfoText = "table master.dbo.testTable";
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
string expected = "master.dbo.testTable";
Assert.Equal(expected, result);
}
/// <summary>
/// Test Extracting the full object name from quickInfoText.
/// Given a null object name string and a vaild quickInfo string containing the object name( and vice versa)
/// Expect null
/// </summary>
[Fact]
public void GetFullObjectNameFromQuickInfoWithNullStringsTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null, null);
string expected = null;
string objectName = null;
string quickInfoText = "table master.dbo.testTable";
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
Assert.Equal(expected, result);
quickInfoText = null;
objectName = "tableName";
result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
Assert.Equal(expected, result);
quickInfoText = null;
objectName = null;
result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
Assert.Equal(expected, result);
}
/// <summary>
/// Test Extracting the full object name from quickInfoText.
/// Given a valid object name string and a vaild quickInfo string that does not contain the object name
/// Expect null
/// </summary>
[Fact]
public void GetFullObjectNameFromQuickInfoWithIncorrectObjectNameTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null, null);
string objectName = "test";
string quickInfoText = "table master.dbo.tableName";
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
string expected = null;
Assert.Equal(expected, result);
}
/// <summary>
/// Test Extracting the object type from quickInfoText.
/// Given a valid object name string and a vaild quickInfo string containing the object name
/// Expect correct object type
/// </summary>
[Fact]
public void GetTokenTypeFromQuickInfoWithValidStringsTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null, null);
string objectName = "tableName";
string quickInfoText = "table master.dbo.tableName";
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
string expected = "table";
Assert.Equal(expected, result);
}
/// <summary>
/// Test Extracting theobject type from quickInfoText.
/// Given a null object name string and a vaild quickInfo string containing the object name( and vice versa)
/// Expect null
/// </summary>
[Fact]
public void GetTokenTypeFromQuickInfoWithNullStringsTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null, null);
string expected = null;
string objectName = null;
string quickInfoText = "table master.dbo.testTable";
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
Assert.Equal(expected, result);
quickInfoText = null;
objectName = "tableName";
result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
Assert.Equal(expected, result);
quickInfoText = null;
objectName = null;
result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
Assert.Equal(expected, result);
}
/// <summary>
/// Test Extracting the object type from quickInfoText.
/// Given a valid object name string and a vaild quickInfo string that does not containthe object name
/// Expect null
/// </summary>
[Fact]
public void GetTokenTypeFromQuickInfoWithIncorrectObjectNameTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null, null);
string objectName = "test";
string quickInfoText = "table master.dbo.tableName";
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
string expected = null;
Assert.Equal(expected, result);
}
/// <summary>
/// test Getting definition using quickInfo text without a live connection
/// Expect an error result( because you cannot script without a live connection)
/// </summary>
[Fact]
public void GetDefinitionUsingQuickInfoWithoutConnectionTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null, null);
string objectName = "tableName";
string quickInfoText = "table master.dbo.tableName";
DefinitionResult result = peekDefinition.GetDefinitionUsingQuickInfoText(quickInfoText, objectName, null);
Assert.NotNull(result);
Assert.True(result.IsErrorResult);
}
/// <summary>
/// test Getting definition using declarration Type without a live connection
/// Expect an error result( because you cannot script without a live connection)
/// </summary>
[Fact]
public void GetDefinitionUsingDeclarationItemWithoutConnectionTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null, null);
string objectName = "tableName";
string fullObjectName = "master.dbo.tableName";
DefinitionResult result = peekDefinition.GetDefinitionUsingDeclarationType(DeclarationType.Table, fullObjectName, objectName, null);
Assert.NotNull(result);
Assert.True(result.IsErrorResult);
} }
} }
} }

View File

@@ -45,7 +45,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
}; };
await testService.RequestOpenDocumentNotification(openParams); await testService.RequestOpenDocumentNotification(openParams);
Thread.Sleep(500); Thread.Sleep(500);
bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath); bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath);
@@ -86,7 +86,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
}; };
await testService.RequestOpenDocumentNotification(openParams); await testService.RequestOpenDocumentNotification(openParams);
Thread.Sleep(500); Thread.Sleep(500);
bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath); bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath);
@@ -136,7 +136,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
}; };
await testService.RequestOpenDocumentNotification(openParams); await testService.RequestOpenDocumentNotification(openParams);
Thread.Sleep(100); Thread.Sleep(100);
var contentChanges = new TextDocumentChangeEvent[1]; var contentChanges = new TextDocumentChangeEvent[1];
@@ -172,7 +172,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
await testService.RequestChangeTextDocumentNotification(changeParams); await testService.RequestChangeTextDocumentNotification(changeParams);
Thread.Sleep(100); Thread.Sleep(100);
contentChanges[0] = new TextDocumentChangeEvent contentChanges[0] = new TextDocumentChangeEvent
{ {
Range = new Range Range = new Range
@@ -211,7 +211,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
} }
/// <summary> /// <summary>
/// Peek Definition/ Go to definition /// Peek Definition/ Go to definition
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Fact] [Fact]
@@ -238,16 +238,20 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
}; };
await testService.RequestOpenDocumentNotification(openParams); await testService.RequestOpenDocumentNotification(openParams);
Thread.Sleep(500); Thread.Sleep(500);
bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath); bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath);
// Wait for intellisense to be ready
var readyParams = await testService.Driver.WaitForEvent(IntelliSenseReadyNotification.Type, 30000);
Assert.NotNull(readyParams);
Assert.True(connected, "Connection is successful"); Assert.True(connected, "Connection is successful");
Thread.Sleep(10000);
// Request definition for "objects" // Request definition for "objects"
Location[] locations = await testService.RequestDefinition(queryTempFile.FilePath, query, lineNumber, position); Location[] locations = await testService.RequestDefinition(queryTempFile.FilePath, query, lineNumber, position);
Assert.True(locations != null, "Location is not null and not empty"); Assert.True(locations != null, "Location is not null and not empty");
await testService.Disconnect(queryTempFile.FilePath); await testService.Disconnect(queryTempFile.FilePath);
} }
@@ -265,7 +269,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath); bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath);
Assert.True(connected, "Connection was not successful"); Assert.True(connected, "Connection was not successful");
Thread.Sleep(500); Thread.Sleep(500);
var settings = new SqlToolsSettings(); var settings = new SqlToolsSettings();
settings.SqlTools.IntelliSense.EnableIntellisense = false; settings.SqlTools.IntelliSense.EnableIntellisense = false;
@@ -422,10 +426,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
public async Task VerifyFunctionSignatureHelpParameter( public async Task VerifyFunctionSignatureHelpParameter(
TestServiceDriverProvider TestService, TestServiceDriverProvider TestService,
string ownerUri, string ownerUri,
int character, int character,
string expectedFunctionName, string expectedFunctionName,
int expectedParameterIndex, int expectedParameterIndex,
string expectedParameterName) string expectedParameterName)
{ {
var position = new TextDocumentPosition() var position = new TextDocumentPosition()