]> granicus.if.org Git - php/commitdiff
PDO MySQL: Use native types for results
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 15 Dec 2020 16:07:27 +0000 (17:07 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 17 Dec 2020 09:54:34 +0000 (10:54 +0100)
Previously, PDO MySQL only fetched data as native int/float if
native prepared statements were used. This patch updates PDO to
have the same behavior for emulated prepared statements, and thus
removes the largest remaining discrepancy between these two modes.

Note that PDO already has a ATTR_STRINGIFY_FETCHES option to control
whether native types are desired or not. The previous output can
be restored by enabling this option.

Most of the tests make use of that option, because this allows the
tests to work under libmysqlclient as well, which currently always
returns string results (independently of whether native or emulated
PS are used).

28 files changed:
UPGRADING
ext/mysqlnd/mysqlnd.h
ext/pdo_mysql/mysql_driver.c
ext/pdo_mysql/mysql_statement.c
ext/pdo_mysql/php_pdo_mysql_int.h
ext/pdo_mysql/tests/bug44327.phpt
ext/pdo_mysql/tests/bug71145.phpt
ext/pdo_mysql/tests/bug75177.phpt
ext/pdo_mysql/tests/bug80458.phpt
ext/pdo_mysql/tests/bug_33689.phpt
ext/pdo_mysql/tests/bug_41125.phpt
ext/pdo_mysql/tests/bug_41997.phpt
ext/pdo_mysql/tests/bug_61411.phpt
ext/pdo_mysql/tests/change_column_count.phpt
ext/pdo_mysql/tests/native_types.phpt [new file with mode: 0644]
ext/pdo_mysql/tests/pdo_mysql_attr_case.phpt
ext/pdo_mysql/tests/pdo_mysql_attr_init_command.phpt
ext/pdo_mysql/tests/pdo_mysql_attr_multi_statements.phpt
ext/pdo_mysql/tests/pdo_mysql_attr_statement_class.phpt
ext/pdo_mysql/tests/pdo_mysql_begintransaction.phpt
ext/pdo_mysql/tests/pdo_mysql_closecursor_error.phpt
ext/pdo_mysql/tests/pdo_mysql_pconnect.phpt
ext/pdo_mysql/tests/pdo_mysql_prepare_emulated.phpt
ext/pdo_mysql/tests/pdo_mysql_prepare_native_clear_error.phpt
ext/pdo_mysql/tests/pdo_mysql_prepare_native_dup_named_placeholder.phpt
ext/pdo_mysql/tests/pdo_mysql_prepare_native_placeholder_everywhere.phpt
ext/pdo_mysql/tests/pdo_mysql_stmt_fetchobject.phpt
ext/pdo_mysql/tests/pdo_mysql_subclass.phpt

index 7f530497e7f5fed9a6ee55c5ef43b2b9e6fe08e5..d2aaa08ac5dd8d47d8e72dee1b5f164b07a95bd9 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -31,6 +31,12 @@ PHP 8.1 UPGRADE NOTES
   . The mysqlnd.fetch_copy_data ini setting has been removed. However, this
     should not result in user-visible behavior changes.
 
+- PDO MySQL:
+  . Integers and floats in result sets will now be returned using native PHP
+    types instead of strings when using emulated prepared statements. This
+    matches the behavior of native prepared statements. You can restore the
+    previous behavior by enabling the PDO::ATTR_STRINGIFY_FETCHES option.
+
 - Standard:
   . version_compare() no longer accepts undocumented operator abbreviations.
 
index 582d8f152b83250089828b1588f055c73ea6d56d..d9e99d69db7ea249ea95b73291e841c567e51e30 100644 (file)
@@ -100,6 +100,8 @@ PHPAPI void mysqlnd_debug(const char *mode);
 /* Query */
 #define mysqlnd_fetch_into(result, flags, ret_val)     (result)->m.fetch_into((result), (flags), (ret_val) ZEND_FILE_LINE_CC)
 #define mysqlnd_fetch_row_c(result)                                            (result)->m.fetch_row_c((result))
+#define mysqlnd_fetch_row_zval(result, row_ptr, fetched) \
+       (result)->m.fetch_row((result), (row_ptr), 0, (fetched))
 #define mysqlnd_fetch_all(result, flags, return_value) (result)->m.fetch_all((result), (flags), (return_value) ZEND_FILE_LINE_CC)
 #define mysqlnd_get_connection_stats(conn, values)             ((conn)->data)->m->get_statistics((conn)->data,  (values) ZEND_FILE_LINE_CC)
 #define mysqlnd_get_client_stats(values)                               _mysqlnd_get_client_stats(mysqlnd_global_stats, (values) ZEND_FILE_LINE_CC)
index 04d0f52cbb7865af5c75dd94202cb1cd2d182bef..0523b81faf0bf358498421636f1a1730368b8aeb 100644 (file)
@@ -826,6 +826,14 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
                goto cleanup;
        }
 
