Skip to content

Commit d3e9279

Browse files
committed
Improve errors for mysqli_stmt_attr_set()
1 parent 27d9ba1 commit d3e9279

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
@@ -2243,9 +2243,6 @@ PHP_FUNCTION(mysqli_stmt_attr_set)
22432243
MY_STMT *stmt;
22442244
zval *mysql_stmt;
22452245
zend_long mode_in;
2246-
#if MYSQL_VERSION_ID >= 50107
2247-
my_bool mode_b;
2248-
#endif
22492246
unsigned long mode;
22502247
zend_long attr;
22512248
void *mode_p;
@@ -2254,27 +2251,57 @@ PHP_FUNCTION(mysqli_stmt_attr_set)
22542251
RETURN_THROWS();
22552252
}
22562253

2257-
/* TODO Improve the mode to depend on the ATTR */
2258-
if (mode_in < 0) {
2259-
zend_argument_value_error(ERROR_ARG_POS(3), "must be greater than or equal to 0");
2260-
RETURN_THROWS();
2261-
}
2262-
22632254
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
22642255

22652256
switch (attr) {
22662257
#if MYSQL_VERSION_ID >= 50107
22672258
case STMT_ATTR_UPDATE_MAX_LENGTH:
2259+
{
2260+
my_bool mode_b;
2261+
if (mode_in != 0 && mode_in != 1) {
2262+
zend_argument_value_error(ERROR_ARG_POS(3), "must be 0 or 1 for attribute MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH");
2263+
RETURN_THROWS();
2264+
}
22682265
mode_b = (my_bool) mode_in;
22692266
mode_p = &mode_b;
22702267
break;
2268+
}
22712269
#endif
2272-
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+
}
22732283
mode = mode_in;
22742284
mode_p = &mode;
22752285
break;
22762286
}
2287+
case STMT_ATTR_PREFETCH_ROWS:
2288+
if (mode_in < 1) {
2289+
zend_argument_value_error(ERROR_ARG_POS(3), "must be greater than 0 for attribute MYSQLI_STMT_ATTR_PREFETCH_ROWS");
2290+
RETURN_THROWS();
2291+
}
2292+
mode = mode_in;
2293+
mode_p = &mode;
2294+
break;
2295+
default:
2296+
zend_argument_value_error(ERROR_ARG_POS(2), "must be one of "
2297+
#if MYSQL_VERSION_ID >= 50107
2298+
"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, "
2299+
#endif
2300+
"MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE");
2301+
RETURN_THROWS();
2302+
}
22772303

2304+
// TODO Can unify this?
22782305
#ifndef MYSQLI_USE_MYSQLND
22792306
if (mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
22802307
#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)