1
0
mirror of https://github.com/php/php-src.git synced 2026-04-18 13:31:27 +02:00

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.
This commit is contained in:
Nikita Popov
2020-07-17 17:18:03 +02:00
parent e3827cea4e
commit 7d3e530f4e
12 changed files with 54 additions and 73 deletions

View 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();

View 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) {}

View 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)

View 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);
}
/* }}} */

View 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 {}
}

View 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)

View 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[];

View 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)

View 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')));

View 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))));

View 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))));

View 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);