+#ifdef PDO_USE_MYSQLND
+       bool int_and_float_native = true;
+       if (mysql_options(H->server, MYSQLND_OPT_INT_AND_FLOAT_NATIVE, (const char *) &int_and_float_native)) {
+               pdo_mysql_error(dbh);
+               goto cleanup;
+       }
+#endif
+
        if (vars[0].optval && mysql_options(H->server, MYSQL_SET_CHARSET_NAME, vars[0].optval)) {
                pdo_mysql_error(dbh);
                goto cleanup;
index 5e0f03fbbac4095ad4faa111a9d09581b9627202..3e83c175992df5abe4fdb6607645ff2a3959257e 100644 (file)
@@ -34,7 +34,6 @@
 #      define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt)
 #endif
 
-
 static void pdo_mysql_free_result(pdo_mysql_stmt *S)
 {
        if (S->result) {
@@ -52,8 +51,16 @@ static void pdo_mysql_free_result(pdo_mysql_stmt *S)
                        efree(S->out_length);
                        S->bound_result = NULL;
                }
+#else
+               if (S->current_row) {
+                       unsigned column_count = mysql_num_fields(S->result);
+                       for (unsigned i = 0; i < column_count; i++) {
+                               zval_ptr_dtor_nogc(&S->current_row[i]);
+                       }
+                       efree(S->current_row);
+                       S->current_row = NULL;
+               }
 #endif
-
                mysql_free_result(S->result);
                S->result = NULL;
        }
@@ -104,12 +111,6 @@ static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
                }
        }
 
-#ifdef PDO_USE_MYSQLND
-       if (!S->stmt && S->current_data) {
-               mnd_efree(S->current_data);
-       }
-#endif /* PDO_USE_MYSQLND */
-
        efree(S);
        PDO_DBG_RETURN(1);
 }
@@ -553,9 +554,24 @@ static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori
                PDO_DBG_RETURN(1);
        }
 
-       if (!S->stmt && S->current_data) {
-               mnd_efree(S->current_data);
+       zval *row_data;
+       if (mysqlnd_fetch_row_zval(S->result, &row_data, &fetched_anything) == FAIL) {
+               pdo_mysql_error_stmt(stmt);
+               PDO_DBG_RETURN(0);
+       }
+
+       if (!fetched_anything) {
+               PDO_DBG_RETURN(0);
+       }
+
+       if (!S->current_row) {
+               S->current_row = ecalloc(sizeof(zval), stmt->column_count);
        }
+       for (unsigned i = 0; i < stmt->column_count; i++) {
+               zval_ptr_dtor_nogc(&S->current_row[i]);
+               ZVAL_COPY_VALUE(&S->current_row[i], &row_data[i]);
+       }
+       PDO_DBG_RETURN(1);
 #else
        int ret;
 
@@ -577,7 +593,6 @@ static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori
 
                PDO_DBG_RETURN(1);
        }
-#endif /* PDO_USE_MYSQLND */
 
        if ((S->current_data = mysql_fetch_row(S->result)) == NULL) {
                if (!S->H->buffered && mysql_errno(S->H->server)) {
@@ -588,6 +603,7 @@ static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori
 
        S->current_lengths = mysql_fetch_lengths(S->result);
        PDO_DBG_RETURN(1);
+#endif /* PDO_USE_MYSQLND */
 }
 /* }}} */
 
@@ -630,13 +646,10 @@ static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */
                cols[i].maxlen = S->fields[i].length;
 
 #ifdef PDO_USE_MYSQLND
-               if (S->stmt) {
-                       cols[i].param_type = PDO_PARAM_ZVAL;
-               } else
+               cols[i].param_type = PDO_PARAM_ZVAL;
+#else
+               cols[i].param_type = PDO_PARAM_STR;
 #endif
-               {
-                       cols[i].param_type = PDO_PARAM_STR;
-               }
        }
        PDO_DBG_RETURN(1);
 }
@@ -652,13 +665,6 @@ static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_
                PDO_DBG_RETURN(0);
        }
 
