Query Management log message update (#23395)

This commit is contained in:
Alan Ren
2023-06-15 21:01:15 -07:00
committed by GitHub
parent ebf9c251a9
commit 7a7a38dd24
14 changed files with 67 additions and 129 deletions

View File

@@ -144,7 +144,7 @@ export class MainThreadQueryEditor extends Disposable implements MainThreadQuery
}
public async $createQueryDocument(options?: { content?: string }, providerId?: string): Promise<URI> {
const queryInput = await this._queryEditorService.newSqlEditor({ initalContent: options.content }, providerId);
const queryInput = await this._queryEditorService.newSqlEditor({ initialContent: options.content }, providerId);
return queryInput.resource;
}
}

View File

@@ -48,7 +48,7 @@ export async function scriptSelect(connectionProfile: IConnectionProfile, metada
let paramDetails = getScriptingParamDetails(connectionService, connectionResult, metadata)!;
const result = await scriptingService.script(connectionResult, metadata, ScriptOperation.Select, paramDetails);
if (result && result.script) {
const owner = await queryEditorService.newSqlEditor({ initalContent: result.script }, connectionProfile?.providerName, connectionResult);
const owner = await queryEditorService.newSqlEditor({ initialContent: result.script }, connectionProfile?.providerName, connectionResult);
// Connect our editor to the input connection
let options: IConnectionCompletionOptions = {
params: { connectionType: ConnectionType.editor, runQueryOnCompletion: RunQueryOnConnectionMode.executeQuery, input: owner },
@@ -133,7 +133,7 @@ export async function script(connectionProfile: IConnectionProfile, metadata: az
if (script) {
let description = (metadata.schema && metadata.schema !== '') ? `${metadata.schema}.${metadata.name}` : metadata.name;
const owner = await queryEditorService.newSqlEditor({ initalContent: script, description }, connectionProfile.providerName, connectionResult);
const owner = await queryEditorService.newSqlEditor({ initialContent: script, description }, connectionProfile.providerName, connectionResult);
// Connect our editor to the input connection
let options: IConnectionCompletionOptions = {
params: { connectionType: ConnectionType.editor, runQueryOnCompletion: RunQueryOnConnectionMode.none, input: owner },

View File

@@ -170,7 +170,7 @@ export class CopyQueryWithResultsKeyboardAction extends Action {
copyString = `${copyString}${value}\t`;
htmlCopyString = `${htmlCopyString}<td style="border:1.0pt solid black;padding:3pt;font-size:9pt;">${escape(value)}</td>`;
}
// Removes the tab seperator from the end of a row
// Removes the tab separator from the end of a row
copyString = copyString.slice(0, -1 * '\t'.length) + '\n';
htmlCopyString = htmlCopyString + '</tr>';
}
@@ -538,7 +538,7 @@ export class ParseSyntaxAction extends Action {
public override async run(): Promise<void> {
const editor = this.editorService.activeEditorPane;
if (editor instanceof QueryEditor) {
if (!editor.isSelectionEmpty()) {
if (!editor.isEditorEmpty()) {
if (this.isConnected(editor)) {
let text = editor.getSelectionText();
if (text === '') {

View File

@@ -22,8 +22,7 @@ import {
INewConnectionParams,
ConnectionType,
RunQueryOnConnectionMode,
IConnectionCompletionOptions,
IConnectableInput
IConnectionCompletionOptions
} from 'sql/platform/connection/common/connectionManagement';
import { QueryEditor } from 'sql/workbench/contrib/query/browser/queryEditor';
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
@@ -113,7 +112,7 @@ export abstract class QueryTaskbarAction extends Action {
}
}
export function openNewQuery(accessor: ServicesAccessor, profile?: IConnectionProfile, initalContent?: string, onConnection?: RunQueryOnConnectionMode): Promise<void> {
export async function openNewQuery(accessor: ServicesAccessor, profile?: IConnectionProfile, initialContent?: string, onConnection?: RunQueryOnConnectionMode): Promise<void> {
const editorService = accessor.get(IEditorService);
const queryEditorService = accessor.get(IQueryEditorService);
const objectExplorerService = accessor.get(IObjectExplorerService);
@@ -121,20 +120,18 @@ export function openNewQuery(accessor: ServicesAccessor, profile?: IConnectionPr
if (!profile) {
profile = getCurrentGlobalConnection(objectExplorerService, connectionManagementService, editorService);
}
return queryEditorService.newSqlEditor({ initalContent }, profile?.providerName).then((owner: IConnectableInput) => {
// Connect our editor to the input connection
let options: IConnectionCompletionOptions = {
params: { connectionType: ConnectionType.editor, runQueryOnCompletion: onConnection, input: owner },
saveTheConnection: false,
showDashboard: false,
showConnectionDialogOnError: true,
showFirewallRuleOnError: true
};
if (profile) {
return connectionManagementService.connect(profile, owner.uri, options).then();
}
return undefined;
});
const editorInput = await queryEditorService.newSqlEditor({ initialContent: initialContent }, profile?.providerName);
// Connect our editor to the input connection
let options: IConnectionCompletionOptions = {
params: { connectionType: ConnectionType.editor, runQueryOnCompletion: onConnection, input: editorInput },
saveTheConnection: false,
showDashboard: false,
showConnectionDialogOnError: true,
showFirewallRuleOnError: true
};
if (profile) {
await connectionManagementService.connect(profile, editorInput.uri, options);
}
}
// --- actions
@@ -210,63 +207,47 @@ export class RunQueryAction extends QueryTaskbarAction {
}
public override async run(): Promise<void> {
if (!this.editor.isSelectionEmpty()) {
const runQueryResult = await this.runQuery(this.editor);
if (!runQueryResult) {
// If we are not already connected, prompt for connection and run the query if the
// connection succeeds. "runQueryOnCompletion=true" will cause the query to run after connection
this.connectEditor(this.editor, RunQueryOnConnectionMode.executeQuery, this.editor.getSelection());
}
}
return;
await this.runQuery();
}
public async runCurrent(): Promise<void> {
if (!this.editor.isSelectionEmpty()) {
const runQueryResult = await this.runQuery(this.editor, true);
if (!runQueryResult) {
// If we are not already connected, prompt for connection and run the query if the
// connection succeeds. "runQueryOnCompletion=true" will cause the query to run after connection
this.connectEditor(this.editor, RunQueryOnConnectionMode.executeCurrentQuery, this.editor.getSelection(false));
}
}
return;
await this.runQuery(true);
}
private async runQuery(editor: QueryEditor, runCurrentStatement: boolean = false): Promise<boolean> {
if (!editor) {
editor = this.editor;
private async runQuery(runCurrentStatement: boolean = false): Promise<void> {
if (this.editor.isEditorEmpty()) {
return;
}
if (this.isConnected(editor)) {
if (this.isConnected(this.editor)) {
// Hide IntelliSense suggestions list when running query to match SSMS behavior
this.commandService?.executeCommand('hideSuggestWidget');
// Do not execute when there are multiple selections in the editor until it can be properly handled.
// Otherwise only the first selection will be executed and cause unexpected issues.
if (editor.getSelections()?.length > 1) {
if (this.editor.getSelections()?.length > 1) {
this.notificationService.error(nls.localize('query.multiSelectionNotSupported', "Running query is not supported when the editor is in multiple selection mode."));
return true;
}
// if the selection isn't empty then execute the selection
// otherwise, either run the statement or the script depending on parameter
let selection = editor.getSelection(false);
let selection = this.editor.getSelection(false);
if (runCurrentStatement && selection && this.isCursorPosition(selection)) {
editor.input.runQueryStatement(selection);
this.editor.input.runQueryStatement(selection);
} else {
if (editor.input.state.isActualExecutionPlanMode) {
selection = editor.getSelection();
editor.input.runQuery(selection, { displayActualQueryPlan: true });
if (this.editor.input.state.isActualExecutionPlanMode) {
selection = this.editor.getSelection();
this.editor.input.runQuery(selection, { displayActualQueryPlan: true });
}
else {
// get the selection again this time with trimming
selection = editor.getSelection();
editor.input.runQuery(selection);
selection = this.editor.getSelection();
this.editor.input.runQuery(selection);
}
}
return true;
} else {
// If we are not already connected, prompt for connection and run the query if the
// connection succeeds. "runQueryOnCompletion=true" will cause the query to run after connection
this.connectEditor(this.editor, runCurrentStatement ? RunQueryOnConnectionMode.executeCurrentQuery : RunQueryOnConnectionMode.executeQuery, this.editor.getSelection(!runCurrentStatement));
}
return false;
}
protected isCursorPosition(selection: IRange) {
@@ -322,7 +303,7 @@ export class EstimatedQueryPlanAction extends QueryTaskbarAction {
}
public override async run(): Promise<void> {
if (!this.editor.isSelectionEmpty()) {
if (!this.editor.isEditorEmpty()) {
if (this.isConnected(this.editor)) {
// If we are already connected, run the query
this.runQuery(this.editor);
@@ -412,7 +393,7 @@ export class ActualQueryPlanAction extends QueryTaskbarAction {
}
public override async run(): Promise<void> {
if (!this.editor.isSelectionEmpty()) {
if (!this.editor.isEditorEmpty()) {
if (this.isConnected(this.editor)) {
// If we are already connected, run the query
this.runQuery(this.editor);
@@ -460,7 +441,7 @@ export class DisconnectDatabaseAction extends QueryTaskbarAction {
public override async run(): Promise<void> {
// Call disconnectEditor regardless of the connection state and let the ConnectionManagementService
// determine if we need to disconnect, cancel an in-progress conneciton, or do nothing
// determine if we need to disconnect, cancel an in-progress connection, or do nothing
this.connectionManagementService.disconnectEditor(this.editor.input);
return;
}
@@ -626,13 +607,13 @@ export class ToggleSqlCmdModeAction extends QueryTaskbarAction {
this.editor.input.state.isSqlCmdMode = toSqlCmdState;
// set query options
let queryoptions: QueryExecutionOptions = { options: {} };
queryoptions.options['isSqlCmdMode'] = toSqlCmdState;
let queryOptions: QueryExecutionOptions = { options: {} };
queryOptions.options['isSqlCmdMode'] = toSqlCmdState;
if (!this.editor.input) {
this.logService.error('editor input was null');
return;
}
this.queryManagementService.setQueryExecutionOptions(this.editor.input.uri, queryoptions);
this.queryManagementService.setQueryExecutionOptions(this.editor.input.uri, queryOptions);
// set intellisense options
toSqlCmdState ? this.connectionManagementService.doChangeLanguageFlavor(this.editor.input.uri, 'sqlcmd', 'MSSQL') : this.connectionManagementService.doChangeLanguageFlavor(this.editor.input.uri, 'sql', 'MSSQL');

View File

@@ -563,7 +563,10 @@ export class QueryEditor extends EditorPane {
// helper functions
public isSelectionEmpty(): boolean {
/**
* Returns a boolean value indicating whether the editor is empty.
*/
public isEditorEmpty(): boolean {
if (this.currentTextEditor && this.currentTextEditor.getControl()) {
let control = this.currentTextEditor.getControl();
let codeEditor: ICodeEditor = <ICodeEditor>control;

View File

@@ -53,7 +53,7 @@ export class QueryEditorLanguageAssociation implements ILanguageAssociation {
const content = (await activeEditor.resolve()).textEditorModel.getValue();
queryEditorInput = await this.queryEditorService.newSqlEditor({
resource: this.editorService.isOpened(activeEditor) ? activeEditor.resource : undefined,
open: false, initalContent: content
open: false, initialContent: content
}) as UntitledQueryEditorInput;
}
@@ -115,7 +115,7 @@ export class FileQueryEditorSerializer implements IEditorSerializer {
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileQueryEditorInput | undefined {
const factory = editorFactoryRegistry.getEditorSerializer(FILE_EDITOR_INPUT_ID);
const fileEditorInput = factory.deserialize(instantiationService, serializedEditorInput) as FileEditorInput;
// only successfully deserilize the file if the resource actually exists
// only successfully deserialize the file if the resource actually exists
if (this.fileService.exists(fileEditorInput.resource)) {
const queryResultsInput = instantiationService.createInstance(QueryResultsInput, fileEditorInput.resource.toString());
return instantiationService.createInstance(FileQueryEditorInput, '', fileEditorInput, queryResultsInput);

View File

@@ -8,8 +8,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import {
IConnectionParams,
INewConnectionParams,
ConnectionType,
RunQueryOnConnectionMode
ConnectionType
} from 'sql/platform/connection/common/connectionManagement';
import {
RunQueryAction, CancelQueryAction, ListDatabasesActionItem,
@@ -61,7 +60,7 @@ suite('SQL QueryAction Tests', () => {
editor.setup(x => x.getSelection()).returns(() => undefined);
editor.setup(x => x.getSelection(false)).returns(() => undefined);
editor.setup(x => x.isSelectionEmpty()).returns(() => false);
editor.setup(x => x.isEditorEmpty()).returns(() => false);
editor.setup(x => x.getSelections()).returns(() => [undefined]);
configurationService = TypeMoq.Mock.ofInstance({
getValue: () => undefined,
@@ -130,53 +129,6 @@ suite('SQL QueryAction Tests', () => {
assert(connected, 'Connected editor should get back a non-undefined URI');
});
test('RunQueryAction calls runQuery() only if URI is connected', async () => {
// ... Create assert variables
let isConnected: boolean = undefined;
let connectionParams: INewConnectionParams = undefined;
let countCalledShowDialog: number = 0;
// ... Mock "isConnected" in ConnectionManagementService
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
connectionManagementService.setup(x => x.showConnectionDialog(TypeMoq.It.isAny()))
.callback((params: INewConnectionParams) => {
connectionParams = params;
countCalledShowDialog++;
})
.returns(() => Promise.resolve());
// ... Mock QueryModelService
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
queryModelService.setup(x => x.runQuery(TypeMoq.It.isAny(), undefined, TypeMoq.It.isAny()));
// If I call run on RunQueryAction when I am not connected
let queryAction: RunQueryAction = new RunQueryAction(editor.object, queryModelService.object, connectionManagementService.object, undefined);
isConnected = false;
calledRunQueryOnInput = false;
await queryAction.run();
// runQuery should not be run
assert.strictEqual(calledRunQueryOnInput, false, 'run should not call runQuery');
testQueryInput.verify(x => x.runQuery(undefined), TypeMoq.Times.never());
// and the connection dialog should open with the correct parameter details
assert.strictEqual(connectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
assert.strictEqual(connectionParams.runQueryOnCompletion, RunQueryOnConnectionMode.executeQuery, 'runQueryOnCompletion should be true`');
assert.strictEqual(connectionParams.input.uri, testUri, 'URI should be set to the test URI');
assert.strictEqual(connectionParams.input, editor.object.input, 'Editor should be set to the mock editor');
// If I call run on RunQueryAction when I am connected
isConnected = true;
await queryAction.run();
//runQuery should be run, and the conneciton dialog should not open
assert.strictEqual(calledRunQueryOnInput, true, 'run should call runQuery');
testQueryInput.verify(x => x.runQuery(undefined), TypeMoq.Times.once());
assert.strictEqual(countCalledShowDialog, 1, 'run should not call showDialog');
});
test('Queries are only run if the QueryEditor selection is not empty', async () => {
// ... Create assert variables
let isSelectionEmpty: boolean = undefined;
@@ -212,7 +164,7 @@ suite('SQL QueryAction Tests', () => {
queryEditor.setup(x => x.input).returns(() => queryInput.object);
queryEditor.setup(x => x.getSelection()).returns(() => undefined);
queryEditor.setup(x => x.getSelection(false)).returns(() => undefined);
queryEditor.setup(x => x.isSelectionEmpty()).returns(() => isSelectionEmpty);
queryEditor.setup(x => x.isEditorEmpty()).returns(() => isSelectionEmpty);
queryEditor.setup(x => x.getSelections()).returns(() => [undefined]);
// If I call run on RunQueryAction when I have a non empty selection
@@ -270,7 +222,7 @@ suite('SQL QueryAction Tests', () => {
let queryEditor = TypeMoq.Mock.ofType(QueryEditor, TypeMoq.MockBehavior.Strict, undefined, new TestThemeService(),
new TestStorageService(), contextkeyservice, undefined, new TestFileService(), undefined, undefined, undefined, undefined, undefined, new TestTextResourceConfigurationService());
queryEditor.setup(x => x.input).returns(() => queryInput.object);
queryEditor.setup(x => x.isSelectionEmpty()).returns(() => false);
queryEditor.setup(x => x.isEditorEmpty()).returns(() => false);
queryEditor.setup(x => x.getSelection()).returns(() => {
return selectionToReturnInGetSelection;
});
@@ -646,7 +598,7 @@ suite('SQL QueryAction Tests', () => {
await queryAction.runCurrent();
// Selection is empty
queryEditor.setup(x => x.isSelectionEmpty()).returns(() => true);
queryEditor.setup(x => x.isEditorEmpty()).returns(() => true);
//connection dialog should not open and runQueryStatement should not be called
assert.strictEqual(calledRunQueryStatementOnInput, false, 'runCurrent should not call runQueryStatemet');

View File

@@ -194,7 +194,7 @@ suite('Query Input Factory', () => {
const response = queryEditorLanguageAssociation.convertInput(input);
assert(isThenable(response));
await response;
assert(newsqlEditorStub.calledWithExactly({ resource: undefined, open: false, initalContent: '' }));
assert(newsqlEditorStub.calledWithExactly({ resource: undefined, open: false, initialContent: '' }));
assert(connectionManagementService.numberConnects === 1, 'Async convert input should have called connect only once for one URI');
});
@@ -325,7 +325,7 @@ suite('Query Input Factory', () => {
const response = queryEditorLanguageAssociation.convertInput(input);
assert(isThenable(response));
await response;
assert(newsqlEditorStub.calledWithExactly({ resource: input.resource, open: false, initalContent: '' }));
assert(newsqlEditorStub.calledWithExactly({ resource: input.resource, open: false, initialContent: '' }));
});
});

View File

@@ -59,7 +59,7 @@ export class ScriptAction extends Action {
public override async run(element: TaskNode): Promise<void> {
if (element instanceof TaskNode) {
if (element.script) {
await this._queryEditorService.newSqlEditor({ initalContent: element.script });
await this._queryEditorService.newSqlEditor({ initialContent: element.script });
}
}
}

View File

@@ -124,7 +124,7 @@ export class QueryManagementService implements IQueryManagementService {
constructor(
@IConnectionManagementService private _connectionService: IConnectionManagementService,
@IAdsTelemetryService private _telemetryService: IAdsTelemetryService,
@ILogService private _logService: ILogService,
@ILogService private _logService: ILogService
) {
}
@@ -278,9 +278,10 @@ export class QueryManagementService implements IQueryManagementService {
const result = [];
let start = rowData.rowsStartIndex;
this._logService.trace(`Getting ${rowData.rowsCount} rows starting from index: ${rowData.rowsStartIndex}.`);
let pageIdx = 1;
do {
const rowCount = Math.min(pageSize, rowData.rowsStartIndex + rowData.rowsCount - start);
this._logService.trace(`Paged Fetch - Getting ${rowCount} rows starting from index: ${start}.`);
this._logService.trace(`Page ${pageIdx} - Getting ${rowCount} rows starting from index: ${start}.`);
const rowSet = await runner.getQueryRows({
ownerUri: rowData.ownerUri,
batchIndex: rowData.batchIndex,
@@ -288,9 +289,10 @@ export class QueryManagementService implements IQueryManagementService {
rowsCount: rowCount,
rowsStartIndex: start
});
this._logService.trace(`Paged Fetch - Received ${rowSet.resultSubset.rows} rows starting from index: ${start}.`);
this._logService.trace(`Page ${pageIdx} - Received ${rowSet.resultSubset.rows.length} rows starting from index: ${start}.`);
result.push(...rowSet.resultSubset.rows);
start += rowCount;
pageIdx++;
if (onProgressCallback) {
onProgressCallback(start - rowData.rowsStartIndex);
}

View File

@@ -60,8 +60,8 @@ export class QueryEditorService implements IQueryEditorService {
const mode = this._connectionManagementService.getProviderLanguageMode(connectionProviderName);
const fileInput = await this._editorService.createEditorInput({ forceUntitled: true, resource: docUri, languageId: mode }) as UntitledTextEditorInput;
let untitledEditorModel = await fileInput.resolve();
if (options.initalContent) {
untitledEditorModel.textEditorModel.setValue(options.initalContent);
if (options.initialContent) {
untitledEditorModel.textEditorModel.setValue(options.initialContent);
if (options.dirty === false || (options.dirty === undefined && !this._configurationService.getValue<IQueryEditorConfiguration>('queryEditor').promptToSaveGeneratedFiles)) {
(untitledEditorModel as UntitledTextEditorModel).setDirty(false);
}

View File

@@ -19,7 +19,7 @@ export interface IQueryEditorOptions extends IEditorOptions {
export const IQueryEditorService = createDecorator<IQueryEditorService>('QueryEditorService');
export interface INewSqlEditorOptions {
initalContent?: string;
initialContent?: string;
/**
* Defaults based on user configuration
*/

View File

@@ -119,7 +119,7 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
try {
this.updateState(this.valid, this.dirty, 'generateScript');
const script = await this._provider.generateScript(this.tableInfo);
this._queryEditorService.newSqlEditor({ initalContent: script });
this._queryEditorService.newSqlEditor({ initialContent: script });
this.updateState(this.valid, this.dirty);
notificationHandle.updateMessage(localize('tableDesigner.generatingScriptCompleted', "Script generated."));
generateScriptEvent.withAdditionalMeasurements({

View File

@@ -213,7 +213,7 @@ export class TaskService implements ITaskService {
if ((task.status === TaskStatus.Succeeded || task.status === TaskStatus.SucceededWithWarning)
&& eventArgs.script && eventArgs.script !== '') {
if (task.taskExecutionMode === TaskExecutionMode.script) {
this.queryEditorService.newSqlEditor({ initalContent: eventArgs.script });
this.queryEditorService.newSqlEditor({ initialContent: eventArgs.script });
} else if (task.taskExecutionMode === TaskExecutionMode.executeAndScript) {
task.script = eventArgs.script;
}