]> granicus.if.org Git - php/commitdiff
Use zpp for PDO fetch mode
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 17 Jul 2020 15:18:03 +0000 (17:18 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 20 Jul 2020 14:05:33 +0000 (16:05 +0200)
Also changing the function signatures to accept variadic args
for the fetch params. If we're already breaking Doctrine anyway,
we may as well do it properly.

12 files changed:
ext/pdo/pdo_dbh.c
ext/pdo/pdo_dbh.stub.php
ext/pdo/pdo_dbh_arginfo.h
ext/pdo/pdo_stmt.c
ext/pdo/pdo_stmt.stub.php
ext/pdo/pdo_stmt_arginfo.h
ext/pdo/php_pdo_int.h
ext/pdo/tests/bug_44173.phpt
ext/pdo/tests/pdo_023.phpt
ext/pdo/tests/pdo_026.phpt
ext/pdo/tests/pdo_029.phpt
ext/pdo/tests/pdo_030.phpt

index 9c6c635cce5077c1d7ae30455aba3342db6849d7..330a7532c51cdfe8e1088efe2897bf2f0f0192c2 100644 (file)
@@ -1025,17 +1025,13 @@ PHP_METHOD(PDO, query)
        pdo_stmt_t *stmt;
        char *statement;
        size_t statement_len;
+       zend_long fetch_mode;
+       zval *args = NULL;
+       uint32_t num_args = 0;
        pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(ZEND_THIS);
        pdo_dbh_t *dbh = dbh_obj->inner;
 
-       /* Return a meaningful error when no parameters were passed */
-       if (!ZEND_NUM_ARGS()) {
-               zend_parse_parameters(0, "z|z", NULL, NULL);
-               RETURN_THROWS();
-       }
-
-       if (FAILURE == zend_parse_parameters(1, "s", &statement,
-                       &statement_len)) {
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l*", &statement, &statement_len, &fetch_mode, &args, &num_args)) {
                RETURN_THROWS();
        }
 
@@ -1065,7 +1061,7 @@ PHP_METHOD(PDO, query)
 
        if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL)) {
                PDO_STMT_CLEAR_ERR();
-               if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) {
+               if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(stmt, fetch_mode, args, num_args)) {
 
                        /* now execute the statement */
                        PDO_STMT_CLEAR_ERR();
index dec3cea0ea54f7f42f1cdaeb34284b37972fb649..2fe9572344a731fb1f042850fb0bfcd97f84beec 100644 (file)
@@ -37,7 +37,7 @@ class PDO
     public function prepare(string $statement, array $driver_options = []) {}
 
     /** @return PDOStatement|false */
-    public function query(string $statement) {}
+    public function query(string $statement, int $fetch_mode = UNKNOWN, ...$fetch_mode_args) {}
 
     /** @return string|false */
     public function quote(string $string, int $parameter_type = PDO::PARAM_STR) {}
index 6e67ad0bf7300c42e43e1d42bd6e38d539240114..5962544c0288687c606fcf74ca57e14929d8d55d 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 38748c44d78c0173218bcb771b466d2a04bc87ad */
+ * Stub hash: c329bfda55244467a2cd62f9d5c5120ec3f24eef */
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO___construct, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(0, dsn, IS_STRING, 0)
@@ -38,7 +38,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO_prepare, 0, 0, 1)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, driver_options, IS_ARRAY, 0, "[]")
 ZEND_END_ARG_INFO()
 
-#define arginfo_class_PDO_query arginfo_class_PDO_exec
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO_query, 0, 0, 1)
+       ZEND_ARG_TYPE_INFO(0, statement, IS_STRING, 0)
+       ZEND_ARG_TYPE_INFO(0, fetch_mode, IS_LONG, 0)
+       ZEND_ARG_VARIADIC_INFO(0, fetch_mode_args)
+ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO_quote, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0)
index 9b13ad8887431d17dcf737431801d322f6d639ff..b49b555a261b1ccfbc9c43d89e84157b14e4e798 100644 (file)
@@ -1725,11 +1725,9 @@ PHP_METHOD(PDOStatement, getColumnMeta)
 
 /* {{{ Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
 
-int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
+int pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, zval *args, uint32_t num_args)
 {
-       zend_long mode = PDO_FETCH_BOTH;
-       int flags = 0, argc = ZEND_NUM_ARGS() - skip;
-       zval *args;
+       int flags = 0;
        zend_class_entry *cep;
        int retval;
 
@@ -1748,29 +1746,11 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
 
        stmt->default_fetch_type = PDO_FETCH_BOTH;
 
-       if (argc == 0) {
-               return SUCCESS;
-       }
-
-       args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval), 0);
-
-       retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
-
-       if (SUCCESS == retval) {
-               if (Z_TYPE(args[skip]) != IS_LONG) {
-                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer");
-                       retval = FAILURE;
-               } else {
-                       mode = Z_LVAL(args[skip]);
-                       flags = mode & PDO_FETCH_FLAGS;
-
-                       retval = pdo_stmt_verify_mode(stmt, mode, 0);
-               }
-       }
+       flags = mode & PDO_FETCH_FLAGS;
+       retval = pdo_stmt_verify_mode(stmt, mode, 0);
 
        if (FAILURE == retval) {
                PDO_STMT_CLEAR_ERR();
-               efree(args);
                return FAILURE;
        }
 
@@ -1785,7 +1765,7 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                case PDO_FETCH_BOUND:
                case PDO_FETCH_NAMED:
                case PDO_FETCH_KEY_PAIR:
-                       if (argc != 1) {
+                       if (num_args != 0) {
                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
                        } else {
                                retval = SUCCESS;
@@ -1793,12 +1773,12 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                        break;
 
                case PDO_FETCH_COLUMN:
-                       if (argc != 2) {
+                       if (num_args != 1) {
                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument");
-                       } else  if (Z_TYPE(args[skip+1]) != IS_LONG) {
+                       } else  if (Z_TYPE(args[0]) != IS_LONG) {
                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer");
                        } else {
-                               stmt->fetch.column = Z_LVAL(args[skip+1]);
+                               stmt->fetch.column = Z_LVAL(args[0]);
                                retval = SUCCESS;
                        }
                        break;
@@ -1806,21 +1786,21 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                case PDO_FETCH_CLASS:
                        /* Gets its class name from 1st column */
                        if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
