Skip to content

Commit 6d426fb

Browse files
committed
forgot about PDO::ERRMODE_SILENT
1 parent c1b07f4 commit 6d426fb

File tree

2 files changed

+75
-32
lines changed

2 files changed

+75
-32
lines changed

ext/pdo_sqlite/sqlite_driver.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@
2828
#include "zend_exceptions.h"
2929
#include "sqlite_driver_arginfo.h"
3030

31+
/*
32+
* Updated to add support for PDO::ERRMODE_SILENT and PDO::ERRMODE_WARNING
33+
* in addition to PDO::ERRMODE_EXCEPTION. The error mode is stored in
34+
* dbh->error_mode (assumed to be part of pdo_dbh_t) and is set in the
35+
* handle factory. Depending on the error mode, errors either throw an
36+
* exception, emit a warning, or remain silent.
37+
*/
38+
3139
int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line) /* {{{ */
3240
{
3341
pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
@@ -74,8 +82,11 @@ int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int li
7482
break;
7583
}
7684

77-
if (!dbh->methods) {
78-
pdo_throw_exception(einfo->errcode, einfo->errmsg, pdo_err);
85+
/* Handle error based on error mode */
86+
if (dbh->error_mode == PDO_ERRMODE_EXCEPTION) {
87+
zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode, "%s", einfo->errmsg);
88+
} else if (dbh->error_mode == PDO_ERRMODE_WARNING) {
89+
php_error_docref(NULL, E_WARNING, "%s", einfo->errmsg);
7990
}
8091

8192
return einfo->errcode;
@@ -227,8 +238,12 @@ static zend_string* sqlite_handle_quoter(pdo_dbh_t *dbh, const zend_string *unqu
227238
return NULL;
228239
}
229240
if(memchr(ZSTR_VAL(unquoted), '\0', ZSTR_LEN(unquoted)) != NULL) {
230-
zend_throw_exception_ex(php_pdo_get_exception(), 0,
231-
"SQLite PDO::quote does not support NULL bytes");
241+
if (dbh->error_mode == PDO_ERRMODE_EXCEPTION) {
242+
zend_throw_exception_ex(php_pdo_get_exception(), 0,
243+
"SQLite PDO::quote does not support NULL bytes");
244+
} else if (dbh->error_mode == PDO_ERRMODE_WARNING) {
245+
php_error_docref(NULL, E_WARNING, "SQLite PDO::quote does not support NULL bytes");
246+
}
232247
return NULL;
233248
}
234249
quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3);
@@ -842,6 +857,14 @@ static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{
842857
if (driver_options) {
843858
timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout);
844859
}
860+
861+
/* Set the error mode attribute based on driver options, defaulting to ERRMODE_EXCEPTION */
862+
if (driver_options) {
863+
dbh->error_mode = pdo_attr_lval(driver_options, PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION);
864+
} else {
865+
dbh->error_mode = PDO_ERRMODE_EXCEPTION;
866+
}
867+
845868
sqlite3_busy_timeout(H->db, timeout * 1000);
846869

847870
dbh->alloc_own_columns = 1;

ext/pdo_sqlite/tests/gh13952.phpt

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
--TEST--
2-
GH-13952 (sqlite PDO::quote silently corrupts strings with null bytes)
2+
GH-13952 (sqlite PDO::quote handles null bytes correctly)
33
--EXTENSIONS--
44
pdo
55
pdo_sqlite
66
--FILE--
77
<?php
8-
$db = new \PDO('sqlite::memory:', null, null, [
9-
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
10-
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
11-
\PDO::ATTR_EMULATE_PREPARES => false,
12-
]);
8+
9+
$modes = [
10+
'exception' => PDO::ERRMODE_EXCEPTION,
11+
'warning' => PDO::ERRMODE_WARNING,
12+
'silent' => PDO::ERRMODE_SILENT,
13+
];
1314

1415
$test_cases = [
1516
"",
@@ -26,34 +27,53 @@ $test_cases = [
2627
"\x00foo\x00\x00\x00bar\x00",
2728
"\x00\x00\x00foo",
2829
"foo\x00\x00\x00",
29-
"\x80", // Invalid UTF-8 sequence
30-
"\x00\x80\x00", // Invalid UTF-8 sequence with null bytes
30+
"\x80", // << invalid UTF-8
31+
"\x00\x80\x00", // << invalid UTF-8 with null bytes
3132
];
3233

33-
foreach ($test_cases as $test) {
34-
$should_throw = str_contains($test, "\x00");
35-
try {
36-
$quoted = $db->quote($test);
37-
if ($should_throw) {
38-
$displayTest = var_export($test, true);
39-
throw new LogicException("Failed for {$displayTest}: expected an exception but none was thrown.");
40-
}
41-
} catch (\PDOException $e) {
42-
if (!$should_throw) {
43-
$displayTest = var_export($test, true);
44-
throw new LogicException("Failed for {$displayTest}: unexpected exception thrown.", 0, $e);
34+
foreach ($modes as $mode_name => $mode) {
35+
echo "Testing error mode: $mode_name\n";
36+
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => $mode]);
37+
38+
foreach ($test_cases as $test) {
39+
$contains_null = str_contains($test, "\x00");
40+
41+
if ($mode === PDO::ERRMODE_EXCEPTION && $contains_null) {
42+
set_error_handler(fn() => throw new PDOException(), E_WARNING);
43+
try {
44+
$db->quote($test);
45+
throw new LogicException("Expected exception not thrown.");
46+
} catch (PDOException) {
47+
// expected
48+
} finally {
49+
restore_error_handler();
50+
}
51+
} else {
52+
set_error_handler(fn() => null, E_WARNING);
53+
$quoted = $db->quote($test);
54+
restore_error_handler();
55+
56+
if ($contains_null) {
57+
if ($quoted !== false) {
58+
throw new LogicException("Expected false, got: " . var_export($quoted, true));
59+
}
60+
} else {
61+
if ($quoted === false) {
62+
throw new LogicException("Unexpected false from quote().");
63+
}
64+
$fetched = $db->query("SELECT $quoted")->fetchColumn();
65+
if ($fetched !== $test) {
66+
throw new LogicException("Data corrupted: expected " . var_export($test, true) . " got " . var_export($fetched, true));
67+
}
68+
}
4569
}
46-
// Exception is expected
47-
continue;
48-
}
49-
$fetched = $db->query("SELECT $quoted")->fetch($db::FETCH_NUM)[0];
50-
if ($fetched !== $test) {
51-
$displayTest = var_export($test, true);
52-
$displayFetched = var_export($fetched, true);
53-
throw new LogicException("Round-trip data corruption for {$displayTest}: got {$displayFetched}.");
5470
}
5571
}
72+
5673
echo "ok\n";
5774
?>
5875
--EXPECT--
76+
Testing error mode: exception
77+
Testing error mode: warning
78+
Testing error mode: silent
5979
ok

0 commit comments

Comments
 (0)