diff --git a/src/sql/parts/modelComponents/queryTextEditor.ts b/src/sql/parts/modelComponents/queryTextEditor.ts index 174efc3c9b..4f2b3235de 100644 --- a/src/sql/parts/modelComponents/queryTextEditor.ts +++ b/src/sql/parts/modelComponents/queryTextEditor.ts @@ -81,6 +81,8 @@ export class QueryTextEditor extends BaseTextEditor { options.hideCursorInOverviewRuler = true; if (!this._selected) { options.renderLineHighlight = 'none'; + options.parameterHints = { enabled: false }; + options.matchBrackets = false; } if (this._hideLineNumbers) { options.lineNumbers = 'off'; diff --git a/src/sql/parts/notebook/cellViews/code.component.ts b/src/sql/parts/notebook/cellViews/code.component.ts index b16eca6695..7fc320efc5 100644 --- a/src/sql/parts/notebook/cellViews/code.component.ts +++ b/src/sql/parts/notebook/cellViews/code.component.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./code'; -import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, Output, EventEmitter, OnChanges, SimpleChange } from '@angular/core'; +import { OnInit, Component, Input, Inject, ElementRef, ViewChild, Output, EventEmitter, OnChanges, SimpleChange } from '@angular/core'; import { AngularDisposable } from 'sql/base/node/lifecycle'; import { QueryTextEditor } from 'sql/parts/modelComponents/queryTextEditor'; @@ -32,6 +32,7 @@ import { CellTypes } from 'sql/parts/notebook/models/contracts'; import { OVERRIDE_EDITOR_THEMING_SETTING } from 'sql/workbench/services/notebook/common/notebookService'; import * as notebookUtils from 'sql/parts/notebook/notebookUtils'; import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; +import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; export const CODE_SELECTOR: string = 'code-component'; const MARKDOWN_CLASS = 'markdown'; @@ -67,6 +68,9 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange this.checkForLanguageMagics(); this.updateLanguageMode(); })); + this._register(value.onValidConnectionSelected(() => { + this.updateConnectionState(this.isActive()); + })); } @Input() set activeCellId(value: string) { @@ -105,6 +109,8 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange this._cellToggleMoreActions = this._instantiationService.createInstance(CellToggleMoreActions); this._register(debounceEvent(this._layoutEmitter.event, (l, e) => e, 250, /*leading=*/false) (() => this.layout())); + // Handle disconnect on removal of the cell, if it was the active cell + this._register({ dispose: () => this.updateConnectionState(false) }); } @@ -121,11 +127,7 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange if (propName === 'activeCellId') { let changedProp = changes[propName]; let isActive = this.cellModel.id === changedProp.currentValue; - if (isActive && this._model.defaultKernel.display_name === notebookConstants.SQL - && this.cellModel.cellType === CellTypes.Code - && this.cellModel.cellUri) { - this._model.notebookOptions.connectionService.connect(this._model.activeConnection, this.cellModel.cellUri.toString()).catch(e => console.log(e)); - } + this.updateConnectionState(isActive); this.toggleMoreActionsButton(isActive); if (this._editor) { this._editor.toggleEditorSelected(isActive); @@ -135,6 +137,28 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange } } + private updateConnectionState(isConnected: boolean) { + if (this.isSqlCodeCell()) { + let cellUri = this.cellModel.cellUri.toString(); + let connectionService = this.connectionService; + if (!isConnected && connectionService && connectionService.isConnected(cellUri)) { + connectionService.disconnect(cellUri).catch(e => console.log(e)); + } else if (this._model.activeConnection && this._model.activeConnection.id !== '-1') { + connectionService.connect(this._model.activeConnection, cellUri).catch(e => console.log(e)); + } + } + } + + private get connectionService(): IConnectionManagementService { + return this._model && this._model.notebookOptions && this._model.notebookOptions.connectionService; + } + + private isSqlCodeCell() { + return this._model.defaultKernel.display_name === notebookConstants.SQL + && this.cellModel.cellType === CellTypes.Code + && this.cellModel.cellUri; + } + ngAfterContentInit(): void { this.createEditor(); this._register(DOM.addDisposableListener(window, DOM.EventType.RESIZE, e => { diff --git a/src/sql/parts/notebook/notebook.component.ts b/src/sql/parts/notebook/notebook.component.ts index edcababef9..aeaa8bde9e 100644 --- a/src/sql/parts/notebook/notebook.component.ts +++ b/src/sql/parts/notebook/notebook.component.ts @@ -134,7 +134,6 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe } ngOnDestroy() { - this.disconnect(); this.dispose(); if (this.notebookService) { this.notebookService.removeNotebookEditor(this); @@ -168,7 +167,6 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe } if (cell !== this.model.activeCell) { if (this.model.activeCell) { - this.disconnect(); this.model.activeCell.active = false; } this._model.activeCell = cell; @@ -177,14 +175,6 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe } } - private disconnect() { - if (this._model.defaultKernel.display_name === notebookConstants.SQL) { - if (this._model.activeCell && this._model.activeCell.cellType === CellTypes.Code && this._model.activeCell.cellUri) { - this.connectionManagementService.disconnect(this._model.activeCell.cellUri.toString()).catch(e => console.log(e)); - } - } - } - public unselectActiveCell() { if (this.model && this.model.activeCell) { this.model.activeCell.active = false; diff --git a/src/sql/workbench/services/notebook/common/sqlSessionManager.ts b/src/sql/workbench/services/notebook/common/sqlSessionManager.ts index 08ae6abee2..acf1821379 100644 --- a/src/sql/workbench/services/notebook/common/sqlSessionManager.ts +++ b/src/sql/workbench/services/notebook/common/sqlSessionManager.ts @@ -5,7 +5,7 @@ 'use strict'; import * as os from 'os'; -import { nb, QueryExecuteSubsetResult, IDbColumn, BatchSummary, IResultMessage } from 'sqlops'; +import { nb, QueryExecuteSubsetResult, IDbColumn, BatchSummary, IResultMessage, ResultSetSummary } from 'sqlops'; import { localize } from 'vs/nls'; import * as strings from 'vs/base/common/strings'; import { FutureInternal, ILanguageMagic } from 'sql/parts/notebook/models/modelInterfaces'; @@ -398,32 +398,51 @@ export class SQLFuture extends Disposable implements FutureInternal { public handleBatchEnd(batch: BatchSummary): void { if (this.ioHandler) { this.handleMessage(strings.format(elapsedTimeLabel, batch.executionElapsed)); + this.processResultSets(batch); + } + } + + private async processResultSets(batch: BatchSummary): Promise { + try { for (let resultSet of batch.resultSetSummaries) { let rowCount = resultSet.rowCount > this.configuredMaxRows ? this.configuredMaxRows : resultSet.rowCount; - this._queryRunner.getQueryRows(0, rowCount, resultSet.batchId, resultSet.id).then(d => { - - let msg: nb.IIOPubMessage = { - channel: 'iopub', - type: 'iopub', - header: { - msg_id: undefined, - msg_type: 'execute_result' - }, - content: { - output_type: 'execute_result', - metadata: {}, - execution_count: this._executionCount, - data: { 'application/vnd.dataresource+json': this.convertToDataResource(resultSet.columnInfo, d), 'text/html': this.convertToHtmlTable(resultSet.columnInfo, d) } - }, - metadata: undefined, - parent_header: undefined - }; - this.ioHandler.handle(msg); - }); + await this.sendResultSetAsIOPub(rowCount, resultSet); } + } catch (err) { + // TODO should we output this somewhere else? + console.log(`Error outputting result sets from Notebook query: ${err}`); } } + private async sendResultSetAsIOPub(rowCount: number, resultSet: ResultSetSummary): Promise { + let subsetResult: QueryExecuteSubsetResult; + if (rowCount > 0) { + subsetResult = await this._queryRunner.getQueryRows(0, rowCount, resultSet.batchId, resultSet.id); + } else { + subsetResult = { message: '', resultSubset: { rowCount: 0, rows: [] }}; + } + let msg: nb.IIOPubMessage = { + channel: 'iopub', + type: 'iopub', + header: { + msg_id: undefined, + msg_type: 'execute_result' + }, + content: { + output_type: 'execute_result', + metadata: {}, + execution_count: this._executionCount, + data: { + 'application/vnd.dataresource+json': this.convertToDataResource(resultSet.columnInfo, subsetResult), + 'text/html': this.convertToHtmlTable(resultSet.columnInfo, subsetResult) + } + }, + metadata: undefined, + parent_header: undefined + }; + this.ioHandler.handle(msg); + } + setIOPubHandler(handler: nb.MessageHandler): void { this.ioHandler = handler; }