dbgate-api-premium 6.3.3 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package.json +9 -7
  2. package/src/controllers/archive.js +99 -6
  3. package/src/controllers/config.js +135 -22
  4. package/src/controllers/connections.js +35 -2
  5. package/src/controllers/databaseConnections.js +76 -1
  6. package/src/controllers/files.js +59 -0
  7. package/src/controllers/jsldata.js +9 -0
  8. package/src/controllers/runners.js +25 -5
  9. package/src/controllers/serverConnections.js +17 -2
  10. package/src/controllers/storage.js +51 -1
  11. package/src/controllers/uploads.js +0 -46
  12. package/src/currentVersion.js +2 -2
  13. package/src/proc/connectProcess.js +14 -2
  14. package/src/proc/databaseConnectionProcess.js +70 -5
  15. package/src/proc/serverConnectionProcess.js +7 -1
  16. package/src/proc/sessionProcess.js +15 -178
  17. package/src/shell/archiveReader.js +3 -1
  18. package/src/shell/collectorWriter.js +2 -2
  19. package/src/shell/copyStream.js +1 -0
  20. package/src/shell/dataReplicator.js +96 -0
  21. package/src/shell/download.js +22 -6
  22. package/src/shell/index.js +12 -2
  23. package/src/shell/jsonLinesWriter.js +4 -3
  24. package/src/shell/queryReader.js +10 -3
  25. package/src/shell/unzipDirectory.js +91 -0
  26. package/src/shell/unzipJsonLinesData.js +60 -0
  27. package/src/shell/unzipJsonLinesFile.js +59 -0
  28. package/src/shell/zipDirectory.js +49 -0
  29. package/src/shell/zipJsonLinesData.js +49 -0
  30. package/src/utility/cloudUpgrade.js +14 -1
  31. package/src/utility/crypting.js +56 -5
  32. package/src/utility/extractSingleFileFromZip.js +77 -0
  33. package/src/utility/handleQueryStream.js +186 -0
  34. package/src/utility/listZipEntries.js +41 -0
  35. package/src/utility/storageReplicatorItems.js +88 -0
  36. package/src/shell/dataDuplicator.js +0 -61
@@ -8,7 +8,7 @@ const { fork, spawn } = require('child_process');
8
8
  const { rundir, uploadsdir, pluginsdir, getPluginBackendPath, packagedPluginList } = require('../utility/directories');
9
9
  const {
10
10
  extractShellApiPlugins,
11
- extractShellApiFunctionName,
11
+ compileShellApiFunctionName,
12
12
  jsonScriptToJavascript,
13
13
  getLogger,
14
14
  safeJsonParse,
@@ -58,7 +58,7 @@ dbgateApi.initializeApiEnvironment();
58
58
  ${requirePluginsTemplate(extractShellApiPlugins(functionName, props))}
59
59
  require=null;
60
60
  async function run() {
61
- const reader=await ${extractShellApiFunctionName(functionName)}(${JSON.stringify(props)});
61
+ const reader=await ${compileShellApiFunctionName(functionName)}(${JSON.stringify(props)});
62
62
  const writer=await dbgateApi.collectorWriter({runid: '${runid}'});
63
63
  await dbgateApi.copyStream(reader, writer);
64
64
  }
@@ -96,9 +96,9 @@ module.exports = {
96
96
 
97
97
  handle_ping() {},
98
98
 
99
- handle_freeData(runid, { freeData }) {
99
+ handle_dataResult(runid, { dataResult }) {
100
100
  const { resolve } = this.requests[runid];
101
- resolve(freeData);
101
+ resolve(dataResult);
102
102
  delete this.requests[runid];
103
103
  },
104
104
 
@@ -273,7 +273,7 @@ module.exports = {
273
273
  const runid = crypto.randomUUID();
274
274
 
275
275
  if (script.type == 'json') {
276
- const js = jsonScriptToJavascript(script);
276
+ const js = await jsonScriptToJavascript(script);
277
277
  return this.startCore(runid, scriptTemplate(js, false));
278
278
  }
279
279
 
@@ -328,4 +328,24 @@ module.exports = {
328
328
  });
329
329
  return promise;
330
330
  },
331
+
332
+ scriptResult_meta: true,
333
+ async scriptResult({ script }) {
334
+ if (script.type != 'json') {
335
+ return { errorMessage: 'Only JSON scripts are allowed' };
336
+ }
337
+
338
+ const promise = new Promise(async (resolve, reject) => {
339
+ const runid = crypto.randomUUID();
340
+ this.requests[runid] = { resolve, reject, exitOnStreamError: true };
341
+ const cloned = _.cloneDeepWith(script, node => {
342
+ if (node?.$replace == 'runid') {
343
+ return runid;
344
+ }
345
+ });
346
+ const js = await jsonScriptToJavascript(cloned);
347
+ this.startCore(runid, scriptTemplate(js, false));
348
+ });
349
+ return promise;
350
+ },
331
351
  };
@@ -54,6 +54,9 @@ module.exports = {
54
54
  if (!connection) {
55
55
  throw new Error(`Connection with conid="${conid}" not found`);
56
56
  }
57
+ if (connection.singleDatabase) {
58
+ return null;
59
+ }
57
60
  if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
58
61
  throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });
