summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatteo Beccati <mbeccati@php.net>2020-08-31 10:45:36 +0200
committerMatteo Beccati <mbeccati@php.net>2020-08-31 11:03:03 +0200
commit44ade0e87547f3f9ab8fdffb7bb0c8d530a90543 (patch)
treee9b76e3f28c0103e1c0d4137a1b31c29bf1220ae
parentad750c3bb6e7b48384c6265eb9d3bcf5b4000652 (diff)
downloadphp-git-44ade0e87547f3f9ab8fdffb7bb0c8d530a90543.tar.gz
Fix #80027 Terrible performance using $query->fetch on queries with many bind parameters
Added new flags that allow skipping param_evt(s) that are not used by drivers, in a backwards and forward compatible manner. Updated the pgsql, mysql, sqlite and oci drivers to properly use the new flags. I've left out pdo_dblib, which doesn't have a param_hook, and pdo_firebird, which seems to be using PARAM_EVT_NORMALIZE in a wrong context (param type vs event type).
-rw-r--r--NEWS4
-rw-r--r--ext/pdo/pdo_stmt.c4
-rw-r--r--ext/pdo/php_pdo_driver.h5
-rw-r--r--ext/pdo_mysql/mysql_driver.c7
-rw-r--r--ext/pdo_oci/oci_driver.c5
-rw-r--r--ext/pdo_pgsql/pgsql_driver.c5
-rw-r--r--ext/pdo_pgsql/pgsql_statement.c2
-rw-r--r--ext/pdo_sqlite/sqlite_driver.c3
8 files changed, 33 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 722f0a7070..8a2432c2df 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,10 @@ PHP NEWS
. Fixed bug #80002 (calc free space for new interned string is wrong).
(t-matsuno)
+- PDO:
+ . Fixed bug #80027 (Terrible performance using $query->fetch on queries with
+ many bind parameters (Matteo)
+
- Standard:
. Fixed bug #79986 (str_ireplace bug with diacritics characters). (cmb)
diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c
index 873f977fb6..f010d0453b 100644
--- a/ext/pdo/pdo_stmt.c
+++ b/ext/pdo/pdo_stmt.c
@@ -163,6 +163,10 @@ static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_typ
struct pdo_bound_param_data *param;
HashTable *ht;
+ if (stmt->dbh->skip_param_evt & (1 << event_type)) {
+ return 1;
+ }
+
if (!stmt->methods->param_hook) {
return 1;
}
diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h
index b002c3e5f3..0dd5b19907 100644
--- a/ext/pdo/php_pdo_driver.h
+++ b/ext/pdo/php_pdo_driver.h
@@ -468,9 +468,12 @@ struct _pdo_dbh_t {
/* when set, convert int/floats to strings */
unsigned stringify:1;
+ /* bitmap for pdo_param_event(s) to skip in dispatch_param_event */
+ unsigned skip_param_evt:7;
+
/* the sum of the number of bits here and the bit fields preceding should
* equal 32 */
- unsigned _reserved_flags:21;
+ unsigned _reserved_flags:14;
/* data source string used to open this handle */
const char *data_source;
diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c
index 6efa0fc620..0d8c77d351 100644
--- a/ext/pdo_mysql/mysql_driver.c
+++ b/ext/pdo_mysql/mysql_driver.c
@@ -617,6 +617,13 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
dbh->driver_data = H;
+ dbh->skip_param_evt =
+ 1 << PDO_PARAM_EVT_FREE |
+ 1 << PDO_PARAM_EVT_EXEC_POST |
+ 1 << PDO_PARAM_EVT_FETCH_PRE |
+ 1 << PDO_PARAM_EVT_FETCH_POST |
+ 1 << PDO_PARAM_EVT_NORMALIZE;
+
#ifndef PDO_USE_MYSQLND
H->max_buffer_size = 1024*1024;
#endif
diff --git a/ext/pdo_oci/oci_driver.c b/ext/pdo_oci/oci_driver.c
index 20f02f3ab3..6207b8a20a 100644
--- a/ext/pdo_oci/oci_driver.c
+++ b/ext/pdo_oci/oci_driver.c
@@ -674,6 +674,11 @@ static int pdo_oci_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ *
H = pecalloc(1, sizeof(*H), dbh->is_persistent);
dbh->driver_data = H;
+ dbh->skip_param_evt =
+ 1 << PDO_PARAM_EVT_FETCH_PRE |
+ 1 << PDO_PARAM_EVT_FETCH_POST |
+ 1 << PDO_PARAM_EVT_NORMALIZE;
+
H->prefetch = PDO_OCI_PREFETCH_DEFAULT;
/* allocate an environment */
diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c
index 794730a225..62ec874ea0 100644
--- a/ext/pdo_pgsql/pgsql_driver.c
+++ b/ext/pdo_pgsql/pgsql_driver.c
@@ -1198,6 +1198,11 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{
H = pecalloc(1, sizeof(pdo_pgsql_db_handle), dbh->is_persistent);
dbh->driver_data = H;
+ dbh->skip_param_evt =
+ 1 << PDO_PARAM_EVT_EXEC_POST |
+ 1 << PDO_PARAM_EVT_FETCH_PRE |
+ 1 << PDO_PARAM_EVT_FETCH_POST;
+
H->einfo.errcode = 0;
H->einfo.errmsg = NULL;
diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c
index 86cb084a1d..c932ba817d 100644
--- a/ext/pdo_pgsql/pgsql_statement.c
+++ b/ext/pdo_pgsql/pgsql_statement.c
@@ -399,7 +399,7 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *
}
break;
}
- } else if (param->is_param) {
+ } else if (param->is_param && event_type == PDO_PARAM_EVT_NORMALIZE) {
/* We need to manually convert to a pg native boolean value */
if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL &&
((param->param_type & PDO_PARAM_INPUT_OUTPUT) != PDO_PARAM_INPUT_OUTPUT)) {
diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c
index 3d85a6db10..a0f3e104f2 100644
--- a/ext/pdo_sqlite/sqlite_driver.c
+++ b/ext/pdo_sqlite/sqlite_driver.c
@@ -797,6 +797,9 @@ static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{
H->einfo.errmsg = NULL;
dbh->driver_data = H;
+ /* skip all but this one param event */
+ dbh->skip_param_evt = 0x7F ^ (1 << PDO_PARAM_EVT_EXEC_PRE);
+
filename = make_filename_safe(dbh->data_source);
if (!filename) {