Skip to content

Commit 27d9ba1

Browse files
committed
Warning to Error promotion in MySQLi extension
1 parent 71de8fe commit 27d9ba1

34 files changed

+461
-269
lines changed

ext/mysqli/mysqli.c

Lines changed: 9 additions & 5 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);
@@ -1025,6 +1024,11 @@ PHP_METHOD(mysqli_result, __construct)
10251024
RETURN_THROWS();
10261025
}
10271026

1027+
if (resmode != MYSQLI_STORE_RESULT && resmode != MYSQLI_USE_RESULT) {
1028+
zend_argument_value_error(2, "must be MYSQLI_STORE_RESULT or MYSQLI_USE_RESULT");
1029+
RETURN_THROWS();
1030+
}
1031+
10281032
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
10291033

10301034
switch (resmode) {
@@ -1034,8 +1038,7 @@ PHP_METHOD(mysqli_result, __construct)
10341038
case MYSQLI_USE_RESULT:
10351039
result = mysql_use_result(mysql->mysql);
10361040
break;
1037-
default:
1038-
php_error_docref(NULL, E_WARNING, "Invalid value for resultmode");
1041+
EMPTY_SWITCH_DEFAULT_CASE();
10391042
}
10401043

10411044
if (!result) {
@@ -1052,7 +1055,7 @@ PHP_METHOD(mysqli_result, __construct)
10521055
PHP_METHOD(mysqli_result, getIterator)
10531056
{
10541057
if (zend_parse_parameters_none() == FAILURE) {
1055-
return;
1058+
RETURN_THROWS();
10561059
}
10571060

10581061
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
@@ -1130,6 +1133,7 @@ void php_mysqli_fetch_into_hash_aux(zval *return_value, MYSQL_RES * result, zend
11301133
}
11311134
/* }}} */
11321135

1136+
/* TODO Split this up */
11331137
/* {{{ php_mysqli_fetch_into_hash */
11341138
void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags, int into_object)
11351139
{

ext/mysqli/mysqli.stub.php

Lines changed: 4 additions & 4 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
@@ -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

ext/mysqli/mysqli_api.c

Lines changed: 72 additions & 25 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("Number of elements in type definition string doesn't match 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("Number of variables doesn't match number of parameters in 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,21 @@ 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)) {
742+
// TODO Promoto to Exception?
735743
php_error_docref(NULL, E_WARNING, "Function cannot be used with MYSQL_USE_RESULT");
736744
RETURN_FALSE;
737745
}
738746

739-
if (offset < 0 || (uint64_t)offset >= mysql_num_rows(result)) {
747+
if ((uint64_t)offset >= mysql_num_rows(result)) {
748+
// TODO Warning/Exception?
740749
RETURN_FALSE;
741750
}
742751

@@ -1181,9 +1190,15 @@ PHP_FUNCTION(mysqli_fetch_field_direct)
11811190
RETURN_THROWS();
11821191
}
11831192

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

1186-
if (offset < 0 || offset >= (zend_long) mysql_num_fields(result)) {
1200+
if (offset >= (zend_long) mysql_num_fields(result)) {
1201+
// TODO ValueError?
11871202
php_error_docref(NULL, E_WARNING, "Field offset is invalid for resultset");
11881203
RETURN_FALSE;
11891204
}
@@ -1215,6 +1230,7 @@ PHP_FUNCTION(mysqli_fetch_lengths)
12151230

12161231
MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
12171232

1233+
// TODO Warning?
12181234
if (!(ret = mysql_fetch_lengths(result))) {
12191235
RETURN_FALSE;
12201236
}
@@ -1260,9 +1276,16 @@ PHP_FUNCTION(mysqli_field_seek)
12601276
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &fieldnr) == FAILURE) {
12611277
RETURN_THROWS();
12621278
}
1279+
1280+
if (fieldnr < 0) {
1281+
zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1282+
RETURN_THROWS();
1283+
}
1284+
12631285
MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
12641286

1265-
if (fieldnr < 0 || (uint32_t)fieldnr >= mysql_num_fields(result)) {
1287+
if ((uint32_t)fieldnr >= mysql_num_fields(result)) {
1288+
// TODO ValueError?
12661289
php_error_docref(NULL, E_WARNING, "Invalid field offset");
12671290
RETURN_FALSE;
12681291
}
@@ -1499,13 +1522,14 @@ PHP_FUNCTION(mysqli_kill)
14991522
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &processid) == FAILURE) {
15001523
RETURN_THROWS();
15011524
}
1502-
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
15031525

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

1531+
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1532+
15091533
if (mysql_kill(mysql->mysql, processid)) {
15101534
MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
15111535
RETURN_FALSE;
@@ -1601,6 +1625,7 @@ PHP_FUNCTION(mysqli_num_rows)
16011625
MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
16021626

16031627
if (mysqli_result_is_unbuffered_and_not_everything_is_fetched(result)) {
1628+
// TODO Exception?
16041629
php_error_docref(NULL, E_WARNING, "Function cannot be used with MYSQL_USE_RESULT");
16051630
RETURN_LONG(0);
16061631
}
@@ -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);
@@ -2225,13 +2253,15 @@ 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