59
62
  }
@@ -142,14 +145,14 @@ module.exports = {
142
145
  if (conid == '__model') return [];
143
146
  testConnectionPermission(conid, req);
144
147
  const opened = await this.ensureOpened(conid);
145
- return opened.databases;
148
+ return opened?.databases ?? [];
146
149
  },
147
150
 
148
151
  version_meta: true,
149
152
  async version({ conid }, req) {
150
153
  testConnectionPermission(conid, req);
151
154
  const opened = await this.ensureOpened(conid);
152
- return opened.version;
155
+ return opened?.version ?? null;
153
156
  },
154
157
 
155
158
  serverStatus_meta: true,
@@ -170,6 +173,9 @@ module.exports = {
170
173
  }
171
174
  this.lastPinged[conid] = new Date().getTime();
172
175
  const opened = await this.ensureOpened(conid);
176
+ if (!opened) {
177
+ return Promise.resolve();
178
+ }
173
179
  try {
174
180
  opened.subprocess.send({ msgtype: 'ping' });
175
181
  } catch (err) {
@@ -194,6 +200,9 @@ module.exports = {
194
200
  async sendDatabaseOp({ conid, msgtype, name }, req) {
195
201
  testConnectionPermission(conid, req);
196
202
  const opened = await this.ensureOpened(conid);
203
+ if (!opened) {
204
+ return null;
205
+ }
197
206
  if (opened.connection.isReadOnly) return false;
198
207
  const res = await this.sendRequest(opened, { msgtype, name });
199
208
  if (res.errorMessage) {
@@ -233,6 +242,9 @@ module.exports = {
233
242
  async loadDataCore(msgtype, { conid, ...args }, req) {
234
243
  testConnectionPermission(conid, req);
235
244
  const opened = await this.ensureOpened(conid);
245
+ if (!opened) {
246
+ return null;
247
+ }
236
248
  const res = await this.sendRequest(opened, { msgtype, ...args });
237
249
  if (res.errorMessage) {
238
250
  console.error(res.errorMessage);
@@ -254,6 +266,9 @@ module.exports = {
254
266
  async summaryCommand({ conid, command, row }, req) {
255
267
  testConnectionPermission(conid, req);
256
268
  const opened = await this.ensureOpened(conid);
269
+ if (!opened) {
270
+ return null;
271
+ }
257
272
  if (opened.connection.isReadOnly) return false;
258
273
  return this.loadDataCore('summaryCommand', { conid, command, row });
259
274
  },
@@ -36,6 +36,8 @@ const {
36
36
  encryptPasswordString,
37
37
  } = require('../utility/crypting');
38
38
  const crypto = require('crypto');
39
+ const dataReplicator = require('../shell/dataReplicator');
40
+ const storageReplicatorItems = require('../utility/storageReplicatorItems');
39
41
 
40
42
  const logger = getLogger('storage');
41
43
 
@@ -597,6 +599,8 @@ module.exports = {
597
599
  );
598
600
  }
599
601
 
602
+ socket.emitChanged('connection-list-changed');
603
+
600
604
  return true;
601
605
  },
602
606
 
@@ -609,6 +613,8 @@ module.exports = {
609
613
 
610
614
  await runQueryFmt(driver, conn, 'delete from ~connections where ~id = %v', id);
611
615
 
616
+ socket.emitChanged('connection-list-changed');
617
+
612
618
  return true;
613
619
  },
614
620
 
@@ -627,7 +633,7 @@ module.exports = {
627
633
  const resp =
628
634
  id == 'new' ? {} : await storageSelectFmt(`select ~roles.~id,~roles.~name from ~roles where ~roles.~id = %v`, id);
629
635
 
630
- const basePermissions = getPredefinedPermissions(resp?.name ?? 'logged-user');
636
+ const basePermissions = getPredefinedPermissions(id < 0 && resp[0]?.name ? resp[0]?.name : 'logged-user');
631
637
  const permissions =
632
638
  id == 'new'
633
639
  ? []
@@ -692,4 +698,48 @@ module.exports = {
692
698
 
693
699
  return true;
694
700
  },
701
+
702
+ async getExportedDatabase() {
703
+ const connections = await storageSelectFmt(`select * from ~connections`);
704
+ const user_permissions = await storageSelectFmt(`select * from ~user_permissions`);
705
+ const users = await storageSelectFmt(`select * from ~users`);
706
+ const auth_methods = await storageSelectFmt(`select * from ~auth_methods`);
707
+ const role_connections = await storageSelectFmt(`select * from ~role_connections`);
708
+ const user_connections = await storageSelectFmt(`select * from ~user_connections`);
709
+ const user_roles = await storageSelectFmt(`select * from ~user_roles`);
710
+ const config = await storageSelectFmt(`select * from ~config`);
711
+ const auth_methods_config = await storageSelectFmt(`select * from ~auth_methods_config`);
712
+ const role_permissions = await storageSelectFmt(`select * from ~role_permissions`);
713
+ const roles = await storageSelectFmt(`select * from ~roles`);
714
+
715
+ return {
716
+ connections,
717
+ user_permissions,
718
+ users,
719
+ auth_methods,
720
+ role_connections,
721
+ user_connections,
722
+ user_roles,
723
+ config,
724
+ auth_methods_config,
725
+ role_permissions,
726
+ roles,
727
+ };
728
+ },
729
+
730
+ async replicateImportedDatabase(db) {
731
+ const [conn, driver] = await getStorageConnection();
732
+ // @ts-ignore
733
+ await dataReplicator({
734
+ systemConnection: conn,
735
+ driver,
736
+ items: storageReplicatorItems
737
+ .map(item => ({
738
+ ...item,
739
+ jsonArray: db[item.name],
740
+ }))
741
+ .filter(x => x.jsonArray),
742
+ });
743
+ socket.emitChanged('connection-list-changed');
744
+ },
695
745
  };
@@ -39,52 +39,6 @@ module.exports = {
39
39
  });
40
40
  },
41
41
 
42
- uploadDataFile_meta: {
43
- method: 'post',
44
- raw: true,
45
- },
46
- uploadDataFile(req, res) {
47
- const { data } = req.files || {};
48
-
49
- if (!data) {
50
- res.json(null);
51
- return;
52
- }
53
-
54
- if (data.name.toLowerCase().endsWith('.sql')) {
55
- logger.info(`Uploading SQL file ${data.name}, size=${data.size}`);
56
- data.mv(path.join(filesdir(), 'sql', data.name), () => {
57
- res.json({
58
- name: data.name,
59
- folder: 'sql',
60
- });
61
-
62
- socket.emitChanged(`files-changed`, { folder: 'sql' });
63
- socket.emitChanged(`all-files-changed`);
64
- });
65
- return;
66
- }
67
-
68
- res.json(null);
69
- },
70
-
71
- saveDataFile_meta: true,
72
- async saveDataFile({ filePath }) {
73
- if (filePath.toLowerCase().endsWith('.sql')) {
74
- logger.info(`Saving SQL file ${filePath}`);
75
- await fs.copyFile(filePath, path.join(filesdir(), 'sql', path.basename(filePath)));
76
-
77
- socket.emitChanged(`files-changed`, { folder: 'sql' });
78
- socket.emitChanged(`all-files-changed`);
79
- return {
80
- name: path.basename(filePath),
81
- folder: 'sql',
82
- };
83
- }
84
-
85
- return null;
86
- },
87
-
88
42
  get_meta: {
89
43
  method: 'get',
90
44
  raw: true,
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '6.3.3',
4
- buildTime: '2025-04-09T10:29:52.002Z'
3
+ version: '6.4.0',
4
+ buildTime: '2025-04-30T07:59:56.792Z'
5
5
  };
@@ -4,6 +4,8 @@ const { connectUtility } = require('../utility/connectUtility');
4
4
  const { handleProcessCommunication } = require('../utility/processComm');
5
5
  const { pickSafeConnectionInfo } = require('../utility/crypting');
6
6
  const _ = require('lodash');
7
+ const { getLogger, extractErrorLogData } = require('dbgate-tools');
8
+ const logger = getLogger('connectProcess');
7
9
 
8
10
  const formatErrorDetail = (e, connection) => `${e.stack}
9
11
 
@@ -23,12 +25,22 @@ function start() {
23
25
  try {
24
26
  const driver = requireEngineDriver(connection);
25
27
  const dbhan = await connectUtility(driver, connection, 'app');
26
- const res = await driver.getVersion(dbhan);
28
+ let version = {
29
+ version: 'Unknown',
30
+ };
31
+ try {
32
+ version = await driver.getVersion(dbhan);
33
+ } catch (err) {
34
+ logger.error(extractErrorLogData(err), 'Error getting DB server version');
35
+ version = {
36
+ version: 'Unknown',
37
+ };
38
+ }
27
39
  let databases = undefined;
28
40
  if (requestDbList) {
29
41
  databases = await driver.listDatabases(dbhan);
30
42
  }
31
- process.send({ msgtype: 'connected', ...res, databases });
43
+ process.send({ msgtype: 'connected', ...version, databases });
32
44
  await driver.close(dbhan);
33
45
  } catch (e) {
34
46
  console.error(e);
@@ -9,13 +9,21 @@ const {
9
9
  dbNameLogCategory,
10
10
  extractErrorMessage,
11
11
  extractErrorLogData,
12
+ ScriptWriterEval,
13
+ SqlGenerator,
14
+ playJsonScriptWriter,
12
15
  } = require('dbgate-tools');
13
16
  const requireEngineDriver = require('../utility/requireEngineDriver');
14
17
  const { connectUtility } = require('../utility/connectUtility');
15
18
  const { handleProcessCommunication } = require('../utility/processComm');
16
- const { SqlGenerator } = require('dbgate-tools');
17
19
  const generateDeploySql = require('../shell/generateDeploySql');
18
20
  const { dumpSqlSelect } = require('dbgate-sqltree');
21
+ const { allowExecuteCustomScript, handleQueryStream } = require('../utility/handleQueryStream');
22
+ const dbgateApi = require('../shell');
23
+ const requirePlugin = require('../shell/requirePlugin');
24
+ const path = require('path');
25
+ const { rundir } = require('../utility/directories');
26
+ const fs = require('fs-extra');
19
27
 
20
28
  const logger = getLogger('dbconnProcess');
21
29
 
@@ -120,10 +128,15 @@ function setStatusName(name) {
120
128
 
121
129
  async function readVersion() {
122
130
  const driver = requireEngineDriver(storedConnection);
123
- const version = await driver.getVersion(dbhan);
124
- logger.debug(`Got server version: ${version.version}`);
125
- process.send({ msgtype: 'version', version });
126
- serverVersion = version;
131
+ try {
132
+ const version = await driver.getVersion(dbhan);
133
+ logger.debug(`Got server version: ${version.version}`);
134
+ serverVersion = version;
135
+ } catch (err) {
136
+ logger.error(extractErrorLogData(err), 'Error getting DB server version');
137
+ serverVersion = { version: 'Unknown' };
138
+ }
139
+ process.send({ msgtype: 'version', version: serverVersion });
127
140
  }
128
141
 
129
142
  async function handleConnect({ connection, structure, globalSettings }) {
@@ -370,6 +383,56 @@ async function handleGenerateDeploySql({ msgid, modelFolder }) {
370
383
  }
371
384
  }
372
385
 
386
+ async function handleExecuteSessionQuery({ sesid, sql }) {
387
+ await waitConnected();
388
+ const driver = requireEngineDriver(storedConnection);
389
+
390
+ if (!allowExecuteCustomScript(storedConnection, driver)) {
391
+ process.send({
392
+ msgtype: 'info',
393
+ info: {
394
+ message: 'Connection without read-only sessions is read only',
395
+ severity: 'error',
396
+ },
397
+ sesid,
398
+ });
399
+ process.send({ msgtype: 'done', sesid, skipFinishedMessage: true });
400
+ return;
401
+ //process.send({ msgtype: 'error', error: e.message });
402
+ }
403
+
404
+ const queryStreamInfoHolder = {
405
+ resultIndex: 0,
406
+ canceled: false,
407
+ };
408
+ for (const sqlItem of splitQuery(sql, {
409
+ ...driver.getQuerySplitterOptions('stream'),
410
+ returnRichInfo: true,
411
+ })) {
412
+ await handleQueryStream(dbhan, driver, queryStreamInfoHolder, sqlItem, sesid);
413
+ if (queryStreamInfoHolder.canceled) {
414
+ break;
415
+ }
416
+ }
417
+ process.send({ msgtype: 'done', sesid });
418
+ }
419
+
420
+ async function handleEvalJsonScript({ script, runid }) {
421
+ const directory = path.join(rundir(), runid);
422
+ fs.mkdirSync(directory);
423
+ const originalCwd = process.cwd();
424
+
425
+ try {
426
+ process.chdir(directory);
427
+
428
+ const evalWriter = new ScriptWriterEval(dbgateApi, requirePlugin, dbhan, runid);
429
+ await playJsonScriptWriter(script, evalWriter);
430
+ process.send({ msgtype: 'runnerDone', runid });
431
+ } finally {
432
+ process.chdir(originalCwd);
433
+ }
434
+ }
435
+
373
436
  // async function handleRunCommand({ msgid, sql }) {
374
437
  // await waitConnected();
375
438
  // const driver = engines(storedConnection);
@@ -400,6 +463,8 @@ const messageHandlers = {
400
463
  sqlSelect: handleSqlSelect,
401
464
  exportKeys: handleExportKeys,
402
465
  schemaList: handleSchemaList,
466
+ executeSessionQuery: handleExecuteSessionQuery,
467
+ evalJsonScript: handleEvalJsonScript,
403
468
  // runCommand: handleRunCommand,
404
469
  };
405
470
 
@@ -46,7 +46,13 @@ async function handleRefresh() {
46
46
 
47
47
  async function readVersion() {
48
48
  const driver = requireEngineDriver(storedConnection);
49
- const version = await driver.getVersion(dbhan);
49
+ let version;
50
+ try {
51
+ version = await driver.getVersion(dbhan);
52
+ } catch (err) {
53
+ logger.error(extractErrorLogData(err), 'Error getting DB server version');
54
+ version = { version: 'Unknown' };
55
+ }
50
56
  process.send({ msgtype: 'version', version });
51
57
  }
52
58
 
@@ -11,6 +11,7 @@ const { decryptConnection } = require('../utility/crypting');
11
11
  const { connectUtility } = require('../utility/connectUtility');
12
12
  const { handleProcessCommunication } = require('../utility/processComm');
13
13
  const { getLogger, extractIntSettingsValue, extractBoolSettingsValue } = require('dbgate-tools');
14
+ const { handleQueryStream, QueryStreamTableWriter, allowExecuteCustomScript } = require('../utility/handleQueryStream');
14
15
 
15
16
  const logger = getLogger('sessionProcess');
16
17
 
@@ -23,175 +24,6 @@ let lastActivity = null;
23
24
  let currentProfiler = null;
24
25
  let executingScripts = 0;
25
26
 
26
- class TableWriter {
27
- constructor() {
28
- this.currentRowCount = 0;
29
- this.currentChangeIndex = 1;
30
- this.initializedFile = false;
31
- }
32
-
33
- initializeFromQuery(structure, resultIndex) {
34
- this.jslid = crypto.randomUUID();
35
- this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`);
36
- fs.writeFileSync(
37
- this.currentFile,
38
- JSON.stringify({
39
- ...structure,
40
- __isStreamHeader: true,
41
- }) + '\n'
42
- );
43
- this.currentStream = fs.createWriteStream(this.currentFile, { flags: 'a' });
44
- this.writeCurrentStats(false, false);
45
- this.resultIndex = resultIndex;
46
- this.initializedFile = true;
47
- process.send({ msgtype: 'recordset', jslid: this.jslid, resultIndex });
48
- }
49
-
50
- initializeFromReader(jslid) {
51
- this.jslid = jslid;
52
- this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`);
53
- this.writeCurrentStats(false, false);
54
- }
55
-
56
- row(row) {
57
- // console.log('ACCEPT ROW', row);
58
- this.currentStream.write(JSON.stringify(row) + '\n');
59
- this.currentRowCount += 1;
60
-
61
- if (!this.plannedStats) {
62
- this.plannedStats = true;
63
- process.nextTick(() => {
64
- if (this.currentStream) this.currentStream.uncork();
65
- process.nextTick(() => this.writeCurrentStats(false, true));
66
- this.plannedStats = false;
67
- });
68
- }
69
- }
70
-
71
- rowFromReader(row) {
72
- if (!this.initializedFile) {
73
- process.send({ msgtype: 'initializeFile', jslid: this.jslid });
74
- this.initializedFile = true;
75
-
76
- fs.writeFileSync(this.currentFile, JSON.stringify(row) + '\n');
77
- this.currentStream = fs.createWriteStream(this.currentFile, { flags: 'a' });
78
- this.writeCurrentStats(false, false);
79
- this.initializedFile = true;
80
- return;
81
- }
82
-
83
- this.row(row);
84
- }
85
-
86
- writeCurrentStats(isFinished = false, emitEvent = false) {
87
- const stats = {
88
- rowCount: this.currentRowCount,
89
- changeIndex: this.currentChangeIndex,
90
- isFinished,
91
- jslid: this.jslid,
92
- };
93
- fs.writeFileSync(`${this.currentFile}.stats`, JSON.stringify(stats));
94
- this.currentChangeIndex += 1;
95
- if (emitEvent) {
96
- process.send({ msgtype: 'stats', ...stats });
97
- }
98
- }
99
-
100
- close(afterClose) {
101
- if (this.currentStream) {
102
- this.currentStream.end(() => {
103
- this.writeCurrentStats(true, true);
104
- if (afterClose) afterClose();
105
- });
106
- }
107
- }
108
- }
109
-
110
- class StreamHandler {
111
- constructor(resultIndexHolder, resolve, startLine) {
112
- this.recordset = this.recordset.bind(this);
113
- this.startLine = startLine;
114
- this.row = this.row.bind(this);
115
- // this.error = this.error.bind(this);
116
- this.done = this.done.bind(this);
117
- this.info = this.info.bind(this);
118
-
119
- // use this for cancelling - not implemented
120
- // this.stream = null;
121
-
122
- this.plannedStats = false;
123
- this.resultIndexHolder = resultIndexHolder;
124
- this.resolve = resolve;
125
- // currentHandlers = [...currentHandlers, this];
126
- }
127
-
128
- closeCurrentWriter() {
129
- if (this.currentWriter) {
130
- this.currentWriter.close();
131
- this.currentWriter = null;
132
- }
133
- }
134
-
135
- recordset(columns) {
136
- this.closeCurrentWriter();
137
- this.currentWriter = new TableWriter();
138
- this.currentWriter.initializeFromQuery(
139
- Array.isArray(columns) ? { columns } : columns,
140
- this.resultIndexHolder.value
141
- );
142
- this.resultIndexHolder.value += 1;
143
-
144
- // this.writeCurrentStats();
145
-
146
- // this.onRow = _.throttle((jslid) => {
147
- // if (jslid == this.jslid) {
148
- // this.writeCurrentStats(false, true);
149
- // }
150
- // }, 500);
151
- }
152
- row(row) {
153
- if (this.currentWriter) this.currentWriter.row(row);
154
- else if (row.message) process.send({ msgtype: 'info', info: { message: row.message } });
155
- // this.onRow(this.jslid);
156
- }
157
- // error(error) {
158
- // process.send({ msgtype: 'error', error });
159
- // }
160
- done(result) {
161
- this.closeCurrentWriter();
162
- // currentHandlers = currentHandlers.filter((x) => x != this);
163
- this.resolve();
164
- }
165
- info(info) {
166
- if (info && info.line != null) {
167
- info = {
168
- ...info,
169
- line: this.startLine + info.line,
170
- };
171
- }
172
- process.send({ msgtype: 'info', info });
173
- }
174
- }
175
-
176
- function handleStream(driver, resultIndexHolder, sqlItem) {
177
- return new Promise((resolve, reject) => {
178
- const start = sqlItem.trimStart || sqlItem.start;
179
- const handler = new StreamHandler(resultIndexHolder, resolve, start && start.line);
180
- driver.stream(dbhan, sqlItem.text, handler);
181
- });
182
- }
183
-
184
- function allowExecuteCustomScript(driver) {
185
- if (driver.readOnlySessions) {
186
- return true;
187
- }
188
- if (storedConnection.isReadOnly) {
189
- return false;
190
- // throw new Error('Connection is read only');
191
- }
192
- return true;
193
- }
194
-
195
27
  async function handleConnect(connection) {
196
28
  storedConnection = connection;
197
29
 
@@ -222,12 +54,12 @@ async function handleStartProfiler({ jslid }) {
222
54
  await waitConnected();
223
55
  const driver = requireEngineDriver(storedConnection);
224
56
 
225
- if (!allowExecuteCustomScript(driver)) {
57
+ if (!allowExecuteCustomScript(storedConnection, driver)) {
226
58
  process.send({ msgtype: 'done' });
227
59
  return;
228
60
  }
229
61
 
230
- const writer = new TableWriter();
62
+ const writer = new QueryStreamTableWriter();
231
63
  writer.initializeFromReader(jslid);
232
64
 
233
65
  currentProfiler = await driver.startProfiler(dbhan, {
@@ -251,7 +83,7 @@ async function handleExecuteControlCommand({ command }) {
251
83
  await waitConnected();
252
84
  const driver = requireEngineDriver(storedConnection);
253
85
 
254
- if (command == 'commitTransaction' && !allowExecuteCustomScript(driver)) {
86
+ if (command == 'commitTransaction' && !allowExecuteCustomScript(storedConnection, driver)) {
255
87
  process.send({
256
88
  msgtype: 'info',
257
89
  info: {
@@ -291,7 +123,7 @@ async function handleExecuteQuery({ sql, autoCommit }) {
291
123
  await waitConnected();
292
124
  const driver = requireEngineDriver(storedConnection);
293
125
 
294
- if (!allowExecuteCustomScript(driver)) {
126
+ if (!allowExecuteCustomScript(storedConnection, driver)) {
295
127
  process.send({
296
128
  msgtype: 'info',
297
129
  info: {
@@ -306,18 +138,23 @@ async function handleExecuteQuery({ sql, autoCommit }) {
306
138
 
307
139
  executingScripts++;
308
140
  try {
309
- const resultIndexHolder = {
310
- value: 0,
141
+ const queryStreamInfoHolder = {
142
+ resultIndex: 0,
143
+ canceled: false,
311
144
  };
312
145
  for (const sqlItem of splitQuery(sql, {
313
146
  ...driver.getQuerySplitterOptions('stream'),
314
147
  returnRichInfo: true,
315
148
  })) {
316
- await handleStream(driver, resultIndexHolder, sqlItem);
149
+ await handleQueryStream(dbhan, driver, queryStreamInfoHolder, sqlItem);
317
150
  // const handler = new StreamHandler(resultIndex);
318
151
  // const stream = await driver.stream(systemConnection, sqlItem, handler);
319
152
  // handler.stream = stream;
320
153
  // resultIndex = handler.resultIndex;
154
+
155
+ if (queryStreamInfoHolder.canceled) {
156
+ break;
157
+ }
321
158
  }
322
159
  process.send({ msgtype: 'done', autoCommit });
323
160
  } finally {
@@ -335,13 +172,13 @@ async function handleExecuteReader({ jslid, sql, fileName }) {
335
172
  if (fileName) {
336
173
  sql = fs.readFileSync(fileName, 'utf-8');
337
174
  } else {
338
- if (!allowExecuteCustomScript(driver)) {
175
+ if (!allowExecuteCustomScript(storedConnection, driver)) {
339
176
  process.send({ msgtype: 'done' });
340
177
  return;
341
178
  }
342
179
  }
343
180
 
344
- const writer = new TableWriter();
181
+ const writer = new QueryStreamTableWriter();
345
182
  writer.initializeFromReader(jslid);
346
183
 
347
184
  const reader = await driver.readQuery(dbhan, sql);