diff options
author | Matteo Beccati <mbeccati@php.net> | 2014-03-09 14:08:17 +0100 |
---|---|---|
committer | Matteo Beccati <mbeccati@php.net> | 2014-03-11 23:10:48 +0100 |
commit | e378348a316008822737d47cf47a4938cbc07dd6 (patch) | |
tree | 5f400db6fec449e140eff0738882ee85bf08295e /ext/pdo_pgsql | |
parent | d72621ab9e8a6cc89fe1005a83c16249fdc02810 (diff) | |
download | php-git-e378348a316008822737d47cf47a4938cbc07dd6.tar.gz |
Added new PDO::PGSQL_ATTR_DISABLE_PREPARES that uses PQexecParams
Faster than prepared statements when queries are run once. Slightly
slower than PDO::ATTR_EMULATE_PREPARES but without the potential
security implications of embedding parameters in the query itself.
Diffstat (limited to 'ext/pdo_pgsql')
-rw-r--r-- | ext/pdo_pgsql/pdo_pgsql.c | 1 | ||||
-rw-r--r-- | ext/pdo_pgsql/pgsql_driver.c | 15 | ||||
-rw-r--r-- | ext/pdo_pgsql/pgsql_statement.c | 12 | ||||
-rw-r--r-- | ext/pdo_pgsql/php_pdo_pgsql_int.h | 2 | ||||
-rw-r--r-- | ext/pdo_pgsql/tests/disable_prepares.phpt | 54 |
5 files changed, 81 insertions, 3 deletions
diff --git a/ext/pdo_pgsql/pdo_pgsql.c b/ext/pdo_pgsql/pdo_pgsql.c index 8e4cc97fb5..fe003f8ab9 100644 --- a/ext/pdo_pgsql/pdo_pgsql.c +++ b/ext/pdo_pgsql/pdo_pgsql.c @@ -86,6 +86,7 @@ ZEND_GET_MODULE(pdo_pgsql) PHP_MINIT_FUNCTION(pdo_pgsql) { REGISTER_PDO_CLASS_CONST_LONG("PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT", PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_ATTR_DISABLE_PREPARES", PDO_PGSQL_ATTR_DISABLE_PREPARES); REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_IDLE", (long)PGSQL_TRANSACTION_IDLE); REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_ACTIVE", (long)PGSQL_TRANSACTION_ACTIVE); REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_INTRANS", (long)PGSQL_TRANSACTION_INTRANS); diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index 0d72d5573e..96f6fa7f72 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -224,6 +224,7 @@ static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, char *nsql = NULL; int nsql_len = 0; int emulate = 0; + int execute_only = 0; S->H = H; stmt->driver_data = S; @@ -246,8 +247,12 @@ static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, if (pdo_attr_lval(driver_options, PDO_ATTR_EMULATE_PREPARES, H->emulate_prepares TSRMLS_CC) == 1) { emulate = 1; } + if (pdo_attr_lval(driver_options, PDO_PGSQL_ATTR_DISABLE_PREPARES, H->disable_prepares TSRMLS_CC) == 1) { + execute_only = 1; + } } else { emulate = H->disable_native_prepares || H->emulate_prepares; + execute_only = H->disable_prepares; } if (!emulate && PQprotocolVersion(H->server) > 2) { @@ -264,8 +269,11 @@ static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, return 0; } - spprintf(&S->stmt_name, 0, "pdo_stmt_%08x", ++H->stmt_counter); - /* that's all for now; we'll defer the actual prepare until the first execute call */ + if (!execute_only) { + /* prepared query: set the query name and defer the + actual prepare until the first execute call */ + spprintf(&S->stmt_name, 0, "pdo_stmt_%08x", ++H->stmt_counter); + } if (nsql) { S->query = nsql; @@ -1112,6 +1120,9 @@ static int pdo_pgsql_set_attr(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "PDO::PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT is deprecated, use PDO::ATTR_EMULATE_PREPARES instead"); H->disable_native_prepares = Z_LVAL_P(val); return 1; + case PDO_PGSQL_ATTR_DISABLE_PREPARES: + H->disable_prepares = Z_LVAL_P(val); + return 1; default: return 0; } diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index 02fc1d6e90..35e69a3c02 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -204,7 +204,17 @@ stmt_retry: S->param_lengths, S->param_formats, 0); + } else if (stmt->supports_placeholders == PDO_PLACEHOLDER_NAMED) { + /* execute query with parameters */ + S->result = PQexecParams(H->server, S->query, + stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0, + S->param_types, + (const char**)S->param_values, + S->param_lengths, + S->param_formats, + 0); } else { + /* execute plain query (with embedded parameters) */ S->result = PQexec(H->server, stmt->active_query_string); } status = PQresultStatus(S->result); @@ -234,7 +244,7 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; - if (S->stmt_name && param->is_param) { + if (stmt->supports_placeholders == PDO_PLACEHOLDER_NAMED && param->is_param) { switch (event_type) { case PDO_PARAM_EVT_FREE: if (param->driver_data) { diff --git a/ext/pdo_pgsql/php_pdo_pgsql_int.h b/ext/pdo_pgsql/php_pdo_pgsql_int.h index 34d89d2078..1fedababd2 100644 --- a/ext/pdo_pgsql/php_pdo_pgsql_int.h +++ b/ext/pdo_pgsql/php_pdo_pgsql_int.h @@ -47,6 +47,7 @@ typedef struct { to keep track of two different attributes having the same effect. */ int emulate_prepares; int disable_native_prepares; /* deprecated since 5.6 */ + int disable_prepares; unsigned int stmt_counter; } pdo_pgsql_db_handle; @@ -90,6 +91,7 @@ extern struct pdo_stmt_methods pgsql_stmt_methods; enum { PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT = PDO_ATTR_DRIVER_SPECIFIC, + PDO_PGSQL_ATTR_DISABLE_PREPARES, }; struct pdo_pgsql_lob_self { diff --git a/ext/pdo_pgsql/tests/disable_prepares.phpt b/ext/pdo_pgsql/tests/disable_prepares.phpt new file mode 100644 index 0000000000..99a7695404 --- /dev/null +++ b/ext/pdo_pgsql/tests/disable_prepares.phpt @@ -0,0 +1,54 @@ +--TEST-- +PDO PgSQL PGSQL_ATTR_DISABLE_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_ERRMODE, PDO::ERRMODE_EXCEPTION); +$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_COLUMN); + +$stmt = $db->prepare("SELECT statement FROM pg_prepared_statements", array( + PDO::ATTR_EMULATE_PREPARES => true)); + +$stmt2 = $db->prepare("SELECT (?)::int2"); +$stmt2->execute(array(1)); +var_dump($stmt2->fetch()); +$stmt2->execute(array(2)); +var_dump($stmt2->fetch()); + +$stmt->execute(); +$first = $stmt->fetchAll(); + +$stmt3 = $db->prepare("SELECT (?)::int4", array( + PDO::PGSQL_ATTR_DISABLE_PREPARES => true)); +$stmt3->execute(array(3)); +var_dump($stmt3->fetch()); +$stmt3->execute(array(4)); +var_dump($stmt3->fetch()); + +$stmt->execute(); +$second = $stmt->fetchAll(); + +var_dump($first, $second); + +?> +--EXPECT-- +string(1) "1" +string(1) "2" +string(1) "3" +string(1) "4" +array(1) { + [0]=> + string(17) "SELECT ($1)::int2" +} +array(1) { + [0]=> + string(17) "SELECT ($1)::int2" +} |