]> granicus.if.org Git - php/commitdiff
Add "Sent SQL" to debug dump for emulated prepares
authorAdam Baratz <adambaratz@php.net>
Tue, 20 Dec 2016 14:59:39 +0000 (09:59 -0500)
committerAdam Baratz <adambaratz@php.net>
Tue, 20 Dec 2016 16:07:04 +0000 (11:07 -0500)
NEWS
ext/pdo/pdo_stmt.c
ext/pdo/tests/debug_emulated_prepares.phpt [new file with mode: 0644]
ext/pdo_dblib/dblib_driver.c
ext/pdo_pgsql/tests/debug_emulated_prepares.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index e4588aa1f22d5f9c486e56d04ef3028298428473..a982bbd8d18c8e0b28cb2a7c5a9694d886d2ef33 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -58,6 +58,9 @@ PHP                                                                        NEWS
 - Mcrypt:
   . The deprecated mcrypt extension has been moved to PECL. (leigh)
 
+- PDO:
+  . Add "Sent SQL" to debug dump for emulated prepares. (Adam Baratz)
+
 - PDO_DBlib:
   . Fixed bug #73234 (Emulated statements let value dictate parameter type).
     (Adam Baratz)
index 9f61a052c4fe1ad757f35c094213a6f8307e0f9c..e68ab959212ffae5380ecc401f8ae129fc2da8db 100644 (file)
@@ -486,6 +486,12 @@ static PHP_METHOD(PDOStatement, execute)
                 * quoted.
          */
 
+               /* string is leftover from previous calls so PDOStatement::debugDumpParams() can access */
+               if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
+                       efree(stmt->active_query_string);
+               }
+               stmt->active_query_string = NULL;
+
                ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
                        &stmt->active_query_string, &stmt->active_query_stringlen);
 
@@ -504,10 +510,6 @@ static PHP_METHOD(PDOStatement, execute)
                RETURN_FALSE;
        }
        if (stmt->methods->executer(stmt)) {
-               if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
-                       efree(stmt->active_query_string);
-               }
-               stmt->active_query_string = NULL;
                if (!stmt->executed) {
                        /* this is the first execute */
 
@@ -526,10 +528,6 @@ static PHP_METHOD(PDOStatement, execute)
 
                RETURN_BOOL(ret);
        }
-       if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
-               efree(stmt->active_query_string);
-       }
-       stmt->active_query_string = NULL;
        PDO_HANDLE_STMT_ERR();
        RETURN_FALSE;
 }
@@ -2108,6 +2106,14 @@ static PHP_METHOD(PDOStatement, debugDumpParams)
                stmt->query_stringlen,
                (int) stmt->query_stringlen, stmt->query_string);
 
+       /* show parsed SQL if emulated prepares enabled */
+       /* pointers will be equal if PDO::query() was invoked */
+       if (stmt->active_query_string != NULL && stmt->active_query_string != stmt->query_string) {
+               php_stream_printf(out, "Sent SQL: [%zd] %.*s\n",
+                       stmt->active_query_stringlen,
+                       (int) stmt->active_query_stringlen, stmt->active_query_string);
+       }
+
        php_stream_printf(out, "Params:  %d\n",
                stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
 
@@ -2317,6 +2323,9 @@ PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt)
        if (stmt->methods && stmt->methods->dtor) {
                stmt->methods->dtor(stmt);
        }
+       if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
+               efree(stmt->active_query_string);
+       }
        if (stmt->query_string) {
                efree(stmt->query_string);
        }
diff --git a/ext/pdo/tests/debug_emulated_prepares.phpt b/ext/pdo/tests/debug_emulated_prepares.phpt
new file mode 100644 (file)
index 0000000..1325238
--- /dev/null
@@ -0,0 +1,66 @@
+--TEST--
+PDO Common: PDOStatement::debugDumpParams() with emulated prepares
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo')) die('skip');
+$dir = getenv('REDIR_TEST_DIR');
+if (false == $dir) die('skip no driver');
+require_once $dir . 'pdo_test.inc';
+PDOTest::skip();
+
+$db = PDOTest::factory();
+if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'pgsql') die('skip pgsql has its own test for this feature');
+if (!$db->getAttribute(PDO::ATTR_EMULATE_PREPARES) && !$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true)) die('skip driver cannot emulate prepared statements');
+?>
+--FILE--
+<?php
+if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.dirname(__FILE__) . '/../../pdo/tests/');
+require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
+
+$db = PDOTest::factory();
+$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
+
+$stmt = $db->query('SELECT 1');
+
+// "Sent SQL" shouldn't display
+var_dump($stmt->debugDumpParams());
+
+$stmt = $db->prepare('SELECT :bool, :int, :string, :null');
+$stmt->bindValue(':bool', true, PDO::PARAM_BOOL);
+$stmt->bindValue(':int', 123, PDO::PARAM_INT);
+$stmt->bindValue(':string', 'foo', PDO::PARAM_STR);
+$stmt->bindValue(':null', null, PDO::PARAM_NULL);
+$stmt->execute();
+
+// "Sent SQL" should display
+var_dump($stmt->debugDumpParams());
+
+?>
+--EXPECT--
+SQL: [8] SELECT 1
+Params:  0
+NULL
+SQL: [34] SELECT :bool, :int, :string, :null
+Sent SQL: [26] SELECT 1, 123, 'foo', NULL
+Params:  4
+Key: Name: [5] :bool
+paramno=-1
+name=[5] ":bool"
+is_param=1
+param_type=5
+Key: Name: [4] :int
+paramno=-1
+name=[4] ":int"
+is_param=1
+param_type=1
+Key: Name: [7] :string
+paramno=-1
+name=[7] ":string"
+is_param=1
+param_type=2
+Key: Name: [5] :null
+paramno=-1
+name=[5] ":null"
+is_param=1
+param_type=0
+NULL
index 4c53b36b2b90c6832f87ca2d5e9578cdec1a8c0d..dd77169d57868afb04499c88a7396322d8c32ef7 100644 (file)
@@ -272,6 +272,11 @@ static int dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
 static int dblib_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value)
 {
        switch (attr) {
+               case PDO_ATTR_EMULATE_PREPARES:
+                       /* this is the only option available, but expose it so common tests and whatever else can introspect */
+                       ZVAL_TRUE(return_value);
+                       break;
+
                case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER:
                        ZVAL_BOOL(return_value, ((pdo_dblib_db_handle *)dbh->driver_data)->stringify_uniqueidentifier);
                        break;
diff --git a/ext/pdo_pgsql/tests/debug_emulated_prepares.phpt b/ext/pdo_pgsql/tests/debug_emulated_prepares.phpt
new file mode 100644 (file)
index 0000000..ddbe4fe
--- /dev/null
@@ -0,0 +1,50 @@
+--TEST--
+PDO PgSQL PDOStatement::debugDumpParams() with emulated prepares
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
+require dirname(__FILE__) . '/config.inc';
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
+
+$stmt = $db->prepare('SELECT :bool, :int, :string, :null');
+$stmt->bindValue(':bool', true, PDO::PARAM_BOOL);
+$stmt->bindValue(':int', 123, PDO::PARAM_INT);
+$stmt->bindValue(':string', 'foo', PDO::PARAM_STR);
+$stmt->bindValue(':null', null, PDO::PARAM_NULL);
+$stmt->execute();
+
+var_dump($stmt->debugDumpParams());
+
+?>
+--EXPECT--
+SQL: [34] SELECT :bool, :int, :string, :null
+Sent SQL: [28] SELECT 't', 123, 'foo', NULL
+Params:  4
+Key: Name: [5] :bool
+paramno=-1
+name=[5] ":bool"
+is_param=1
+param_type=2
+Key: Name: [4] :int
+paramno=-1
+name=[4] ":int"
+is_param=1
+param_type=1
+Key: Name: [7] :string
+paramno=-1
+name=[7] ":string"
+is_param=1
+param_type=2
+Key: Name: [5] :null
+paramno=-1
+name=[5] ":null"
+is_param=1
+param_type=0
+NULL