fix(MySQL Node): Fix "Maximum call stack size exceeded" error when handling a large number of rows (#11242)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2024-10-14 12:57:30 +02:00 committed by GitHub
parent 566529ca11
commit b7ee0c4087
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -209,22 +209,22 @@ export function configureQueryRunner(
return []; return [];
} }
const returnData: INodeExecutionData[] = []; let returnData: INodeExecutionData[] = [];
const mode = (options.queryBatching as QueryMode) || BATCH_MODE.SINGLE; const mode = (options.queryBatching as QueryMode) || BATCH_MODE.SINGLE;
const connection = await pool.getConnection(); const connection = await pool.getConnection();
if (mode === BATCH_MODE.SINGLE) { if (mode === BATCH_MODE.SINGLE) {
const formatedQueries = queries.map(({ query, values }) => connection.format(query, values)); const formattedQueries = queries.map(({ query, values }) => connection.format(query, values));
try { try {
//releasing connection after formating queries, otherwise pool.query() will fail with timeout //releasing connection after formatting queries, otherwise pool.query() will fail with timeout
connection.release(); connection.release();
let singleQuery = ''; let singleQuery = '';
if (formatedQueries.length > 1) { if (formattedQueries.length > 1) {
singleQuery = formatedQueries.map((query) => query.trim().replace(/;$/, '')).join(';'); singleQuery = formattedQueries.map((query) => query.trim().replace(/;$/, '')).join(';');
} else { } else {
singleQuery = formatedQueries[0]; singleQuery = formattedQueries[0];
} }
let response: IDataObject | IDataObject[] = ( let response: IDataObject | IDataObject[] = (
@ -249,11 +249,11 @@ export function configureQueryRunner(
response = [response]; response = [response];
} }
//because single query is used in this mode mapping itemIndex not posible, setting all items as paired //because single query is used in this mode mapping itemIndex not possible, setting all items as paired
const pairedItem = generatePairedItemData(queries.length); const pairedItem = generatePairedItemData(queries.length);
returnData.push( returnData = returnData.concat(
...prepareOutput( prepareOutput(
response, response,
options, options,
statements, statements,
@ -262,24 +262,24 @@ export function configureQueryRunner(
), ),
); );
} catch (err) { } catch (err) {
const error = parseMySqlError.call(this, err, 0, formatedQueries); const error = parseMySqlError.call(this, err, 0, formattedQueries);
if (!this.continueOnFail()) throw error; if (!this.continueOnFail()) throw error;
returnData.push({ json: { message: error.message, error: { ...error } } }); returnData.push({ json: { message: error.message, error: { ...error } } });
} }
} else { } else {
if (mode === BATCH_MODE.INDEPENDENTLY) { if (mode === BATCH_MODE.INDEPENDENTLY) {
let formatedQuery = ''; let formattedQuery = '';
for (const [index, queryWithValues] of queries.entries()) { for (const [index, queryWithValues] of queries.entries()) {
try { try {
const { query, values } = queryWithValues; const { query, values } = queryWithValues;
formatedQuery = connection.format(query, values); formattedQuery = connection.format(query, values);
let statements; let statements;
if ((options?.nodeVersion as number) <= 2.3) { if ((options?.nodeVersion as number) <= 2.3) {
statements = formatedQuery.split(';').map((q) => q.trim()); statements = formattedQuery.split(';').map((q) => q.trim());
} else { } else {
statements = splitQueryToStatements(formatedQuery, false); statements = splitQueryToStatements(formattedQuery, false);
} }
const responses: IDataObject[] = []; const responses: IDataObject[] = [];
@ -290,8 +290,8 @@ export function configureQueryRunner(
responses.push(response); responses.push(response);
} }
returnData.push( returnData = returnData.concat(
...prepareOutput( prepareOutput(
responses, responses,
options, options,
statements, statements,
@ -300,7 +300,7 @@ export function configureQueryRunner(
), ),
); );
} catch (err) { } catch (err) {
const error = parseMySqlError.call(this, err, index, [formatedQuery]); const error = parseMySqlError.call(this, err, index, [formattedQuery]);
if (!this.continueOnFail()) { if (!this.continueOnFail()) {
connection.release(); connection.release();
@ -314,17 +314,17 @@ export function configureQueryRunner(
if (mode === BATCH_MODE.TRANSACTION) { if (mode === BATCH_MODE.TRANSACTION) {
await connection.beginTransaction(); await connection.beginTransaction();
let formatedQuery = ''; let formattedQuery = '';
for (const [index, queryWithValues] of queries.entries()) { for (const [index, queryWithValues] of queries.entries()) {
try { try {
const { query, values } = queryWithValues; const { query, values } = queryWithValues;
formatedQuery = connection.format(query, values); formattedQuery = connection.format(query, values);
let statements; let statements;
if ((options?.nodeVersion as number) <= 2.3) { if ((options?.nodeVersion as number) <= 2.3) {
statements = formatedQuery.split(';').map((q) => q.trim()); statements = formattedQuery.split(';').map((q) => q.trim());
} else { } else {
statements = splitQueryToStatements(formatedQuery, false); statements = splitQueryToStatements(formattedQuery, false);
} }
const responses: IDataObject[] = []; const responses: IDataObject[] = [];
@ -335,8 +335,8 @@ export function configureQueryRunner(
responses.push(response); responses.push(response);
} }
returnData.push( returnData = returnData.concat(
...prepareOutput( prepareOutput(
responses, responses,
options, options,
statements, statements,
@ -345,7 +345,7 @@ export function configureQueryRunner(
), ),
); );
} catch (err) { } catch (err) {
const error = parseMySqlError.call(this, err, index, [formatedQuery]); const error = parseMySqlError.call(this, err, index, [formattedQuery]);
if (connection) { if (connection) {
await connection.rollback(); await connection.rollback();