Skip to content

Commit 355a3b7

Browse files
authored
Merge pull request #195 from codefori/feature/cancel
Feature/cancel
2 parents 671bc57 + 95d83c7 commit 355a3b7

File tree

7 files changed

+174
-93
lines changed

7 files changed

+174
-93
lines changed

package.json

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,12 @@
347347
"category": "Db2 for i",
348348
"icon": "$(notebook-execute)"
349349
},
350+
{
351+
"command": "vscode-db2i.statement.cancel",
352+
"title": "Cancel",
353+
"category": "Db2 for i",
354+
"icon": "$(stop)"
355+
},
350356
{
351357
"command": "vscode-db2i.editorExplain.withRun",
352358
"title": "Run and explain statement",
@@ -598,16 +604,21 @@
598604
],
599605
"editor/title": [
600606
{
601-
"when": "editorLangId == sql && code-for-ibmi:connected == true",
602-
"group": "navigation@sql",
607+
"when": "editorLangId == sql && code-for-ibmi:connected == true && vscode-db2i:statementCanCancel != true",
608+
"group": "navigation@1",
603609
"submenu": "sql/editor/context"
610+
},
611+
{
612+
"command": "vscode-db2i.statement.cancel",
613+
"when": "editorLangId == sql && vscode-db2i:statementCanCancel == true",
614+
"group": "navigation@1"
604615
}
605616
],
606617
"sql/editor/context": [
607618
{
608619
"command": "vscode-db2i.runEditorStatement",
609-
"when": "editorLangId == sql",
610-
"group": "1_general@sql"
620+
"when": "editorLangId == sql && vscode-db2i:statementCanCancel != true",
621+
"group": "navigation@1"
611622
},
612623
{
613624
"command": "vscode-db2i.editorExplain.withRun",

src/connection/manager.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ export interface JobInfo {
1111
job: SQLJob;
1212
}
1313

14+
const NO_SELECTED_JOB = -1;
15+
1416
export class SQLJobManager {
1517
private totalJobs = 0;
1618
private jobs: JobInfo[] = [];
17-
selectedJob: number = -1;
19+
selectedJob: number = NO_SELECTED_JOB;
1820

1921
constructor() { }
2022

@@ -50,13 +52,13 @@ export class SQLJobManager {
5052
}
5153

5254
getRunningJobs() {
53-
return this.jobs.filter(info => [JobStatus.Ready, JobStatus.Active].includes(info.job.getStatus()));
55+
return this.jobs.filter(info => [JobStatus.Ready, JobStatus.Busy].includes(info.job.getStatus()));
5456
}
5557

5658
async endAll() {
5759
await Promise.all(this.jobs.map(current => current.job.close()));
5860
this.jobs = [];
59-
this.selectedJob = -1;
61+
this.selectedJob = NO_SELECTED_JOB;
6062
}
6163

6264
async closeJob(index?: number) {
@@ -86,12 +88,12 @@ export class SQLJobManager {
8688
return this.jobs.find(info => info.name === name);
8789
}
8890

89-
setSelection(selectedName: string): boolean {
91+
setSelection(selectedName: string): JobInfo|undefined {
9092
const jobExists = this.jobs.findIndex(info => info.name === selectedName);
9193

9294
this.selectedJob = jobExists;
9395

94-
return (this.selectedJob >= 0);
96+
return this.jobs[jobExists];
9597
}
9698

9799
/**
@@ -103,7 +105,6 @@ export class SQLJobManager {
103105
* @returns
104106
*/
105107
async runSQL<T>(query: string, opts?: QueryOptions): Promise<T[]> {
106-
107108
// 2147483647 is NOT arbitrary. On the server side, this is processed as a Java
108109
// int. This is the largest number available without overflow (Integer.MAX_VALUE)
109110
const rowsToFetch = 2147483647;

src/connection/sqlJob.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { CommandResult } from "@halcyontech/vscode-ibmi-types";
21
import { getInstance } from "../base";
32
import { ServerComponent } from "./serverComponent";
43
import { JDBCOptions, ConnectionResult, Rows, QueryResult, JobLogEntry, CLCommandResult, VersionCheckResult, GetTraceDataResult, ServerTraceDest, ServerTraceLevel, SetConfigResult, QueryOptions, ExplainResults } from "./types";
@@ -8,7 +7,7 @@ import { EventEmitter } from "stream";
87
export enum JobStatus {
98
NotStarted = "notStarted",
109
Ready = "ready",
11-
Active = "active",
10+
Busy = "busy",
1211
Ended = "ended"
1312
}
1413

@@ -36,7 +35,6 @@ const TransactionCountQuery = [
3635
const DB2I_VERSION = (process.env[`DB2I_VERSION`] || `<version unknown>`) + ((process.env.DEV) ? ``:`-dev`);
3736

3837
export class SQLJob {
39-
4038
private static uniqueIdCounter: number = 0;
4139
private channel: any;
4240
private responseEmitter: EventEmitter = new EventEmitter();
@@ -130,7 +128,6 @@ export class SQLJob {
130128

131129
let req: ReqRespFmt = JSON.parse(content);
132130
this.channel.stdin.write(content + `\n`);
133-
this.status = JobStatus.Active;
134131
return new Promise((resolve, reject) => {
135132
this.responseEmitter.on(req.id, (x: string) => {
136133
this.responseEmitter.removeAllListeners(req.id);
@@ -140,7 +137,9 @@ export class SQLJob {
140137
}
141138

142139
getStatus() {
143-
return this.status;
140+
const currentListenerCount = this.responseEmitter.eventNames().length;
141+
142+
return currentListenerCount > 0 ? JobStatus.Busy : this.status;
144143
}
145144

146145
async connect(): Promise<ConnectionResult> {
@@ -204,6 +203,20 @@ export class SQLJob {
204203
return new Query(this, sql, opts);
205204
}
206205

206+
async requestCancel(): Promise<boolean> {
207+
const instance = getInstance();
208+
const content = instance.getContent();
209+
210+
// Note that this statement is run via the base extension since it has to be done on a job other than the one whose SQL is getting canceled
211+
await content.runSQL(`CALL QSYS2.CANCEL_SQL('${this.id}')`);
212+
213+
const [row] = await content.runSQL(`select V_SQL_STMT_STATUS as STATUS from table(qsys2.get_job_info('${this.id}'))`) as {STATUS: string|null}[];
214+
215+
if (row && row.STATUS === `ACTIVE`) return false;
216+
217+
return true;
218+
}
219+
207220
async getVersion(): Promise<VersionCheckResult> {
208221
const verObj = {
209222
id: SQLJob.getNewUniqueId(),
@@ -304,7 +317,7 @@ export class SQLJob {
304317
}
305318

306319
underCommitControl() {
307-
return this.options["transaction isolation"] !== `none`;
320+
return this.options["transaction isolation"] && this.options["transaction isolation"] !== `none`;
308321
}
309322

310323
async getPendingTransactions() {

src/views/jobManager/jobManagerView.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import vscode, { ProgressLocation, TreeDataProvider, TreeItemCollapsibleState, U
22
import { JobManager } from "../../config";
33
import { JobInfo } from "../../connection/manager";
44
import { ServerComponent } from "../../connection/serverComponent";
5-
import { SQLJob, TransactionEndType } from "../../connection/sqlJob";
5+
import { JobStatus, SQLJob, TransactionEndType } from "../../connection/sqlJob";
66
import { JDBCOptions, ServerTraceDest, ServerTraceLevel } from "../../connection/types";
77
import { ConfigGroup, ConfigManager } from "./ConfigManager";
88
import { editJobUi } from "./editJob";
99
import { displayJobLog } from "./jobLog";
1010
import { selfCodesMap } from "./selfCodes/selfCodes";
1111
import { SelfCodesQuickPickItem } from "./selfCodes/selfCodesBrowser";
1212
import { updateStatusBar } from "./statusBar";
13+
import { setCancelButtonVisibility } from "../results";
1314

1415
const selectJobCommand = `vscode-db2i.jobManager.selectJob`;
1516
const activeColor = new vscode.ThemeColor(`minimapGutter.addedBackground`);
@@ -302,6 +303,9 @@ export class JobManagerView implements TreeDataProvider<any> {
302303
refresh() {
303304
this._onDidChangeTreeData.fire();
304305
updateStatusBar();
306+
307+
const selectedJob = JobManager.getSelection();
308+
setCancelButtonVisibility(selectedJob && selectedJob.job.getStatus() === JobStatus.Busy);
305309
}
306310

307311
getTreeItem(element: vscode.TreeItem) {

src/views/jobManager/statusBar.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getInstance } from "../../base";
55

66
const item = window.createStatusBarItem(`sqlJob`, StatusBarAlignment.Left);
77

8-
export async function updateStatusBar(options: {newJob?: boolean} = {}) {
8+
export async function updateStatusBar(options: {newJob?: boolean, canceling?: boolean, jobIsBusy?: boolean, executing?: boolean} = {}) {
99
const instance = getInstance();
1010
const connection = instance.getConnection();
1111

@@ -16,6 +16,15 @@ export async function updateStatusBar(options: {newJob?: boolean} = {}) {
1616
let backgroundColour: ThemeColor|undefined = undefined;
1717
let toolTipItems = [];
1818

19+
if (options.executing) {
20+
text = `$(sync~spin) Executing...`;
21+
} else
22+
if (options.canceling) {
23+
text = `$(sync~spin) Canceling...`;
24+
} else
25+
if (options.jobIsBusy) {
26+
text = `🙁 Job is busy`;
27+
} else
1928
if (options.newJob) {
2029
text = `$(sync~spin) Spinning up job...`;
2130
} else

0 commit comments

Comments
 (0)