From 65364fe7d00319f6bfb4814980988d34183f9f78 Mon Sep 17 00:00:00 2001 From: Keyur Govande Date: Wed, 30 Jul 2014 02:28:31 +0000 Subject: [PATCH] Corrected patch for bug #60616 For unixODBC, use ODBC version as defined by it (as of v2.2.14 it is 3.5). This allows us to use newer features like SQL_DESC_OCTET_LENGTH (which returns the number of bytes required to store the data). This fixes the issue in #60616. If the newer version is not available, over-allocate to accomodate 4-byte Unicode characters for CHAR and VARCHAR datatypes (and their Wide counterparts). version. Fixed a couple of failing tests. --- ext/odbc/php_odbc.c | 63 +++++++++++++++------- ext/odbc/php_odbc_includes.h | 7 ++- ext/odbc/tests/bug60616.phpt | 69 ++++++++++++++++++++++++ ext/odbc/tests/odbc_columns_001.phpt | 6 +-- ext/odbc/tests/odbc_free_result_001.phpt | 2 +- main/php_version.h | 1 - 6 files changed, 121 insertions(+), 27 deletions(-) create mode 100644 ext/odbc/tests/bug60616.phpt diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index a6544d31e4..19f9fe4eb0 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -780,8 +780,9 @@ PHP_MINIT_FUNCTION(odbc) REGISTER_LONG_CONSTANT("SQL_TYPE_DATE", SQL_TYPE_DATE, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("SQL_TYPE_TIME", SQL_TYPE_TIME, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT("SQL_TYPE_TIMESTAMP", SQL_TYPE_TIMESTAMP, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("SQL_TYPE_WVARCHAR", SQL_TYPE_WVARCHAR, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("SQL_TYPE_WLONGVARCHAR", SQL_TYPE_WLONGVARCHAR, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQL_WCHAR", SQL_WCHAR, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQL_WVARCHAR", SQL_WVARCHAR, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQL_WLONGVARCHAR", SQL_WLONGVARCHAR, CONST_PERSISTENT | CONST_CS); /* * SQLSpecialColumns values @@ -945,9 +946,13 @@ int odbc_bindcols(odbc_result *result TSRMLS_DC) { RETCODE rc; int i; - SQLSMALLINT colnamelen; /* Not used */ - SQLLEN displaysize; + SQLSMALLINT colnamelen; /* Not used */ + SQLLEN displaysize; + SQLUSMALLINT colfieldid; + int charextraalloc; + colfieldid = SQL_COLUMN_DISPLAY_SIZE; + charextraalloc = 0; result->values = (odbc_result_value *) safe_emalloc(sizeof(odbc_result_value), result->numcols, 0); result->longreadlen = ODBCG(defaultlrl); @@ -968,8 +973,9 @@ int odbc_bindcols(odbc_result *result TSRMLS_DC) case SQL_VARBINARY: case SQL_LONGVARBINARY: case SQL_LONGVARCHAR: - case SQL_WVARCHAR: +#if defined(ODBCVER) && (ODBCVER >= 0x0300) case SQL_WLONGVARCHAR: +#endif result->values[i].value = NULL; break; @@ -980,15 +986,27 @@ int odbc_bindcols(odbc_result *result TSRMLS_DC) 27, &result->values[i].vallen); break; #endif /* HAVE_ADABAS */ + case SQL_CHAR: + case SQL_VARCHAR: +#if defined(ODBCVER) && (ODBCVER >= 0x0300) + case SQL_WCHAR: + case SQL_WVARCHAR: + colfieldid = SQL_DESC_OCTET_LENGTH; +#else + charextraalloc = 1; +#endif default: - rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_DISPLAY_SIZE, - NULL, 0, NULL, &displaysize); - displaysize = displaysize <= result->longreadlen ? displaysize : - result->longreadlen; + rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), colfieldid, + NULL, 0, NULL, &displaysize); /* Workaround for Oracle ODBC Driver bug (#50162) when fetching TIMESTAMP column */ if (result->values[i].coltype == SQL_TIMESTAMP) { displaysize += 3; } + + if (charextraalloc) { + /* Since we don't know the exact # of bytes, allocate extra */ + displaysize *= 4; + } result->values[i].value = (char *)emalloc(displaysize + 1); rc = SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value, displaysize + 1, &result->values[i].vallen); @@ -1728,9 +1746,10 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type) if (result->binmode == 1) { sql_c_type = SQL_C_BINARY; } - case SQL_WVARCHAR: - case SQL_WLONGVARCHAR: case SQL_LONGVARCHAR: +#if defined(ODBCVER) && (ODBCVER >= 0x0300) + case SQL_WLONGVARCHAR: +#endif if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) { Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC(); break; @@ -1882,9 +1901,11 @@ PHP_FUNCTION(odbc_fetch_into) break; } if (result->binmode == 1) sql_c_type = SQL_C_BINARY; - case SQL_WVARCHAR: - case SQL_WLONGVARCHAR: + case SQL_LONGVARCHAR: +#if defined(ODBCVER) && (ODBCVER >= 0x0300) + case SQL_WLONGVARCHAR: +#endif if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) { Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC(); break; @@ -2103,8 +2124,9 @@ PHP_FUNCTION(odbc_result) break; } case SQL_LONGVARCHAR: - case SQL_WVARCHAR: +#if defined(ODBCVER) && (ODBCVER >= 0x0300) case SQL_WLONGVARCHAR: +#endif if (IS_SQL_LONG(result->values[field_ind].coltype)) { if (result->longreadlen <= 0) { break; @@ -2142,9 +2164,11 @@ PHP_FUNCTION(odbc_result) } /* Reduce fieldlen by 1 if we have char data. One day we might have binary strings... */ - if ((result->values[field_ind].coltype == SQL_LONGVARCHAR) || - (result->values[field_ind].coltype == SQL_WVARCHAR) || - (result->values[field_ind].coltype == SQL_WLONGVARCHAR)) { + if ((result->values[field_ind].coltype == SQL_LONGVARCHAR) +#if defined(ODBCVER) && (ODBCVER >= 0x0300) + || (result->values[field_ind].coltype == SQL_WLONGVARCHAR) +#endif + ) { fieldsize -= 1; } /* Don't duplicate result, saves one emalloc. @@ -2259,9 +2283,10 @@ PHP_FUNCTION(odbc_result_all) break; } if (result->binmode <= 1) sql_c_type = SQL_C_BINARY; - case SQL_WVARCHAR: - case SQL_WLONGVARCHAR: case SQL_LONGVARCHAR: +#if defined(ODBCVER) && (ODBCVER >= 0x0300) + case SQL_WLONGVARCHAR: +#endif if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) { php_printf("Not printable"); diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h index b3ae889974..06113d9624 100644 --- a/ext/odbc/php_odbc_includes.h +++ b/ext/odbc/php_odbc_includes.h @@ -115,6 +115,7 @@ PHP_FUNCTION(solid_fetch_prev); #endif #define ODBC_TYPE "unixODBC" +#undef ODBCVER #include #include #define HAVE_SQL_EXTENDED_FETCH 1 @@ -284,7 +285,11 @@ int odbc_bindcols(odbc_result *result TSRMLS_DC); void odbc_sql_error(ODBC_SQL_ERROR_PARAMS); -#define IS_SQL_LONG(x) (x == SQL_LONGVARBINARY || x == SQL_LONGVARCHAR || x == SQL_WVARCHAR || x == SQL_WLONGVARCHAR) +#if defined(ODBCVER) && (ODBCVER >= 0x0300) +#define IS_SQL_LONG(x) (x == SQL_LONGVARBINARY || x == SQL_LONGVARCHAR || x == SQL_WLONGVARCHAR) +#else +#define IS_SQL_LONG(x) (x == SQL_LONGVARBINARY || x == SQL_LONGVARCHAR) +#endif #define IS_SQL_BINARY(x) (x == SQL_BINARY || x == SQL_VARBINARY || x == SQL_LONGVARBINARY) #ifdef ZTS diff --git a/ext/odbc/tests/bug60616.phpt b/ext/odbc/tests/bug60616.phpt new file mode 100644 index 0000000000..937049a9b8 --- /dev/null +++ b/ext/odbc/tests/bug60616.phpt @@ -0,0 +1,69 @@ +--TEST-- +odbc_exec(): Getting accurate unicode data from query +--SKIPIF-- + +--FILE-- + +--EXPECT-- +EUC-JP matched +ASCII matched +--CLEAN-- + diff --git a/ext/odbc/tests/odbc_columns_001.phpt b/ext/odbc/tests/odbc_columns_001.phpt index f6da78e8e7..fbbc3e2e03 100644 --- a/ext/odbc/tests/odbc_columns_001.phpt +++ b/ext/odbc/tests/odbc_columns_001.phpt @@ -24,9 +24,5 @@ resource(%d) of type (odbc result) bool(false) resource(%d) of type (odbc result) bool(false) - -Warning: odbc_columns(): SQL error: Failed to fetch error message, SQL state HY000 in SQLColumns in %s on line %d +resource(%d) of type (odbc result) bool(false) - -Warning: odbc_fetch_row() expects parameter 1 to be resource, boolean given in %s on line %d -NULL diff --git a/ext/odbc/tests/odbc_free_result_001.phpt b/ext/odbc/tests/odbc_free_result_001.phpt index 4fcd5cda2c..9704501413 100644 --- a/ext/odbc/tests/odbc_free_result_001.phpt +++ b/ext/odbc/tests/odbc_free_result_001.phpt @@ -12,7 +12,7 @@ $conn = odbc_connect($dsn, $user, $pass); odbc_exec($conn, 'CREATE DATABASE odbcTEST'); odbc_exec($conn, 'CREATE TABLE FOO (TEST INT)'); -odbc_exec($conn, 'ALTER TABLE FOO ADD PRIMARY KEY FOO(TEST)'); +odbc_exec($conn, 'ALTER TABLE FOO ADD PRIMARY KEY (TEST)'); odbc_exec($conn, 'INSERT INTO FOO VALUES (1)'); odbc_exec($conn, 'INSERT INTO FOO VALUES (2)'); diff --git a/main/php_version.h b/main/php_version.h index c6aa024436..a1d9d8ec80 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -3,7 +3,6 @@ #define PHP_MAJOR_VERSION 5 #define PHP_MINOR_VERSION 4 #define PHP_RELEASE_VERSION 32 - #define PHP_EXTRA_VERSION "-dev" #define PHP_VERSION "5.4.32-dev" #define PHP_VERSION_ID 50432 -- 2.40.0