Skip to content

Commit 7a95e94

Browse files
committed
Promote warnings to Error in MySQLi extension
Closes GH-5803
1 parent 7e61c2e commit 7a95e94

38 files changed

+541
-356
lines changed

ext/mysqli/mysqli.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,7 @@ static int mysqli_object_has_property(zend_object *object, zend_string *name, in
384384
}
385385
break;
386386
}
387-
default:
388-
php_error_docref(NULL, E_WARNING, "Invalid value for has_set_exists");
387+
EMPTY_SWITCH_DEFAULT_CASE();
389388
}
390389
} else {
391390
ret = zend_std_has_property(object, name, has_set_exists, cache_slot);
@@ -1035,7 +1034,8 @@ PHP_METHOD(mysqli_result, __construct)
10351034
result = mysql_use_result(mysql->mysql);
10361035
break;
10371036
default:
1038-
php_error_docref(NULL, E_WARNING, "Invalid value for resultmode");
1037+
zend_argument_value_error(2, "must be either MYSQLI_STORE_RESULT or MYSQLI_USE_RESULT");
1038+
RETURN_THROWS();
10391039
}
10401040

10411041
if (!result) {
@@ -1052,7 +1052,7 @@ PHP_METHOD(mysqli_result, __construct)
10521052
PHP_METHOD(mysqli_result, getIterator)
10531053
{
10541054
if (zend_parse_parameters_none() == FAILURE) {
1055-
return;
1055+
RETURN_THROWS();
10561056
}
10571057

10581058
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
@@ -1130,6 +1130,7 @@ void php_mysqli_fetch_into_hash_aux(zval *return_value, MYSQL_RES * result, zend
11301130
}
11311131
/* }}} */
11321132

1133+
/* TODO Split this up */
11331134
/* {{{ php_mysqli_fetch_into_hash */
11341135
void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags, int into_object)
11351136
{

ext/mysqli/mysqli.stub.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public function prepare(string $query) {}
164164
* @return mysqli_result|bool
165165
* @alias mysqli_query
166166
*/
167-
public function query(string $query, int $resultmode = MYSQLI_STORE_RESULT) {}
167+
public function query(string $query, int $result_mode = MYSQLI_STORE_RESULT) {}
168168

169169
/**
170170
* @return bool
@@ -301,7 +301,7 @@ public function refresh(int $options) {}
301301

302302
class mysqli_result implements IteratorAggregate
303303
{
304-
public function __construct(object $mysqli_link, int $resmode = MYSQLI_STORE_RESULT) {}
304+
public function __construct(object $mysqli_link, int $result_mode = MYSQLI_STORE_RESULT) {}
305305

306306
/**
307307
* @return void
@@ -421,7 +421,7 @@ public function bind_result(mixed &...$vars) {}
421421
public function close() {}
422422

423423
/**
424-
* @return bool|null
424+
* @return void
425425
* @alias mysqli_stmt_data_seek
426426
*/
427427
public function data_seek(int $offset) {}
@@ -641,7 +641,7 @@ function mysqli_prepare(mysqli $mysqli_link, string $query): mysqli_stmt|false {
641641

642642
function mysqli_report(int $flags): bool {}
643643

644-
function mysqli_query(mysqli $mysqli_link, string $query, int $resultmode = MYSQLI_STORE_RESULT): mysqli_result|bool {}
644+
function mysqli_query(mysqli $mysqli_link, string $query, int $result_mode = MYSQLI_STORE_RESULT): mysqli_result|bool {}
645645

646646
function mysqli_real_connect(
647647
mysqli $mysqli_link,
@@ -672,7 +672,7 @@ function mysqli_set_charset(mysqli $mysqli_link, string $charset): bool {}
672672

673673
function mysqli_stmt_affected_rows(mysqli_stmt $mysql_stmt): int|string {}
674674

675-
function mysqli_stmt_attr_get(mysqli_stmt $mysql_stmt, int $attr): int|false {}
675+
function mysqli_stmt_attr_get(mysqli_stmt $mysql_stmt, int $attr): int {}
676676

677677
function mysqli_stmt_attr_set(mysqli_stmt $mysql_stmt, int $attr, int $mode_in): bool {}
678678

@@ -682,7 +682,7 @@ function mysqli_stmt_bind_result(mysqli_stmt $mysql_stmt, mixed &...$vars): bool
682682

683683
function mysqli_stmt_close(mysqli_stmt $mysql_stmt): bool {}
684684

685-
function mysqli_stmt_data_seek(mysqli_stmt $mysql_stmt, int $offset): ?bool {}
685+
function mysqli_stmt_data_seek(mysqli_stmt $mysql_stmt, int $offset): void {}
686686

687687
function mysqli_stmt_errno(mysqli_stmt $mysql_stmt): int {}
688688

ext/mysqli/mysqli_api.c

Lines changed: 99 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "mysqli_priv.h"
3232
#include "ext/mysqlnd/mysql_float_to_double.h"
3333

34+
#define ERROR_ARG_POS(arg_num) (getThis() ? (arg_num-1) : (arg_num))
35+
3436

3537
#ifndef MYSQLI_USE_MYSQLND
3638
/* {{{ mysqli_tx_cor_options_to_string */
@@ -324,19 +326,19 @@ PHP_FUNCTION(mysqli_stmt_bind_param)
324326
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
325327

326328
if (!types_len) {
327-
php_error_docref(NULL, E_WARNING, "Invalid type or no types specified");
328-
RETURN_FALSE;
329+
zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
330+
RETURN_THROWS();
329331
}
330332

331333
if (types_len != (size_t) argc) {
332334
/* number of bind variables doesn't match number of elements in type definition string */
333-
php_error_docref(NULL, E_WARNING, "Number of elements in type definition string doesn't match number of bind variables");
334-
RETURN_FALSE;
335+
zend_argument_count_error("The number of elements in the type definition string must match the number of bind variables");
336+
RETURN_THROWS();
335337
}
336338

337339
if (types_len != mysql_stmt_param_count(stmt->stmt)) {
338-
php_error_docref(NULL, E_WARNING, "Number of variables doesn't match number of parameters in prepared statement");
339-
RETURN_FALSE;
340+
zend_argument_count_error("The number of variables must match the number of parameters in the prepared statement");
341+
RETURN_THROWS();
340342
}
341343

342344
RETVAL_BOOL(!mysqli_stmt_bind_param_do_bind(stmt, argc, args, types, getThis() ? 1 : 2));
@@ -557,8 +559,8 @@ PHP_FUNCTION(mysqli_stmt_bind_result)
557559
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
558560

559561
if ((uint32_t)argc != mysql_stmt_field_count(stmt->stmt)) {
560-
php_error_docref(NULL, E_WARNING, "Number of bind variables doesn't match number of fields in prepared statement");
561-
RETURN_FALSE;
562+
zend_argument_count_error("Number of bind variables doesn't match number of fields in prepared statement");
563+
RETURN_THROWS();
562564
}
563565

564566
rc = mysqli_stmt_bind_result_do_bind(stmt, args, argc);
@@ -729,14 +731,23 @@ PHP_FUNCTION(mysqli_data_seek)
729731
RETURN_THROWS();
730732
}
731733

734+
if (offset < 0) {
735+
zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
736+
RETURN_THROWS();
737+
}
738+
732739
MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
733740

734741
if (mysqli_result_is_unbuffered(result)) {
735-
php_error_docref(NULL, E_WARNING, "Function cannot be used with MYSQL_USE_RESULT");
736-
RETURN_FALSE;
742+
if (getThis()) {
743+
zend_throw_error(NULL, "mysqli_result::data_seek() cannot be used with MYSQLI_USE_RESULT");
744+
} else {
745+
zend_throw_error(NULL, "mysqli_data_seek() cannot be used with MYSQLI_USE_RESULT");
746+
}
747+
RETURN_THROWS();
737748
}
738749

739-
if (offset < 0 || (uint64_t)offset >= mysql_num_rows(result)) {
750+
if ((uint64_t)offset >= mysql_num_rows(result)) {
740751
RETURN_FALSE;
741752
}
742753

@@ -1181,11 +1192,16 @@ PHP_FUNCTION(mysqli_fetch_field_direct)
11811192
RETURN_THROWS();
11821193
}
11831194

1195+
if (offset < 0) {
1196+
zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1197+
RETURN_THROWS();
1198+
}
1199+
11841200
MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
11851201

1186-
if (offset < 0 || offset >= (zend_long) mysql_num_fields(result)) {
1187-
php_error_docref(NULL, E_WARNING, "Field offset is invalid for resultset");
1188-
RETURN_FALSE;
1202+
if (offset >= (zend_long) mysql_num_fields(result)) {
1203+
zend_argument_value_error(ERROR_ARG_POS(2), "must be less than the number of fields for this result set");
1204+
RETURN_THROWS();
11891205
}
11901206

11911207
if (!(field = mysql_fetch_field_direct(result,offset))) {
@@ -1215,6 +1231,7 @@ PHP_FUNCTION(mysqli_fetch_lengths)
12151231

12161232
MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
12171233

1234+
// TODO Warning?
12181235
if (!(ret = mysql_fetch_lengths(result))) {
12191236
RETURN_FALSE;
12201237
}
@@ -1260,9 +1277,16 @@ PHP_FUNCTION(mysqli_field_seek)
12601277
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &fieldnr) == FAILURE) {
12611278
RETURN_THROWS();
12621279
}
1280+
1281+
if (fieldnr < 0) {
1282+
zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1283+
RETURN_THROWS();
1284+
}
1285+
12631286
MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
12641287

1265-
if (fieldnr < 0 || (uint32_t)fieldnr >= mysql_num_fields(result)) {
1288+
if ((uint32_t)fieldnr >= mysql_num_fields(result)) {
1289+
// TODO ValueError?
12661290
php_error_docref(NULL, E_WARNING, "Invalid field offset");
12671291
RETURN_FALSE;
12681292
}
@@ -1499,13 +1523,14 @@ PHP_FUNCTION(mysqli_kill)
14991523
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &processid) == FAILURE) {
15001524
RETURN_THROWS();
15011525
}
1502-
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
15031526

15041527
if (processid <= 0) {
1505-
php_error_docref(NULL, E_WARNING, "processid should have positive value");
1506-
RETURN_FALSE;
1528+
zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than 0");
1529+
RETURN_THROWS();
15071530
}
15081531

1532+
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1533+
15091534
if (mysql_kill(mysql->mysql, processid)) {
15101535
MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
15111536
RETURN_FALSE;
@@ -1601,8 +1626,8 @@ PHP_FUNCTION(mysqli_num_rows)
16011626
MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
16021627

16031628
if (mysqli_result_is_unbuffered_and_not_everything_is_fetched(result)) {
1604-
php_error_docref(NULL, E_WARNING, "Function cannot be used with MYSQL_USE_RESULT");
1605-
RETURN_LONG(0);
1629+
zend_throw_error(NULL, "mysqli_num_rows() cannot be used with MYSQLI_USE_RESULT");
1630+
RETURN_THROWS();
16061631
}
16071632

16081633
MYSQLI_RETURN_LONG_INT(mysql_num_rows(result));
@@ -1922,12 +1947,14 @@ PHP_FUNCTION(mysqli_stmt_send_long_data)
19221947
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ols", &mysql_stmt, mysqli_stmt_class_entry, &param_nr, &data, &data_len) == FAILURE) {
19231948
RETURN_THROWS();
19241949
}
1950+
19251951
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
19261952

19271953
if (param_nr < 0) {
1928-
php_error_docref(NULL, E_WARNING, "Invalid parameter number");
1929-
RETURN_FALSE;
1954+
zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1955+
RETURN_THROWS();
19301956
}
1957+
19311958
if (mysql_stmt_send_long_data(stmt->stmt, param_nr, data, data_len)) {
19321959
RETURN_FALSE;
19331960
}
@@ -1984,9 +2011,10 @@ PHP_FUNCTION(mysqli_stmt_data_seek)
19842011
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &offset) == FAILURE) {
19852012
RETURN_THROWS();
19862013
}
2014+
19872015
if (offset < 0) {
1988-
php_error_docref(NULL, E_WARNING, "Offset must be positive");
1989-
RETURN_FALSE;
2016+
zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
2017+
RETURN_THROWS();
19902018
}
19912019

