Skip to content

MySQL PDO: PDOStatement::execute fails and returns false without neither throwing an exception nor setting PDOStatement::errorCode if many (~1000) query parameters are bound #8773

@nagmat84

Description

@nagmat84

Summary

If a query binds many (i.e. around 1000) parameters, the method PDOStatement::execute() fails and returns false. Even though PDO::ERRMODE_EXCEPTION is set as part of the PDO options no exception is thrown. PDOStatement::execute() neither sets PDOStatement::errorCode(). However, a subsequent fetchAll returns an empty array with zero query results.

Note, that the bug can be worked around, if the binding are resolved manually. This mean if all placeholders '?' inside the query string are replaced by their actual value before the query is passed to PDOStatement::prepare(), then PDOStatement::execute() does not fail and a subsequent PDOStatement::fetchAll() returns the expected number of results.

The issue has been reported by a couple of our users of https://github.com/LycheeOrg/Lychee. We have tracked it down to the PDO layer, i.e. it is not a bug in our code nor in the Laravel framework. A MWE which triggers the bug is located in https://github.com/LycheeOrg/MySQL1000Bug. The bug only occurs for a couple of users not everyone. But if the bug occurs for a specific setup, then the bug occurs deterministically. So far, we have seen bug reports from users with PHP 8.1.2 and 8.1.5 – 8.1.7. We haven't seen any bug reports for 8.0.x, but this doesn't mean that the bug might not exist there as well. Among the core developer team @qwerty287 has been able to reproduce the faulty behaviour on his development machine.

As the bug only occurs for many query parameters and only for specific setups it smells like a memory corruption bug in the MySQL PDO code which is responsible for parameter binding.

Steps to reproduce the problem

  1. Checkout the repository https://github.com/LycheeOrg/MySQL1000Bug
  2. Create a new MySQL/Maria DB
  3. Load the included MySQL dump into the DB.
  4. Make a copy config.php of the provided config.php.example and adopt it to your DB settings.
  5. Run the test script ./mysql_1000_bug.

Output if the bug occurs

Test #1 - Query without bindings
bind_values()       : bound 0 values in total
select_query()      : $statement->fetchAll returned 7380 results
check_db_result()   : Everything seems fine :-(

Test #2 - Query with bindings
bind_values()       : binding value __OcYDO3i7Bm9MaCx5SWJj_D as string to placeholder 1 succeeded
...
bind_values()       : binding value Zzik4C_-V-WhyyYcn2QLlaEG as string to placeholder 1074 succeeded
bind_values()       : bound 1074 values in total
select_query()      : $statement->execute() failed without exception, oh, oh
select_query()      : $statement->execute() returned error: 00000
select_query()      : $statement->execute() returned error info:
array(3) {
  [0]=>
  string(5) "00000"
  [1]=>
  NULL
  [2]=>
  NULL
}
select_query()      : $statement->fetchAll returned 0 results
check_db_result     : fetched wrong number of size variants; got 0, expected 7380

Expected output if the bug does not occur

Test #1 - Query without bindings
bind_values()       : bound 0 values in total
select_query()      : $statement->fetchAll returned 7380 results
check_db_result()   : Everything seems fine :-(

Test #2 - Query with bindings
bind_values()       : binding value __OcYDO3i7Bm9MaCx5SWJj_D as string to placeholder 1 succeeded
...
bind_values()       : binding value Zzik4C_-V-WhyyYcn2QLlaEG as string to placeholder 1074 succeeded
bind_values()       : bound 1074 values in total
select_query()      : $statement->fetchAll returned 7380 results
check_db_result()   : Everything seems fine :-(

Further information

PHP version for which the bug has been observed: 8.1.2 and 8.1.5 – 8.1.7
Downstream issue: LycheeOrg/Lychee#1326
MWE repo: https://github.com/LycheeOrg/MySQL1000Bug

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions