PDO_ODBC truncating CHAR field Db2i driver
还没有人认领这个 Issue。
- 主要语言
- C
- 星标
- 40.4k
- 派生
- 8.1k
- 平均合并
- 2 天 13 小时
- 30 天内合并 PR
- 96
描述
Description
The following code:
<?php
user = {myUser};
$password = {myPassword};
$rdb = {myDsn};
$dsn = "DSN={{$rdb}};NAM=1;ALWAYSCALCLEN=1;CCSID=1208";
$sql = "
SELECT long_char_field
FROM table
WHERE id = '1'
";
$attrOpions = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
$db = new PDO("odbc:$dsn", $user, $password, $attrOpions);
$stmt = $db->prepare($sql);
$stmt->execute();
while (($row = $stmt->fetch())) {
var_dump($row["LONG_CHAR_FIELD"]);
}
$db = odbc_connect($dsn, $user, $password);
$stmt = odbc_prepare($db, $sql);
odbc_execute($stmt);
while (($row = odbc_fetch_array($stmt))) {
var_dump($row["LONG_CHAR_FIELD"]);
}
Resulted in this output:
string(256) "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
string(560) "00000000016500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
But I expected this output instead:
string(560) "00000000016500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
string(560) "00000000016500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
I've seen a lot of discussion around pdo_odbc and long field fetching, but nothing that exactly matched what I'm seeing here. Similar though. We have a field that's defined in ddl as CHAR(560) on db2 for i (using up to date drivers from here). After upgrading our php from 7.0.1 to 8.3.20 we're having the issue where this column is only returning 256 chars, and the data returned is not positionally correct (i.e. the chunks seem to get overlaid on one another).
The problematic logic seems to be the chunk approach for retrieving "long" columns starting here
I was able to debug, and patched in @NattyNarwhal 's printfs from here https://gist.github.com/NattyNarwhal/278aedf8e3c48bb8dcb4ae14cde0b283#file-debugging-printf-patch
What I see in both cases is that the driver is fetching a length of 256 at first, but the logic to continue the loop is (correctly) triggered 2x
if (rc==SQL_SUCCESS_WITH_INFO || (rc==SQL_SUCCESS && C->fetched_len > 255))
What I see happening as I step through is that though the original_fetched_len is 256, the status is still SQL_SUCCESS_WITH_INFO causing it to drop into this logic block that overlays the result with the new data.
str = zend_string_realloc(str, used + 256, 0);
memcpy(ZSTR_VAL(str) + used, buf2, 256);
used = used + 255;
Interestingly, if we patch a rollback of this commit, eliminating the recalculation of used, things go back to working.
I also suspect that this PR would fix it too, but I don't know if that's still planned to go in.
Here's the logging output from the patch above.
!!! Get col stmt 0x7ffffe68e000 col 0
*** Is long string? 1
*** After fetching 256, fetched len 256 data "00000000016500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
*** Actually long
@@@ fixed_used 0 = orig_fetched_len 256 - C->fetched_len 256
@@@ (and used = 255)
@@@ strange fetch_len 256, buf "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
@@@ fixed_used 206 = orig_fetched_len 256 - C->fetched_len 50
@@@ (and used = 255)
@@@ normal fetch_len 50, buf "00000000000000000000000000000000000000000000000000"
@@@ fixed_used 256 = orig_fetched_len 256 - C->fetched_len 0
@@@ (and used = 256)
*** Unicode? 0
*** OK, got string "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
PHP Version
PHP 8.3.20 (cli) (built: Apr 8 2025 20:21:18) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.3.20, Copyright (c) Zend Technologies
with Zend OPcache v8.3.20, Copyright (c), by Zend Technologies
with Xdebug v3.4.2, Copyright (c) 2002-2025, by Derick Rethans
Operating System
Red Hat Enterprise Linux release 9.5 (Plow)
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
从 ext/pdo_odbc/odbc_stmt.c 中第 654 行附近的长列检索逻辑开始,然后将其与 commit bccca0b53aa60a62e2988c750fc73c02d109e642 和 PR 10809 进行比较。使用 PHP 8.3.20 和当前驱动复现带有 CHAR(560) 字段的 Db2 for i 案例。完成标准是 PDO 和 ODBC 都返回完整的 560 个字符的值,且不存在位置覆盖。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- c, php
- 领域
- database
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 停滞
- 描述清晰度
- 基本清楚
- 新手友好度
- 38/100