php / php-src

The PHP Interpreter
https://www.php.net
Other
38.18k stars 7.75k forks source link

Null normalizes to 'f' when PDO::ATTR_EMULATE_PREPARES = true #12581

Open juffin-halli opened 1 year ago

juffin-halli commented 1 year ago

Description

The following code:

<?php

$pdo = new PDO(
    'pgsql:host=localhost;port=5432;dbname=test',
    'postgres',
    'postgres',
    [
        PDO::ATTR_EMULATE_PREPARES => true,
    ],
);

/** @var PDOStatement $stmt */
$stmt = $pdo->prepare('SELECT :bool_val as bv');
$stmt->bindValue(':bool_val', null, PDO::PARAM_BOOL);
$stmt->execute();

foreach ($stmt->getIterator() as $item) {
    var_dump($item['bv']);
}

Resulted in this output:

string(1) "f"

But I expected this output instead:

NULL

When ATTR_EMULATE_PREPARES not used, NULL is actually returned.

PHP Version

PHP 8.2.11

Operating System

Alpine Linux 3.18

SakiTakamachi commented 1 year ago

Apparently there are other cases besides this one that give strange results. I'll watch it tomorrow if I have time.

SakiTakamachi commented 1 year ago

This is a phenomenon caused by PARAM_TYPE being handled differently depending on whether it is in emulation mode or not.

https://github.com/php/php-src/blob/1b846f89b965940f8370ea841d4a4f45ecad3786/ext/pdo/pdo_sql_parser.re#L266 https://github.com/php/php-src/blob/1b846f89b965940f8370ea841d4a4f45ecad3786/ext/pdo_pgsql/pgsql_statement.c#L385

In this case, emulated mode may actually be the correct behavior, and we may need to modify the behavior of non-emulated mode.

SakiTakamachi commented 1 year ago

@devnexen Do you think the non-emulated mode behavior needs to be fixed?

SakiTakamachi commented 1 year ago

I verified it in detail. In this case, NULL is probably correct. However, I found a number of other strange behaviors, so I'll summarize my thoughts for a moment.

https://docs.google.com/spreadsheets/d/1wwvHtfzFPmi4OGxioADBIgAHUBX1CMNKkIZCCj_lxNA/edit?usp=sharing