Skip to content

Commit 7d3e530

Browse files
committed
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.
1 parent e3827ce commit 7d3e530

12 files changed

+54
-73
lines changed

ext/pdo/pdo_dbh.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,17 +1025,13 @@ PHP_METHOD(PDO, query)
10251025
pdo_stmt_t *stmt;
10261026
char *statement;
10271027
size_t statement_len;
1028+
zend_long fetch_mode;
1029+
zval *args = NULL;
1030+
uint32_t num_args = 0;
10281031
pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(ZEND_THIS);
10291032
pdo_dbh_t *dbh = dbh_obj->inner;
10301033

1031-
/* Return a meaningful error when no parameters were passed */
1032-
if (!ZEND_NUM_ARGS()) {
1033-
zend_parse_parameters(0, "z|z", NULL, NULL);
1034-
RETURN_THROWS();
1035-
}
1036-
1037-
if (FAILURE == zend_parse_parameters(1, "s", &statement,
1038-
&statement_len)) {
1034+
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l*", &statement, &statement_len, &fetch_mode, &args, &num_args)) {
10391035
RETURN_THROWS();
10401036
}
10411037

@@ -1065,7 +1061,7 @@ PHP_METHOD(PDO, query)
10651061

10661062
if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL)) {
10671063
PDO_STMT_CLEAR_ERR();
1068-
if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) {
1064+
if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(stmt, fetch_mode, args, num_args)) {
10691065

10701066
/* now execute the statement */
10711067
PDO_STMT_CLEAR_ERR();

ext/pdo/pdo_dbh.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function lastInsertId(?string $name = null) {}
3737
public function prepare(string $statement, array $driver_options = []) {}
3838

3939
/** @return PDOStatement|false */
40-
public function query(string $statement) {}
40+
public function query(string $statement, int $fetch_mode = UNKNOWN, ...$fetch_mode_args) {}
4141

4242
/** @return string|false */
4343
public function quote(string $string, int $parameter_type = PDO::PARAM_STR) {}

ext/pdo/pdo_dbh_arginfo.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 38748c44d78c0173218bcb771b466d2a04bc87ad */
2+
* Stub hash: c329bfda55244467a2cd62f9d5c5120ec3f24eef */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO___construct, 0, 0, 1)
55
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)
3838
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, driver_options, IS_ARRAY, 0, "[]")
3939
ZEND_END_ARG_INFO()
4040

41-
#define arginfo_class_PDO_query arginfo_class_PDO_exec
41+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO_query, 0, 0, 1)
42+
ZEND_ARG_TYPE_INFO(0, statement, IS_STRING, 0)
43+
ZEND_ARG_TYPE_INFO(0, fetch_mode, IS_LONG, 0)
44+
ZEND_ARG_VARIADIC_INFO(0, fetch_mode_args)
45+
ZEND_END_ARG_INFO()
4246

4347
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO_quote, 0, 0, 1)
4448
ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0)

ext/pdo/pdo_stmt.c

Lines changed: 28 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,11 +1725,9 @@ PHP_METHOD(PDOStatement, getColumnMeta)
17251725

