|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2003-10-23 23:26 UTC] phpbug at chipple dot net
Description: ------------ This bug has been observed with PHP 4.3.3 and 4.3.4RC2. Database: MSSQL 2000 (8.00.760) SP3 I have a MSSQL database with a table containing a column tTitle of type nvarchar(80) (which stands for 80 multi-byte characters). When a string of 60 Japanese double-byte characters (120 bytes) stored in column tTitle is retrieved using PHP's ODBC extension, the value is truncated to 80 bytes. The PHP MSSQL extension retrieves the data correctly. Microsoft's ODBC driver (used from ASP) retrieves the data correctly. MSSQL table structure: CREATE TABLE [dbo].[T_Course] ( [aCourseID] [int] IDENTITY (1, 1) NOT NULL , [tTitle] [nvarchar] (80) COLLATE Japanese_CI_AS NOT NULL ) ON [PRIMARY] GO Test data (CSV): aCourseID,tTitle 1,[string of 60 Japanese double-byte characters] SQL query: SELECT * FROM T_Course WHERE aCourseID=1 Reproduce code: --------------- // ODBC EXTENSION, data truncated $oConn = odbc_connect(C_Gen_sDbDSN,C_Gen_sDbUser,C_Gen_sDbPassword); $oRs = odbc_exec($oConn,"SELECT * FROM T_Course WHERE aCourseID=1"); $aRow = odbc_fetch_array($oRs); // BAD: Title truncated to 80 _bytes_ echo $aRow["tTitle"]; odbc_close($oConn); // MSSQL EXTENSION, data retrieved correctly $oConn = odbc_connect(C_Gen_sDbDSN,C_Gen_sDbUser,C_Gen_sDbPassword); $oRs = odbc_exec($oConn,"SELECT * FROM T_Course WHERE aCourseID=1"); $aRow = odbc_fetch_array($oRs); // GOOD: Complete title retrieved (60 chars=120 bytes) echo $aRow["tTitle"]; odbc_close($oConn); Expected result: ---------------- The ODBC extension should truncate the retrieved data to 80 characters (instead of 80 bytes). Actual result: -------------- The ODBC extension truncates the retrieved data to 80 bytes. PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Tue Nov 04 16:00:01 2025 UTC |
Sorry here's the MSSQL extension code that should have been in the 2nd part of "Reproduce code". // MSSQL EXTENSION, data retrieved correctly $oConn = mssql_connect("localhost",C_Gen_sDbUser,C_Gen_sDbPassword); mssql_select_db("icds",$oConn); $oRs = mssql_query("SELECT * FROM T_Course WHERE aCourseID=1"); $aRow = mssql_fetch_array($oRs); // GOOD: Complete title retrieved (60 chars=120 bytes) echo $aRow["tTitle"]; mssql_close($oConn);Thank you very much for the attention to my bug report. I gave the fix a try in my environment but then all field values received are empty (details below). Perhaps the SQL_COLUMN_LENGTH attribute always contains the value 0? // Test code $oOdbcConn = odbc_connect(C_Gen_sDbDSN,C_Gen_sDbUser,C_Gen_sDbPassword); $oOdbcRs = odbc_exec($oOdbcConn,$sSql); $aOdbcRow = odbc_fetch_array($oOdbcRs); for ($i = 1; $i <= odbc_num_fields($oOdbcRs); $i++) echo odbc_field_name($oOdbcRs,$i).": ". odbc_field_len($oOdbcRs,$i).": ". strlen($aOdbcRow[odbc_field_name($oOdbcRs,$i)]).": ". gettype($aOdbcRow[odbc_field_name($oOdbcRs,$i)])."<br>"; // Result with php4-STABLE-200311050430 before change // (SQL_COLUMN_DISPLAY_SIZE) aCourseID: 10: 1: string tTitle: 80: 86: string // Result with php4-STABLE-200311050430 after change // (SQL_COLUMN_LENGTH) aCourseID: 10: 0: NULL tTitle: 80: 0: NULLI have the same problem with php 5.3.8 using PostgreSQL with char columns. If 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 charater 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.