From: Nikita Popov Date: Fri, 17 Jul 2020 15:18:03 +0000 (+0200) Subject: Use zpp for PDO fetch mode X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7d3e530f4e8700a4cdfc4ff2a747d9dcb7e5e806;p=php Use zpp for PDO fetch mode 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. --- diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 9c6c635cce..330a7532c5 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -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(); diff --git a/ext/pdo/pdo_dbh.stub.php b/ext/pdo/pdo_dbh.stub.php index dec3cea0ea..2fe9572344 100644 --- a/ext/pdo/pdo_dbh.stub.php +++ b/ext/pdo/pdo_dbh.stub.php @@ -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) {} diff --git a/ext/pdo/pdo_dbh_arginfo.h b/ext/pdo/pdo_dbh_arginfo.h index 6e67ad0bf7..5962544c02 100644 --- a/ext/pdo/pdo_dbh_arginfo.h +++ b/ext/pdo/pdo_dbh_arginfo.h @@ -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) diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 9b13ad8887..b49b555a26 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -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); } /* }}} */ diff --git a/ext/pdo/pdo_stmt.stub.php b/ext/pdo/pdo_stmt.stub.php index 1407fcfc62..bab620d627 100644 --- a/ext/pdo/pdo_stmt.stub.php +++ b/ext/pdo/pdo_stmt.stub.php @@ -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 {} } diff --git a/ext/pdo/pdo_stmt_arginfo.h b/ext/pdo/pdo_stmt_arginfo.h index 101970e94e..aa9227d83b 100644 --- a/ext/pdo/pdo_stmt_arginfo.h +++ b/ext/pdo/pdo_stmt_arginfo.h @@ -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) diff --git a/ext/pdo/php_pdo_int.h b/ext/pdo/php_pdo_int.h index 00131cdf6b..87eb79256e 100644 --- a/ext/pdo/php_pdo_int.h +++ b/ext/pdo/php_pdo_int.h @@ -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[]; diff --git a/ext/pdo/tests/bug_44173.phpt b/ext/pdo/tests/bug_44173.phpt index c5ced633a4..1c1d14068c 100644 --- a/ext/pdo/tests/bug_44173.phpt +++ b/ext/pdo/tests/bug_44173.phpt @@ -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) diff --git a/ext/pdo/tests/pdo_023.phpt b/ext/pdo/tests/pdo_023.phpt index 61c614ba52..834c99309e 100644 --- a/ext/pdo/tests/pdo_023.phpt +++ b/ext/pdo/tests/pdo_023.phpt @@ -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'))); diff --git a/ext/pdo/tests/pdo_026.phpt b/ext/pdo/tests/pdo_026.phpt index 4bb1890b36..23d599e847 100644 --- a/ext/pdo/tests/pdo_026.phpt +++ b/ext/pdo/tests/pdo_026.phpt @@ -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)))); diff --git a/ext/pdo/tests/pdo_029.phpt b/ext/pdo/tests/pdo_029.phpt index 10ab369128..4eaf922bfd 100644 --- a/ext/pdo/tests/pdo_029.phpt +++ b/ext/pdo/tests/pdo_029.phpt @@ -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)))); diff --git a/ext/pdo/tests/pdo_030.phpt b/ext/pdo/tests/pdo_030.phpt index 2d054e0dd6..e21047d630 100644 --- a/ext/pdo/tests/pdo_030.phpt +++ b/ext/pdo/tests/pdo_030.phpt @@ -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);