used transaction for save table data

This commit is contained in:
Jan Prochazka 2023-02-05 19:17:46 +01:00
parent 722789ca01
commit e9a01a1ffd
6 changed files with 38 additions and 10 deletions

View File

@ -171,11 +171,11 @@ module.exports = {
}, },
runScript_meta: true, runScript_meta: true,
async runScript({ conid, database, sql }, req) { async runScript({ conid, database, sql, useTransaction }, req) {
testConnectionPermission(conid, req); testConnectionPermission(conid, req);
logger.info({ conid, database, sql }, 'Processing script'); logger.info({ conid, database, sql }, 'Processing script');
const opened = await this.ensureOpened(conid, database); const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, { msgtype: 'runScript', sql }); const res = await this.sendRequest(opened, { msgtype: 'runScript', sql, useTransaction });
return res; return res;
}, },

View File

@ -158,12 +158,12 @@ function resolveAnalysedPromises() {
afterAnalyseCallbacks = []; afterAnalyseCallbacks = [];
} }
async function handleRunScript({ msgid, sql }, skipReadonlyCheck = false) { async function handleRunScript({ msgid, sql, useTransaction }, skipReadonlyCheck = false) {
await waitConnected(); await waitConnected();
const driver = requireEngineDriver(storedConnection); const driver = requireEngineDriver(storedConnection);
try { try {
if (!skipReadonlyCheck) ensureExecuteCustomScript(driver); if (!skipReadonlyCheck) ensureExecuteCustomScript(driver);
await driver.script(systemConnection, sql); await driver.script(systemConnection, sql, { useTransaction });
process.send({ msgtype: 'response', msgid }); process.send({ msgtype: 'response', msgid });
} catch (err) { } catch (err) {
process.send({ msgtype: 'response', msgid, errorMessage: err.message }); process.send({ msgtype: 'response', msgid, errorMessage: err.message });

View File

@ -533,6 +533,10 @@ export class SqlDumper implements AlterProcessor {
this.putCmd('^commit'); this.putCmd('^commit');
} }
rollbackTransaction() {
this.putCmd('^rollback');
}
alterProlog() {} alterProlog() {}
alterEpilog() {} alterEpilog() {}

View File

@ -2,6 +2,7 @@ import _compact from 'lodash/compact';
import { SqlDumper } from './SqlDumper'; import { SqlDumper } from './SqlDumper';
import { splitQuery } from 'dbgate-query-splitter'; import { splitQuery } from 'dbgate-query-splitter';
import { dumpSqlSelect } from 'dbgate-sqltree'; import { dumpSqlSelect } from 'dbgate-sqltree';
import { EngineDriver, RunScriptOptions } from 'dbgate-types';
const dialect = { const dialect = {
limitSelect: true, limitSelect: true,
@ -19,6 +20,12 @@ const dialect = {
defaultSchemaName: null, defaultSchemaName: null,
}; };
export async function runCommandOnDriver(pool, driver: EngineDriver, cmd: (dmp: SqlDumper) => void) {
const dmp = driver.createDumper();
cmd(dmp as any);
await driver.query(pool, dmp.s, { discardResult: true });
}
export const driverBase = { export const driverBase = {
analyserClass: null, analyserClass: null,
dumperClass: SqlDumper, dumperClass: SqlDumper,
@ -41,12 +48,25 @@ export const driverBase = {
const analyser = new this.analyserClass(pool, this, version); const analyser = new this.analyserClass(pool, this, version);
return analyser.incrementalAnalysis(structure); return analyser.incrementalAnalysis(structure);
}, },
createDumper(options = null) { createDumper(options = null): SqlDumper {
return new this.dumperClass(this, options); return new this.dumperClass(this, options);
}, },
async script(pool, sql) { async script(pool, sql, options: RunScriptOptions) {
if (options?.useTransaction) {
runCommandOnDriver(pool, this, dmp => dmp.beginTransaction());
}
for (const sqlItem of splitQuery(sql, this.getQuerySplitterOptions('script'))) { for (const sqlItem of splitQuery(sql, this.getQuerySplitterOptions('script'))) {
await this.query(pool, sqlItem, { discardResult: true }); try {
await this.query(pool, sqlItem, { discardResult: true });
} catch (err) {
if (options?.useTransaction) {
runCommandOnDriver(pool, this, dmp => dmp.rollbackTransaction());
}
throw err;
}
}
if (options?.useTransaction) {
runCommandOnDriver(pool, this, dmp => dmp.commitTransaction());
} }
}, },
getNewObjectTemplates() { getNewObjectTemplates() {
@ -113,5 +133,5 @@ export const driverBase = {
return this.readQuery(pool, dmp.s, structure); return this.readQuery(pool, dmp.s, structure);
}, },
showConnectionField: (field, values) => false, showConnectionField: (field, values) => false,
showConnectionTab: (field) => true, showConnectionTab: field => true,
}; };

View File

@ -12,6 +12,10 @@ export interface StreamOptions {
info?: (info) => void; info?: (info) => void;
} }
export interface RunScriptOptions {
useTransaction: boolean;
}
export interface QueryOptions { export interface QueryOptions {
discardResult?: boolean; discardResult?: boolean;
} }
@ -130,7 +134,7 @@ export interface EngineDriver {
createDatabase(pool: any, name: string): Promise; createDatabase(pool: any, name: string): Promise;
dropDatabase(pool: any, name: string): Promise; dropDatabase(pool: any, name: string): Promise;
getQuerySplitterOptions(usage: 'stream' | 'script' | 'editor'): any; getQuerySplitterOptions(usage: 'stream' | 'script' | 'editor'): any;
script(pool: any, sql: string): Promise; script(pool: any, sql: string, options?: RunScriptOptions): Promise;
getNewObjectTemplates(): NewObjectTemplate[]; getNewObjectTemplates(): NewObjectTemplate[];
// direct call of pool method, only some methods could be supported, on only some drivers // direct call of pool method, only some methods could be supported, on only some drivers
callMethod(pool, method, args); callMethod(pool, method, args);

View File

@ -121,7 +121,7 @@
const [changeSetStore, dispatchChangeSet] = createUndoReducer(createChangeSet()); const [changeSetStore, dispatchChangeSet] = createUndoReducer(createChangeSet());
async function handleConfirmSql(sql) { async function handleConfirmSql(sql) {
const resp = await apiCall('database-connections/run-script', { conid, database, sql }); const resp = await apiCall('database-connections/run-script', { conid, database, sql, useTransaction: true });
const { errorMessage } = resp || {}; const { errorMessage } = resp || {};
if (errorMessage) { if (errorMessage) {
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage }); showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });