diff options
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | ext/pdo/pdo_stmt.c | 25 | ||||
-rw-r--r-- | ext/pdo/tests/debug_emulated_prepares.phpt | 66 | ||||
-rw-r--r-- | ext/pdo_dblib/dblib_driver.c | 5 | ||||
-rw-r--r-- | ext/pdo_pgsql/tests/debug_emulated_prepares.phpt | 50 |
5 files changed, 141 insertions, 8 deletions
@@ -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) diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 9f61a052c4..e68ab95921 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -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 index 0000000000..13252382fe --- /dev/null +++ b/ext/pdo/tests/debug_emulated_prepares.phpt @@ -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 diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index 4c53b36b2b..dd77169d57 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -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 index 0000000000..ddbe4fea59 --- /dev/null +++ b/ext/pdo_pgsql/tests/debug_emulated_prepares.phpt @@ -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 |