From:
Operating system: Linux
PHP version: 5.3.8
Package: ODBC related
Bug Type: Bug
Bug description:odbc_fetch_into returns junk data at end of multi-byte char
fields
Description:
------------
This relates to bug#25792, which has been marked Analyzed but does not seem
to be fixed.
When retrieving data from a char() field containing multi-byte characters
using e.g. odbc_fetch_into(), if the number of bytes used exceeds the
number of characters then junk data is returned at the end of the string.
I have experience this with Postgres char columns when the database is
created with e.g the EUC_CN character encoding(createdb -E EUC_CN).
This encoding uses between 1 and 3 bytes per character. So a char(10) could
need up to 30 bytes.
The problem is in the odbc_bindcols function in ext/odbc/php_odbc.c
SQLColAttributes is called with SQL_COLUMN_DISPLAY_SIZE but this
indicates the maximum number of characters required not the number of
bytes.
This means the buffer allocated for the value may not be big enough
result->values[i].value=(char)emalloc(displaysize+1);
Later on in e.g. odbc_fetch_into
Z_STRLEN_P(tmp) = result->values[i].vallen;
Z_STRVAL_P(tmp) = estrndup(result->values[i].value,Z_STRLEN_P(tmp));
This can result in a vallen bigger that displaysize. But the ODBC driver
will only fill in at most displaysize+1 bytes(including null terminator).
This means character data is missed and junk bytes are returned instead.
The same problem may exist in ext/pdo_odbc/odbc_stmt.c. Where
rc = SQLColAttribute(S->stmt, colno+1, SQL_DESC_DISPLAY_SIZE,
NULL, 0, NULL, &displaysize);
is called. But I have not tested this.
The following fixes odbc_bindcols for the char(x) datatype. I believe 4
bytes is the maximum required for any character encoding.
php_odbc.c:line 988
if (result->values[i].coltype == SQL_CHAR) {
//If using a multibyte character encoding
//number of bytes could be 4*SQL_COLUMN_DISPLAY_SIZE.
//Without this workaround various functions
//e.g. odbc_fetch_into will return data with a null after
//diplaysize bytes and extra junk data at the end as
//vallen can be bigger than displaysize. Tested using
//PostgreSQL with EUC_CN encoding.
displaysize*=4;
}
The fix may be needed for other data types as well as SQL_CHAR.
--
Edit bug report at https://bugs.php.net/bug.php?id=60616&edit=1
--
Try a snapshot (PHP 5.4):
https://bugs.php.net/fix.php?id=60616&r=trysnapshot54
Try a snapshot (PHP 5.3):
https://bugs.php.net/fix.php?id=60616&r=trysnapshot53
Try a snapshot (trunk):
https://bugs.php.net/fix.php?id=60616&r=trysnapshottrunk
Fixed in SVN:
https://bugs.php.net/fix.php?id=60616&r=fixed
Fixed in SVN and need be documented:
https://bugs.php.net/fix.php?id=60616&r=needdocs
Fixed in release:
https://bugs.php.net/fix.php?id=60616&r=alreadyfixed
Need backtrace:
https://bugs.php.net/fix.php?id=60616&r=needtrace
Need Reproduce Script:
https://bugs.php.net/fix.php?id=60616&r=needscript
Try newer version:
https://bugs.php.net/fix.php?id=60616&r=oldversion
Not developer issue:
https://bugs.php.net/fix.php?id=60616&r=support
Expected behavior:
https://bugs.php.net/fix.php?id=60616&r=notwrong
Not enough info:
https://bugs.php.net/fix.php?id=60616&r=notenoughinfo
Submitted twice:
https://bugs.php.net/fix.php?id=60616&r=submittedtwice
register_globals:
https://bugs.php.net/fix.php?id=60616&r=globals
PHP 4 support discontinued:
https://bugs.php.net/fix.php?id=60616&r=php4
Daylight Savings: https://bugs.php.net/fix.php?id=60616&r=dst
IIS Stability:
https://bugs.php.net/fix.php?id=60616&r=isapi
Install GNU Sed:
https://bugs.php.net/fix.php?id=60616&r=gnused
Floating point limitations:
https://bugs.php.net/fix.php?id=60616&r=float
No Zend Extensions:
https://bugs.php.net/fix.php?id=60616&r=nozend
MySQL Configuration Error:
https://bugs.php.net/fix.php?id=60616&r=mysqlcfg