19922020
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
@@ -2216,7 +2244,7 @@ PHP_FUNCTION(mysqli_stmt_attr_set)
22162244
zval *mysql_stmt;
22172245
zend_long mode_in;
22182246
#if MYSQL_VERSION_ID >= 50107
2219-
my_bool mode_b;
2247+
my_bool mode_b;
22202248
#endif
22212249
unsigned long mode;
22222250
zend_long attr;
@@ -2225,25 +2253,54 @@ PHP_FUNCTION(mysqli_stmt_attr_set)
22252253
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oll", &mysql_stmt, mysqli_stmt_class_entry, &attr, &mode_in) == FAILURE) {
22262254
RETURN_THROWS();
22272255
}
2228-
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
22292256

2230-
if (mode_in < 0) {
2231-
php_error_docref(NULL, E_WARNING, "Mode should be non-negative, " ZEND_LONG_FMT " passed", mode_in);
2232-
RETURN_FALSE;
2233-
}
2257+
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
22342258

22352259
switch (attr) {
22362260
#if MYSQL_VERSION_ID >= 50107
22372261
case STMT_ATTR_UPDATE_MAX_LENGTH:
2262+
if (mode_in != 0 && mode_in != 1) {
2263+
zend_argument_value_error(ERROR_ARG_POS(3), "must be 0 or 1 for attribute MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH");
2264+
RETURN_THROWS();
2265+
}
22382266
mode_b = (my_bool) mode_in;
22392267
mode_p = &mode_b;
22402268
break;
22412269
#endif
2242-
default:
2270+
case STMT_ATTR_CURSOR_TYPE:
2271+
switch (mode_in) {
2272+
case CURSOR_TYPE_NO_CURSOR:
2273+
case CURSOR_TYPE_READ_ONLY:
2274+
case CURSOR_TYPE_FOR_UPDATE:
2275+
case CURSOR_TYPE_SCROLLABLE:
2276+
break;
2277+
default:
2278+
zend_argument_value_error(ERROR_ARG_POS(3), "must be one of MYSQLI_CURSOR_TYPE_NO_CURSOR, "
2279+
"MYSQLI_CURSOR_TYPE_READ_ONLY, MYSQLI_CURSOR_TYPE_FOR_UPDATE, or MYSQLI_CURSOR_TYPE_SCROLLABLE "
2280+
"for attribute MYSQLI_STMT_ATTR_CURSOR_TYPE");
2281+
RETURN_THROWS();
2282+
}
22432283
mode = mode_in;
22442284
mode_p = &mode;
22452285
break;
2286+
case STMT_ATTR_PREFETCH_ROWS:
2287+
if (mode_in < 1) {
2288+
zend_argument_value_error(ERROR_ARG_POS(3), "must be greater than 0 for attribute MYSQLI_STMT_ATTR_PREFETCH_ROWS");
2289+
RETURN_THROWS();
2290+
}
2291+
mode = mode_in;
2292+
mode_p = &mode;
2293+
break;
2294+
default:
2295+
zend_argument_value_error(ERROR_ARG_POS(2), "must be one of "
2296+
#if MYSQL_VERSION_ID >= 50107
2297+
"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, "
2298+
#endif
2299+
"MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE");
2300+
RETURN_THROWS();
22462301
}
2302+
2303+
// TODO Can unify this?
22472304
#ifndef MYSQLI_USE_MYSQLND
22482305
if (mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
22492306
#else
@@ -2267,11 +2324,20 @@ PHP_FUNCTION(mysqli_stmt_attr_get)
22672324
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &attr) == FAILURE) {
22682325
RETURN_THROWS();
22692326
}
2327+
22702328
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
22712329

22722330
if ((rc = mysql_stmt_attr_get(stmt->stmt, attr, &value))) {
2273-
RETURN_FALSE;
2274-
}
2331+
/* Success corresponds to 0 return value and a non-zero value
2332+
* should only happen if the attr/option is unknown */
2333+
zend_argument_value_error(ERROR_ARG_POS(2), "must be one of "
2334+
#if MYSQL_VERSION_ID >= 50107
2335+
"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, "
2336+
#endif
2337+
"MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE");
2338+
RETURN_THROWS();
2339+
}
2340+
22752341

22762342
#if MYSQL_VERSION_ID >= 50107
22772343
if (attr == STMT_ATTR_UPDATE_MAX_LENGTH)

0 commit comments

Comments
 (0)