dbgate-api-premium 6.6.1 → 6.6.2

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.
@@ -8,7 +8,13 @@ const { handleProcessCommunication } = require('../utility/processComm');
8
8
  const lock = new AsyncLock();
9
9
  const config = require('./config');
10
10
  const processArgs = require('../utility/processArgs');
11
- const { testConnectionPermission } = require('../utility/hasPermission');
11
+ const {
12
+ testConnectionPermission,
13
+ loadPermissionsFromRequest,
14
+ hasPermission,
15
+ loadDatabasePermissionsFromRequest,
16
+ getDatabasePermissionRole,
17
+ } = require('../utility/hasPermission');
12
18
  const { MissingCredentialsError } = require('../utility/exceptions');
13
19
  const pipeForkLogs = require('../utility/pipeForkLogs');
14
20
  const { getLogger, extractErrorLogData } = require('dbgate-tools');
@@ -40,7 +46,7 @@ module.exports = {
40
46
  existing.status = status;
41
47
  socket.emitChanged(`server-status-changed`);
42
48
  },
43
- handle_ping() {},
49
+ handle_ping() { },
44
50
  handle_response(conid, { msgid, ...response }) {
45
51
  const [resolve, reject] = this.requests[msgid];
46
52
  resolve(response);
@@ -135,7 +141,7 @@ module.exports = {
135
141
 
136
142
  disconnect_meta: true,
137
143
  async disconnect({ conid }, req) {
138
- testConnectionPermission(conid, req);
144
+ await testConnectionPermission(conid, req);
139
145
  await this.close(conid, true);
140
146
  return { status: 'ok' };
141
147
  },
@@ -144,7 +150,9 @@ module.exports = {
144
150
  async listDatabases({ conid }, req) {
145
151
  if (!conid) return [];
146
152
  if (conid == '__model') return [];
147
- testConnectionPermission(conid, req);
153
+ const loadedPermissions = await loadPermissionsFromRequest(req);
154
+
155
+ await testConnectionPermission(conid, req, loadedPermissions);
148
156
  const opened = await this.ensureOpened(conid);
149
157
  sendToAuditLog(req, {
150
158
  category: 'serverop',
@@ -157,12 +165,29 @@ module.exports = {
157
165
  sessionGroup: 'listDatabases',
158
166
  message: `Loaded databases for connection`,
159
167
  });
168
+
169
+ if (!hasPermission(`all-databases`, loadedPermissions)) {
170
+ // filter databases by permissions
171
+ const databasePermissions = await loadDatabasePermissionsFromRequest(req);
172
+ const res = [];
173
+ for (const db of opened?.databases ?? []) {
174
+ const databasePermissionRole = getDatabasePermissionRole(db.id, db.name, databasePermissions);
175
+ if (databasePermissionRole != 'deny') {
176
+ res.push({
177
+ ...db,
178
+ databasePermissionRole,
179
+ });
180
+ }
181
+ }
182
+ return res;
183
+ }
184
+
160
185
  return opened?.databases ?? [];
161
186
  },
162
187
 
163
188
  version_meta: true,
164
189
  async version({ conid }, req) {
165
- testConnectionPermission(conid, req);
190
+ await testConnectionPermission(conid, req);
166
191
  const opened = await this.ensureOpened(conid);
167
192
  return opened?.version ?? null;
168
193
  },
@@ -202,7 +227,7 @@ module.exports = {
202
227
 
203
228
  refresh_meta: true,
204
229
  async refresh({ conid, keepOpen }, req) {
205
- testConnectionPermission(conid, req);
230
+ await testConnectionPermission(conid, req);
206
231
  if (!keepOpen) this.close(conid);
207
232
 
208
233
  await this.ensureOpened(conid);
@@ -210,7 +235,7 @@ module.exports = {
210
235
  },
211
236
 
212
237
  async sendDatabaseOp({ conid, msgtype, name }, req) {
213
- testConnectionPermission(conid, req);
238
+ await testConnectionPermission(conid, req);
214
239
  const opened = await this.ensureOpened(conid);
215
240
  if (!opened) {
216
241
  return null;
@@ -252,7 +277,7 @@ module.exports = {
252
277
  },
253
278
 
254
279
  async loadDataCore(msgtype, { conid, ...args }, req) {
255
- testConnectionPermission(conid, req);
280
+ await testConnectionPermission(conid, req);
256
281
  const opened = await this.ensureOpened(conid);
257
282
  if (!opened) {
258
283
  return null;
@@ -270,13 +295,43 @@ module.exports = {
270
295
 
271
296
  serverSummary_meta: true,
272
297
  async serverSummary({ conid }, req) {
273
- testConnectionPermission(conid, req);
298
+ await testConnectionPermission(conid, req);
299
+ logger.info({ conid }, 'DBGM-00260 Processing server summary');
274
300
  return this.loadDataCore('serverSummary', { conid });
275
301
  },
276
302
 
303
+ listDatabaseProcesses_meta: true,
304
+ async listDatabaseProcesses(ctx, req) {
305
+ const { conid } = ctx;
306
+ // logger.info({ conid }, 'DBGM-00261 Listing processes of database server');
307
+ testConnectionPermission(conid, req);
308
+
309
+ const opened = await this.ensureOpened(conid);
310
+ if (!opened) {
311
+ return null;
312
+ }
313
+ if (opened.connection.isReadOnly) return false;
314
+
315
+ return this.sendRequest(opened, { msgtype: 'listDatabaseProcesses' });
316
+ },
317
+
318
+ killDatabaseProcess_meta: true,
319
+ async killDatabaseProcess(ctx, req) {
320
+ const { conid, pid } = ctx;
321
+ testConnectionPermission(conid, req);
322
+
323
+ const opened = await this.ensureOpened(conid);
324
+ if (!opened) {
325
+ return null;
326
+ }
327
+ if (opened.connection.isReadOnly) return false;
328
+
329
+ return this.sendRequest(opened, { msgtype: 'killDatabaseProcess', pid });
330
+ },
331
+
277
332
  summaryCommand_meta: true,
278
333
  async summaryCommand({ conid, command, row }, req) {
279
- testConnectionPermission(conid, req);
334
+ await testConnectionPermission(conid, req);
280
335
  const opened = await this.ensureOpened(conid);
281
336
  if (!opened) {
282
337
  return null;
@@ -12,6 +12,7 @@ const { getLogger, extractErrorLogData } = require('dbgate-tools');
12
12
  const pipeForkLogs = require('../utility/pipeForkLogs');
13
13
  const config = require('./config');
14
14
  const { sendToAuditLog } = require('../utility/auditlog');
15
+ const { testStandardPermission, testDatabaseRolePermission } = require('../utility/hasPermission');
15
16
 
16
17
  const logger = getLogger('sessions');
17
18
 
@@ -94,7 +95,7 @@ module.exports = {
94
95
  socket.emit(`session-initialize-file-${jslid}`);
95
96
  },
96
97
 
97
- handle_ping() {},
98
+ handle_ping() { },
98
99
 
99
100
  create_meta: true,
100
101
  async create({ conid, database }) {
@@ -148,10 +149,12 @@ module.exports = {
148
149
 
149
150
  executeQuery_meta: true,
150
151
  async executeQuery({ sesid, sql, autoCommit, autoDetectCharts, limitRows, frontMatter }, req) {
152
+ await testStandardPermission('dbops/query', req);
151
153
  const session = this.opened.find(x => x.sesid == sesid);
152
154
  if (!session) {
153
155
  throw new Error('Invalid session');
154
156
  }
157
+ await testDatabaseRolePermission(session.conid, session.database, 'run_script', req);
155
158
 
156
159
  sendToAuditLog(req, {
157
160
  category: 'dbop',
@@ -2,20 +2,20 @@ const fs = require('fs-extra');
2
2
  const _ = require('lodash');
3
3
  const path = require('path');
4
4
  const { setAuthProviders, getAuthProviderById } = require('../auth/authProvider');
5
- const { createStorageAuthProvider } = require('../auth/storageAuthProvider');
5
+ const { createStorageAuthProvider, SuperadminAuthProvider } = require('../auth/storageAuthProvider');
6
6
  const {
7
7
  getStorageConnection,
8
8
  getDbConnectionParams,
9
9
  storageSelectFmt,
10
10
  storageReadUserRolePermissions,
11
- loadSuperadminPermissions,
12
11
  storageReadConfig,
13
12
  storageWriteConfig,
14
13
  getStorageConnectionError,
15
14
  storageSaveRelationDiff,
16
15
  selectStorageIdentity,
16
+ storageSaveDetailPermissionsDiff,
17
17
  } = require('./storageDb');
18
- const { hasPermission } = require('../utility/hasPermission');
18
+ const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
19
19
  const { changeSetToSql, removeSchemaFromChangeSet } = require('dbgate-datalib');
20
20
  const storageModel = require('../storageModel');
21
21
  const { dumpSqlCommand, dumpSqlSelect, createLogCompoudCondition } = require('dbgate-sqltree');
@@ -64,6 +64,7 @@ module.exports = {
64
64
  if (defIndex < 0) {
65
65
  defIndex = enabledConfig.findIndex(x => x.type == 'local');
66
66
  }
67
+ providers.push(new SuperadminAuthProvider());
67
68
 
68
69
  setAuthProviders(providers, providers[defIndex]);
69
70
 
@@ -112,6 +113,7 @@ module.exports = {
112
113
 
113
114
  connections_meta: true,
114
115
  async connections(req) {
116
+ const loadedPermissions = await loadPermissionsFromRequest(req);
115
117
  if (!process.env.STORAGE_DATABASE) {
116
118
  return null;
117
119
  }
@@ -121,7 +123,7 @@ module.exports = {
121
123
 
122
124
  let resp = null;
123
125
 
124
- if (hasPermission('all-connections', req)) {
126
+ if (hasPermission('all-connections', loadedPermissions)) {
125
127
  resp = await storageSelectFmt(`select ~connections.* from ~connections`);
126
128
  } else if (userId) {
127
129
  resp = await storageSelectFmt(
@@ -152,7 +154,7 @@ module.exports = {
152
154
  return [];
153
155
  }
154
156
  const res = [];
155
- if (hasPermission('internal-storage', req)) {
157
+ if (hasPermission('internal-storage', loadedPermissions)) {
156
158
  res.push(await this.getConnection({ conid: '__storage' }));
157
159
  }
158
160
  if (resp) {
@@ -329,10 +331,6 @@ module.exports = {
329
331
  return storageReadUserRolePermissions(userId);
330
332
  },
331
333
 
332
- async loadSuperadminPermissions() {
333
- return loadSuperadminPermissions();
334
- },
335
-
336
334
  getConnectionsForLoginPage_meta: true,
337
335
  getConnectionsForLoginPage({ amoid }) {
338
336
  return getAuthProviderById(amoid).getLoginPageConnections();
@@ -487,6 +485,10 @@ module.exports = {
487
485
  : (await storageSelectFmt('select ~connection_id from ~user_connections where ~user_id = %v', id)).map(
488
486
  x => x.connection_id
489
487
  );
488
+ const databasePermissions =
489
+ id == 'new' ? [] : await storageSelectFmt('select * from ~user_databases where ~user_id = %v', id);
490
+ const tablePermissions =
491
+ id == 'new' ? [] : await storageSelectFmt('select * from ~user_tables where ~user_id = %v', id);
490
492
 
491
493
  return {
492
494
  ...resp[0],
@@ -496,6 +498,8 @@ module.exports = {
496
498
  usedRoles,
497
499
  allConnections,
498
500
  usedConnections,
501
+ databasePermissions,
502
+ tablePermissions,
499
503
  encryptPassword: !!(resp[0]?.password?.startsWith('crypt:') || id == 'new'),
500
504
  };
501
505
  },
@@ -504,7 +508,8 @@ module.exports = {
504
508
  async saveUserDetail(user) {
505
509
  const [conn, driver] = await getStorageConnection();
506
510
 
507
- const { login, password, email, usedRoles, usedConnections, permissions } = encryptUser(user);
511
+ const { login, password, email, usedRoles, usedConnections, permissions, databasePermissions, tablePermissions } =
512
+ encryptUser(user);
508
513
  let id = user.id;
509
514
 
510
515
  if (id == null) {
@@ -533,6 +538,32 @@ module.exports = {
533
538
  await storageSaveRelationDiff('user_roles', 'user_id', 'role_id', id, usedRoles);
534
539
  await storageSaveRelationDiff('user_connections', 'user_id', 'connection_id', id, usedConnections);
535
540
 
541
+ await storageSaveDetailPermissionsDiff(
542
+ 'user_databases',
543
+ 'user_id',
544
+ id,
545
+ ['connection_id', 'database_names_list', 'database_names_regex', 'database_permission_role_id'],
546
+ databasePermissions
547
+ );
548
+
549
+ await storageSaveDetailPermissionsDiff(
550
+ 'user_tables',
551
+ 'user_id',
552
+ id,
553
+ [
554
+ 'connection_id',
555
+ 'database_names_list',
556
+ 'database_names_regex',
557
+ 'schema_names_list',
558
+ 'schema_names_regex',
559
+ 'table_names_list',
560
+ 'table_names_regex',
561
+ 'table_permission_role_id',
562
+ 'table_permission_scope_id',
563
+ ],
564
+ tablePermissions
565
+ );
566
+
536
567
  return true;
537
568
  },
538
569
 
@@ -677,6 +708,11 @@ module.exports = {
677
708
  : (await storageSelectFmt('select ~connection_id from ~role_connections where ~role_id = %v', id)).map(
678
709
  x => x.connection_id
679
710
  );
711
+ const databasePermissions =
712
+ id == 'new' ? [] : await storageSelectFmt('select * from ~role_databases where ~role_id = %v', id);
713
+ const tablePermissions =
714
+ id == 'new' ? [] : await storageSelectFmt('select * from ~role_tables where ~role_id = %v', id);
715
+
680
716
 
681
717
  return {
682
718
  ...resp[0],
@@ -686,6 +722,8 @@ module.exports = {
686
722
  usedUsers,
687
723
  allConnections,
688
724
  usedConnections,
725
+ databasePermissions,
726
+ tablePermissions,
689
727
  };
690
728
  },
691
729
 
@@ -705,7 +743,7 @@ module.exports = {
705
743
  async saveRoleDetail(role) {
706
744
  const [conn, driver] = await getStorageConnection();
707
745
 
708
- const { name, usedConnections, usedUsers, permissions } = encryptUser(role);
746
+ const { name, usedConnections, usedUsers, permissions, databasePermissions, tablePermissions } = role;
709
747
  let id = role.id;
710
748
 
711
749
  if (id == null) {
@@ -721,6 +759,32 @@ module.exports = {
721
759
  await storageSaveRelationDiff('user_roles', 'role_id', 'user_id', id, usedUsers);
722
760
  await storageSaveRelationDiff('role_connections', 'role_id', 'connection_id', id, usedConnections);
723
761
 
762
+ await storageSaveDetailPermissionsDiff(
763
+ 'role_databases',
764
+ 'role_id',
765
+ id,
766
+ ['connection_id', 'database_names_list', 'database_names_regex', 'database_permission_role_id'],
767
+ databasePermissions
768
+ );
769
+
770
+ await storageSaveDetailPermissionsDiff(
771
+ 'role_tables',
772
+ 'role_id',
773
+ id,
774
+ [
775
+ 'connection_id',
776
+ 'database_names_list',
777
+ 'database_names_regex',
778
+ 'schema_names_list',
779
+ 'schema_names_regex',
780
+ 'table_names_list',
781
+ 'table_names_regex',
782
+ 'table_permission_role_id',
783
+ 'table_permission_scope_id',
784
+ ],
785
+ tablePermissions
786
+ );
787
+
724
788
  return true;
725
789
  },
726
790
 
@@ -104,7 +104,9 @@ async function getStorageConnectionCore() {
104
104
  try {
105
105
  newConnection = await storageDriver.connect(dbConnectionParams);
106
106
  const version = await storageDriver.getVersion(newConnection);
107
- logger.info(`DBGM-00023 Connected to storage database ${dbConnectionParams.engine}, version ${version?.versionText}`);
107
+ logger.info(
108
+ `DBGM-00023 Connected to storage database ${dbConnectionParams.engine}, version ${version?.versionText}`
109
+ );
108
110
  storageConnectionError = null;
109
111
  } catch (err) {
110
112
  storageConnectionError = err;
@@ -217,6 +219,34 @@ async function storageReadRolePermissions(roleId) {
217
219
  return resp.map(x => x.permission);
218
220
  }
219
221
 
222
+ async function readComplexUserRolePermissions(userId, userPermissionsTable, rolePermissionsTable) {
223
+ const rolePermissionsResp = await storageSelectFmt(
224
+ 'select * from %i where %i.~role_id in (select ~role_id from ~user_roles where ~user_roles.~user_id = %v)',
225
+ rolePermissionsTable,
226
+ rolePermissionsTable,
227
+ userId
228
+ );
229
+
230
+ const userPermissionsResp = await storageSelectFmt(
231
+ 'select * from %i where %i.~user_id = %v',
232
+ userPermissionsTable,
233
+ userPermissionsTable,
234
+ userId
235
+ );
236
+
237
+ return [...rolePermissionsResp, ...userPermissionsResp];
238
+ }
239
+
240
+ async function readComplexRolePermissions(roleId, rolePermissionsTable) {
241
+ const rolePermissionsResp = await storageSelectFmt(
242
+ 'select * from %i where %i.~role_id = %v',
243
+ rolePermissionsTable,
244
+ rolePermissionsTable,
245
+ roleId
246
+ );
247
+ return rolePermissionsResp;
248
+ }
249
+
220
250
  async function loadSuperadminPermissions() {
221
251
  const rolePermissions = await storageReadRolePermissions(-3);
222
252
  return [...getPredefinedPermissions('superadmin'), ...rolePermissions];
@@ -284,6 +314,57 @@ async function storageSaveRelationDiff(table, idColumn, valueColumn, idValue, ne
284
314
  }
285
315
  }
286
316
 
317
+ function sanitizePermissionCollectionRow(collectionRow, valueColumns) {
318
+ const res = {};
319
+ let hasValue = false;
320
+ for (const col of valueColumns) {
321
+ if (col.endsWith('_list') || col.endsWith('_regex')) {
322
+ res[col] = collectionRow[col]?.trim() ? collectionRow[col]?.trim() : null;
323
+ } else if (col.endsWith('_id')) {
324
+ res[col] = collectionRow[col] ? parseInt(collectionRow[col]) : null;
325
+ } else {
326
+ res[col] = collectionRow[col] || null;
327
+ }
328
+ if (res[col]) {
329
+ hasValue = true;
330
+ }
331
+ }
332
+ if (!hasValue) {
333
+ return null;
334
+ }
335
+ return res;
336
+ }
337
+
338
+ async function storageSaveDetailPermissionsDiff(table, idColumn, idValue, valueColumns, valuesCollection) {
339
+ const [conn, driver] = await getStorageConnection();
340
+ if (!conn) {
341
+ return null;
342
+ }
343
+
344
+ if (valuesCollection) {
345
+ // Delete existing database permissions for this user
346
+ await runQueryFmt(driver, conn, 'delete from %i where %i = %v', table, idColumn, idValue);
347
+
348
+ // Insert new database permissions
349
+ for (const collectionRow of valuesCollection) {
350
+ const sanitizedRow = sanitizePermissionCollectionRow(collectionRow, valueColumns);
351
+ if (!sanitizedRow) {
352
+ continue;
353
+ }
354
+ await runQueryFmt(
355
+ driver,
356
+ conn,
357
+ 'insert into %i (%i, %,i) values (%v, %,v)',
358
+ table,
359
+ idColumn,
360
+ valueColumns,
361
+ idValue,
362
+ valueColumns.map(col => sanitizedRow[col])
363
+ );
364
+ }
365
+ }
366
+ }
367
+
287
368
  function getStorageConnectionError() {
288
369
  return storageConnectionError;
289
370
  }
@@ -301,6 +382,33 @@ async function selectStorageIdentity(tableName) {
301
382
  return Object.entries(resp.rows[0])[0][1];
302
383
  }
303
384
 
385
+ async function storageCheckRoleConnectionAccess(roleId, conid) {
386
+ const resp = await storageSelectFmt(
387
+ 'select 1 from ~role_connections inner join ~connections on ~role_connections.~connection_id = ~connections.~id where ~role_connections.~role_id = %v and ~connections.~conid = %v',
388
+ roleId,
389
+ conid
390
+ );
391
+ return resp.length > 0;
392
+ }
393
+
394
+ async function storageCheckUserRoleConnectionAccess(userId, conid) {
395
+ const respByUser = await storageSelectFmt(
396
+ 'select 1 from ~user_connections inner join ~connections on ~user_connections.~connection_id = ~connections.~id where ~user_connections.~user_id = %v and ~connections.~conid = %v',
397
+ userId,
398
+ conid
399
+ );
400
+ const respByRole = await storageSelectFmt(
401
+ 'select 1 from ~role_connections inner join ~user_roles on ~role_connections.~role_id = ~user_roles.~role_id inner join ~connections on ~role_connections.~connection_id = ~connections.~id where ~user_roles.~user_id = %v and ~connections.~conid = %v',
402
+ userId,
403
+ conid
404
+ );
405
+ const respByLogged = await storageSelectFmt(
406
+ 'select 1 from ~role_connections inner join ~connections on ~role_connections.~connection_id = ~connections.~id where ~role_connections.~role_id = -2 and ~connections.~conid = %v',
407
+ conid
408
+ );
409
+ return respByUser.length > 0 || respByRole.length > 0 || respByLogged.length > 0;
410
+ }
411
+
304
412
  module.exports = {
305
413
  getStorageConnection,
306
414
  storageSelectFmt,
@@ -315,4 +423,9 @@ module.exports = {
315
423
  storageSqlCommandFmt,
316
424
  storageSaveRelationDiff,
317
425
  selectStorageIdentity,
426
+ storageSaveDetailPermissionsDiff,
427
+ readComplexUserRolePermissions,
428
+ readComplexRolePermissions,
429
+ storageCheckRoleConnectionAccess,
430
+ storageCheckUserRoleConnectionAccess,
318
431
  };
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '6.6.1',
4
- buildTime: '2025-08-14T15:32:48.560Z'
3
+ version: '6.6.2',
4
+ buildTime: '2025-08-29T07:26:38.959Z'
5
5
  };
package/src/index.js CHANGED
@@ -5,6 +5,7 @@ const moment = require('moment');
5
5
  const path = require('path');
6
6
  const { logsdir, setLogsFilePath, getLogsFilePath } = require('./utility/directories');
7
7
  const currentVersion = require('./currentVersion');
8
+ const _ = require('lodash');
8
9
 
9
10
  const logger = getLogger('apiIndex');
10
11
 
@@ -68,7 +69,7 @@ function configureLogger() {
68
69
  }
69
70
  const additionals = {};
70
71
  const finalMsg =
71
- msg.msg && msg.msg.match(/^DBGM-\d\d\d\d\d/)
72
+ _.isString(msg.msg) && msg.msg.match(/^DBGM-\d\d\d\d\d/)
72
73
  ? {
73
74
  ...msg,
74
75
  msg: msg.msg.substring(10).trimStart(),
@@ -17,13 +17,14 @@ const requireEngineDriver = require('../utility/requireEngineDriver');
17
17
  const { connectUtility } = require('../utility/connectUtility');
18
18
  const { handleProcessCommunication } = require('../utility/processComm');
19
19
  const generateDeploySql = require('../shell/generateDeploySql');
20
- const { dumpSqlSelect } = require('dbgate-sqltree');
20
+ const { dumpSqlSelect, scriptToSql } = require('dbgate-sqltree');
21
21
  const { allowExecuteCustomScript, handleQueryStream } = require('../utility/handleQueryStream');
22
22
  const dbgateApi = require('../shell');
23
23
  const requirePlugin = require('../shell/requirePlugin');
24
24
  const path = require('path');
25
25
  const { rundir } = require('../utility/directories');
26
26
  const fs = require('fs-extra');
27
+ const { changeSetToSql } = require('dbgate-datalib');
27
28
 
28
29
  const logger = getLogger('dbconnProcess');
29
30
 
@@ -348,6 +349,27 @@ async function handleUpdateCollection({ msgid, changeSet }) {
348
349
  }
349
350
  }
350
351
 
352
+ async function handleSaveTableData({ msgid, changeSet }) {
353
+ await waitStructure();
354
+ try {
355
+ const driver = requireEngineDriver(storedConnection);
356
+ const script = driver.createSaveChangeSetScript(changeSet, analysedStructure, () =>
357
+ changeSetToSql(changeSet, analysedStructure, driver.dialect)
358
+ );
359
+ const sql = scriptToSql(driver, script);
360
+ await driver.script(dbhan, sql, { useTransaction: true });
361
+ process.send({ msgtype: 'response', msgid });
362
+ } catch (err) {
363
+ process.send({
364
+ msgtype: 'response',
365
+ msgid,
366
+ errorMessage: extractErrorMessage(err, 'Error executing SQL script'),
367
+ });
368
+ }
369
+
370
+
371
+ }
372
+
351
373
  async function handleSqlPreview({ msgid, objects, options }) {
352
374
  await waitStructure();
353
375
  const driver = requireEngineDriver(storedConnection);
@@ -464,6 +486,7 @@ const messageHandlers = {
464
486
  runScript: handleRunScript,
465
487
  runOperation: handleRunOperation,
466
488
  updateCollection: handleUpdateCollection,
489
+ saveTableData: handleSaveTableData,
467
490
  collectionData: handleCollectionData,
468
491
  loadKeys: handleLoadKeys,
469
492
  scanKeys: handleScanKeys,
@@ -146,6 +146,30 @@ async function handleServerSummary({ msgid }) {
146
146
  return handleDriverDataCore(msgid, driver => driver.serverSummary(dbhan));
147
147
  }
148
148
 
149
+ async function handleKillDatabaseProcess({ msgid, pid }) {
150
+ await waitConnected();
151
+ const driver = requireEngineDriver(storedConnection);
152
+
153
+ try {
154
+ const result = await driver.killProcess(dbhan, Number(pid));
155
+ process.send({ msgtype: 'response', msgid, result });
156
+ } catch (err) {
157
+ process.send({ msgtype: 'response', msgid, errorMessage: err.message });
158
+ }
159
+ }
160
+
161
+ async function handleListDatabaseProcesses({ msgid }) {
162
+ await waitConnected();
163
+ const driver = requireEngineDriver(storedConnection);
164
+
165
+ try {
166
+ const result = await driver.listProcesses(dbhan);
167
+ process.send({ msgtype: 'response', msgid, result });
168
+ } catch (err) {
169
+ process.send({ msgtype: 'response', msgid, errorMessage: err.message });
170
+ }
171
+ }
172
+
149
173
  async function handleSummaryCommand({ msgid, command, row }) {
150
174
  return handleDriverDataCore(msgid, driver => driver.summaryCommand(dbhan, command, row));
151
175
  }
@@ -154,6 +178,8 @@ const messageHandlers = {
154
178
  connect: handleConnect,
155
179
  ping: handlePing,
156
180
  serverSummary: handleServerSummary,
181
+ killDatabaseProcess: handleKillDatabaseProcess,
182
+ listDatabaseProcesses: handleListDatabaseProcesses,
157
183
  summaryCommand: handleSummaryCommand,
158
184
  createDatabase: props => handleDatabaseOp('createDatabase', props),
159
185
  dropDatabase: props => handleDatabaseOp('dropDatabase', props),