migrations icon indicating copy to clipboard operation
migrations copied to clipboard

PostgreSQL JSONB contains operator is broken

Open alvaro-octal opened this issue 4 years ago • 3 comments

BC Break Report

Q A
BC Break yes
Version 3.0.2

Summary

The migrations worked fine with 3.0.1, but version 3.0.2 seems to be trying to replace the ? PostgreSQL operand by $1 of queries like this:

UPDATE "user" u
SET permissions = permissions::jsonb || '["dashboard"]'::jsonb
WHERE (u.permissions_old->'dashboard'->'api')::jsonb ? 'read'

https://www.postgresql.org/docs/9.4/functions-json.html#FUNCTIONS-JSONB-OP-TABLE

Previous behavior

This migration was valid

Current behavior

[error] Migration App\Migrations\Version20201023161652 failed during Execution. Error: "An exception occurred while executing '
            UPDATE "user" u
            SET permissions = permissions::jsonb || '["dashboard"]'::jsonb
            WHERE (u.permissions_old->'dashboard'->'api')::jsonb ? 'read'
        ':
SQLSTATE[42601]: Syntax error: 7 ERROR:  syntax error at or near "$1"
LINE 4: ...ERE (u.permissions_old->'dashboard'->'api')::jsonb $1 'read'
                                                              ^"
In AbstractPostgreSQLDriver.php line 73:
                                                                              
  An exception occurred while executing '                                     
              UPDATE "user" u                                                 
              SET permissions = permissions::jsonb || '["dashboard"]'::jsonb  
              WHERE (u.permissions_old->'dashboard'->'api')::jsonb ? 'read'   
          ':                                                                  
                                                                              
  SQLSTATE[42601]: Syntax error: 7 ERROR:  syntax error at or near "$1"       
  LINE 4: ...ERE (u.permissions_old->'dashboard'->'api')::jsonb $1 'read'     

How to reproduce

Make any migration with the ? operand on a PostgreSQL database on (at least) PHP 7.3

alvaro-octal avatar Dec 31 '20 11:12 alvaro-octal

This is actually a PHP bug, solved in 7.4 by https://wiki.php.net/rfc/pdo_escape_placeholders (see also https://bugs.php.net/bug.php?id=71885)

goetas avatar Dec 31 '20 18:12 goetas

I do not believe this is purely a PHP bug. The same query works just fine in doctrine/migrations v3.0.1 and breaks in v3.0.2.

shadowhand avatar Jan 01 '21 15:01 shadowhand

Same happening here, just by upgrading to 3.0.2 on PHP 7.4.13.

I traced it down with xdebug to https://github.com/doctrine/migrations/commit/d3cf2855ed2c09655e3b0b8ce15bac3458776c59#diff-234fe782577400df58580164cb830c2a2067c411c7a33f649a220719794d76fbL297 (takes while until it jumps).

Incoming params and types are an empty array.

The change from executeUpdate (deprecated, but using PDO statements) to executeQuery (using PDO query) introduced this bug. Most likely as query tries to analyze possible placeholders, while a statement needs them given as parameters.

The deprecation notice for executeUpdate also states the replacement should be executeStatement, not executeQuery.

Hope thats the right hunch.

adrianrudnik avatar Jan 06 '21 04:01 adrianrudnik