mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-30 17:24:00 +00:00
query splitter refactor
This commit is contained in:
@@ -112,6 +112,14 @@ module.exports = {
|
||||
return res;
|
||||
},
|
||||
|
||||
runScript_meta: 'post',
|
||||
async runScript({ conid, database, sql }) {
|
||||
console.log(`Processing script, conid=${conid}, database=${database}, sql=${sql}`);
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
const res = await this.sendRequest(opened, { msgtype: 'runScript', sql });
|
||||
return res;
|
||||
},
|
||||
|
||||
collectionData_meta: 'post',
|
||||
async collectionData({ conid, database, options }) {
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const stableStringify = require('json-stable-stringify');
|
||||
const { splitQuery } = require('dbgate-query-splitter');
|
||||
const childProcessChecker = require('../utility/childProcessChecker');
|
||||
const { extractBoolSettingsValue, extractIntSettingsValue } = require('dbgate-tools');
|
||||
const requireEngineDriver = require('../utility/requireEngineDriver');
|
||||
@@ -52,7 +53,7 @@ async function handleIncrementalRefresh(forceSend) {
|
||||
if (newStructure != null) {
|
||||
analysedStructure = newStructure;
|
||||
}
|
||||
|
||||
|
||||
if (forceSend || newStructure != null) {
|
||||
process.send({ msgtype: 'structure', structure: analysedStructure });
|
||||
}
|
||||
@@ -120,6 +121,17 @@ function waitConnected() {
|
||||
});
|
||||
}
|
||||
|
||||
async function handleRunScript({ msgid, sql }) {
|
||||
await waitConnected();
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
try {
|
||||
await driver.script(sql);
|
||||
process.send({ msgtype: 'response', msgid });
|
||||
} catch (err) {
|
||||
process.send({ msgtype: 'response', msgid, errorMessage: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
async function handleQueryData({ msgid, sql }) {
|
||||
await waitConnected();
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
@@ -188,6 +200,7 @@ function handlePing() {
|
||||
const messageHandlers = {
|
||||
connect: handleConnect,
|
||||
queryData: handleQueryData,
|
||||
runScript: handleRunScript,
|
||||
updateCollection: handleUpdateCollection,
|
||||
collectionData: handleCollectionData,
|
||||
sqlPreview: handleSqlPreview,
|
||||
|
||||
@@ -3,7 +3,7 @@ const path = require('path');
|
||||
const fs = require('fs');
|
||||
const _ = require('lodash');
|
||||
const childProcessChecker = require('../utility/childProcessChecker');
|
||||
const goSplit = require('../utility/goSplit');
|
||||
const { splitQuery } = require('dbgate-query-splitter');
|
||||
|
||||
const { jsldir } = require('../utility/directories');
|
||||
const requireEngineDriver = require('../utility/requireEngineDriver');
|
||||
@@ -166,7 +166,7 @@ async function handleExecuteQuery({ sql }) {
|
||||
const resultIndexHolder = {
|
||||
value: 0,
|
||||
};
|
||||
for (const sqlItem of goSplit(sql)) {
|
||||
for (const sqlItem of splitQuery(sql, driver.getQuerySplitterOptions('stream'))) {
|
||||
await handleStream(driver, resultIndexHolder, sqlItem);
|
||||
// const handler = new StreamHandler(resultIndex);
|
||||
// const stream = await driver.stream(systemConnection, sqlItem, handler);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const goSplit = require('../utility/goSplit');
|
||||
const { splitQuery } = require('dbgate-query-splitter');
|
||||
const requireEngineDriver = require('../utility/requireEngineDriver');
|
||||
const { decryptConnection } = require('../utility/crypting');
|
||||
const connectUtility = require('../utility/connectUtility');
|
||||
|
||||
async function executeQuery({ connection, sql }) {
|
||||
@@ -10,9 +9,9 @@ async function executeQuery({ connection, sql }) {
|
||||
const pool = await connectUtility(driver, connection);
|
||||
console.log(`Connected.`);
|
||||
|
||||
for (const sqlItem of goSplit(sql)) {
|
||||
for (const sqlItem of splitQuery(sql, driver.getQuerySplitterOptions('script'))) {
|
||||
console.log('Executing query', sqlItem);
|
||||
await driver.query(pool, sqlItem);
|
||||
await driver.query(pool, sqlItem, { discardResult: true });
|
||||
}
|
||||
|
||||
console.log(`Query finished`);
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
function goSplit(sql) {
|
||||
if (!sql) return [];
|
||||
const lines = sql.split('\n');
|
||||
const res = [];
|
||||
let buffer = '';
|
||||
for (const line of lines) {
|
||||
if (/^\s*go\s*$/i.test(line)) {
|
||||
if (buffer.trim()) res.push(buffer);
|
||||
buffer = '';
|
||||
} else {
|
||||
buffer += line + '\n';
|
||||
}
|
||||
}
|
||||
if (buffer.trim()) res.push(buffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
module.exports = goSplit;
|
||||
@@ -7,6 +7,7 @@ export interface SplitterOptions {
|
||||
allowCustomDelimiter: boolean;
|
||||
allowGoDelimiter: boolean;
|
||||
allowDollarDollarString: boolean;
|
||||
noSplit: boolean;
|
||||
}
|
||||
|
||||
export const defaultSplitterOptions: SplitterOptions = {
|
||||
@@ -18,6 +19,7 @@ export const defaultSplitterOptions: SplitterOptions = {
|
||||
allowCustomDelimiter: false,
|
||||
allowGoDelimiter: false,
|
||||
allowDollarDollarString: false,
|
||||
noSplit: false,
|
||||
};
|
||||
|
||||
export const mysqlSplitterOptions: SplitterOptions = {
|
||||
@@ -48,3 +50,17 @@ export const postgreSplitterOptions: SplitterOptions = {
|
||||
stringsEnds: { "'": "'", '"': '"' },
|
||||
stringEscapes: { "'": "'", '"': '"' },
|
||||
};
|
||||
|
||||
export const sqliteSplitterOptions: SplitterOptions = {
|
||||
...defaultSplitterOptions,
|
||||
|
||||
stringsBegins: ["'", '"'],
|
||||
stringsEnds: { "'": "'", '"': '"' },
|
||||
stringEscapes: { "'": "'", '"': '"' },
|
||||
};
|
||||
|
||||
export const noSplitSplitterOptions: SplitterOptions = {
|
||||
...defaultSplitterOptions,
|
||||
|
||||
noSplit: true,
|
||||
};
|
||||
|
||||
@@ -162,6 +162,15 @@ function pushQuery(context) {
|
||||
}
|
||||
|
||||
export function splitQuery(sql: string, options: SplitterOptions = null): string[] {
|
||||
const usedOptions = {
|
||||
...defaultSplitterOptions,
|
||||
...options,
|
||||
};
|
||||
|
||||
if (usedOptions.noSplit) {
|
||||
return [sql];
|
||||
}
|
||||
|
||||
const context: SplitExecutionContext = {
|
||||
source: sql,
|
||||
end: sql.length,
|
||||
@@ -170,10 +179,7 @@ export function splitQuery(sql: string, options: SplitterOptions = null): string
|
||||
currentCommandStart: 0,
|
||||
output: [],
|
||||
wasDataOnLine: false,
|
||||
options: {
|
||||
...defaultSplitterOptions,
|
||||
...options,
|
||||
},
|
||||
options: usedOptions,
|
||||
};
|
||||
|
||||
while (context.position < context.end) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mysqlSplitterOptions, mssqlSplitterOptions, postgreSplitterOptions } from './options';
|
||||
import { mysqlSplitterOptions, mssqlSplitterOptions, postgreSplitterOptions, noSplitSplitterOptions } from './options';
|
||||
import { splitQuery } from './splitQuery';
|
||||
|
||||
test('simple query', () => {
|
||||
@@ -71,3 +71,9 @@ test('go delimiter', () => {
|
||||
const output = splitQuery(input, mssqlSplitterOptions);
|
||||
expect(output).toEqual(['SELECT 1', 'SELECT 2']);
|
||||
});
|
||||
|
||||
test('no split', () => {
|
||||
const input = 'SELECT 1;SELECT 2';
|
||||
const output = splitQuery(input, noSplitSplitterOptions);
|
||||
expect(output).toEqual(['SELECT 1;SELECT 2']);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { SqlDumper } from './SqlDumper';
|
||||
import { splitQuery } from 'dbgate-query-splitter';
|
||||
|
||||
const dialect = {
|
||||
limitSelect: true,
|
||||
@@ -34,4 +35,9 @@ export const driverBase = {
|
||||
createDumper() {
|
||||
return new this.dumperClass(this);
|
||||
},
|
||||
async script(pool, sql) {
|
||||
for (const sqlItem of splitQuery(sql, this.getQuerySplitterOptions('script'))) {
|
||||
await this.query(pool, sqlItem, { discardResult: true });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
8
packages/types/engines.d.ts
vendored
8
packages/types/engines.d.ts
vendored
@@ -12,6 +12,10 @@ export interface StreamOptions {
|
||||
info?: (info) => void;
|
||||
}
|
||||
|
||||
export interface QueryOptions {
|
||||
discardResult?: boolean;
|
||||
}
|
||||
|
||||
export interface WriteTableOptions {
|
||||
dropIfExists?: boolean;
|
||||
truncate?: boolean;
|
||||
@@ -45,7 +49,7 @@ export interface EngineDriver {
|
||||
databaseUrlPlaceholder?: string;
|
||||
connect({ server, port, user, password, database }): Promise<any>;
|
||||
close(pool): Promise<any>;
|
||||
query(pool: any, sql: string): Promise<QueryResult>;
|
||||
query(pool: any, sql: string, options?: QueryOptions): Promise<QueryResult>;
|
||||
stream(pool: any, sql: string, options: StreamOptions);
|
||||
readQuery(pool: any, sql: string, structure?: TableInfo): Promise<stream.Readable>;
|
||||
writeTable(pool: any, name: NamedObjectInfo, options: WriteTableOptions): Promise<stream.Writeable>;
|
||||
@@ -73,6 +77,8 @@ export interface EngineDriver {
|
||||
updateCollection(pool: any, changeSet: any): Promise<any>;
|
||||
getCollectionUpdateScript(changeSet: any): string;
|
||||
createDatabase(pool: any, name: string): Promise;
|
||||
getQuerySplitterOptions(usage: 'stream' | 'script'): any;
|
||||
script(pool: any, sql: string): Promise;
|
||||
|
||||
analyserClass?: any;
|
||||
dumperClass?: any;
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
async function handleConfirmSql(sql) {
|
||||
const resp = await axiosInstance.request({
|
||||
url: 'database-connections/query-data',
|
||||
url: 'database-connections/run-script',
|
||||
method: 'post',
|
||||
params: {
|
||||
conid,
|
||||
|
||||
Reference in New Issue
Block a user