我正在使用MySQLi编写一个PHP应用程序.在这个应用程序的运行过程中,我连续准备了许多SQL预准备语句,然后在整个应用程序过程中根据需要执行它们.

但是,当我在应用程序中运行相同的特定语句两次(使用特定参数)时,我会得到以下错误:mysqli_stmt::execute(): Premature EOF in result field metadata.

为了进一步澄清我的问题,我附上了一个最小的可重复使用的代码示例.首先,我的数据库包含一个名为GET_USER_ID_FROM_USERNAME的存储过程.顾名思义,它接受一个字符串用户名作为参数,判断用户名是否存在,然后返回两个值--一个标记为User_Exists的布尔值,用于判断数据库中是否知道该用户名,以及一个标记为ID的整数(如果前者是true).以下是此过程的代码:

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

这完全符合我的要求-当我传入一个已知的用户名时,它在User_Exists列中返回true,在eps列中返回相关用户的ID,当我传入一个不在数据库中的用户名时,它在User_Exists列中返回false.

当我调用这个过程twice(即使我调用中间的其他过程)并且只调用when the first time is an existing username and the second time is an unknown one(即,当第一次User_Exists的值是true,而第二次的值是false)时,问题就出现了.我使用准备好的语句调用此 routine ,并将所需的用户名绑定到该语句.

以下是抛出所需错误的代码的最小示例:

// 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

在第一个用户名已知而第二个用户名未知的情况下,此(且仅此)配置会抛出错误.如果仅使用已知或未知用户名调用该语句一次,它将返回我所期望的结果.如果首先使用已知用户名调用该语句,然后使用不同的已知用户名调用该语句,它也会返回我所期望的结果.

查找错误消息Premature EOF in result field metadata未产生任何结果.如果有人知道这条消息是如何或为什么出现的,或者知道我的代码做错了什么,我将不胜感激!

这是我为本例设置的Users表:

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

行:

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

(PASS_HASH为Password1,已散列).

我在其上运行此程序的设置:

Windows上的MAMP

PHP 8.1.0

MySQL 5.7.24

推荐答案

这是PHP中的一个错误,它是fixed in PHP 8.1.23 & 8.2.10

这是公关https://github.com/php/php-src/pull/11551

我已经验证了这是同一个错误,尽管错误描述略有不同.


正如您所看到的,这个问题以前也被报告过,尽管有不同的症状.我猜没有多少人会遇到这个问题,因为你所做的事情很不寻常.存储过程通常不会在PHP代码中使用,当它们使用时,它们通常只执行一次.使用预准备语句多次执行存储过程并不是没有考虑到的,但这是相当罕见的情况.

Php相关问答推荐

如何使用URL链接(mdl)切换选项卡

累加平面数组中数字子集的所有组合,以生成组合及其乘积的二维数组

在函数内部获取一致的单选按钮值以更新WordPress用户数据

在特定订单状态更改时自定义WooCommerce订单发货项目

在WooCommerce产品中按类型对产品属性术语进行分类以供显示

在PHP中循环访问多维数组,并按组显示内容

如何将隐式乘法添加到PHPPEG基本计算器语法中?

Laravel:如何展平多维Eager 加载的集合

服务器迁移后无法上载文件-可能存在权限问题

使用php ZipArhive类将Zip压缩文件分成多个部分

如何在 apache Laragon - laravel 10 中允许方法 DELETE?

显示 woocommerce 中所选变体的属性术语描述

为什么从一个页面到另一个页面都找不到 JQuery,因为它们使用相同的 twig 模板?

PHP 在数组中搜索值

图像未在 Laravel Ajax Crud 中显示

CodeIgniter 4中嵌套过滤器组不起作用

在WooCommerce中显示 checkout 的高级自定义字段(Advanced Custom Fields)并保存其值

如何在 Laravel 中验证多个输入?

为什么 PDO 允许使用带命名占位符的索引数组,但仅在禁用仿真时才允许?

递归数组处理