From 53a038885898ff464a228a618f6d566ced41213f Mon Sep 17 00:00:00 2001 From: Aasim Khan Date: Mon, 11 Jul 2022 19:14:47 -0700 Subject: [PATCH] Deleting old query plan code (#19996) --- .../contrib/queryPlan/browser/media/qp.css | 224 ------------- .../queryPlan/browser/media/qp_icons.png | Bin 63962 -> 0 bytes .../queryPlan/browser/planXmlParser.ts | 300 ------------------ .../browser/queryPlan.contribution.ts | 56 ---- .../contrib/queryPlan/browser/queryPlan.ts | 112 ------- .../queryPlan/browser/queryPlanEditor.ts | 73 ----- .../queryPlan/browser/topOperations.ts | 128 -------- .../queryPlan/common/queryPlanInput.ts | 56 ---- src/vs/workbench/workbench.common.main.ts | 3 - 9 files changed, 952 deletions(-) delete mode 100644 src/sql/workbench/contrib/queryPlan/browser/media/qp.css delete mode 100644 src/sql/workbench/contrib/queryPlan/browser/media/qp_icons.png delete mode 100644 src/sql/workbench/contrib/queryPlan/browser/planXmlParser.ts delete mode 100644 src/sql/workbench/contrib/queryPlan/browser/queryPlan.contribution.ts delete mode 100755 src/sql/workbench/contrib/queryPlan/browser/queryPlan.ts delete mode 100644 src/sql/workbench/contrib/queryPlan/browser/queryPlanEditor.ts delete mode 100644 src/sql/workbench/contrib/queryPlan/browser/topOperations.ts delete mode 100644 src/sql/workbench/contrib/queryPlan/common/queryPlanInput.ts diff --git a/src/sql/workbench/contrib/queryPlan/browser/media/qp.css b/src/sql/workbench/contrib/queryPlan/browser/media/qp.css deleted file mode 100644 index a92b99af25..0000000000 --- a/src/sql/workbench/contrib/queryPlan/browser/media/qp.css +++ /dev/null @@ -1,224 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -div.qp-node { - margin: 2px; - padding: 2px; - border: 1px solid; -} - -div.qp-statement-header { - margin: 2px; - padding: 2px; - font-size: 12px; - line-height: normal; -} - -div.qp-node, -div.qp-tt { - font-size: 11px; - line-height: normal; -} - -.qp-node>div { - font-family: Monospace; - text-align: center; -} - -div[class|='qp-icon'] { - height: 32px; - width: 32px; - margin-left: auto; - margin-right: auto; - background-repeat: no-repeat; -} - -.qp-tt { - top: 4em; - left: 2em; - border: 1px solid; - padding: 2px; - width: 30em; -} - -.qp-tt div, -.qp-tt table { - font-family: Sans-Serif; - text-align: left; -} - -.qp-tt table { - border-width: 0px; - border-spacing: 0px; - margin-top: 10px; - margin-bottom: 10px; - width: 100%; -} - -.qp-tt td, -.qp-tt th { - font-size: 11px; - border-bottom: solid 1px; - padding: 1px; -} - -.qp-tt td { - text-align: right; - padding-left: 10px; -} - -.qp-tt th { - text-align: left; -} - -.qp-bold, -.qp-tt-header { - font-weight: bold; -} - -.qp-tt-header { - text-align: center; -} - -/* Icons */ -.qp-icon-Catchall{background: url('qp_icons.png') -96px -0px } -.qp-icon-ArithmeticExpression{background: url('qp_icons.png') -0px -0px } -.qp-icon-Assert{background: url('qp_icons.png') -32px -0px } -.qp-icon-Assign{background: url('qp_icons.png') -64px -0px } -.qp-icon-Bitmap{background: url('qp_icons.png') -96px -0px } -.qp-icon-BookmarkLookup{background: url('qp_icons.png') -128px -0px } -.qp-icon-ClusteredIndexDelete{background: url('qp_icons.png') -160px -0px } -.qp-icon-ClusteredIndexInsert{background: url('qp_icons.png') -192px -0px } -.qp-icon-ClusteredIndexScan{background: url('qp_icons.png') -224px -0px } -.qp-icon-ClusteredIndexSeek{background: url('qp_icons.png') -256px -0px } -.qp-icon-KeyLookup{background: url('qp_icons.png') -256px -0px } -.qp-icon-ClusteredIndexUpdate{background: url('qp_icons.png') -288px -0px } -.qp-icon-Collapse{background: url('qp_icons.png') -0px -32px } -.qp-icon-ComputeScalar{background: url('qp_icons.png') -32px -32px } -.qp-icon-Concatenation{background: url('qp_icons.png') -64px -32px } -.qp-icon-ConstantScan{background: url('qp_icons.png') -96px -32px } -.qp-icon-Convert{background: url('qp_icons.png') -128px -32px } -.qp-icon-CursorCatchall{background: url('qp_icons.png') -96px -0px } -.qp-icon-Declare{background: url('qp_icons.png') -160px -32px } -.qp-icon-Delete{background: url('qp_icons.png') -288px -160px } -.qp-icon-DistributeStreams{background: url('qp_icons.png') -224px -32px } -.qp-icon-Dynamic{background: url('qp_icons.png') -256px -32px } -.qp-icon-EagerSpool{background: url('qp_icons.png') -192px -160px } -.qp-icon-FetchQuery{background: url('qp_icons.png') -288px -32px } -.qp-icon-Filter{background: url('qp_icons.png') -0px -64px } -.qp-icon-GatherStreams{background: url('qp_icons.png') -32px -64px } -.qp-icon-HashMatch{background: url('qp_icons.png') -64px -64px } -.qp-icon-HashMatchRoot{background: url('qp_icons.png') -64px -64px } -.qp-icon-HashMatchTeam{background: url('qp_icons.png') -64px -64px } -.qp-icon-If{background: url('qp_icons.png') -96px -64px } -.qp-icon-Insert{background: url('qp_icons.png') -0px -192px } -.qp-icon-InsertedScan{background: url('qp_icons.png') -128px -64px } -.qp-icon-Intrinsic{background: url('qp_icons.png') -160px -64px } -.qp-icon-IteratorCatchall{background: url('qp_icons.png') -96px -0px } -.qp-icon-Keyset{background: url('qp_icons.png') -192px -64px } -.qp-icon-LanguageElementCatchall{background: url('qp_icons.png') -96px -0px } -.qp-icon-LazySpool{background: url('qp_icons.png') -192px -160px } -.qp-icon-LogRowScan{background: url('qp_icons.png') -224px -64px } -.qp-icon-MergeInterval{background: url('qp_icons.png') -256px -64px } -.qp-icon-MergeJoin{background: url('qp_icons.png') -288px -64px } -.qp-icon-NestedLoops{background: url('qp_icons.png') -0px -96px } -.qp-icon-NonclusteredIndexDelete{background: url('qp_icons.png') -32px -96px } -.qp-icon-NonclusteredIndexInsert{background: url('qp_icons.png') -64px -96px } -.qp-icon-IndexScan{background: url('qp_icons.png') -96px -96px } -.qp-icon-IndexSeek{background: url('qp_icons.png') -128px -96px } -.qp-icon-NonclusteredIndexSpool{background: url('qp_icons.png') -160px -96px } -.qp-icon-NonclusteredIndexUpdate{background: url('qp_icons.png') -192px -96px } -.qp-icon-OnlineIndexInsert{background: url('qp_icons.png') -224px -96px } -.qp-icon-ParameterTableScan{background: url('qp_icons.png') -256px -96px } -.qp-icon-PopulationQuery{background: url('qp_icons.png') -288px -96px } -.qp-icon-RdiLookup{background: url('qp_icons.png') -0px -128px } -.qp-icon-RefreshQuery{background: url('qp_icons.png') -32px -128px } -.qp-icon-RemoteDelete{background: url('qp_icons.png') -64px -128px } -.qp-icon-RemoteInsert{background: url('qp_icons.png') -96px -128px } -.qp-icon-RemoteQuery{background: url('qp_icons.png') -128px -128px } -.qp-icon-RemoteScan{background: url('qp_icons.png') -160px -128px } -.qp-icon-RemoteUpdate{background: url('qp_icons.png') -192px -128px } -.qp-icon-RepartitionStreams{background: url('qp_icons.png') -224px -128px } -.qp-icon-Result{background: url('qp_icons.png') -256px -128px } -.qp-icon-RowCountSpool{background: url('qp_icons.png') -288px -128px } -.qp-icon-Segment{background: url('qp_icons.png') -0px -160px } -.qp-icon-Sequence{background: url('qp_icons.png') -32px -160px } -.qp-icon-Sequenceproject{background: url('qp_icons.png') -64px -160px } -.qp-icon-Snapshot{background: url('qp_icons.png') -96px -160px } -.qp-icon-Sort{background: url('qp_icons.png') -128px -160px } -.qp-icon-Split{background: url('qp_icons.png') -160px -160px } -.qp-icon-Spool{background: url('qp_icons.png') -192px -160px } -.qp-icon-Statement{background: url('qp_icons.png') -256px -128px } -.qp-icon-StreamAggregate{background: url('qp_icons.png') -224px -160px } -.qp-icon-Switch{background: url('qp_icons.png') -256px -160px } -.qp-icon-TableDelete{background: url('qp_icons.png') -288px -160px } -.qp-icon-TableInsert{background: url('qp_icons.png') -0px -192px } -.qp-icon-TableScan{background: url('qp_icons.png') -32px -192px } -.qp-icon-TableSpool{background: url('qp_icons.png') -64px -192px } -.qp-icon-TableUpdate{background: url('qp_icons.png') -96px -192px } -.qp-icon-TableValuedFunction{background: url('qp_icons.png') -128px -192px } -.qp-icon-Top{background: url('qp_icons.png') -160px -192px } -.qp-icon-Udx{background: url('qp_icons.png') -192px -192px } -.qp-icon-Update{background: url('qp_icons.png') -96px -192px } -.qp-icon-While{background: url('qp_icons.png') -224px -192px } -.qp-icon-PopulateQuery{background: url('qp_icons.png') -96px -0px } -.qp-icon-StmtCursor{background: url('qp_icons.png') -96px -0px } -.qp-icon-SequenceProject{background: url('qp_icons.png') -96px -0px } -.qp-icon-FastForward{background: url('qp_icons.png') -96px -0px } -.qp-icon-SnapShot{background: url('qp_icons.png') -96px -0px } - -/* Layout - can't touch this */ -.qp-tt { - position: absolute; - z-index: 1; - white-space: normal; - -webkit-transition-delay: 0.5s; - transition-delay: 0.5s; -} - -div.qp-node .qp-tt, -.qp-noCssTooltip div.qp-node:hover .qp-tt { - visibility: hidden; - position: absolute; - overflow: hidden; -} - -div.qp-node:hover .qp-tt { - visibility: visible; -} - -.qp-tt table { - white-space: nowrap; -} - -.qp-node { - position: relative; - white-space: nowrap; -} - -.qp-tr { - display: table; -} - -.qp-tr>div { - display: table-cell; - padding-left: 15px; -} - -.qp-root { - display: table; - position: relative; -} - -.qp-root svg { - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - z-index: 0; - background: transparent; - pointer-events: none; -} diff --git a/src/sql/workbench/contrib/queryPlan/browser/media/qp_icons.png b/src/sql/workbench/contrib/queryPlan/browser/media/qp_icons.png deleted file mode 100644 index fa4aaab8542d5dde35e9c5a680a4a8de478116a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63962 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

-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 { - total += element.actualRow ?? 0; - }); - } - - return total; - } - - public get actualExecutions(): number { - let total = 0; - if (this.runtimePerThreads) { - this.runtimePerThreads.forEach(element => { - total += element.actualExecutions ?? 0; - }); - } - return total; - } -} - -interface RuntimePerThread { - threadId?: number; - actualRow?: number; - actualExecutionMode?: string; - actualExecutions?: number; -} - -class IndexObject { - public database?: string; - public schema?: string; - public table?: string; - public index?: string; - public indexKind?: string; - - public get title() { - let title: string = ''; - if (this.database && this.schema && this.table) { - title = `${this.database}.${this.schema}.${this.table}.${this.index}`; - if (this.indexKind && this.indexKind !== '') { - title += `(${this.indexKind})`; - } - } - return title; - } -} - -class PlanNode { - private childrenNodes: PlanNode[] = []; - - public root?: PlanNode; - public subtreeCost?: number; - public parent?: PlanNode; - public physicalOp?: string; - public logicalOp?: string; - public id?: number; - public estimateRows?: string; - public estimateIo?: string; - public estimateCpu?: string; - public parallel?: boolean; - public partitioned?: boolean; - public estimateRewinds?: string; - public estimateRebinds?: string; - public runtimeInfo?: RunTimeInformation; - public indexObject?: IndexObject; - - public addChildren(children: PlanNode[]): void { - if (children) { - children.forEach(element => { - element.parent = this; - }); - } - this.childrenNodes = children; - } - - public get totalSubTreeCost(): number { - let total = this.subtreeCost ?? 0; - if (total === 0) { - this.children.forEach(element => { - total += element.subtreeCost ?? 0; - }); - } - return total; - } - - public get children(): PlanNode[] { - return this.childrenNodes; - } - - public get cost(): number { - let total = this.subtreeCost ?? 0; - if (this.children && total !== 0) { - this.children.forEach(element => { - total -= element.subtreeCost ?? 0; - }); - } - return total; - } - - public get relativeCost(): number { - let overallCost = this.root?.totalSubTreeCost ?? 0; - return overallCost > 0 ? this.cost / overallCost : 0; - } - - public get estimatedOperatorCost(): number { - return Math.round(this.relativeCost * 100); - } - - public get estimatedSubtreeCost(): number { - let total = this.estimatedOperatorCost; - if (this.children) { - this.children.forEach(element => { - total += element.estimatedSubtreeCost; - }); - } - return total; - } - - public get title(): string { - if (this.physicalOp === this.logicalOp) { - return this.physicalOp ?? ''; - } else { - return `${this.physicalOp}(${this.logicalOp})`; - } - } - - public get treeViewPrefix(): string { - return this.parent === undefined ? '' : `${this.parent.treeViewPrefix}-----`; - } - - public get treeViewTitle(): string { - return `${this.treeViewPrefix}${this.title}`; - } -} - -export class PlanXmlParser { - public parser: DOMParser = new DOMParser(); - public doc?: Document; - public planXml?: string; - public root?: PlanNode; - - constructor(planXml: string) { - - this.doc = this.parser.parseFromString(planXml, 'application/xml'); - this.planXml = planXml; - let queryPlanNode = this.findChildren(this.doc.children[0], 'QueryPlan'); - if (queryPlanNode && queryPlanNode.length > 0) { - this.root = new PlanNode(); - let ops = this.createPlanNodes(queryPlanNode[0], 'RelOp', this.root); - - this.root.addChildren(ops); - this.root.subtreeCost = 0; - } - } - - public get topOperations(): PlanNode[] { - let operations: PlanNode[] = []; - if (this.root && this.root.children) { - operations = this.addOperationsToList(operations, this.root.children); - operations.sort((a, b) => { - if (a.estimatedOperatorCost > b.estimatedOperatorCost) { - return -1; - } else if (a.estimatedOperatorCost <= b.estimatedOperatorCost) { - return 1; - } else { - return 0; - } - }); - } - return operations; - } - - public get toTreeViewList(): PlanNode[] { - let operations: PlanNode[] = []; - if (this.root) { - operations = this.addOperationsToList(operations, this.root.children); - } - - return operations; - } - - private addOperationsToList(list: PlanNode[], nodes: PlanNode[]): PlanNode[] { - list = list.concat(nodes); - nodes.forEach(element => { - list = this.addOperationsToList(list, element.children); - }); - return list; - } - - private findChildren(element: Element, elementName: string, untilNode: string | undefined = undefined): Element[] | undefined { - let elements: Element[] = []; - if (element === undefined) { - return undefined; - } - - for (let index = 0; index < element.childNodes.length; index++) { - if (element.childNodes[index].nodeName.toLocaleLowerCase() === elementName.toLocaleLowerCase()) { - elements = elements.concat(element.children[index]); - } - } - if (elements.length > 0) { - return elements; - } - for (let index = 0; index < element.childNodes.length; index++) { - if (untilNode && element.childNodes[index].nodeName === untilNode) { - continue; - } - let result = this.findChildren(element.children[index], elementName, untilNode); - if (result !== undefined) { - return result; - } - } - - return undefined; - } - - private createPlanNodes(element: Element, elementName: string, root: PlanNode): PlanNode[] { - let nodePlans: PlanNode[] = []; - - let children = this.findChildren(element, elementName); - if (children) { - for (let index = 0; index < children.length; index++) { - let childNode = children[index]; - - let planNode = this.convertToPlanNode(childNode); - planNode.root = root; - planNode.addChildren(this.createPlanNodes(childNode, elementName, root)); - planNode.runtimeInfo = new RunTimeInformation(); - planNode.indexObject = new IndexObject(); - - let runtimeInfoNodes = this.findChildren(childNode, 'RunTimeCountersPerThread'); - if (runtimeInfoNodes) { - planNode.runtimeInfo.runtimePerThreads = runtimeInfoNodes.map(x => this.convertToRuntimeInfo(x)); - } - - let objectNodes = this.findChildren(childNode, 'Object', 'RelOp'); - if (objectNodes && objectNodes.length > 0) { - planNode.indexObject = this.convertToObject(objectNodes[0]); - } - nodePlans = nodePlans.concat(planNode); - } - } - - return nodePlans; - } - - private convertToPlanNode(element: Element): PlanNode { - let planNode = new PlanNode(); - planNode.id = Number(this.findAttribute(element.attributes, 'NodeId')); - planNode.logicalOp = this.findAttribute(element.attributes, 'LogicalOp'); - planNode.physicalOp = this.findAttribute(element.attributes, 'PhysicalOp'); - planNode.subtreeCost = Number(this.findAttribute(element.attributes, 'EstimatedTotalSubtreeCost')); - planNode.estimateRows = this.findAttribute(element.attributes, 'EstimateRows'); - planNode.estimateCpu = this.findAttribute(element.attributes, 'EstimateCPU'); - planNode.estimateIo = this.findAttribute(element.attributes, 'EstimateIO'); - planNode.estimateRebinds = this.findAttribute(element.attributes, 'EstimateRebinds'); - planNode.estimateRewinds = this.findAttribute(element.attributes, 'EstimateRewinds'); - planNode.parallel = this.findAttribute(element.attributes, 'Parallel') === '1'; - planNode.partitioned = this.findAttribute(element.attributes, 'Partitioned') === '1'; - return planNode; - } - - private convertToRuntimeInfo(element: Element): RuntimePerThread { - return { - actualExecutionMode: this.findAttribute(element.attributes, 'ActualExecutionMode'), - actualExecutions: Number(this.findAttribute(element.attributes, 'ActualExecutions')), - actualRow: Number(this.findAttribute(element.attributes, 'ActualRows')), - threadId: Number(this.findAttribute(element.attributes, 'Thread')) - }; - } - - private convertToObject(element: Element): IndexObject { - let objectNode = new IndexObject(); - objectNode.database = this.findAttribute(element.attributes, 'Database'); - objectNode.index = this.findAttribute(element.attributes, 'Index'); - objectNode.indexKind = this.findAttribute(element.attributes, 'IndexKind'); - objectNode.schema = this.findAttribute(element.attributes, 'Schema'); - objectNode.table = this.findAttribute(element.attributes, 'Table'); - return objectNode; - } - - private findAttribute(attributes: NamedNodeMap, attName: string): string | undefined { - for (let index = 0; index < attributes.length; index++) { - let attribute = attributes[index]; - if (attribute.name === attName) { - return attribute.value; - } - } - return undefined; - } -} diff --git a/src/sql/workbench/contrib/queryPlan/browser/queryPlan.contribution.ts b/src/sql/workbench/contrib/queryPlan/browser/queryPlan.contribution.ts deleted file mode 100644 index b405c0f13a..0000000000 --- a/src/sql/workbench/contrib/queryPlan/browser/queryPlan.contribution.ts +++ /dev/null @@ -1,56 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { QueryPlanInput } from 'sql/workbench/contrib/queryPlan/common/queryPlanInput'; -import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; -import { EditorExtensions } from 'vs/workbench/common/editor'; -import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { QueryPlanEditor } from 'sql/workbench/contrib/queryPlan/browser/queryPlanEditor'; -import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { IEditorResolverService, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; - -// Query Plan editor registration - -const queryPlanEditorDescriptor = EditorPaneDescriptor.create( - QueryPlanEditor, - QueryPlanEditor.ID, - QueryPlanEditor.LABEL -); - -Registry.as(EditorExtensions.EditorPane) - .registerEditorPane(queryPlanEditorDescriptor, [new SyncDescriptor(QueryPlanInput)]); - -export class QueryPlanEditorOverrideContribution extends Disposable implements IWorkbenchContribution { - constructor( - @IInstantiationService private _instantiationService: IInstantiationService, - @IEditorResolverService private _editorResolverService: IEditorResolverService - ) { - super(); - this.registerEditorOverride(); - } - - private registerEditorOverride(): void { - this._editorResolverService.registerEditor( - '', //Removing sqlplan glob pattern. TODO: to be removed entirely from ADS. - { - id: QueryPlanEditor.ID, - label: QueryPlanEditor.LABEL, - priority: RegisteredEditorPriority.builtin - }, - {}, - (editorInput, group) => { - const queryPlanInput = this._instantiationService.createInstance(QueryPlanInput, editorInput.resource); - return { editor: queryPlanInput, options: editorInput.options, group: group }; - } - ); - } -} - -Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(QueryPlanEditorOverrideContribution, LifecyclePhase.Restored); diff --git a/src/sql/workbench/contrib/queryPlan/browser/queryPlan.ts b/src/sql/workbench/contrib/queryPlan/browser/queryPlan.ts deleted file mode 100755 index 04495f977a..0000000000 --- a/src/sql/workbench/contrib/queryPlan/browser/queryPlan.ts +++ /dev/null @@ -1,112 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import 'vs/css!./media/qp'; -import * as QP from 'kburtram-query-plan'; - -import { IPanelView, IPanelTab } from 'sql/base/browser/ui/panel/panel'; - -import { Dimension, clearNode } from 'vs/base/browser/dom'; -import { localize } from 'vs/nls'; -import { dispose } from 'vs/base/common/lifecycle'; -import { QueryPlanState } from 'sql/workbench/common/editor/query/queryPlanState'; - -export class QueryPlanTab implements IPanelTab { - public readonly title = localize('queryPlanTitle', "Query Plan"); - public readonly identifier = 'QueryPlanTab'; - public readonly view: QueryPlanView; - - constructor() { - this.view = new QueryPlanView(); - } - - public dispose() { - dispose(this.view); - } - - public clear() { - this.view.clear(); - } -} - -export class QueryPlanView implements IPanelView { - private qp?: QueryPlan; - private xml?: string; - private container = document.createElement('div'); - private _state?: QueryPlanState; - - public render(container: HTMLElement): void { - container.appendChild(this.container); - this.container.style.overflow = 'scroll'; - if (!this.qp) { - this.qp = new QueryPlan(this.container); - if (this.xml) { - this.qp.xml = this.xml; - } - } - } - - dispose() { - this.container.remove(); - this.qp = undefined; - } - - public layout(dimension: Dimension): void { - this.container.style.width = dimension.width + 'px'; - this.container.style.height = dimension.height + 'px'; - } - - public clear() { - if (this.qp) { - this.qp.xml = undefined; - } - } - - public showPlan(xml: string) { - if (this.qp) { - this.qp.xml = xml; - } else { - this.xml = xml; - } - if (this.state) { - this.state.xml = xml; - } - } - - public setState(val: QueryPlanState) { - this._state = val; - if (this._state.xml) { - this.showPlan(this._state.xml); - } - } - - public get state(): QueryPlanState | undefined { - return this._state; - } -} - -export class QueryPlan { - private _xml?: string; - constructor(private container: HTMLElement) { - } - - public set xml(xml: string | undefined) { - this._xml = xml; - clearNode(this.container); - if (this.xml) { - QP.showPlan(this.container, this.xml, { - jsTooltips: false - }); - this.container.querySelectorAll('div.qp-tt').forEach(toolTip => { - toolTip.classList.add('monaco-editor'); - toolTip.classList.add('monaco-editor-hover'); - }); - } - } - - public get xml(): string | undefined { - return this._xml; - } -} diff --git a/src/sql/workbench/contrib/queryPlan/browser/queryPlanEditor.ts b/src/sql/workbench/contrib/queryPlan/browser/queryPlanEditor.ts deleted file mode 100644 index 102d70f23b..0000000000 --- a/src/sql/workbench/contrib/queryPlan/browser/queryPlanEditor.ts +++ /dev/null @@ -1,73 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as DOM from 'vs/base/browser/dom'; -import { localize } from 'vs/nls'; -import { IEditorOpenContext } from 'vs/workbench/common/editor'; -import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { QueryPlanInput } from 'sql/workbench/contrib/queryPlan/common/queryPlanInput'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { QueryPlanView } from 'sql/workbench/contrib/queryPlan/browser/queryPlan'; -import { IEditorOptions } from 'vs/platform/editor/common/editor'; - -export class QueryPlanEditor extends EditorPane { - - public static ID: string = 'workbench.editor.queryplan'; - public static LABEL: string = localize('queryPlanEditor', "Query Plan Editor"); - - private view = this._register(new QueryPlanView()); - - constructor( - @ITelemetryService telemetryService: ITelemetryService, - @IThemeService themeService: IThemeService, - @IStorageService storageService: IStorageService - ) { - super(QueryPlanEditor.ID, telemetryService, themeService, storageService); - } - - /** - * Called to create the editor in the parent element. - */ - public createEditor(parent: HTMLElement): void { - //Enable scrollbars when drawing area is larger than viewport - parent.style.overflow = 'auto'; - //Set background of parent to white (same as .qp-root from src\sql\parts\grid\load\css\qp.css) - //This is because the bottom-most tooltips can extend past the drawing area, which causes the - //scrolling area to have gaps on the bottom and left. So if the colors aren't matched then - //these gaps show up as different colors and look bad. - //Another option would be to check the tooltip positions and reposition them if necessary - //during the load - but changing the background color was the simplest and least error prone - //(plus it's probable that we won't be using this control in the future anyways if development) - //continues on the Query plan feature - parent.style.background = '#fff'; - this.view.render(parent); - } - - /** - * Updates the internal variable keeping track of the editor's size, and re-calculates the sash position. - * To be called when the container of this editor changes size. - */ - public layout(dimension: DOM.Dimension): void { - this.view.layout(dimension); - } - - public override async setInput(input: QueryPlanInput, options: IEditorOptions, context: IEditorOpenContext): Promise { - if (this.input instanceof QueryPlanInput && this.input.matches(input)) { - return Promise.resolve(undefined); - } - await input.resolve(); - - await super.setInput(input, options, context, CancellationToken.None); - - this.view.showPlan(input.planXml!); - } - - public override dispose(): void { - super.dispose(); - } -} diff --git a/src/sql/workbench/contrib/queryPlan/browser/topOperations.ts b/src/sql/workbench/contrib/queryPlan/browser/topOperations.ts deleted file mode 100644 index 8d42b82d94..0000000000 --- a/src/sql/workbench/contrib/queryPlan/browser/topOperations.ts +++ /dev/null @@ -1,128 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Dimension } from 'vs/base/browser/dom'; -import { localize } from 'vs/nls'; -import { Disposable } from 'vs/base/common/lifecycle'; - -import { Table } from 'sql/base/browser/ui/table/table'; -import { PlanXmlParser } from 'sql/workbench/contrib/queryPlan/browser/planXmlParser'; -import { IPanelView, IPanelTab } from 'sql/base/browser/ui/panel/panel'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { attachTableStyler } from 'sql/platform/theme/common/styler'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { TableDataView } from 'sql/base/browser/ui/table/tableDataView'; -import { TopOperationsState } from 'sql/workbench/common/editor/query/topOperationsState'; -import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; -import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; - -const topOperationColumns: Array> = [ - { name: localize('topOperations.operation', "Operation"), field: 'operation', sortable: true, width: 300 }, - { name: localize('topOperations.object', "Object"), field: 'object', sortable: true }, - { name: localize('topOperations.estCost', "Est Cost"), field: 'estCost', sortable: true }, - { name: localize('topOperations.estSubtreeCost', "Est Subtree Cost"), field: 'estSubtreeCost', sortable: true }, - { name: localize('topOperations.actualRows', "Actual Rows"), field: 'actualRows', sortable: true }, - { name: localize('topOperations.estRows', "Est Rows"), field: 'estRows', sortable: true }, - { name: localize('topOperations.actualExecutions', "Actual Executions"), field: 'actualExecutions', sortable: true }, - { name: localize('topOperations.estCPUCost', "Est CPU Cost"), field: 'estCPUCost', sortable: true }, - { name: localize('topOperations.estIOCost', "Est IO Cost"), field: 'estIOCost', sortable: true }, - { name: localize('topOperations.parallel', "Parallel"), field: 'parallel', sortable: true }, - { name: localize('topOperations.actualRebinds', "Actual Rebinds"), field: 'actualRebinds', sortable: true }, - { name: localize('topOperations.estRebinds', "Est Rebinds"), field: 'estRebinds', sortable: true }, - { name: localize('topOperations.actualRewinds', "Actual Rewinds"), field: 'actualRewinds', sortable: true }, - { name: localize('topOperations.estRewinds', "Est Rewinds"), field: 'estRewinds', sortable: true }, - { name: localize('topOperations.partitioned', "Partitioned"), field: 'partitioned', sortable: true } -]; - -export class TopOperationsTab extends Disposable implements IPanelTab { - public readonly title = localize('topOperationsTitle', "Top Operations"); - public readonly identifier = 'TopOperationsTab'; - public readonly view: TopOperationsView; - - constructor(@IInstantiationService instantiationService: IInstantiationService) { - super(); - this.view = this._register(instantiationService.createInstance(TopOperationsView)); - } - - public clear() { - this.view.clear(); - } -} - -export class TopOperationsView extends Disposable implements IPanelView { - private _state?: TopOperationsState; - private table: Table; - private container = document.createElement('div'); - private dataView = new TableDataView(); - - constructor( - @IThemeService private themeService: IThemeService, - @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService - ) { - super(); - this.table = new Table(this.container, { - columns: topOperationColumns, - dataProvider: this.dataView, - sorter: (args) => { - this.dataView.sort(args); - } - }); - this._register(this.table); - this._register(attachTableStyler(this.table, this.themeService)); - this._register(this.dataView.onRowCountChange(() => this.table.updateRowCount())); - } - - public render(container: HTMLElement): void { - container.appendChild(this.container); - - this.telemetryService.sendActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.ViewTopOperations); - } - - public layout(dimension: Dimension): void { - this.table.layout(dimension); - } - - public clear() { - this.dataView.clear(); - } - - public showPlan(xml: string) { - this.state!.xml = xml; - this.dataView.clear(); - let parser = new PlanXmlParser(xml); - let operations = parser.topOperations; - let data = operations.map(i => { - return { - operation: i.title, - object: i.indexObject?.title, - estCost: i.estimatedOperatorCost, - estSubtreeCost: i.subtreeCost, - actualRows: i.runtimeInfo?.actualRows, - estRows: i.estimateRows, - actualExecutions: i.runtimeInfo?.actualExecutions, - estCPUCost: i.estimateCpu, - estIOCost: i.estimateIo, - parallel: i.parallel, - actualRebinds: '', - estRebinds: i.estimateRebinds, - actualRewinds: '', - estRewinds: i.estimateRewinds, - partitioned: i.partitioned - }; - }); - this.dataView.push(data); - } - - public setState(val: TopOperationsState) { - this._state = val; - if (this._state.xml) { - this.showPlan(this._state.xml); - } - } - - public get state(): TopOperationsState | undefined { - return this._state; - } -} diff --git a/src/sql/workbench/contrib/queryPlan/common/queryPlanInput.ts b/src/sql/workbench/contrib/queryPlan/common/queryPlanInput.ts deleted file mode 100644 index 5c71da02cf..0000000000 --- a/src/sql/workbench/contrib/queryPlan/common/queryPlanInput.ts +++ /dev/null @@ -1,56 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { URI } from 'vs/base/common/uri'; -import { EditorInput } from 'vs/workbench/common/editor/editorInput'; -import { EditorModel } from 'vs/workbench/common/editor/editorModel'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; - -export class QueryPlanInput extends EditorInput { - - public static ID: string = 'workbench.editorinputs.queryplan'; - public static SCHEMA: string = 'queryplan'; - - private _xml?: string; - - constructor( - private _uri: URI, - @ITextFileService private readonly fileService: ITextFileService - ) { - super(); - } - - override get typeId(): string { - return UntitledTextEditorInput.ID; - } - - public override getName(): string { - return 'Query Plan'; - } - - public get planXml(): string | undefined { - return this._xml; - } - - public getUri(): string { - return this._uri.toString(); - } - - public supportsSplitEditor(): boolean { - return false; - } - - public override async resolve(refresh?: boolean): Promise { - if (!this._xml) { - this._xml = (await this.fileService.read(this._uri, { acceptTextOnly: true })).value; - } - return null; - } - - get resource(): URI | undefined { - return undefined; - } -} diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index f3e5721ebc..138c8414de 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -474,9 +474,6 @@ import 'sql/workbench/contrib/objectExplorer/common/serverGroup.contribution'; // edit data editor import 'sql/workbench/contrib/editData/browser/editData.contribution'; -// query plan editor -import 'sql/workbench/contrib/queryPlan/browser/queryPlan.contribution'; - //acounts import 'sql/workbench/contrib/accounts/browser/accounts.contribution'; import 'sql/workbench/contrib/accounts/browser/accountManagement.contribution';