2257+
/* TODO Improve the mode to depend on the ATTR */
22302258
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;
2259+
zend_argument_value_error(ERROR_ARG_POS(3), "must be greater than or equal to 0");
2260+
RETURN_THROWS();
22332261
}
22342262

2263+
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2264+
22352265
switch (attr) {
22362266
#if MYSQL_VERSION_ID >= 50107
22372267
case STMT_ATTR_UPDATE_MAX_LENGTH:
@@ -2244,6 +2274,7 @@ PHP_FUNCTION(mysqli_stmt_attr_set)
22442274
mode_p = &mode;
22452275
break;
22462276
}
2277+
22472278
#ifndef MYSQLI_USE_MYSQLND
22482279
if (mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
22492280
#else
@@ -2262,20 +2293,36 @@ PHP_FUNCTION(mysqli_stmt_attr_get)
22622293
zval *mysql_stmt;
22632294
unsigned long value = 0;
22642295
zend_long attr;
2265-
int rc;
22662296

22672297
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &attr) == FAILURE) {
22682298
RETURN_THROWS();
22692299
}
22702300
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
22712301

2272-
if ((rc = mysql_stmt_attr_get(stmt->stmt, attr, &value))) {
2273-
RETURN_FALSE;
2302+
switch (attr) {
2303+
#if MYSQL_VERSION_ID >= 50107
2304+
case STMT_ATTR_UPDATE_MAX_LENGTH:
2305+
#endif
2306+
case STMT_ATTR_CURSOR_TYPE:
2307+
case STMT_ATTR_PREFETCH_ROWS:
2308+
break;
2309+
default:
2310+
zend_argument_value_error(ERROR_ARG_POS(2), "must be one of "
2311+
#if MYSQL_VERSION_ID >= 50107
2312+
"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, "
2313+
#endif
2314+
"MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE");
2315+
RETURN_THROWS();
22742316
}
22752317

2318+
/* Success corresponds to 0 return value and a non-zero value
2319+
* should only happen if the attr/option is unknown */
2320+
ZEND_ASSERT(mysql_stmt_attr_get(stmt->stmt, attr, &value) == 0);
2321+
22762322
#if MYSQL_VERSION_ID >= 50107
2277-
if (attr == STMT_ATTR_UPDATE_MAX_LENGTH)
2323+
if (attr == STMT_ATTR_UPDATE_MAX_LENGTH) {
22782324
value = *((my_bool *)&value);
2325+
}
22792326
#endif
22802327
RETURN_LONG((unsigned long)value);
22812328
}

ext/mysqli/mysqli_arginfo.h

Lines changed: 4 additions & 4 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: a8626c7c42e4d117b08df7f42a7523f60f357b82 */
2+
* Stub hash: 473cceef8ade1758128ddb348ec3c90216d12b3f */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_affected_rows, 0, 1, MAY_BE_LONG|MAY_BE_STRING)
55
ZEND_ARG_OBJ_INFO(0, mysql_link, mysqli, 0)
@@ -233,7 +233,7 @@ ZEND_END_ARG_INFO()
233233
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_mysqli_query, 0, 2, mysqli_result, MAY_BE_BOOL)
234234
ZEND_ARG_OBJ_INFO(0, mysqli_link, mysqli, 0)
235235
ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 0)
236-
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, resultmode, IS_LONG, 0, "MYSQLI_STORE_RESULT")
236+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, result_mode, IS_LONG, 0, "MYSQLI_STORE_RESULT")
237237
ZEND_END_ARG_INFO()
238238

239239
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_real_connect, 0, 1, _IS_BOOL, 0)
@@ -285,7 +285,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_stmt_affected_rows, 0, 1,
285285
ZEND_ARG_OBJ_INFO(0, mysql_stmt, mysqli_stmt, 0)
286286
ZEND_END_ARG_INFO()
287287

288-
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_stmt_attr_get, 0, 2, MAY_BE_LONG|MAY_BE_FALSE)
288+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_stmt_attr_get, 0, 2, IS_LONG, 0)
289289
ZEND_ARG_OBJ_INFO(0, mysql_stmt, mysqli_stmt, 0)
290290
ZEND_ARG_TYPE_INFO(0, attr, IS_LONG, 0)
291291
ZEND_END_ARG_INFO()
@@ -502,7 +502,7 @@ ZEND_END_ARG_INFO()
502502

503503
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_query, 0, 0, 1)
504504
ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 0)
505-
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, resultmode, IS_LONG, 0, "MYSQLI_STORE_RESULT")
505+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, result_mode, IS_LONG, 0, "MYSQLI_STORE_RESULT")
506506
ZEND_END_ARG_INFO()
507507

508508
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_real_connect, 0, 0, 0)

0 commit comments

Comments
 (0)