[php-src] Issue #10110: mysqli_error() after mysqli_stmt_execute() gets unset at the end of the function

From: Date: Thu, 15 Dec 2022 22:26:54 +0000
Subject: [php-src] Issue #10110: mysqli_error() after mysqli_stmt_execute() gets unset at the end of the function
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-243154@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/10110
Author: weary-adventurer

### Description

Given this MySQL table:
```sql
CREATE TABLE test (
   id int(10) unsigned NOT NULL AUTO_INCREMENT,
   foo varchar(256) NOT NULL,
   PRIMARY KEY (id)
);
```

This code sets up a MySQLi connection and runs two SQL queries:
```php
<?php

define("DB_HOSTNAME", "localhost");
define("DB_USERNAME", "root");
define("DB_PASSWORD", "");
define("DB_DATABASE", "my_database_name");

function db_init() : ?mysqli {
    mysqli_report(MYSQLI_REPORT_OFF);
    $db = @mysqli_connect(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
    return $db === false ? null : $db;
}

function db_query(mysqli &$db, string $query, ?string $types = null, ...$values) {
    $stmt = mysqli_prepare($db, $query);
    
    if (!$stmt) {
        echo "| mysqli_prepare failed\n";
        echo "| mysqli_error() = '" . mysqli_error($db) . "'\n";
        return null;
    }

    if (!mysqli_stmt_bind_param($stmt, $types, ...$values)) {
        echo "| mysqli_stmt_bind_param failed\n";
        echo "| mysqli_error() = '" . mysqli_error($db) . "'\n";
        return null;
    }

    if (!mysqli_stmt_execute($stmt)) {
        echo "| mysqli_stmt_execute failed\n";
        echo "| mysqli_error() = '" . mysqli_error($db) . "'\n";
        return null;
    }

    $result = mysqli_stmt_get_result($stmt);

    echo "| db_query succeeded\n";
    echo "| result = '" . print_r($result, true) . "'\n";
    echo "| mysqli_error() = '" . mysqli_error($db) . "'\n";

    return $result;
}

function main() {
    echo "connecting...\n";
    echo "| phpversion() = " . phpversion() . "\n";

    $db = db_init();
    if (!$db) {
        echo "| mysqli_connect_error() = " . mysqli_connect_error($db) . "\n";
        return;
    }

    echo "\n";
    echo "connected\n";
    echo "| mysqli_error() = '" . mysqli_error($db) . "'\n";

    echo "\n";
    echo "trying to fail mysqli_prepare ...\n";
    db_query($db, "INSERT INTO non_existent (foo) VALUES (?)", "s", null);

    echo "\n";
    echo "state after mysqli_prepare is:\n";
    echo "| mysqli_error() = '" . mysqli_error($db) . "'\n";

    echo "\n";
    echo "trying to fail mysqli_stmt_execute ...\n";
    db_query($db, "INSERT INTO test (foo) VALUES (?)", "s", null);

    echo "\n";
    echo "state after mysqli_stmt_execute is:\n";
    echo "| mysqli_error() = '" . mysqli_error($db) . "'\n";
}

echo "<pre>";
main();
echo "</pre>";
exit;

?>
```

The following output is produced:
```
connecting...
| phpversion() = 8.2.0

connected
| mysqli_error() = ''

trying to fail mysqli_prepare ...
| mysqli_prepare failed
| mysqli_error() = 'Table 'my_database_name.non_existent' doesn't exist'

state after mysqli_prepare is:
| mysqli_error() = 'Table 'my_database_name.non_existent' doesn't exist'

trying to fail mysqli_stmt_execute ...
| mysqli_stmt_execute failed
| mysqli_error() = 'Column 'foo' cannot be null'

state after mysqli_stmt_execute is:
| mysqli_error() = ''
```

What this does:
* The first query tries to insert a row in a non-existing table, which fails the
mysqli_prepare() call.
* The second query tries to insert a row with a NULL value, which fails the
mysqli_stmt_execute() call.

In both cases a MySQLi error is generated and the message can be obtained with
mysqli_error().

But this error gets unset after the db_query function exits, and it only happens if the
failing function was mysqli_stmt_execute().

### PHP Version

PHP 8.2.0

### Operating System

Windows 10.0.19043


Thread (1 message)

  • weary-adventurer
« previous php.bugs (#243154) next »