-                               if (argc != 1) {
+                               if (num_args != 0) {
                                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
                                } else {
                                        stmt->fetch.cls.ce = NULL;
                                        retval = SUCCESS;
                                }
                        } else {
-                               if (argc < 2) {
+                               if (num_args < 1) {
                                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument");
-                               } else if (argc > 3) {
+                               } else if (num_args > 2) {
                                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments");
-                               } else if (Z_TYPE(args[skip+1]) != IS_STRING) {
+                               } else if (Z_TYPE(args[0]) != IS_STRING) {
                                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string");
                                } else {
-                                       cep = zend_lookup_class(Z_STR(args[skip+1]));
+                                       cep = zend_lookup_class(Z_STR(args[0]));
                                        if (cep) {
                                                retval = SUCCESS;
                                                stmt->fetch.cls.ce = cep;
@@ -1835,12 +1815,12 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                                        php_error_docref(NULL, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement.  This will be fixed in a later release");
                                }
 #endif
-                               if (argc == 3) {
-                                       if (Z_TYPE(args[skip+2]) != IS_NULL && Z_TYPE(args[skip+2]) != IS_ARRAY) {
+                               if (num_args == 2) {
+                                       if (Z_TYPE(args[1]) != IS_NULL && Z_TYPE(args[1]) != IS_ARRAY) {
                                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array");
                                                retval = FAILURE;
-                                       } else if (Z_TYPE(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[skip+2]))) {
-                                               ZVAL_ARR(&stmt->fetch.cls.ctor_args, zend_array_dup(Z_ARRVAL(args[skip+2])));
+                                       } else if (Z_TYPE(args[1]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[1]))) {
+                                               ZVAL_ARR(&stmt->fetch.cls.ctor_args, zend_array_dup(Z_ARRVAL(args[1])));
                                        }
                                }
 
@@ -1852,9 +1832,9 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                        break;
 
                case PDO_FETCH_INTO:
-                       if (argc != 2) {
+                       if (num_args != 1) {
                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter");
-                       } else if (Z_TYPE(args[skip+1]) != IS_OBJECT) {
+                       } else if (Z_TYPE(args[0]) != IS_OBJECT) {
                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object");
                        } else {
                                retval = SUCCESS;
@@ -1866,7 +1846,7 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                                        php_error_docref(NULL, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement.  This will be fixed in a later release");
                                }
 #endif
-                               ZVAL_COPY(&stmt->fetch.into, &args[skip+1]);
+                               ZVAL_COPY(&stmt->fetch.into, &args[0]);
                        }
 
                        break;
@@ -1888,19 +1868,21 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
         */
        PDO_STMT_CLEAR_ERR();
 
-       efree(args);
-
        return retval;
 }
 
 PHP_METHOD(PDOStatement, setFetchMode)
 {
+       zend_long fetch_mode;
+       zval *args = NULL;
+       uint32_t num_args = 0;
        PHP_STMT_GET_OBJ;
 
-       RETVAL_BOOL(
-               pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
-                       stmt, 0) == SUCCESS
-               );
+       if (zend_parse_parameters(ZEND_NUM_ARGS(), "l*", &fetch_mode, &args, &num_args) == FAILURE) {
+               RETURN_THROWS();
+       }
+
+       RETVAL_BOOL(pdo_stmt_setup_fetch_mode(stmt, fetch_mode, args, num_args) == SUCCESS);
 }
 /* }}} */
 
index 1407fcfc6232b0507cc63e40f24016dba878f3ac..bab620d627c80eda443138383c69606b9da7af5b 100644 (file)
@@ -75,7 +75,7 @@ class PDOStatement implements IteratorAggregate
     public function setAttribute(int $attribute, $value) {}
 
     /** @return bool */
-    public function setFetchMode(int $mode, $param1 = UNKNOWN, $param2 = UNKNOWN) {}
+    public function setFetchMode(int $mode, ...$params) {}
 
     public function getIterator(): Iterator {}
 }
index 101970e94ef9297d7514d6b758442730a4575d19..aa9227d83bab8e9238a8fd7366d02d319ddb562e 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 77e61065025ff7394466ef6d683d37b4a1c793e7 */
+ * Stub hash: 590a642abbc8d54be143a1c595e9e704888e9b5f */
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDOStatement_bindColumn, 0, 0, 2)
        ZEND_ARG_TYPE_MASK(0, column, MAY_BE_LONG|MAY_BE_STRING, NULL)
@@ -78,8 +78,7 @@ ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDOStatement_setFetchMode, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0)
-       ZEND_ARG_INFO(0, param1)
-       ZEND_ARG_INFO(0, param2)
+       ZEND_ARG_VARIADIC_INFO(0, params)
 ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_PDOStatement_getIterator, 0, 0, Iterator, 0)
