Skip to content

Bug in query-param-parsing regex #1088

@adamcameron

Description

@adamcameron

You use this pattern to parse yer SQL where clause and extarct values for query params:

\s*(((?:\s+(?:NOT\s+)?LIKE)|(?:\s+(?:NOT\s+)?IN)|(?:\s+IS(?:\s+NOT)?)|(?:<>)|(?:<=)|(?:>=)|(?:!=)|(?:!<)|(?:!>)|=|<|>))\s*(\('.+?'\)|\(((?:\+|-)?[0-9\.],?)+\)|'.+?'()|''|((?:\+|-)?[0-9\.]+)()|NULL)((\s*$|\)|\s+(AND|OR)))

This is derived from here: https://github.com/cfwheels/cfwheels/blob/master/wheels/model/initialization.cfm#L23-L25

There's a slight bug in it. It should be:

\s*(((?:\s+(?:NOT\s+)?LIKE)|(?:\s+(?:NOT\s+)?IN)|(?:\s+IS(?:\s+NOT)?)|(?:<>)|(?:<=)|(?:>=)|(?:!=)|(?:!<)|(?:!>)|=|<|>))\s*(\('.+?'\)|\(((?:\+|-)?[0-9\.],?)+\)|'.+?'()|''|((?:\+|-)?[0-9\.]+)()|NULL)((\s*$|\s*\)|\s+(AND|OR)))

The key bit is how you handle identifying the end of a [operand / operator / value] block:

(\s*$|\)

So: either the end of the string ($) or a closing parenthesis (\)). You overlook the fact that there might be whitespace between the previously matched value and the closing parenthesis.

This situation can arise from how the SQL clause is indented in the source code, eg:

lines = invoice.lines(
	where="
        someColumn IN ('x', 'y')
        AND anotherCoumn > '#someValue#'
	" // <--- note the space there after the value
)

CFWheels goes ahead and wraps that in parentheses, so it ends up being:

(
        someColumn IN ('x', 'y')
        AND anotherColumn > '#someValue#'
	)

An easy work around is for me to control that whitespace in my code, but obvs I should not have to.

I wonder if you didn't do yourselves any favours by running that entire pattern into one continuous string, whereas if you used the (?x) flag you could have broken it down into sections with comments explaining what yer up to. If you had done that, you'd've probably noticed the problem.

Some reading on the (?x) flag here: https://blog.adamcameron.me/2013/01/regular-expressions-in-coldfusion-part.html#regexcomments

It would also be super helpful for ppl like me who are trying to troubleshoot bugs, and despite being pretty comfortable with regex patterns, could benefit from explanatory comments that articulate what you think the pattern is doing. So I can spot where it's not actually doing that ;-)

Also when testing regexes, you really need discrete test cases for each subexpression, and each conditional. If you had those, you'd've like caught the problem too. That said I didn't check your testing, but just assumed it's superficial cos testing of this sort of thing usually is.

No urgency on this from my perspective cos I can solve it on my end, and know now to avoid it in future. But figured you'd like to know about it.

Lastly, can I recommend you drop this approach in CFWheels 3.x. If ppl want to put params in their SQL, they just can with param markers now (? or :paramRef), and pass an array or struct with the param values. This would be more "modern CFML" than hacking <cfqueryparam> tags into a <cfquery> tag, and a lot easier and less error prone for you.

Cheers!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions