Skip to content

Commit 2cb06f8

Browse files
committed
Improve errors for mysqli_stmt_attr_set()
1 parent 3fe8c12 commit 2cb06f8

File tree

2 files changed

+62
-40
lines changed

2 files changed

+62
-40
lines changed

ext/mysqli/mysqli_api.c

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,9 +2279,6 @@ PHP_FUNCTION(mysqli_stmt_attr_set)
22792279
MY_STMT *stmt;
22802280
zval *mysql_stmt;
22812281
zend_long mode_in;
2282-
#if MYSQL_VERSION_ID >= 50107
2283-
my_bool mode_b;
2284-
#endif
22852282
unsigned long mode;
22862283
zend_long attr;
22872284
void *mode_p;
@@ -2290,27 +2287,57 @@ PHP_FUNCTION(mysqli_stmt_attr_set)
22902287
RETURN_THROWS();
22912288
}
22922289

2293-
/* TODO Improve the mode to depend on the ATTR */
2294-
if (mode_in < 0) {
2295-
zend_argument_value_error(ERROR_ARG_POS(3), "must be greater than or equal to 0");
2296-
RETURN_THROWS();
2297-
}
2298-
22992290
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
23002291

23012292
switch (attr) {
23022293
#if MYSQL_VERSION_ID >= 50107
23032294
case STMT_ATTR_UPDATE_MAX_LENGTH:
2295+
{
2296+
my_bool mode_b;
2297+
if (mode_in != 0 && mode_in != 1) {
2298+
zend_argument_value_error(ERROR_ARG_POS(3), "must be 0 or 1 for attribute MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH");
2299+
RETURN_THROWS();
2300+
}
23042301
mode_b = (my_bool) mode_in;
23052302
mode_p = &mode_b;
23062303
break;
2304+
}
23072305
#endif
2308-
default:
2306+
case STMT_ATTR_CURSOR_TYPE: {
2307+
switch (mode_in) {
2308+
case CURSOR_TYPE_NO_CURSOR:
2309+
case CURSOR_TYPE_READ_ONLY:
2310+
case CURSOR_TYPE_FOR_UPDATE:
2311+
case CURSOR_TYPE_SCROLLABLE:
2312+
break;
2313+
default:
2314+
zend_argument_value_error(ERROR_ARG_POS(3), "must be one of MYSQLI_CURSOR_TYPE_NO_CURSOR, "
2315+
"MYSQLI_CURSOR_TYPE_READ_ONLY, MYSQLI_CURSOR_TYPE_FOR_UPDATE, or MYSQLI_CURSOR_TYPE_SCROLLABLE "
2316+
"for attribute MYSQLI_STMT_ATTR_CURSOR_TYPE");
2317+
RETURN_THROWS();
2318+
}
23092319
mode = mode_in;
23102320
mode_p = &mode;
23112321
break;
23122322
}
2323+
case STMT_ATTR_PREFETCH_ROWS:
2324+
if (mode_in < 1) {
2325+
zend_argument_value_error(ERROR_ARG_POS(3), "must be greater than 0 for attribute MYSQLI_STMT_ATTR_PREFETCH_ROWS");
2326+
RETURN_THROWS();
2327+
}
2328+
mode = mode_in;
2329+
mode_p = &mode;
2330+
break;
2331+
default:
2332+
zend_argument_value_error(ERROR_ARG_POS(2), "must be one of "
2333+
#if MYSQL_VERSION_ID >= 50107
2334+
"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, "
2335+
#endif
2336+
"MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE");
2337+
RETURN_THROWS();
2338+
}
23132339

2340+
// TODO Can unify this?
23142341
#ifndef MYSQLI_USE_MYSQLND
23152342
if (mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
23162343
#else

ext/mysqli/tests/mysqli_stmt_attr_set.phpt

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,11 @@ require_once("connect.inc");
3333
}
3434

3535
$stmt->prepare("SELECT * FROM test");
36-
37-
mt_srand(microtime(true));
38-
39-
for ($i = -100; $i < 1000; $i++) {
40-
if (in_array($i, $valid_attr))
41-
continue;
42-
$invalid_attr = $i;
43-
try {
44-
if (false !== ($tmp = mysqli_stmt_attr_set($stmt, $invalid_attr, 0))) {
45-
printf("[006a] Expecting boolean/false for attribute %d, got %s/%s\n", $invalid_attr, gettype($tmp), $tmp);
46-
}
47-
} catch (\ValueError $e) {/* Suppress because RANDOM */}
48-
}
49-
50-
for ($i = 0; $i < 2; $i++) {
51-
do {
52-
$invalid_attr = mt_rand(-1 * (min(4294967296, PHP_INT_MAX) + 1), min(4294967296, PHP_INT_MAX));
53-
} while (in_array($invalid_attr, $valid_attr));
54-
try {
55-
if (false !== ($tmp = mysqli_stmt_attr_set($stmt, $invalid_attr, 0))) {
56-
printf("[006b] Expecting boolean/false for attribute %d, got %s/%s\n", $invalid_attr, gettype($tmp), $tmp);
57-
}
58-
} catch (\ValueError $e) {/* Suppress because RANDOM */}
36+
// Invalid Attribute (2nd argument)
37+
try {
38+
mysqli_stmt_attr_set($stmt, -1, 0);
39+
} catch (\ValueError $e) {
40+
echo $e->getMessage() . \PHP_EOL;
5941
}
6042
$stmt->close();
6143

@@ -117,6 +99,13 @@ require_once("connect.inc");
11799
if ($meta->max_length !== 0)
118100
printf("[009] max_length should not be set (= 0), got %s for field %s\n", $meta->max_length, $meta->name);
119101
}
102+
103+
// Invalid mode for MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH
104+
try {
105+
$stmt->attr_set(MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, -1);
106+
} catch (\ValueError $e) {
107+
echo $e->getMessage() . \PHP_EOL;
108+
}
120109
$res->close();
121110
$stmt->close();
122111

@@ -129,13 +118,9 @@ require_once("connect.inc");
129118
$stmt = mysqli_stmt_init($link);
130119
$stmt->prepare("SELECT id, label FROM test");
131120

121+
// Invalid cursor type
132122
try {
133-
$stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, -100);
134-
} catch (\ValueError $e) {
135-
echo $e->getMessage() . \PHP_EOL;
136-
}
137-
try {
138-
$stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, 200);
123+
$stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, -1);
139124
} catch (\ValueError $e) {
140125
echo $e->getMessage() . \PHP_EOL;
141126
}
@@ -211,6 +196,13 @@ require_once("connect.inc");
211196

212197
$stmt = mysqli_stmt_init($link);
213198
$stmt->prepare("SELECT id, label FROM test");
199+
// Invalid prefetch value
200+
try {
201+
$stmt->attr_set(MYSQLI_STMT_ATTR_PREFETCH_ROWS, 0);
202+
} catch (\ValueError $e) {
203+
echo $e->getMessage() . \PHP_EOL;
204+
}
205+
214206
if (true !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_PREFETCH_ROWS, 1)))
215207
printf("[020] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
216208
$stmt->execute();
@@ -265,5 +257,8 @@ require_once("connect.inc");
265257
?>
266258
--EXPECT--
267259
Error: mysqli_stmt object is not fully initialized
268-
mysqli_stmt::attr_set(): Argument #2 ($mode_in) must be greater than or equal to 0
260+
mysqli_stmt_attr_set(): Argument #2 ($attr) must be one of MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE
261+
mysqli_stmt::attr_set(): Argument #2 ($mode_in) must be 0 or 1 for attribute MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH
262+
mysqli_stmt::attr_set(): Argument #2 ($mode_in) must be one of MYSQLI_CURSOR_TYPE_NO_CURSOR, MYSQLI_CURSOR_TYPE_READ_ONLY, MYSQLI_CURSOR_TYPE_FOR_UPDATE, or MYSQLI_CURSOR_TYPE_SCROLLABLE for attribute MYSQLI_STMT_ATTR_CURSOR_TYPE
263+
mysqli_stmt::attr_set(): Argument #2 ($mode_in) must be greater than 0 for attribute MYSQLI_STMT_ATTR_PREFETCH_ROWS
269264
done!

0 commit comments

Comments
 (0)