@@ -81,18 +81,24 @@ public function error(): string
8181
8282 /**
8383 * Escapes a string for use in a query.
84+ *
85+ * Note: Unlike PDO::quote(), this method intentionally does NOT add surrounding quotes.
86+ * It mirrors the behavior of other drivers (e.g., Sqlite3::escapeString), returning
87+ * only the escaped content so callers can uniformly wrap values in SQL strings.
8488 */
8589 public function escape (string $ string ): string
8690 {
87- return $ this ->pdo ->quote ($ string );
91+ // For SQLite, escaping single quotes by doubling them is enough.
92+ return str_replace ("' " , "'' " , $ string );
8893 }
8994
9095 /**
9196 * Fetch a result row as an associative array.
9297 */
9398 public function fetchArray (mixed $ result ): ?array
9499 {
95- return $ result ->fetch (PDO ::FETCH_ASSOC );
100+ $ row = $ result ->fetch (PDO ::FETCH_ASSOC );
101+ return $ row === false || $ row === null ? null : $ row ;
96102 }
97103
98104 /**
@@ -126,15 +132,37 @@ public function fetchAll(mixed $result): ?array
126132 */
127133 public function fetchObject (mixed $ result ): mixed
128134 {
129- return $ result ->fetch (PDO ::FETCH_OBJ );
135+ $ obj = $ result ->fetch (PDO ::FETCH_OBJ );
136+ return $ obj === false ? null : $ obj ;
130137 }
131138
132139 /**
133140 * Number of rows in a result.
134141 */
135142 public function numRows (mixed $ result ): int
136143 {
137- return $ result ->rowCount ();
144+ try {
145+ $ sql = $ result ->queryString ?? '' ;
146+ if (is_string ($ sql ) && $ sql !== '' && preg_match ('/^\s*SELECT\b/i ' , $ sql ) === 1 ) {
147+ $ inner = rtrim ($ sql , " \t\n\r\0\x0B; " );
148+ $ countSql = 'SELECT COUNT(*) AS c FROM ( ' . $ inner . ') AS _pmf_cnt ' ;
149+ $ stmt = $ this ->pdo ->query ($ countSql );
150+ if ($ stmt === false ) {
151+ return 0 ;
152+ }
153+ $ row = $ stmt ->fetch (PDO ::FETCH_NUM );
154+ return isset ($ row [0 ]) ? (int ) $ row [0 ] : 0 ;
155+ }
156+ } catch (\Throwable ) {
157+ // ignore
158+ }
159+
160+ // Fallback: for non-SELECT statements rely on rowCount (INSERT/UPDATE/DELETE)
161+ try {
162+ return (int ) $ result ->rowCount ();
163+ } catch (\Throwable ) {
164+ return 0 ;
165+ }
138166 }
139167
140168 /**
0 commit comments