-       /* With mysqlnd data is stored inside mysqlnd, not S->current_data */
-       if (!S->stmt) {
-               if (S->current_data == NULL || !S->result) {
-                       PDO_DBG_RETURN(0);
-               }
-       }
-
        if (colno >= stmt->column_count) {
                /* error invalid column */
                PDO_DBG_RETURN(0);
@@ -667,9 +673,12 @@ static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_
        if (S->stmt) {
                Z_TRY_ADDREF(S->stmt->data->result_bind[colno].zv);
                *ptr = (char*)&S->stmt->data->result_bind[colno].zv;
-               *len = sizeof(zval);
-               PDO_DBG_RETURN(1);
+       } else {
+               Z_TRY_ADDREF(S->current_row[colno]);
+               *ptr = (char*)&S->current_row[colno];
        }
+       *len = sizeof(zval);
+       PDO_DBG_RETURN(1);
 #else
        if (S->stmt) {
                if (S->out_null[colno]) {
@@ -688,10 +697,14 @@ static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_
                *len = S->out_length[colno];
                PDO_DBG_RETURN(1);
        }
-#endif
+
+       if (S->current_data == NULL) {
+               PDO_DBG_RETURN(0);
+       }
        *ptr = S->current_data[colno];
        *len = S->current_lengths[colno];
        PDO_DBG_RETURN(1);
+#endif
 } /* }}} */
 
 static char *type_to_name_native(int type) /* {{{ */
index 553437829e9b21eb081557e053fbc7dec63024f3..e83ac735dce25c13fd96c91881c5976cf7564192 100644 (file)
@@ -120,12 +120,6 @@ typedef struct {
        pdo_mysql_db_handle     *H;
        MYSQL_RES                               *result;
        const MYSQL_FIELD               *fields;
-       MYSQL_ROW                               current_data;
-#ifdef PDO_USE_MYSQLND
-       const size_t                    *current_lengths;
-#else
-       unsigned long                   *current_lengths;
-#endif
        pdo_mysql_error_info    einfo;
 #ifdef PDO_USE_MYSQLND
        MYSQLND_STMT                    *stmt;
@@ -137,10 +131,14 @@ typedef struct {
 #ifndef PDO_USE_MYSQLND
        my_bool                                 *in_null;
        zend_ulong                      *in_length;
-#endif
        PDO_MYSQL_PARAM_BIND    *bound_result;
        my_bool                                 *out_null;
        zend_ulong                              *out_length;
+       MYSQL_ROW                               current_data;
+       unsigned long                   *current_lengths;
+#else
+       zval                                    *current_row;
+#endif
        unsigned                                max_length:1;
        /* Whether all result sets have been fully consumed.
         * If this flag is not set, they need to be consumed during destruction. */
index 8fa0025dd62612337ea775ffe0eaec1f2c5fdc66..ad31d21ff82fdf62343ca538805109fcb0225286 100644 (file)
@@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
 <?php
     require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
     $db = MySQLPDOTest::factory();
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
     $stmt = $db->prepare("SELECT 1 AS \"one\"");
     $stmt->execute();
@@ -51,7 +52,7 @@ string(1) "1"
 string(1) "1"
 string(17) "SELECT 1 AS "one""
 ----------------------------------
-object(PDORow)#%d (2) {
+object(PDORow)#5 (2) {
   ["queryString"]=>
   string(19) "SELECT id FROM test"
   ["id"]=>
index b3f887d7c4d89c494d8a5731cfdc6d19e8a5776a..2f2834cbca2133d552319e20e81413e7abdbadae 100644 (file)
@@ -14,6 +14,7 @@ require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
 $attr = array(
     PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
     PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci; SET SESSION sql_mode=traditional',
+    PDO::ATTR_STRINGIFY_FETCHES => true,
 );
 putenv('PDOTEST_ATTR=' . serialize($attr));
 
index f6414f0b296f0b6724f20ad02e9a1555b1cbb6cb..b580c9a929c574f9760532e7db1826a5fd0cb1d3 100644 (file)
@@ -5,6 +5,7 @@ PDO MySQL Bug #75177 Type 'bit' is fetched as unexpected string
 require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc');
 require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
 MySQLPDOTest::skip();
+if (!MySQLPDOTest::isPDOMySQLnd()) die('skip only for mysqlnd');
 ?>
 --FILE--
 <?php
@@ -18,14 +19,23 @@ $pdo->query("INSERT INTO $tbl (`bit`) VALUES (1)");
 $pdo->query("INSERT INTO $tbl (`bit`) VALUES (0b011)");
 $pdo->query("INSERT INTO $tbl (`bit`) VALUES (0b01100)");
 
+$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
 $ret = $pdo->query("SELECT * FROM $tbl")->fetchAll();
+foreach ($ret as $i) {
+    var_dump($i["bit"]);
+}
 
+$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+$ret = $pdo->query("SELECT * FROM $tbl")->fetchAll();
 foreach ($ret as $i) {
     var_dump($i["bit"]);
 }
 
 ?>
 --EXPECT--
-string(1) "1"
-string(1) "3"
-string(2) "12"
+int(1)
+int(3)
+int(12)
+int(1)
+int(3)
+int(12)
index 86e171d302d27510047761083c71bec45faea353..10bf305d60decc0e957fc39b7394e0ada8433e68 100644 (file)
@@ -14,6 +14,7 @@ require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
 $db = MySQLPDOTest::factory();
 $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
 $db->query('DROP TABLE IF EXISTS test');
 $db->query('CREATE TABLE test (first int) ENGINE = InnoDB');
@@ -127,9 +128,9 @@ array(1) {
   [0]=>
   array(2) {
     ["first"]=>
-    int(5)
+    string(1) "5"
     [0]=>
-    int(5)
+    string(1) "5"
   }
 }
 array(0) {
@@ -138,9 +139,9 @@ array(1) {
   [0]=>
   array(2) {
     ["first"]=>
-    int(7)
+    string(1) "7"
     [0]=>
-    int(7)
+    string(1) "7"
   }
 }
 array(0) {
@@ -179,8 +180,8 @@ array(1) {
   [0]=>
   array(2) {
     ["first"]=>
-    int(16)
+    string(2) "16"
     [0]=>
-    int(16)
+    string(2) "16"
   }
 }
index 84b8f5b914be130ee80c560a0738dfd5e972a556..463a74ed58818fba9393c4835c1eb8438b490184 100644 (file)
@@ -27,8 +27,8 @@ $stmt->execute();
 $tmp = $stmt->getColumnMeta(0);
 
 // libmysql and mysqlnd will show the pdo_type entry at a different position in the hash
-if (!isset($tmp['pdo_type']) || (isset($tmp['pdo_type']) && $tmp['pdo_type'] != 2))
-    printf("Expecting pdo_type = 2 got %s\n", $tmp['pdo_type']);
+if (!isset($tmp['pdo_type']) || (isset($tmp['pdo_type']) && $tmp['pdo_type'] != 1))
+    printf("Expecting pdo_type = 1 got %s\n", $tmp['pdo_type']);
 else
     unset($tmp['pdo_type']);
 
index d96778d75468ba831eb323217ee741a2dca70668..5962cec8988f2e7d8ac2500d3d5026ea1423dcf2 100644 (file)
@@ -21,6 +21,7 @@ if ($version < 40100)
 <?php
 require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
 $db = MySQLPDOTest::factory();
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 $db->exec("DROP TABLE IF EXISTS test");
 
 // And now allow the evil to do his work
index 769080f86a228541d5d5c755d8c7a1d17d7fc00d..8d20ed737e195eda40f1241e5cebd9b9fff841ea 100644 (file)
@@ -21,6 +21,7 @@ if ($version < 50000)
 <?php
 require __DIR__ . '/mysql_pdo_test.inc';
 $db = MySQLPDOTest::factory();
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
 $db->exec('DROP PROCEDURE IF EXISTS p');
 $db->exec('CREATE PROCEDURE p() BEGIN SELECT 1 AS "one"; END');
index 9390e2abffb986c6f0ba19eda6e4e336ff7cb256..d80c685cd79cdeeb1fa7267f0c1454f48cebbf02 100644 (file)
@@ -30,6 +30,7 @@ if (!$attr) {
 }
 $attr[PDO::ATTR_PERSISTENT] = true;
 $attr[PDO::ATTR_EMULATE_PREPARES] = false;
+$attr[PDO::ATTR_STRINGIFY_FETCHES] = true;
 putenv('PDOTEST_ATTR='.serialize($attr));
 
 $db = MySQLPDOTest::factory();
@@ -46,8 +47,8 @@ print "done!";
 --EXPECT--
 array(2) {
   [1]=>
-  int(1)
+  string(1) "1"
   [0]=>
-  int(1)
+  string(1) "1"
 }
 done!
index 5bb521d300c243a5a7365b931c83a48b5ec7f4b4..6349be3ea445820e55e6a4d919d5f676a9a4a77f 100644 (file)
@@ -12,7 +12,8 @@ MySQLPDOTest::skip();
 require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
 
 $db = MySQLPDOTest::factory();
-$db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
 $db->exec('DROP TABLE IF EXISTS test');
 $db->exec('CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(255) NOT NULL)');
diff --git a/ext/pdo_mysql/tests/native_types.phpt b/ext/pdo_mysql/tests/native_types.phpt
new file mode 100644 (file)
index 0000000..8c6be68
--- /dev/null
@@ -0,0 +1,50 @@
+--TEST--
+PDO MySQL should use native types if ATTR_STRINGIFY_FETCHES is not enabled
+--SKIPIF--
+<?php
+require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc');
+require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+MySQLPDOTest::skip();
+if (!MySQLPDOTest::isPDOMySQLnd()) die('skip mysqlnd only');
+?>
+--FILE--
+<?php
+require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+
+$db = MySQLPDOTest::factory();
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+$db->exec('DROP TABLE IF EXISTS test');
+$db->exec('CREATE TABLE test (i INT, f FLOAT)');
+$db->exec('INSERT INTO test VALUES (42, 42.5)');
+
+$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+var_dump($db->query('SELECT * FROM test')->fetchAll(PDO::FETCH_ASSOC));
+
+$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
+var_dump($db->query('SELECT * FROM test')->fetchAll(PDO::FETCH_ASSOC));
+?>
+--CLEAN--
+<?php
+require __DIR__ . '/mysql_pdo_test.inc';
+MySQLPDOTest::dropTestTable();
+?>
+--EXPECT--
+array(1) {
+  [0]=>
+  array(2) {
+    ["i"]=>
+    int(42)
+    ["f"]=>
+    float(42.5)
+  }
+}
+array(1) {
+  [0]=>
+  array(2) {
+    ["i"]=>
+    int(42)
+    ["f"]=>
+    float(42.5)
+  }
+}
index 2b45154248cf82628278baf47c8a1f9adf1469bc..f9f0f55afb9ace2de0c0f147bee68505e8e030bd 100644 (file)
@@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
 <?php
     require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
     $db = MySQLPDOTest::factory();
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
     MySQLPDOTest::createTestTable($db);
 
     $default =  $db->getAttribute(PDO::ATTR_CASE);
index c979075fd7fc82a2dda68954662fb36b7a335607..b12161d4f3e34ecb076a07ec9b0e775a91aed216 100644 (file)
@@ -24,6 +24,7 @@ error_reporting=E_ALL
     $create = sprintf('CREATE TABLE %s(id INT)', $table);
     var_dump($create);
     $db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => $create));
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
     $info = $db->errorInfo();
     var_dump($info[0]);
index f268117821d21fff75cab8c3d2395e0601648794..34d9d57ce3c30ec4a98a79290e4f97e9dfcd2dbc 100644 (file)
@@ -20,6 +20,7 @@ error_reporting=E_ALL
     $table = sprintf("test_%s", md5(mt_rand(0, PHP_INT_MAX)));
     $db = new PDO($dsn, $user, $pass);
     $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
     $db->exec(sprintf('DROP TABLE IF EXISTS %s', $table));
     $create = sprintf('CREATE TABLE %s(id INT)', $table);
     $db->exec($create);
@@ -37,6 +38,7 @@ error_reporting=E_ALL
     // New connection, does not allow multiple statements.
     $db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => false));
     $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
     $stmt = $db->query(sprintf('SELECT * FROM %s; INSERT INTO %s(id) VALUES (3)', $table, $table));
     var_dump($stmt);
     $info = $db->errorInfo();
index 77f231d28fa653d6a53faeb67dc1ea96e25ce0d7..4bbf63993970bdefe3432982d47a3f80344fc934 100644 (file)
@@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
 <?php
     require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
     $db = MySQLPDOTest::factory();
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
     MySQLPDOTest::createTestTable($db);
 
     $default =  $db->getAttribute(PDO::ATTR_STATEMENT_CLASS);
index fb550b1aa2d33a9249365cc410e02104f7844756..cdecc97b2e3ba02252d0af86635ca3410e9c4f38 100644 (file)
@@ -13,6 +13,7 @@ if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
 <?php
     require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
     $db = MySQLPDOTest::factory();
+
     MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
 
     if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
@@ -31,6 +32,7 @@ if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
     /* This is the PDO way to close a connection */
     $db = null;
     $db = MySQLPDOTest::factory();
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
     /* Autocommit was off - by definition. Commit was not issued. DELETE should have been rolled back. */
     if (!($stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC')))
index 1f9421fe8af1e420247ac5140f37c2b5da1ea445..5d4c9335426f8692b44d4029ff573b05ca5e7792 100644 (file)
@@ -10,6 +10,7 @@ MySQLPDOTest::skip();
 <?php
 require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
 $db = MySQLPDOTest::factory();
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
 $stmt = $db->query('SELECT 1; SELECT x FROM does_not_exist');
 var_dump($stmt->fetchAll());
index 51e5b7b44af9ce067e973269b40a5504f92b6c60..72a29f9e36eed190e30fbe253a0aea03e8817ee5 100644 (file)
@@ -23,7 +23,7 @@ MySQLPDOTest::skip();
         $db1->exec('SET @pdo_persistent_connection=1');
         $stmt = $db2->query('SELECT @pdo_persistent_connection as _pers');
         $tmp = $stmt->fetch(PDO::FETCH_ASSOC);
-        if ($tmp['_pers'] !== '1')
+        if ($tmp['_pers'] != 1)
             printf("[001] Both handles should use the same connection.");
 
         $stmt = $db1->query('SELECT CONNECTION_ID() as _con1');
index b23d697efa89ec5681e68d176c77d28a3c98f5d9..f4f1dcd13d61fcda432d7e4d6218bf69d96d837e 100644 (file)
@@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
 <?php
     require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
     $db = MySQLPDOTest::factory();
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
     function prepex($offset, &$db, $query, $input_params = null, $error_info = null) {
 
index 88f9f5dcf1be15d142483a3e5bd3b1ee4539ea20..5f32da7412f11e92ab94a04272893eabc7dc9cd6 100644 (file)
@@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
 <?php
     require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
     $db = MySQLPDOTest::factory();
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
     try {
 
index 1c5ddc407fa63eb55fa03de652d6d05e391b2846..8e521549026936b68a3171b619479e95e1781e92 100644 (file)
@@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
 <?php
     require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
     $db = MySQLPDOTest::factory();
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 
     try {
 
index a7a76a462bf565eaa2fa9d6eebf4ffb83630e237..50819f969531832a12d59d997a7765b4216b6052 100644 (file)
@@ -11,6 +11,8 @@ $db = MySQLPDOTest::factory();
 <?php
     require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
     $db = MySQLPDOTest::factory();
+    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
+
     try {
         $db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
         if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
@@ -41,16 +43,7 @@ $db = MySQLPDOTest::factory();
                 var_export($stmt->errorCode(), true),
                 var_export($stmt->errorInfo(), true));
 
-        $tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
-        if (!MySQLPDOTest::isPDOMySQLnd()) {
-            if (isset($tmp[0]['id'])) {
-                // libmysql should return a string here whereas mysqlnd returns a native int
-                if (gettype($tmp[0]['id']) == 'string')
-                    // convert to int for the test output...
-                    settype($tmp[0]['id'], 'integer');
-            }
-        }
-        var_dump($tmp);
+        var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
 
     } catch (PDOException $e) {
         printf("[001] %s [%s] %s\n",
@@ -82,7 +75,7 @@ array(1) {
     ["?"]=>
     string(2) "id"
     ["id"]=>
-    int(1)
+    string(1) "1"
     ["label"]=>
     string(4) "row1"
   }
index e83a99f5290b5c735a6fbdf0696d12013d94c0c1..bb92353fbe112bc4a2fb9ce5887f49ca8b700d5f 100644 (file)
@@ -21,6 +21,7 @@ if (!$ok)
 <?php
 require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
 $db = MySQLPDOTest::factory();
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
 MySQLPDOTest::createTestTable($db);
 
 try {
index 0a996be8f5fcebaa70ca225fec53d20616eda5cb..d79de1486263cb31468b50b56724c1e8aa208ebb 100644 (file)
@@ -51,6 +51,7 @@ MySQLPDOTest::skip();
         }
 
         $db = new MyPDO(PDO_MYSQL_TEST_DSN, PDO_MYSQL_TEST_USER, PDO_MYSQL_TEST_PASS);
+        $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
         $db->exec('DROP TABLE IF EXISTS test');
         $db->exec('CREATE TABLE test(id INT)');
         $db->exec('INSERT INTO test(id) VALUES (1), (2)');