amphp / postgres

Async Postgres client for PHP based on Amp.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Question mark operators interpreted as unnamed parameters

Bilge opened this issue · comments

commented

In the following query, the @? JSONB operator will be erroneously interpreted by this library as an unnamed parameter.

SELECT *
FROM foo
WHERE bar::jsonb @? '$[*].baz' 

This library treats the ? component of the @? operator as though it were an unnamed parameter by making this erroneous transformation:

SELECT *
FROM foo
WHERE bar::jsonb @$1 '$[*].baz' 

Note that even though I want to use @?, there are also ?|, ?& and even bareword ? JSONB operators. Therefore it may not be sufficient to solve this problem with regex. Perhaps the library should be smarter about doing question mark substitution such that if the statement is not executed with any unnamed parameters, unnamed substitution does not occur. That is, if one wants to use JSONB operators and parameter substitution, they should use named substitution only.

Note further this does not just apply to JSONB. Geometric functions also include a whole other class of operators, many of which contain the question mark. Moreover, extensions are free to implement their own operators that may include question marks too; the same applies to custom operators.

Solutions

  1. Improve the regex to exclude most operators
  2. Implicitly ignore question mark placeholders when no numeric keys specified
  3. Explicitly ignore question mark placeholders
  4. Add an escape sequence for question marks

Improve the regex to exclude most operators

Considering operators may include the following characters, + - * / < > = ~ ! @ # % ^ & | ` ?, the regex can be extended to exclude question marks surrounded by these other characters. This does not interfere with normal usage, such as INSERT INTO foo VALUES (?, ?), where question marks are typically only surrounded by braces, commas and whitespace, which are not valid operator characters. However, this solution would never be able to handle the bare question mark case (?).

Implicitly ignore question mark placeholders when no numeric keys specified

If we assume when that when no parameters are specified with numeric keys, we can safely disable question mark substitution, this could be an elegant and implicit way to avoid the problem in some cases.

Explicitly ignore question mark placeholders

Similar to above, we could add an explicit option to disable question mark placeholders. This is the approach taken by some other client libraries such as DBD::Pg.

Add an escape sequence for question marks

Allowing question marks to be escaped makes it clear they are not to be used as placeholders.

WHERE bar::jsonb @\? '$[*].baz' 

This approach also supports the bare question mark case. However, the a weakness to this approach is it makes the query less portable (e.g. pasting into another program to test).

A combination of these solutions may also be feasible. For example, improving the regex and also implementing the escape just for the bare question mark case.

Also note that the parsing of queries to find parameters is incorrect, it makes false assumptions about the syntax of quoted literals. For example, using '\' as a literal (which is valid SQL) looks like it will confuse the parser.

The handling of numbered parameters seems dubious too; note that it's valid, and sometimes necessary, for a numbered parameter to appear more than once.