diff --git a/packages/server/src/threads/query.js b/packages/server/src/threads/query.js index 270c2cc713..d6089567b8 100644 --- a/packages/server/src/threads/query.js +++ b/packages/server/src/threads/query.js @@ -9,6 +9,8 @@ const { const { doInAppContext, getAppDB } = require("@budibase/backend-core/context") const { isSQL } = require("../integrations/utils") +const CONST_CHAR_REGEX = new RegExp("'[^']*'", "g") + class QueryRunner { constructor(input, flags = { noRecursiveQuery: false }) { this.datasource = input.datasource @@ -37,17 +39,22 @@ class QueryRunner { arrays = [] for (let binding of bindings) { // look for array/list operations in the SQL statement, which will need handled later - const listRegex = new RegExp(`(in|IN|In|iN)( )+${binding}`) - const listRegexMatch = sql.match(listRegex) + const listRegexMatch = sql.match( + new RegExp(`(in|IN|In|iN)( )+[(]?${binding}[)]?`) + ) // check if the variable was used as part of a string concat e.g. 'Hello {{binding}}' - const charConstRegex = new RegExp(`'[^']*${binding}[^']*'`) - const charConstMatch = sql.match(charConstRegex) - if (charConstMatch) { - let [part1, part2] = charConstMatch[0].split(binding) + // start by finding all the instances of const character strings + const charConstMatch = sql.match(CONST_CHAR_REGEX) || [] + // now look within them to see if a binding is used + const charConstBindingMatch = charConstMatch.find(string => + string.match(new RegExp(`'[^']*${binding}[^']*'`)) + ) + if (charConstBindingMatch) { + let [part1, part2] = charConstBindingMatch.split(binding) part1 = `'${part1.substring(1)}'` part2 = `'${part2.substring(0, part2.length - 1)}'` sql = sql.replace( - charConstMatch[0], + charConstBindingMatch, integration.getStringConcat([ part1, integration.getBindingIdentifier(), @@ -63,12 +70,14 @@ class QueryRunner { "," ) // build a string like ($1, $2, $3) - sql = sql.replace( - binding, - `(${Array.apply(null, Array(value.length)) - .map(() => integration.getBindingIdentifier()) - .join(",")})` - ) + let replacement = `${Array.apply(null, Array(value.length)) + .map(() => integration.getBindingIdentifier()) + .join(",")}` + // check if parentheses are needed + if (!listRegexMatch[0].includes(`(${binding})`)) { + replacement = `(${replacement})` + } + sql = sql.replace(binding, replacement) } else { sql = sql.replace(binding, integration.getBindingIdentifier()) }