php / php/php-src

PDO_ODBC truncating CHAR field Db2i driver

Aperta
#18,349 8 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Bug Extension: pdo_odbc Status: Needs Triage
Lingua principale
C
Stelle
40.4k
Fork
8.1k
Merge medio
2g 13h
PR unite (30g)
96

Descrizione

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)

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia in ext/pdo_odbc/odbc_stmt.c, intorno alla logica di recupero delle colonne lunghe vicino alla riga 654, quindi confrontala con il commit bccca0b53aa60a62e2988c750fc73c02d109e642 e la PR 10809. Riproduci il caso Db2 for i con un campo CHAR(560) usando PHP 8.3.20 e i driver correnti. Il lavoro è completato quando sia PDO sia ODBC restituiscono il valore completo di 560 caratteri senza sovrapposizione posizionale.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
c, php
Ambito
database
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
38/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.