mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-19 01:25:36 -05:00
Add query execution plan extensibility APIs (#4072)
* WIP 1 * WIP 2 * Fix typos * Iterate on API a bit * Query Tab WIP * More dynamic query tab impl * Fix merge breaks * Update interfaces * Update to single event handler for query events * Remove query plan extension * Add generated JS file
This commit is contained in:
@@ -16,7 +16,8 @@ import {
|
||||
EditSubsetResult,
|
||||
EditCreateRowResult,
|
||||
EditRevertCellResult,
|
||||
ExecutionPlanOptions
|
||||
ExecutionPlanOptions,
|
||||
queryeditor
|
||||
} from 'azdata';
|
||||
import { QueryInfo } from 'sql/platform/query/common/queryModelService';
|
||||
|
||||
@@ -24,6 +25,18 @@ export const SERVICE_ID = 'queryModelService';
|
||||
|
||||
export const IQueryModelService = createDecorator<IQueryModelService>(SERVICE_ID);
|
||||
|
||||
export interface IQueryPlanInfo {
|
||||
providerId: string;
|
||||
fileUri: string;
|
||||
planXml: string;
|
||||
}
|
||||
|
||||
export interface IQueryEvent {
|
||||
type: queryeditor.QueryEvent;
|
||||
uri: string;
|
||||
params?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for the logic of handling running queries and grid interactions for all URIs.
|
||||
*/
|
||||
@@ -56,7 +69,7 @@ export interface IQueryModelService {
|
||||
|
||||
onRunQueryStart: Event<string>;
|
||||
onRunQueryComplete: Event<string>;
|
||||
|
||||
onQueryEvent: Event<IQueryEvent>;
|
||||
|
||||
// Edit Data Functions
|
||||
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): void;
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as GridContentEvents from 'sql/parts/grid/common/gridContentEvents';
|
||||
import * as LocalizedConstants from 'sql/parts/query/common/localizedConstants';
|
||||
import QueryRunner, { EventType as QREvents } from 'sql/platform/query/common/queryRunner';
|
||||
import { DataService } from 'sql/parts/grid/services/dataService';
|
||||
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
|
||||
import { IQueryModelService, IQueryPlanInfo, IQueryEvent } from 'sql/platform/query/common/queryModel';
|
||||
import { QueryInput } from 'sql/parts/query/common/queryInput';
|
||||
import { QueryStatusbarItem } from 'sql/parts/query/execution/queryStatus';
|
||||
import { SqlFlavorStatusbarItem } from 'sql/parts/query/common/flavorStatus';
|
||||
@@ -68,11 +68,13 @@ export class QueryModelService implements IQueryModelService {
|
||||
private _queryInfoMap: Map<string, QueryInfo>;
|
||||
private _onRunQueryStart: Emitter<string>;
|
||||
private _onRunQueryComplete: Emitter<string>;
|
||||
private _onQueryEvent: Emitter<IQueryEvent>;
|
||||
private _onEditSessionReady: Emitter<azdata.EditSessionReadyParams>;
|
||||
|
||||
// EVENTS /////////////////////////////////////////////////////////////
|
||||
public get onRunQueryStart(): Event<string> { return this._onRunQueryStart.event; }
|
||||
public get onRunQueryComplete(): Event<string> { return this._onRunQueryComplete.event; }
|
||||
public get onQueryEvent(): Event<IQueryEvent> { return this._onQueryEvent.event; }
|
||||
public get onEditSessionReady(): Event<azdata.EditSessionReadyParams> { return this._onEditSessionReady.event; }
|
||||
|
||||
// CONSTRUCTOR /////////////////////////////////////////////////////////
|
||||
@@ -83,6 +85,7 @@ export class QueryModelService implements IQueryModelService {
|
||||
this._queryInfoMap = new Map<string, QueryInfo>();
|
||||
this._onRunQueryStart = new Emitter<string>();
|
||||
this._onRunQueryComplete = new Emitter<string>();
|
||||
this._onQueryEvent = new Emitter<IQueryEvent>();
|
||||
this._onEditSessionReady = new Emitter<azdata.EditSessionReadyParams>();
|
||||
|
||||
// Register Statusbar items
|
||||
@@ -308,13 +311,40 @@ export class QueryModelService implements IQueryModelService {
|
||||
});
|
||||
queryRunner.addListener(QREvents.COMPLETE, totalMilliseconds => {
|
||||
this._onRunQueryComplete.fire(uri);
|
||||
|
||||
// fire extensibility API event
|
||||
let event: IQueryEvent = {
|
||||
type: 'queryStop',
|
||||
uri: uri
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
|
||||
// fire UI event
|
||||
this._fireQueryEvent(uri, 'complete', totalMilliseconds);
|
||||
});
|
||||
queryRunner.addListener(QREvents.START, () => {
|
||||
this._onRunQueryStart.fire(uri);
|
||||
|
||||
// fire extensibility API event
|
||||
let event: IQueryEvent = {
|
||||
type: 'queryStart',
|
||||
uri: uri
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
|
||||
this._fireQueryEvent(uri, 'start');
|
||||
});
|
||||
|
||||
queryRunner.addListener(QREvents.QUERY_PLAN_AVAILABLE, (planInfo) => {
|
||||
// fire extensibility API event
|
||||
let event: IQueryEvent = {
|
||||
type: 'executionPlan',
|
||||
uri: planInfo.fileUri,
|
||||
params: planInfo
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
});
|
||||
|
||||
info.queryRunner = queryRunner;
|
||||
info.dataService = this._instantiationService.createInstance(DataService, uri);
|
||||
this._queryInfoMap.set(uri, info);
|
||||
@@ -422,10 +452,26 @@ export class QueryModelService implements IQueryModelService {
|
||||
});
|
||||
queryRunner.addListener(QREvents.COMPLETE, totalMilliseconds => {
|
||||
this._onRunQueryComplete.fire(ownerUri);
|
||||
// fire extensibility API event
|
||||
let event: IQueryEvent = {
|
||||
type: 'queryStop',
|
||||
uri: ownerUri
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
|
||||
// fire UI event
|
||||
this._fireQueryEvent(ownerUri, 'complete', totalMilliseconds);
|
||||
});
|
||||
queryRunner.addListener(QREvents.START, () => {
|
||||
this._onRunQueryStart.fire(ownerUri);
|
||||
// fire extensibility API event
|
||||
let event: IQueryEvent = {
|
||||
type: 'queryStart',
|
||||
uri: ownerUri
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
|
||||
// fire UI event
|
||||
this._fireQueryEvent(ownerUri, 'start');
|
||||
});
|
||||
queryRunner.addListener(QREvents.EDIT_SESSION_READY, e => {
|
||||
|
||||
@@ -25,6 +25,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ResultSerializer } from 'sql/platform/node/resultSerializer';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IQueryPlanInfo } from 'sql/platform/query/common/queryModel';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
@@ -41,7 +42,8 @@ export const enum EventType {
|
||||
BATCH_START = 'batchStart',
|
||||
BATCH_COMPLETE = 'batchComplete',
|
||||
RESULT_SET = 'resultSet',
|
||||
EDIT_SESSION_READY = 'editSessionReady'
|
||||
EDIT_SESSION_READY = 'editSessionReady',
|
||||
QUERY_PLAN_AVAILABLE = 'queryPlanAvailable'
|
||||
}
|
||||
|
||||
export interface IEventType {
|
||||
@@ -52,6 +54,7 @@ export interface IEventType {
|
||||
batchComplete: azdata.BatchSummary;
|
||||
resultSet: azdata.ResultSetSummary;
|
||||
editSessionReady: IEditSessionReadyEvent;
|
||||
queryPlanAvailable: IQueryPlanInfo;
|
||||
}
|
||||
|
||||
export interface IGridMessage extends azdata.IResultMessage {
|
||||
@@ -363,7 +366,11 @@ export default class QueryRunner extends Disposable {
|
||||
// check if this result has show plan, this needs work, it won't work for any other provider
|
||||
let hasShowPlan = !!result.resultSetSummary.columnInfo.find(e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
||||
if (hasShowPlan) {
|
||||
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => this._planXml.resolve(e.resultSubset.rows[0][0].displayValue));
|
||||
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => {
|
||||
if (e.resultSubset.rows) {
|
||||
this._planXml.resolve(e.resultSubset.rows[0][0].displayValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// we will just ignore the set if we already have it
|
||||
@@ -387,7 +394,20 @@ export default class QueryRunner extends Disposable {
|
||||
// check if this result has show plan, this needs work, it won't work for any other provider
|
||||
let hasShowPlan = !!result.resultSetSummary.columnInfo.find(e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
||||
if (hasShowPlan) {
|
||||
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => this._planXml.resolve(e.resultSubset.rows[0][0].displayValue));
|
||||
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => {
|
||||
if (e.resultSubset.rows) {
|
||||
let planXmlString = e.resultSubset.rows[0][0].displayValue;
|
||||
this._planXml.resolve(e.resultSubset.rows[0][0].displayValue);
|
||||
// fire query plan available event if execution is completed
|
||||
if (result.resultSetSummary.complete) {
|
||||
this._eventEmitter.emit(EventType.QUERY_PLAN_AVAILABLE, {
|
||||
providerId: 'MSSQL',
|
||||
fileUri: result.ownerUri,
|
||||
planXml: planXmlString
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (batchSet) {
|
||||
|
||||
Reference in New Issue
Block a user