17261726
/* {{{ Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
17271727

1728-
int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
1728+
int pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, zval *args, uint32_t num_args)
17291729
{
1730-
zend_long mode = PDO_FETCH_BOTH;
1731-
int flags = 0, argc = ZEND_NUM_ARGS() - skip;
1732-
zval *args;
1730+
int flags = 0;
17331731
zend_class_entry *cep;
17341732
int retval;
17351733

@@ -1748,29 +1746,11 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
17481746

17491747
stmt->default_fetch_type = PDO_FETCH_BOTH;
17501748

1751-
if (argc == 0) {
1752-
return SUCCESS;
1753-
}
1754-
1755-
args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval), 0);
1756-
1757-
retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
1758-
1759-
if (SUCCESS == retval) {
1760-
if (Z_TYPE(args[skip]) != IS_LONG) {
1761-
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer");
1762-
retval = FAILURE;
1763-
} else {
1764-
mode = Z_LVAL(args[skip]);
1765-
flags = mode & PDO_FETCH_FLAGS;
1766-
1767-
retval = pdo_stmt_verify_mode(stmt, mode, 0);
1768-
}
1769-
}
1749+
flags = mode & PDO_FETCH_FLAGS;
1750+
retval = pdo_stmt_verify_mode(stmt, mode, 0);
17701751

17711752
if (FAILURE == retval) {
17721753
PDO_STMT_CLEAR_ERR();
1773-
efree(args);
17741754
return FAILURE;
17751755
}
17761756

@@ -1785,42 +1765,42 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
17851765
case PDO_FETCH_BOUND:
17861766
case PDO_FETCH_NAMED:
17871767
case PDO_FETCH_KEY_PAIR:
1788-
if (argc != 1) {
1768+
if (num_args != 0) {
17891769
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
17901770
} else {
17911771
retval = SUCCESS;
17921772
}
17931773
break;
17941774

17951775
case PDO_FETCH_COLUMN:
1796-
if (argc != 2) {
1776+
if (num_args != 1) {
17971777
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument");
1798-
} else if (Z_TYPE(args[skip+1]) != IS_LONG) {
1778+
} else if (Z_TYPE(args[0]) != IS_LONG) {
17991779
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer");
18001780
} else {
1801-
stmt->fetch.column = Z_LVAL(args[skip+1]);
1781+
stmt->fetch.column = Z_LVAL(args[0]);
18021782
retval = SUCCESS;
18031783
}
18041784
break;
18051785

18061786
case PDO_FETCH_CLASS:
18071787
/* Gets its class name from 1st column */
18081788
if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1809-
if (argc != 1) {
1789+
if (num_args != 0) {
18101790
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
18111791
} else {
18121792
stmt->fetch.cls.ce = NULL;
18131793
retval = SUCCESS;
18141794
}
18151795
} else {
1816-
if (argc < 2) {
1796+
if (num_args < 1) {
18171797
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument");
1818-
} else if (argc > 3) {
1798+
} else if (num_args > 2) {
18191799
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments");
1820-
} else if (Z_TYPE(args[skip+1]) != IS_STRING) {
1800+
} else if (Z_TYPE(args[0]) != IS_STRING) {
18211801
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string");
18221802
} else {
1823-
cep = zend_lookup_class(Z_STR(args[skip+1]));
1803+
cep = zend_lookup_class(Z_STR(args[0]));
18241804
if (cep) {
18251805
retval = SUCCESS;
18261806
stmt->fetch.cls.ce = cep;
@@ -1835,12 +1815,12 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
18351815
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");
18361816
}
18371817
#endif
1838-
if (argc == 3) {
1839-
if (Z_TYPE(args[skip+2]) != IS_NULL && Z_TYPE(args[skip+2]) != IS_ARRAY) {
1818+
if (num_args == 2) {
1819+
if (Z_TYPE(args[1]) != IS_NULL && Z_TYPE(args[1]) != IS_ARRAY) {
18401820
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array");
18411821
retval = FAILURE;
1842-
} else if (Z_TYPE(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[skip+2]))) {
1843-
ZVAL_ARR(&stmt->fetch.cls.ctor_args, zend_array_dup(Z_ARRVAL(args[skip+2])));
1822+
} else if (Z_TYPE(args[1]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[1]))) {
1823+
ZVAL_ARR(&stmt->fetch.cls.ctor_args, zend_array_dup(Z_ARRVAL(args[1])));
18441824
}
18451825
}
18461826

@@ -1852,9 +1832,9 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
18521832
break;
18531833

18541834
case PDO_FETCH_INTO:
1855-
if (argc != 2) {
1835+
if (num_args != 1) {
18561836
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter");
1857-
} else if (Z_TYPE(args[skip+1]) != IS_OBJECT) {
1837+
} else if (Z_TYPE(args[0]) != IS_OBJECT) {
18581838
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object");
18591839
} else {
18601840
retval = SUCCESS;
@@ -1866,7 +1846,7 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
18661846
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");
18671847
}
18681848
#endif
1869-
ZVAL_COPY(&stmt->fetch.into, &args[skip+1]);
1849+
ZVAL_COPY(&stmt->fetch.into, &args[0]);
18701850
}
18711851

18721852
break;
@@ -1888,19 +1868,21 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
18881868
*/
18891869
PDO_STMT_CLEAR_ERR();
18901870

1891-
efree(args);
1892-
18931871
return retval;
18941872
}
18951873

18961874
PHP_METHOD(PDOStatement, setFetchMode)
18971875
{
1876+
zend_long fetch_mode;
1877+
zval *args = NULL;
1878+
uint32_t num_args = 0;
18981879
PHP_STMT_GET_OBJ;
18991880

1900-
RETVAL_BOOL(
1901-
pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
1902-
stmt, 0) == SUCCESS
1903-
);
1881+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l*", &fetch_mode, &args, &num_args) == FAILURE) {
1882+
RETURN_THROWS();
1883+
}
1884+
1885+
RETVAL_BOOL(pdo_stmt_setup_fetch_mode(stmt, fetch_mode, args, num_args) == SUCCESS);
19041886
}
19051887
/* }}} */
19061888

