]> granicus.if.org Git - php/commitdiff
Corrected patch for bug #60616
authorKeyur Govande <keyur@php.net>
Wed, 30 Jul 2014 02:28:31 +0000 (02:28 +0000)
committerKeyur Govande <keyur@php.net>
Wed, 30 Jul 2014 02:28:31 +0000 (02:28 +0000)
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
ext/odbc/php_odbc_includes.h
ext/odbc/tests/bug60616.phpt [new file with mode: 0644]
ext/odbc/tests/odbc_columns_001.phpt
ext/odbc/tests/odbc_free_result_001.phpt
main/php_version.h

index a6544d31e4ccf2823b300a22d652331ff1a7cdcf..19f9fe4eb0c5c364170b3082ec1b749acc067c50 100644 (file)
@@ -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("<td>Not printable</td>"); 
index b3ae88997403e17322dbc0cf395402f5e6987e7e..06113d9624a0f77c2d2c139e145afab63ee02207 100644 (file)
@@ -115,6 +115,7 @@ PHP_FUNCTION(solid_fetch_prev);
 #endif
 
 #define ODBC_TYPE "unixODBC"
+#undef ODBCVER
 #include <sql.h>
 #include <sqlext.h>
 #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 (file)
index 0000000..937049a
--- /dev/null
@@ -0,0 +1,69 @@
+--TEST--
+odbc_exec(): Getting accurate unicode data from query
+--SKIPIF--
+<?php include 'skipif.inc'; ?>
+--FILE--
+<?php
+
+// Test strings
+mb_internal_encoding("EUC_JP");
+$euc_jp_base64 = 'pdal6aWkpcCl676uyqo=';
+$euc_jp = base64_decode($euc_jp_base64);
+$ascii = 'abcdefghijklmnopqrstuvwxyz;]=#0123456789';
+
+include 'config.inc';
+ini_set("odbc.defaultlrl", 4); // Set artifically low
+
+$conn = odbc_connect($dsn, $user, $pass);
+
+odbc_exec($conn, 'CREATE DATABASE odbcTEST ENCODING=\'EUC_JP\'');
+
+odbc_exec($conn, 'CREATE TABLE FOO (ID INT, CHAR_COL CHAR(200), VARCHAR_COL VARCHAR(200), TEXT_COL TEXT)');
+
+odbc_exec($conn, "INSERT INTO FOO(ID, CHAR_COL, VARCHAR_COL, TEXT_COL) VALUES (1, '$euc_jp', '$euc_jp', '$euc_jp')");
+odbc_exec($conn, "INSERT INTO FOO(ID, CHAR_COL, VARCHAR_COL, TEXT_COL) VALUES (2, '$ascii', '$ascii', '$ascii')");
+
+$res = odbc_exec($conn, 'SELECT * FROM FOO ORDER BY ID ASC');
+
+while(odbc_fetch_row($res)) {
+       $char_col = odbc_result($res, "CHAR_COL");
+       $varchar_col = odbc_result($res, "VARCHAR_COL");
+       $id = odbc_result($res, "ID");
+       $text_col = "";
+       while (($chunk=odbc_result($res, "TEXT_COL")) !== false) {
+               $text_col .= $chunk;
+       }
+
+       if ($id == 1) {
+               $euc_jp_check = $euc_jp . str_repeat(" ", (200 - mb_strlen($euc_jp)));
+               if (strcmp($char_col, $euc_jp_check) == 0 && strcmp($varchar_col, $euc_jp) == 0 &&
+                       strcmp($text_col, $euc_jp) == 0) {
+                       print "EUC-JP matched\n";
+               } else {
+                       print "EUC-JP mismatched\n";
+               }
+       } else {
+               $ascii_check = $ascii . str_repeat(" ", (200 - strlen($ascii)));
+               if (strcmp($char_col, $ascii_check) == 0 && strcmp($varchar_col, $ascii) == 0 &&
+                       strcmp($text_col, $ascii) == 0) {
+                       print "ASCII matched\n";
+               } else {
+                       print "ASCII mismatched\n";
+               }
+       }
+}
+
+?>
+--EXPECT--
+EUC-JP matched
+ASCII matched
+--CLEAN--
+<?php
+include 'config.inc';
+
+$conn = odbc_connect($dsn, $user, $pass);
+
+odbc_exec($conn, 'DROP TABLE FOO');
+odbc_exec($conn, 'DROP DATABASE odbcTEST');
+
+?>
index f6da78e8e713f4ad390db2174ab2f40b4440441b..fbbc3e2e0334acc4c277b9c555627cdf15a1e18e 100644 (file)
@@ -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
index 4fcd5cda2cc712c963cf48057612586bdde739a6..970450141375bfcb9677ad2d8c64a99d592693af 100644 (file)
@@ -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)');
index c6aa0244365f528437b9d83c6ded285979a4e5ad..a1d9d8ec808d8539f57452e841fb9237abf6e49b 100644 (file)
@@ -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