PDO 截断 bigint 值?

8

我在使用PDO通过MySQL将大整数存储在BIGINT列中时遇到了问题。

如果我运行这个测试:

$number = "30123456789";
var_dump($number); //prints string(11) "30123456789"

$new_number = (int)$number;
var_dump($new_number); //prints int(30123456789) 

所以目前为止一切都很好...
如果我直接在MySQL中运行这个SQL:
update my_table set bigint_field = 30123456789 where id_field = 1

一切都运行良好...

问题出现在我尝试通过PDO保存该数字时,我将问题缩小到了以下代码行:

//parameterized query
//update my_table set bigint_field = :bigint_field where id_field = :id_field
$statement->bindValue(":bigint_field", $new_number, PDO::PARAM_INT);

如果可选的第三个type参数缺失或等于PDO::PARAM_STR,则该值保存得很好,否则该值将被截断为58685709。如果我尝试保存20288976024,则该值将被截断为0。这里发生了什么?
我在Debian Wheezy x64上运行PHP 5.5.33和MySQL 5.6.25。

我脑海中只想到了一件事。你的pdo是否基于mysqlnd? - Your Common Sense
@YourCommonSense 我不确定,我怎么知道呢? - Matías Cánepa
phpinfo(),pdo部分,应该有单词“mysqlnd”。当启用仿真模式和关闭仿真模式时,比较结果会很有趣。 - Your Common Sense
在PDO下:PDO驱动程序 > mysql。在pdo_mysql下:客户端API版本 > 5.6.25。 - Matías Cánepa
1
那我建议安装php-mysqlnd或者Debian中叫什么名字,然后再试一次。能够看到完整可重现的代码片段仍然是非常好的。 - Your Common Sense
显示剩余2条评论
1个回答

4

我无法重现您的情况。

在x86系统上,intval()已经使2147483647成为可能,在64位系统上一切正常。

将bigint值绑定为字符串可能会导致错误的结果,因为该值将被强制转换为浮点数并丢失精度。

编辑:事实证明这是一个旧的libmysql问题。以这种方式配置PHP后,我能够重现此问题:

$number     = 30123456789;
$new_number = 20288976024;
var_dump($number, $new_number);

$pdo->query("CREATE TEMPORARY TABLE bint_test(i BIGINT unsigned)");

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);

$stmt = $pdo->prepare("insert into bint_test values (?)");
$stmt->bindValue(1, $number, PDO::PARAM_INT);
$stmt->execute();
$stmt->bindValue(1, $new_number, PDO::PARAM_INT);
$stmt->execute();

echo json_encode($pdo->query("SELECT * FROM bint_test")->fetchAll());

打印输出。
int(30123456789)
int(20288976024)
[{"i":"58685717"},{"i":"0"}

有两种可能的解决方案:

  1. (首选)安装 php-mysqlnd,您必须这样做,因为mysqlnd是旧的libmysql连接器的新替代品。
  2. 打开模拟模式 - 由PDO构建的查询也可以无误地工作。

在 Windows 7 x64 上,我唯一能够使一切正常工作的方式是使用编译有 VC14 的 php7 x64 和 apache 2.4 x64,但在 Debian 服务器上,似乎要使其工作更加复杂。 - Matías Cánepa
你应该发布完整的可重现代码,从表格创建到显示结果 - 这样每个人都可以测试。 - Your Common Sense
你有关于“转换为浮点数”语句的任何参考文献吗?虽然我不使用显式类型规范,但出于好奇,我尝试验证了您的说法,但没有发生任何舍入。这个大整数2884545454545976024被保存为PARAM_STR,没有任何问题。 - Hanky Panky
谢谢!对于 Bigint,应该使用哪种 pdo 参数类型?我的意思是那些想要明确指定的人。 - Hanky Panky
@HankyPanky PARAM_INT 应该可以工作,至少对于 64 位系统来说是这样的。我希望我能够重现 OP 的情况,但目前还没有成功。 - Your Common Sense
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接