query splitter refactor

This commit is contained in:
Jan Prochazka
2021-06-03 11:27:49 +02:00
parent a76e742ce6
commit 0c48a5ee09
26 changed files with 203 additions and 172 deletions

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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`);

View File

@@ -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;

View File

@@ -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,
};

View File

@@ -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) {

View File

@@ -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']);
});

View File

@@ -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 });
}
},
};

View File

@@ -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;

View File

@@ -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,