diff --git a/packages/nodes-base/nodes/MySql/MySql.node.ts b/packages/nodes-base/nodes/MySql/MySql.node.ts index aad3df9bdce8a..30cbbaada0b12 100644 --- a/packages/nodes-base/nodes/MySql/MySql.node.ts +++ b/packages/nodes-base/nodes/MySql/MySql.node.ts @@ -11,7 +11,7 @@ export class MySql extends VersionedNodeType { name: 'mySql', icon: 'file:mysql.svg', group: ['input'], - defaultVersion: 2.3, + defaultVersion: 2.4, description: 'Get, add and update data in MySQL', parameterPane: 'wide', }; @@ -22,6 +22,7 @@ export class MySql extends VersionedNodeType { 2.1: new MySqlV2(baseDescription), 2.2: new MySqlV2(baseDescription), 2.3: new MySqlV2(baseDescription), + 2.4: new MySqlV2(baseDescription), }; super(nodeVersions, baseDescription); diff --git a/packages/nodes-base/nodes/MySql/test/v2/utils.test.ts b/packages/nodes-base/nodes/MySql/test/v2/utils.test.ts index 1f98b9adf2884..92bfa58ed0862 100644 --- a/packages/nodes-base/nodes/MySql/test/v2/utils.test.ts +++ b/packages/nodes-base/nodes/MySql/test/v2/utils.test.ts @@ -8,6 +8,7 @@ import { addSortRules, replaceEmptyStringsByNulls, escapeSqlIdentifier, + splitQueryToStatements, } from '../../v2/helpers/utils'; const mySqlMockNode: INode = { @@ -175,3 +176,29 @@ describe('Test MySql V2, escapeSqlIdentifier', () => { expect(escapedIdentifier).toEqual('`db_name`.`some.dotted.tbl_name`'); }); }); + +describe('Test MySql V2, splitQueryToStatements', () => { + it('should split query into statements', () => { + const query = + "insert into models (`created_at`, custom_ship_time, id) values ('2023-09-07 10:26:20', 'some random; data with a semicolon', 1); insert into models (`created_at`, custom_ship_time, id) values ('2023-09-07 10:27:55', 'random data without semicolon\n', 2);"; + + const statements = splitQueryToStatements(query); + + expect(statements).toBeDefined(); + expect(statements).toEqual([ + "insert into models (`created_at`, custom_ship_time, id) values ('2023-09-07 10:26:20', 'some random; data with a semicolon', 1)", + "insert into models (`created_at`, custom_ship_time, id) values ('2023-09-07 10:27:55', 'random data without semicolon', 2)", + ]); + }); + it('should not split by ; inside string literal', () => { + const query = + "SELECT custom_ship_time FROM models WHERE models.custom_ship_time LIKE CONCAT('%', ';', '%') LIMIT 10"; + + const statements = splitQueryToStatements(query); + + expect(statements).toBeDefined(); + expect(statements).toEqual([ + "SELECT custom_ship_time FROM models WHERE models.custom_ship_time LIKE CONCAT('%', ';', '%') LIMIT 10", + ]); + }); +}); diff --git a/packages/nodes-base/nodes/MySql/v2/actions/versionDescription.ts b/packages/nodes-base/nodes/MySql/v2/actions/versionDescription.ts index c1802bd063663..2c1b7b3e7db70 100644 --- a/packages/nodes-base/nodes/MySql/v2/actions/versionDescription.ts +++ b/packages/nodes-base/nodes/MySql/v2/actions/versionDescription.ts @@ -8,7 +8,7 @@ export const versionDescription: INodeTypeDescription = { name: 'mySql', icon: 'file:mysql.svg', group: ['input'], - version: [2, 2.1, 2.2, 2.3], + version: [2, 2.1, 2.2, 2.3, 2.4], subtitle: '={{ $parameter["operation"] }}', description: 'Get, add and update data in MySQL', defaults: { diff --git a/packages/nodes-base/nodes/MySql/v2/helpers/utils.ts b/packages/nodes-base/nodes/MySql/v2/helpers/utils.ts index be48ed42e64fd..40b0f30b9c9dc 100644 --- a/packages/nodes-base/nodes/MySql/v2/helpers/utils.ts +++ b/packages/nodes-base/nodes/MySql/v2/helpers/utils.ts @@ -190,6 +190,14 @@ export function prepareOutput( return returnData; } +const END_OF_STATEMENT = /;(?=(?:[^'\\]|'[^']*?'|\\[\s\S])*?$)/g; +export const splitQueryToStatements = (query: string, filterOutEmpty = true) => { + const statements = query + .replace(/\n/g, '') + .split(END_OF_STATEMENT) + .map((statement) => statement.trim()); + return filterOutEmpty ? statements.filter((statement) => statement !== '') : statements; +}; export function configureQueryRunner( this: IExecuteFunctions, @@ -225,10 +233,15 @@ export function configureQueryRunner( if (!response) return []; - const statements = singleQuery - .replace(/\n/g, '') - .split(';') - .filter((statement) => statement !== ''); + let statements; + if ((options?.nodeVersion as number) <= 2.3) { + statements = singleQuery + .replace(/\n/g, '') + .split(';') + .filter((statement) => statement !== ''); + } else { + statements = splitQueryToStatements(singleQuery); + } if (Array.isArray(response)) { if (statements.length === 1) response = [response]; @@ -261,7 +274,13 @@ export function configureQueryRunner( try { const { query, values } = queryWithValues; formatedQuery = connection.format(query, values); - const statements = formatedQuery.split(';').map((q) => q.trim()); + + let statements; + if ((options?.nodeVersion as number) <= 2.3) { + statements = formatedQuery.split(';').map((q) => q.trim()); + } else { + statements = splitQueryToStatements(formatedQuery, false); + } const responses: IDataObject[] = []; for (const statement of statements) { @@ -300,7 +319,13 @@ export function configureQueryRunner( try { const { query, values } = queryWithValues; formatedQuery = connection.format(query, values); - const statements = formatedQuery.split(';').map((q) => q.trim()); + + let statements; + if ((options?.nodeVersion as number) <= 2.3) { + statements = formatedQuery.split(';').map((q) => q.trim()); + } else { + statements = splitQueryToStatements(formatedQuery, false); + } const responses: IDataObject[] = []; for (const statement of statements) {