Merge pull request #5240 from Budibase/fix/4978

Fix for IN SQL query parsing - handling parentheses and string interpolation
This commit is contained in:
Michael Drury 2022-04-05 14:32:16 +01:00 committed by GitHub
commit d1a08f6530
1 changed files with 22 additions and 13 deletions

View File

@ -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())
}