mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
fix issue caused by execution plan provider (#21533)
This commit is contained in:
@@ -577,6 +577,7 @@
|
|||||||
"connectionProvider": {
|
"connectionProvider": {
|
||||||
"providerId": "MSSQL",
|
"providerId": "MSSQL",
|
||||||
"displayName": "%mssql.provider.displayName%",
|
"displayName": "%mssql.provider.displayName%",
|
||||||
|
"isExecutionPlanProvider": true,
|
||||||
"supportedExecutionPlanFileExtensions": [
|
"supportedExecutionPlanFileExtensions": [
|
||||||
"sqlplan"
|
"sqlplan"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ export interface ConnectionProviderProperties {
|
|||||||
azureResource?: string;
|
azureResource?: string;
|
||||||
connectionOptions: azdata.ConnectionOption[];
|
connectionOptions: azdata.ConnectionOption[];
|
||||||
isQueryProvider?: boolean;
|
isQueryProvider?: boolean;
|
||||||
|
isExecutionPlanProvider?: boolean;
|
||||||
supportedExecutionPlanFileExtensions?: string[];
|
supportedExecutionPlanFileExtensions?: string[];
|
||||||
connectionStringOptions?: ConnectionStringOptions;
|
connectionStringOptions?: ConnectionStringOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,21 +27,59 @@ export class ExecutionPlanService implements IExecutionPlanService {
|
|||||||
this._providerRegisterEvent = this._onProviderRegister.event;
|
this._providerRegisterEvent = this._onProviderRegister.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async ensureCapabilitiesRegistered(): Promise<void> {
|
||||||
|
let providers = Object.keys(this._capabilitiesService.providers);
|
||||||
|
if (!providers) {
|
||||||
|
await new Promise<void>(resolve => {
|
||||||
|
this._capabilitiesService.onCapabilitiesRegistered(e => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getExecutionPlanProvider(providerId: string): Promise<azdata.executionPlan.ExecutionPlanProvider> {
|
||||||
|
await this.ensureCapabilitiesRegistered();
|
||||||
|
const provider = this._capabilitiesService.providers[providerId];
|
||||||
|
// Return undefined if the provider is not registered or it is not a execution plan provider.
|
||||||
|
if (!provider || !provider.connection?.isExecutionPlanProvider) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let handler = this._providers[providerId];
|
||||||
|
if (handler) {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
// Ensure the extension is loaded
|
||||||
|
await this._extensionService.whenInstalledExtensionsRegistered();
|
||||||
|
handler = this._providers[providerId];
|
||||||
|
if (!handler) {
|
||||||
|
handler = await new Promise((resolve, reject) => {
|
||||||
|
this._providerRegisterEvent(e => {
|
||||||
|
if (e.id === providerId) {
|
||||||
|
resolve(e.provider);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
/**
|
||||||
|
* Handling a possible edge case where provider registered event
|
||||||
|
* might have been called before we await for it.
|
||||||
|
*/
|
||||||
|
resolve(this._providers[providerId]);
|
||||||
|
}, 30000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the actions using the provider that supports the fileFormat provided.
|
* Runs the actions using the provider that supports the fileFormat provided.
|
||||||
* @param fileFormat fileformat of the underlying execution plan file. It is used to get the provider that support it.
|
* @param fileFormat fileformat of the underlying execution plan file. It is used to get the provider that support it.
|
||||||
* @param action executionPlanService action to be performed.
|
* @param action executionPlanService action to be performed.
|
||||||
*/
|
*/
|
||||||
private async _runAction<T>(fileFormat: string, action: (handler: azdata.executionPlan.ExecutionPlanProvider) => Thenable<T>): Promise<T> {
|
private async _runAction<T>(fileFormat: string, action: (handler: azdata.executionPlan.ExecutionPlanProvider) => Thenable<T>): Promise<T> {
|
||||||
|
await this.ensureCapabilitiesRegistered();
|
||||||
let providers = Object.keys(this._capabilitiesService.providers);
|
let providers = Object.keys(this._capabilitiesService.providers);
|
||||||
if (!providers) {
|
|
||||||
providers = await new Promise(resolve => {
|
|
||||||
this._capabilitiesService.onCapabilitiesRegistered(e => {
|
|
||||||
resolve(Object.keys(this._capabilitiesService.providers));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let epProviders: string[] = [];
|
let epProviders: string[] = [];
|
||||||
for (let i = 0; i < providers.length; i++) {
|
for (let i = 0; i < providers.length; i++) {
|
||||||
const providerCapabilities = this._capabilitiesService.getCapabilities(providers[i]);
|
const providerCapabilities = this._capabilitiesService.getCapabilities(providers[i]);
|
||||||
@@ -81,70 +119,7 @@ export class ExecutionPlanService implements IExecutionPlanService {
|
|||||||
if (!selectedProvider) {
|
if (!selectedProvider) {
|
||||||
return Promise.reject(new Error(localize('providerIdNotValidError', "Valid provider is required in order to interact with ExecutionPlanService")));
|
return Promise.reject(new Error(localize('providerIdNotValidError', "Valid provider is required in order to interact with ExecutionPlanService")));
|
||||||
}
|
}
|
||||||
await this._extensionService.whenInstalledExtensionsRegistered();
|
const handler = await this.getExecutionPlanProvider(selectedProvider);
|
||||||
let handler = this._providers[selectedProvider];
|
|
||||||
if (!handler) {
|
|
||||||
handler = await new Promise((resolve, reject) => {
|
|
||||||
this._providerRegisterEvent(e => {
|
|
||||||
if (e.id === selectedProvider) {
|
|
||||||
resolve(e.provider);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
/**
|
|
||||||
* Handling a possible edge case where provider registered event
|
|
||||||
* might have been called before we await for it.
|
|
||||||
*/
|
|
||||||
resolve(this._providers[selectedProvider]);
|
|
||||||
}, 30000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (handler) {
|
|
||||||
return Promise.resolve(action(handler));
|
|
||||||
} else {
|
|
||||||
return Promise.reject(new Error(localize('noHandlerRegistered', "No valid execution plan handler is registered")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs the action using the specified provider.
|
|
||||||
* @param providerId The provider ID that will be used to run an action.
|
|
||||||
* @param action executionPlanService action to be performed.
|
|
||||||
*/
|
|
||||||
private async _runActionForProvider<T>(providerId: string, action: (handler: azdata.executionPlan.ExecutionPlanProvider) => Thenable<T>): Promise<T> {
|
|
||||||
let providers = Object.keys(this._capabilitiesService.providers);
|
|
||||||
if (!providers) {
|
|
||||||
providers = await new Promise(resolve => {
|
|
||||||
this._capabilitiesService.onCapabilitiesRegistered(e => {
|
|
||||||
resolve(Object.keys(this._capabilitiesService.providers));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedProvider: string | undefined = providers.find(p => p === providerId);
|
|
||||||
if (!selectedProvider) {
|
|
||||||
return Promise.reject(new Error(localize('providerIdNotValidError', "Valid provider is required in order to interact with ExecutionPlanService")));
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._extensionService.whenInstalledExtensionsRegistered();
|
|
||||||
let handler = this._providers[selectedProvider];
|
|
||||||
if (!handler) {
|
|
||||||
handler = await new Promise((resolve, reject) => {
|
|
||||||
this._providerRegisterEvent(e => {
|
|
||||||
if (e.id === selectedProvider) {
|
|
||||||
resolve(e.provider);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
/**
|
|
||||||
* Handling a possible edge case where provider registered event
|
|
||||||
* might have been called before we await for it.
|
|
||||||
*/
|
|
||||||
resolve(this._providers[selectedProvider]);
|
|
||||||
}, 30000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
return Promise.resolve(action(handler));
|
return Promise.resolve(action(handler));
|
||||||
} else {
|
} else {
|
||||||
@@ -175,10 +150,17 @@ export class ExecutionPlanService implements IExecutionPlanService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isExecutionPlan(providerId: string, value: string): Promise<azdata.executionPlan.IsExecutionPlanResult> {
|
async isExecutionPlan(providerId: string, value: string): Promise<azdata.executionPlan.IsExecutionPlanResult> {
|
||||||
return this._runActionForProvider(providerId, (runner) => {
|
const handler = await this.getExecutionPlanProvider(providerId);
|
||||||
return runner.isExecutionPlan(value);
|
if (handler) {
|
||||||
});
|
return await handler.isExecutionPlan(value);
|
||||||
|
} else {
|
||||||
|
// If the provider is not an execution plan provider, then return false.
|
||||||
|
return {
|
||||||
|
isExecutionPlan: false,
|
||||||
|
queryExecutionPlanFileExtension: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSupportedExecutionPlanExtensionsForProvider(providerId: string): string[] | undefined {
|
getSupportedExecutionPlanExtensionsForProvider(providerId: string): string[] | undefined {
|
||||||
|
|||||||
Reference in New Issue
Block a user