Search code examples
phpmysqli

mysqli_stmt::execute(): Premature EOF in result field metadata


I am writing a PHP application using MySQLi. During the run of this application, I prepare many SQL prepared statements in succession, and then execute them as needed throughout the course of the application.

However, when I run the same specific statement twice within my application (with specific parameters), I get the following error: mysqli_stmt::execute(): Premature EOF in result field metadata.

To further clarify my problem, I attach a minimal reproducible example of my code. Firstly, my database contains a stored procedure called GET_USER_ID_FROM_USERNAME. This is exactly as the name suggests - it takes a string username as parameter, checks if the username exists, and then returns two values - a boolean labelled User_Exists to check if the username is known in the database, and (if the former is true) an integer labelled ID. Here is the code for this procedure:

CREATE PROCEDURE GET_USER_ID_FROM_USERNAME (IN Username_Param TINYTEXT CHARSET utf8mb4)
BEGIN
    IF ((SELECT COUNT(1) FROM Users WHERE Username = Username_Param) = 1) THEN
    SELECT ID, TRUE AS User_Exists FROM Users WHERE Username = Username_Param;
    ELSE
    SELECT FALSE AS User_Exists;
    END IF;
END

This works exactly how I want it to - when I pass in a known username, it returns true in the User_Exists column and the relevant user's ID in the eponymous column, and when I pass in a username not featuring in the database, it returns false in the User_Exists column.

The problem arises when I call this procedure twice (even if I call other procedures in between), and only when the first time is an existing username and the second time is an unknown one (i.e. when the User_Exists value is true the first time but false the second). I call this routine using a prepared statement, to which I bind the username desired.

Here is a minimal example of the code which throws the desired error:

// CONNECT
$mysqli = new mysqli("localhost", "root", "root", "test_database");
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli->autocommit(false);
$mysqli->set_charset('utf8mb4');

// PREPARE STATEMENT
$stmt = $mysqli->prepare("CALL GET_USER_ID_FROM_USERNAME (?);");

// BIND PARAMETER
$username = "";
$stmt->bind_param("s", $username);

// EXECUTE WITH KNOWN VALUE
$username = "Existing_Username";
$stmt->execute();
// Flush result (if I exclude this I get a "commands out of sync" error)
$stmt->get_result();
$mysqli->next_result();

// All fine so far

// EXECUTE WITH UNKNOWN VALUE
$username = "Fake_Username";
$stmt->execute(); // <- Error thrown here: mysqli_stmt::execute(): Premature EOF in result field metadata

This (and only this) configuration, where the first username is known and the second is not, throws the error. If the statement is only called once, with either a known or unknown username, it returns what I expect. If the statement is called first with a known username and second with a different known username, it also returns what I expect.

Looking for the error message Premature EOF in result field metadata has yielded no results. If someone knows how or why this message appears, or has an idea of what I am doing wrong with my code, I'd be grateful to know!

This is the Users table as I have set it up for the purposes of this example:

CREATE TABLE Users (
  ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
  Username TINYTEXT NOT NULL,
  Pass_Hash TINYTEXT NOT NULL
);

Rows:

ID   -   Username      -     Pass_Hash
------------------------------------------------------------------------------------------
1        Existing_Username   $2y$10$l8y.GEK3LFnLyJWhAmHdg.7lMb45SezorBDODrqWUq4M0K1P3rDCq

(the Pass_Hash is Password1, hashed).

The setup I am running this on:

MAMP on Windows

PHP 8.1.0

MySQL 5.7.24


Solution

  • This is a bug in PHP and it was fixed in PHP 8.1.23 & 8.2.10

    Here is the PR https://github.com/php/php-src/pull/11551

    I have verified that this is the same bug, despite the bug description being a little bit different.


    As you can see the issue has been reported before although with different symptoms. I'd guess that not many people run into this problem because what you are doing is quite unusual. Stored procedures are not usually used from within PHP code and when they are they are usually executed only once. It's not unthought of to execute stored procedure multiple times using a prepared statement, but it's a rather rare circumstance.