Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDO PostreSQL - parser is broken for '...\' #13958

Open
mvorisek opened this issue Apr 13, 2024 · 15 comments
Open

PDO PostreSQL - parser is broken for '...\' #13958

mvorisek opened this issue Apr 13, 2024 · 15 comments

Comments

@mvorisek
Copy link
Contributor

mvorisek commented Apr 13, 2024

Description

The following code:

<?php

$pdo = new PDO('pgsql:host=127.0.0.1;dbname=xxx', 'user', 'pass');

$sql = <<<'EOF'
    select :a x, '\' x2
    EOF;
$statement = $pdo->prepare($sql);
$statement->bindValue('a', 'va');

$statement->execute();
$res = $statement->fetchAll(PDO::FETCH_ASSOC);
var_dump($res);

$sql = <<<'EOF'
    select :a x, '\' x2, :b y, '\' y2
    EOF;
$statement = $pdo->prepare($sql);
$statement->bindValue('a', 'va');
$statement->bindValue('b', 'vb');

$statement->execute();
$res = $statement->fetchAll(PDO::FETCH_ASSOC);
var_dump($res);

Resulted in this output:

array(1) {
  [0]=>
  array(2) {
    ["x"]=>
    string(2) "va"
    ["x2"]=>
    string(1) "\"
  }
}

Warning: PDOStatement::bindValue(): SQLSTATE[HY093]: Invalid parameter number: :b in C:\...\repro.php on line 20
array(0) {
}

But I expected this output instead:

array(1) {
  [0]=>
  array(2) {
    ["x"]=>
    string(2) "va"
    ["x2"]=>
    string(1) "\"
  }
}
array(1) {
  [0]=>
  array(4) {
    ["x"]=>
    string(2) "va"
    ["x2"]=>
    string(1) "\"
    ["y"]=>
    string(2) "vb"
    ["y2"]=>
    string(1) "\"
  }
}

'\' is causing the issue - but it is absolutely correct string syntax.

Identifier escaping ("\") is broken as well.

It seems php-src parses the SQL using the old mode (default until PostgreSQL 9.1) - https://www.postgresql.org/docs/current/runtime-config-compatible.html#GUC-STANDARD-CONFORMING-STRINGS.

PHP Version

any (tested 7.4 and 8.3)

Operating System

any (tested Windows and linux)

@mvorisek mvorisek changed the title PDO_PGSQL - PDOException: SQLSTATE[HY093]: Invalid parameter number: :b PDO PostreSQL - parser is broken for '...\' Apr 13, 2024
@mvorisek
Copy link
Contributor Author

@devnexen this is definitely a bug, the SQL is parsed somehow by php wrongly.

@devnexen
Copy link
Member

devnexen commented Apr 14, 2024

the extension does not support it (AFAIK part of this extension still rely on old postgresql versions behavior), I do not think it qualifies for php 8.2/8.3 though.

@mvorisek
Copy link
Contributor Author

The relation with PostgreSQL 9.1 is my pure guess, but if true, the version was released more than 12 years ago. So I would say we have a bug in SQL parsing affecting basically all pdo pgsql users.

@MorganLOCode
Copy link

Note in contrast that the PostgreSQL extension does parse the string literal correctly:

$connection = pg_connect('host=127.0.0.1 dbname=xxx user=xxx password=xxx');

$sql = <<<'EOF'
    select $1 x, '\' x2
    EOF;
$statement = pg_prepare($connection, 'q1', $sql);
$result = pg_fetch_all(pg_execute($connection, 'q1', ['va']));

var_dump($result);

$sql = <<<'EOF'
    select $1 x, '\' x2, $2 y, '\' y2
    EOF;
$statement = pg_prepare($connection, 'q2', $sql);
$result = pg_fetch_all(pg_execute($connection, 'q2', ['va', 'vb']));

var_dump($result);

@devnexen
Copy link
Member

pdo pgsql and pgsql are distinct code wise :)

@mvorisek
Copy link
Contributor Author

mvorisek commented Apr 14, 2024

@MorganLOCode
Copy link

pdo pgsql and pgsql are distinct code wise :)

Yes, I know. One works correctly (it defers to libpq), the other doesn't.

@SakiTakamachi
Copy link
Member

After some testing, I think this might qualify as a bug.

However, I think this is a bit of a gray area, right on the border between a bug and a feature request.

As mentioned, this is due to PDO's common query parser not taking into account PostgreSQL-specific behavior.

I'm not sure how much change will be needed until I work a bit more into this, but I'll get started.

@SakiTakamachi SakiTakamachi self-assigned this Apr 15, 2024
@MorganLOCode
Copy link

MorganLOCode commented Apr 15, 2024

Well, as far as quoting goes, recognising '\' as a string literal containing a single backslash isn't so much PostgreSQL-specific as standard ISO/ANSI behaviour.

@mvorisek
Copy link
Contributor Author

@mbeccati
Copy link
Contributor

Pls see https://wiki.php.net/rfc/pdo_driver_specific_parsers ;-)

@mvorisek
Copy link
Contributor Author

Can this be fixed for PHP 8.2/8.3?

@mbeccati
Copy link
Contributor

@mvorisek I'm afraid not. The required changes are too deep for anything but the next 8.x version.

@devnexen
Copy link
Member

@mvorisek See why I put the feature label first, it was not to bother you.

@mvorisek
Copy link
Contributor Author

We ended up with this workaround https://github.com/atk4/data/blob/c2baf07324/src/Persistence/Sql/Postgresql/ExpressionTrait.php#L28-L36

however native fix would be much faster

also for identifiers such workaround is not possible, possibly there is no workaround

and for SQL server we have to workaround https://github.com/atk4/data/blob/c2baf07324/src/Persistence/Sql/Mssql/ExpressionTrait.php#L34-L43 - would that be fixed by #14035? The SQL driver calls the PDO parsing in https://github.com/microsoft/msphpsql/blob/v5.12.0/source/pdo_sqlsrv/pdo_dbh.cpp#L836.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants