]> granicus.if.org Git - php/commitdiff
Fix #80027 Terrible performance using $query->fetch on queries with many bind parameters
authorMatteo Beccati <mbeccati@php.net>
Mon, 31 Aug 2020 08:45:36 +0000 (10:45 +0200)
committerMatteo Beccati <mbeccati@php.net>
Mon, 31 Aug 2020 09:02:34 +0000 (11:02 +0200)
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).

ext/pdo/pdo_stmt.c
ext/pdo/php_pdo_driver.h
ext/pdo_mysql/mysql_driver.c
ext/pdo_oci/oci_driver.c
ext/pdo_pgsql/pgsql_driver.c
ext/pdo_pgsql/pgsql_statement.c
ext/pdo_sqlite/sqlite_driver.c

index 96f7574638e88b35d6528fa40d8a3c6fbc1ac1d0..b0f7bbeede81386d1d60a5de6995d6a8b64b84c3 100644 (file)
@@ -92,6 +92,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;
        }
index e0b4b3986fc34b26e10711552f502fca02f0a3f8..960ddec4efe089b8e22a439e353550448742fa3c 100644 (file)
@@ -466,9 +466,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;
index cb9a50667346a4191ec99812a9d5d8fdb2ad0ded..9596bdd04f45c16f701c1f77266a4d6c34d52963 100644 (file)
@@ -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
index 3cb2cab56d559375456df2cb0b85174e9b0dac49..d2115b81b80f3a4e881ac8da9e33e6de1e10bf58 100644 (file)
@@ -724,6 +724,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 */
index 27af12544eab70c09ab6c17d95fbf8132b712041..38ea304a30e9bc0f8b7cab406dd0354cd51c2cd6 100644 (file)
@@ -1192,6 +1192,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;
 
index 0edb3d7f8e8d9636cc4ab4982f141bbd0a66f271..88031622a438417d62b010400c33e1c4cca17e5a 100644 (file)
@@ -397,7 +397,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)) {
index dcbc604739607a6b8399652eb24199dda867aa70..26fa1c00eb82968c51f802722baf2393ee85c89f 100644 (file)
@@ -773,6 +773,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) {