index 00131cdf6bdbc7a5824c211ff7c7976e1d992e91..87eb79256e7af4bca2554c86dd3a8d36163627f4 100644 (file)
@@ -41,7 +41,7 @@ void pdo_dbstmt_free_storage(zend_object *std);
 zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref);
 extern zend_object_handlers pdo_dbstmt_object_handlers;
 int pdo_stmt_describe_columns(pdo_stmt_t *stmt);
-int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip_first_arg);
+int pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long fetch_mode, zval *args, uint32_t num_args);
 
 extern zend_object *pdo_row_new(zend_class_entry *ce);
 extern const zend_function_entry pdo_row_functions[];
index c5ced633a4a14986c9a19c51f8055f5394127b13..1c1d14068cc1725c3ea7132c531c7ca7cf58e6d0 100644 (file)
@@ -24,9 +24,11 @@ var_dump($stmt);
 
 
 // Bug entry [3]
-$stmt = $db->query("SELECT * FROM test", 'abc');
-var_dump($stmt);
-
+try {
+    $stmt = $db->query("SELECT * FROM test", 'abc');
+} catch (TypeError $e) {
+    echo $e->getMessage(), "\n";
+}
 
 // Bug entry [4]
 $stmt = $db->query("SELECT * FROM test", PDO::FETCH_CLASS, 0, 0, 0);
@@ -52,9 +54,7 @@ var_dump($stmt);
 --EXPECTF--
 Warning: PDO::query(): SQLSTATE[HY000]: General error: fetch mode doesn't allow any extra arguments in %s
 bool(false)
-
-Warning: PDO::query(): SQLSTATE[HY000]: General error: mode must be an integer in %s
-bool(false)
+PDO::query(): Argument #2 ($fetch_mode) must be of type int, string given
 
 Warning: PDO::query(): SQLSTATE[HY000]: General error: too many arguments in %s
 bool(false)
index 61c614ba52b0cd8af5de5b5161f75be04ceaae78..834c99309e66e5f4321ccbfdc97944a8af48f022 100644 (file)
@@ -47,7 +47,7 @@ class PDODatabaseX extends PDO
         $this->test2 = 22;
     }
 
-    function query($sql)
+    function query($sql, ...$rest)
     {
         echo __METHOD__ . "()\n";
         $stmt = parent::prepare($sql, array(PDO::ATTR_STATEMENT_CLASS=>array('PDOStatementx')));
index 4bb1890b361a6528f7cba1e18331f6d0a77ff9fe..23d599e847d7584520977ddc377cb32fe1a0c893 100644 (file)
@@ -42,7 +42,7 @@ class PDODatabase extends PDO
         echo __METHOD__ . "()\n";
     }
 
-    function query($sql)
+    function query($sql, ...$rest)
     {
         echo __METHOD__ . "()\n";
         $stmt = $this->prepare($sql, array(PDO::ATTR_STATEMENT_CLASS=>array('PDOStatementx', array($this))));
index 10ab369128860ff6c772c725a6367915202e273e..4eaf922bfd915e4310b1833eeb4d0e9abf9c32e8 100644 (file)
@@ -48,7 +48,7 @@ class PDODatabase extends PDO
         echo __METHOD__ . "()\n";
     }
 
-    function query($sql)
+    function query($sql, ...$rest)
     {
         echo __METHOD__ . "()\n";
         $stmt = $this->prepare($sql, array(PDO::ATTR_STATEMENT_CLASS=>array('PDOStatementx', array($this))));
index 2d054e0dd67c240decc29cbe3dcb191e3e1b43c2..e21047d630011189102b2baaa97d1ee7448bbacc 100644 (file)
@@ -49,7 +49,7 @@ class PDODatabase extends PDO
         echo __METHOD__ . "()\n";
     }
 
-    function query($sql)
+    function query($sql, ...$rest)
     {
         echo __METHOD__ . "()\n";
         return parent::query($sql);