ext/pdo/pdo_stmt.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function rowCount() {}
7575
public function setAttribute(int $attribute, $value) {}
7676

7777
/** @return bool */
78-
public function setFetchMode(int $mode, $param1 = UNKNOWN, $param2 = UNKNOWN) {}
78+
public function setFetchMode(int $mode, ...$params) {}
7979

8080
public function getIterator(): Iterator {}
8181
}

ext/pdo/pdo_stmt_arginfo.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 77e61065025ff7394466ef6d683d37b4a1c793e7 */
2+
* Stub hash: 590a642abbc8d54be143a1c595e9e704888e9b5f */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDOStatement_bindColumn, 0, 0, 2)
55
ZEND_ARG_TYPE_MASK(0, column, MAY_BE_LONG|MAY_BE_STRING, NULL)
@@ -78,8 +78,7 @@ ZEND_END_ARG_INFO()
7878

7979
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDOStatement_setFetchMode, 0, 0, 1)
8080
ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0)
81-
ZEND_ARG_INFO(0, param1)
82-
ZEND_ARG_INFO(0, param2)
81+
ZEND_ARG_VARIADIC_INFO(0, params)
8382
ZEND_END_ARG_INFO()
8483

8584
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_PDOStatement_getIterator, 0, 0, Iterator, 0)

ext/pdo/php_pdo_int.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void pdo_dbstmt_free_storage(zend_object *std);
4141
zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref);
4242
extern zend_object_handlers pdo_dbstmt_object_handlers;
4343
int pdo_stmt_describe_columns(pdo_stmt_t *stmt);
44-
int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip_first_arg);
44+
int pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long fetch_mode, zval *args, uint32_t num_args);
4545

4646
extern zend_object *pdo_row_new(zend_class_entry *ce);
4747
extern const zend_function_entry pdo_row_functions[];

ext/pdo/tests/bug_44173.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ var_dump($stmt);
2424

2525

2626
// Bug entry [3]
27-
$stmt = $db->query("SELECT * FROM test", 'abc');
28-
var_dump($stmt);
29-
27+
try {
28+
$stmt = $db->query("SELECT * FROM test", 'abc');
29+
} catch (TypeError $e) {
30+
echo $e->getMessage(), "\n";
31+
}
3032

3133
// Bug entry [4]
3234
$stmt = $db->query("SELECT * FROM test", PDO::FETCH_CLASS, 0, 0, 0);
@@ -52,9 +54,7 @@ var_dump($stmt);
5254
--EXPECTF--
5355
Warning: PDO::query(): SQLSTATE[HY000]: General error: fetch mode doesn't allow any extra arguments in %s
5456
bool(false)
55-
56-
Warning: PDO::query(): SQLSTATE[HY000]: General error: mode must be an integer in %s
57-
bool(false)
57+
PDO::query(): Argument #2 ($fetch_mode) must be of type int, string given
5858

5959
Warning: PDO::query(): SQLSTATE[HY000]: General error: too many arguments in %s
6060
bool(false)

ext/pdo/tests/pdo_023.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class PDODatabaseX extends PDO
4747
$this->test2 = 22;
4848
}
4949

50-
function query($sql)
50+
function query($sql, ...$rest)
5151
{
5252
echo __METHOD__ . "()\n";
5353
$stmt = parent::prepare($sql, array(PDO::ATTR_STATEMENT_CLASS=>array('PDOStatementx')));

ext/pdo/tests/pdo_026.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class PDODatabase extends PDO
4242
echo __METHOD__ . "()\n";
4343
}
4444

45-
function query($sql)
45+
function query($sql, ...$rest)
4646
{
4747
echo __METHOD__ . "()\n";
4848
$stmt = $this->prepare($sql, array(PDO::ATTR_STATEMENT_CLASS=>array('PDOStatementx', array($this))));

ext/pdo/tests/pdo_029.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class PDODatabase extends PDO
4848
echo __METHOD__ . "()\n";
4949
}
5050

51-
function query($sql)
51+
function query($sql, ...$rest)
5252
{
5353
echo __METHOD__ . "()\n";
5454
$stmt = $this->prepare($sql, array(PDO::ATTR_STATEMENT_CLASS=>array('PDOStatementx', array($this))));

ext/pdo/tests/pdo_030.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class PDODatabase extends PDO
4949
echo __METHOD__ . "()\n";
5050
}
5151

52-
function query($sql)
52+
function query($sql, ...$rest)
5353
{
5454
echo __METHOD__ . "()\n";
5555
return parent::query($sql);

0 commit comments

Comments
 (0)