PluginProbe
SQLite Database Integration / 3.0.2
SQLite Database Integration v3.0.2
3.0.2 3.0.1 trunk 2.1.13 2.1.14 2.1.15 2.1.16 2.2.0 2.2.1 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.17 2.2.18 2.2.19 2.2.2 2.2.20 2.2.21 2.2.22 2.2.23 2.2.3 All 32 releases
sqlite-database-integration / wp-includes / database / sqlite / class-wp-mysql-on-sqlite-statement.php

class-wp-mysql-on-sqlite-statement.php in SQLite Database Integration 3.0.2, at wp-includes/database/sqlite/class-wp-mysql-on-sqlite-statement.php

458 lines 16.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * The SQLite driver uses PDO. Enable PDO function calls:
5 * phpcs:disable WordPress.DB.RestrictedClasses.mysql__PDO
6 * phpcs:disable WordPress.DB.RestrictedClasses.mysql__PDOStatement
7 *
8 * PDO uses camel case naming, enable non-snake case:
9 * phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
10 * phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
11 * phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
12 *
13 * PDO uses $class as a variable name, enable it:
14 * phpcs:disable Universal.NamingConventions.NoReservedKeywordParameterNames.classFound
15 *
16 * Some PDOStatement methods use $var as a variable name, enable it:
17 * phpcs:disable Universal.NamingConventions.NoReservedKeywordParameterNames.varFound
18 *
19 * We use traits to support different PHP versions with incompatible PDO statement
20 * method signatures. For that, enable multiple object structures in one file:
21 * phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound
22 */
23
24 /**
25 * Some PDOStatement methods are not compatible across different PHP versions.
26 * To address "Declaration of ... should be compatible with ..." PHP warnings,
27 * we conditionally define traits with different APIs based on the PHP version.
28 */
29 if ( PHP_VERSION_ID < 80000 ) {
30 /**
31 * PHP compatibility methods for WP_MySQL_On_SQLite_Statement.
32 *
33 * @access private
34 */
35 trait WP_MySQL_On_SQLite_Statement_PHP_Compat {
36 /**
37 * Set the default fetch mode for this statement.
38 *
39 * @param int $mode The fetch mode to set as the default.
40 * @param mixed $params Additional parameters for the default fetch mode.
41 * @return bool True on success, false on failure.
42 */
43 public function setFetchMode( $mode, $params = null ): bool {
44 // Do not pass additional arguments when they are NULL to prevent
45 // "fetch mode doesn't allow any extra arguments" error.
46 if ( null === $params ) {
47 return $this->setDefaultFetchMode( $mode );
48 }
49 return $this->setDefaultFetchMode( $mode, $params );
50 }
51
52 /**
53 * Fetch all remaining rows from the result set.
54 *
55 * @param int $mode The fetch mode to use.
56 * @param mixed $class_name With PDO::FETCH_CLASS, the name of the class to instantiate.
57 * @param mixed $constructor_args With PDO::FETCH_CLASS, the parameters to pass to the class constructor.
58 * @return array The result set as an array of rows.
59 */
60 public function fetchAll( $mode = null, $class_name = null, $constructor_args = null ): array {
61 // Do not pass additional arguments when they are NULL to prevent
62 // "Extraneous additional parameters" error.
63 if ( null === $class_name && null === $constructor_args ) {
64 return $this->fetchAllRows( $mode );
65 }
66 return $this->fetchAllRows( $mode, $class_name, $constructor_args );
67 }
68
69 /**
70 * Get metadata for a column in a result set.
71 *
72 * @param int $column The index of the column (0-indexed).
73 * @return array|false The column metadata as an associative array,
74 * or false if the column does not exist.
75 */
76 #[ReturnTypeWillChange]
77 public function getColumnMeta( $column ) {
78 return $this->getColumnMetadata( $column );
79 }
80 }
81 } else {
82 /**
83 * PHP compatibility methods for WP_MySQL_On_SQLite_Statement.
84 *
85 * @access private
86 */
87 trait WP_MySQL_On_SQLite_Statement_PHP_Compat {
88 /**
89 * Set the default fetch mode for this statement.
90 *
91 * @param int $mode The fetch mode to set as the default.
92 * @param mixed $args Additional parameters for the default fetch mode.
93 * @return bool True on success, false on failure.
94 */
95 #[ReturnTypeWillChange]
96 public function setFetchMode( $mode, ...$args ): bool {
97 return $this->setDefaultFetchMode( $mode, ...$args );
98 }
99
100 /**
101 * Fetch all remaining rows from the result set.
102 *
103 * @param int $mode The fetch mode to use.
104 * @param mixed $args Additional parameters for the fetch mode.
105 * @return array The result set as an array of rows.
106 */
107 public function fetchAll( $mode = PDO::FETCH_DEFAULT, ...$args ): array {
108 return $this->fetchAllRows( $mode, ...$args );
109 }
110
111 /**
112 * Get metadata for a column in a result set.
113 *
114 * @param int $column The index of the column (0-indexed).
115 * @return array|false The column metadata as an associative array,
116 * or false if the column does not exist.
117 */
118 #[ReturnTypeWillChange]
119 public function getColumnMeta( int $column ) {
120 if ( $column < 0 ) {
121 throw new ValueError( 'PDOStatement::getColumnMeta(): Argument #1 ($column) must be greater than or equal to 0' );
122 }
123 return $this->getColumnMetadata( $column );
124 }
125 }
126 }
127
128 /**
129 * PDOStatement implementation for MySQL-on-SQLite query results.
130 *
131 * Delegates operations to the underlying SQLite statement while adapting
132 * MySQL-specific behavior such as affected row counts.
133 *
134 * PDO supports the following fetch modes:
135 * - PDO::FETCH_DEFAULT: current default fetch mode (available from PHP 8.0)
136 * - PDO::FETCH_BOTH: default
137 * - PDO::FETCH_NUM: numeric array
138 * - PDO::FETCH_ASSOC: associative array
139 * - PDO::FETCH_NAMED: associative array retaining duplicate columns
140 * - PDO::FETCH_COLUMN: single column value [1 extra arg]
141 * - PDO::FETCH_KEY_PAIR: key-value pair
142 * - PDO::FETCH_OBJ: object (stdClass)
143 * - PDO::FETCH_CLASS: object (custom class) [1-2 extra args]
144 * - PDO::FETCH_INTO: update an existing object, can't be used with fetchAll() [1 extra arg]
145 * - PDO::FETCH_LAZY: lazy fetch via PDORow, can't be used with fetchAll()
146 * - PDO::FETCH_BOUND: bind values to PHP variables, can't be used with fetchAll()
147 * - PDO::FETCH_FUNC: custom function, only works with fetchAll(), can't be default [1 extra arg]
148 */
149 class WP_MySQL_On_SQLite_Statement extends PDOStatement implements IteratorAggregate {
150 use WP_MySQL_On_SQLite_Statement_PHP_Compat;
151
152 /**
153 * The original PDO statement.
154 *
155 * @var PDOStatement
156 */
157 private $statement;
158
159 /**
160 * Resolve MySQL-compatible metadata by column index.
161 *
162 * @var callable
163 */
164 private $column_meta_resolver;
165
166 /**
167 * Resolved MySQL-compatible metadata, keyed by column index.
168 *
169 * @var array<int, array|false>
170 */
171 private $resolved_column_meta = array();
172
173 /**
174 * The number of affected rows.
175 *
176 * @var int|null
177 */
178 private $affected_rows;
179
180 /**
181 * Constructor.
182 *
183 * @param PDOStatement $statement The original PDO statement.
184 * @param string $query The original MySQL query.
185 * @param callable $column_meta_resolver Resolves metadata by column index.
186 * @param int|null $affected_rows The number of affected rows.
187 */
188 public function __construct(
189 PDOStatement $statement,
190 string $query,
191 callable $column_meta_resolver,
192 ?int $affected_rows = null
193 ) {
194 $this->statement = $statement;
195
196 // Userland can only initialize PDOStatement::$queryString on PHP 8.1+.
197 if ( PHP_VERSION_ID >= 80100 ) {
198 $this->queryString = $query;
199 }
200 $this->column_meta_resolver = $column_meta_resolver;
201 $this->affected_rows = $affected_rows;
202 }
203
204 /**
205 * Execute a prepared statement.
206 *
207 * @param mixed $params The values to bind to the parameters of the prepared statement.
208 * @return bool True on success, false on failure.
209 */
210 public function execute( $params = null ): bool {
211 // The wrapped SQLite statement represents the result of MySQL emulation.
212 // Re-executing it would not repeat the original MySQL operation.
213 // TODO: Implement statement execution together with the prepare() flow.
214 throw new RuntimeException( 'Not implemented' );
215 }
216
217 /**
218 * Get the number of columns in the result set.
219 *
220 * @return int The number of columns in the result set.
221 */
222 public function columnCount(): int {
223 return $this->statement->columnCount();
224 }
225
226 /**
227 * Get the number of rows affected by the statement.
228 *
229 * @return int The number of rows affected by the statement.
230 */
231 public function rowCount(): int {
232 return $this->affected_rows ?? $this->statement->rowCount();
233 }
234
235 /**
236 * Fetch the next row from the result set.
237 *
238 * @param int|null $mode The fetch mode. Controls how the row is returned.
239 * Default: PDO::FETCH_DEFAULT (null for PHP < 8.0)
240 * @param int|null $cursorOrientation The cursor orientation. Controls which row is returned.
241 * Default: PDO::FETCH_ORI_NEXT (null for PHP < 8.0)
242 * @param int|null $cursorOffset The cursor offset. Controls which row is returned.
243 * Default: 0 (null for PHP < 8.0)
244 * @return mixed The row data formatted according to the fetch mode;
245 * false if there are no more rows or a failure occurs.
246 */
247 #[ReturnTypeWillChange]
248 public function fetch(
249 $mode = 0, // PDO::FETCH_DEFAULT (available from PHP 8.0)
250 $cursorOrientation = 0,
251 $cursorOffset = 0
252 ) {
253 return $this->statement->fetch( $mode, $cursorOrientation, $cursorOffset );
254 }
255
256 /**
257 * Fetch a single column from the next row of a result set.
258 *
259 * @param int $column The index of the column to fetch (0-indexed).
260 * @return mixed The value of the column; false if there are no more rows.
261 */
262 #[ReturnTypeWillChange]
263 public function fetchColumn( $column = 0 ) {
264 return $this->statement->fetchColumn( $column );
265 }
266
267 /**
268 * Fetch the next row as an object.
269 *
270 * @param string $class The name of the class to instantiate.
271 * @param array $constructorArgs The parameters to pass to the class constructor.
272 * @return object The next row as an object.
273 */
274 #[ReturnTypeWillChange]
275 public function fetchObject( $class = 'stdClass', $constructorArgs = array() ) {
276 return $this->statement->fetchObject( $class, $constructorArgs );
277 }
278
279 /**
280 * Fetch the SQLSTATE associated with the last statement operation.
281 *
282 * @return string|null The SQLSTATE error code (as defined by the ANSI SQL standard),
283 * or null if there is no error.
284 */
285 public function errorCode(): ?string {
286 return $this->statement->errorCode();
287 }
288
289 /**
290 * Fetch error information associated with the last statement operation.
291 *
292 * @return array The array consists of at least the following fields:
293 * 0: SQLSTATE error code (as defined by the ANSI SQL standard).
294 * 1: Driver-specific error code.
295 * 2: Driver-specific error message.
296 */
297 public function errorInfo(): array {
298 // Normalize successful results. PDO SQLite may retain stale driver-specific fields on PHP < 8.0.
299 if ( '00000' === $this->statement->errorCode() ) {
300 return array( '00000', null, null );
301 }
302 return $this->statement->errorInfo();
303 }
304
305 /**
306 * Get a statement attribute.
307 *
308 * @param int $attribute The attribute to get.
309 * @return mixed The value of the attribute.
310 */
311 #[ReturnTypeWillChange]
312 public function getAttribute( $attribute ) {
313 return $this->statement->getAttribute( $attribute );
314 }
315
316 /**
317 * Set a statement attribute.
318 *
319 * @param int $attribute The attribute to set.
320 * @param mixed $value The value of the attribute.
321 * @return bool True on success, false on failure.
322 */
323 public function setAttribute( $attribute, $value ): bool {
324 return $this->statement->setAttribute( $attribute, $value );
325 }
326
327 /**
328 * Get result set as iterator.
329 *
330 * @return Iterator The iterator for the result set.
331 */
332 public function getIterator(): Iterator {
333 yield from $this->statement;
334 }
335
336 /**
337 * Advances to the next rowset in a multi-rowset statement handle.
338 *
339 * @return bool True on success, false on failure.
340 */
341 public function nextRowset(): bool {
342 throw new RuntimeException( 'Not implemented' );
343 }
344
345 /**
346 * Close the cursor and release the associated resources.
347 *
348 * @return bool True on success, false on failure.
349 */
350 public function closeCursor(): bool {
351 return $this->statement->closeCursor();
352 }
353
354 /**
355 * Bind a column to a PHP variable.
356 *
357 * @param int|string $column Number of the column (1-indexed) or name of the column in the result set.
358 * @param mixed $var PHP variable to which the column will be bound.
359 * @param int $type Data type of the parameter, specified by the PDO::PARAM_* constants.
360 * @param int $maxLength A hint for pre-allocation.
361 * @param mixed $driverOptions Optional parameters for the driver.
362 * @return bool True on success, false on failure.
363 */
364 public function bindColumn( $column, &$var, $type = PDO::PARAM_STR, $maxLength = 0, $driverOptions = null ): bool {
365 return $this->statement->bindColumn( $column, $var, $type, $maxLength, $driverOptions );
366 }
367
368 /**
369 * Bind a parameter to a PHP variable.
370 *
371 * @param int|string $param Parameter identifier. Either a 1-indexed position of the parameter or a named parameter.
372 * @param mixed $var PHP variable to which the parameter will be bound.
373 * @param int $type Data type of the parameter, specified by the PDO::PARAM_* constants.
374 * @param int $maxLength Length of the data type.
375 * @param mixed $driverOptions Optional parameters for the driver.
376 * @return bool True on success, false on failure.
377 */
378 public function bindParam( $param, &$var, $type = PDO::PARAM_STR, $maxLength = 0, $driverOptions = null ): bool {
379 throw new RuntimeException( 'Not implemented' );
380 }
381
382 /**
383 * Bind a value to a parameter.
384 *
385 * @param int|string $param Parameter identifier. Either a 1-indexed position of the parameter or a named parameter.
386 * @param mixed $value The value to bind to the parameter.
387 * @param int $type Data type of the parameter, specified by the PDO::PARAM_* constants.
388 * @return bool True on success, false on failure.
389 */
390 public function bindValue( $param, $value, $type = PDO::PARAM_STR ): bool {
391 throw new RuntimeException( 'Not implemented' );
392 }
393
394 /**
395 * Dump information about the statement.
396 *
397 * Dumps the SQL query and parameter information.
398 *
399 * @return bool|null Returns null, or false on failure.
400 */
401 public function debugDumpParams(): ?bool {
402 throw new RuntimeException( 'Not implemented' );
403 }
404
405 /**
406 * Get metadata for a column in a result set.
407 *
408 * This is used internally by the "WP_MySQL_On_SQLite_Statement_PHP_Compat" trait,
409 * that is defined conditionally based on the current PHP version.
410 *
411 * @param int $column The index of the column (0-indexed).
412 * @return array|false The column metadata as an associative array,
413 * or false if the column does not exist.
414 */
415 private function getColumnMetadata( $column ) {
416 if ( ! array_key_exists( $column, $this->resolved_column_meta ) ) {
417 $this->resolved_column_meta[ $column ] = ( $this->column_meta_resolver )( $column );
418 }
419 return $this->resolved_column_meta[ $column ];
420 }
421
422 /**
423 * Fetch all remaining rows from the result set.
424 *
425 * This is used internally by the "WP_MySQL_On_SQLite_Statement_PHP_Compat" trait,
426 * that is defined conditionally based on the current PHP version.
427 *
428 * @param int $mode The fetch mode to use.
429 * @param mixed $args Additional parameters for the fetch mode.
430 * @return array The result set as an array of rows.
431 */
432 private function fetchAllRows( $mode = null, ...$args ): array {
433 return $this->statement->fetchAll( $mode, ...$args );
434 }
435
436 /**
437 * Set the default fetch mode for this statement.
438 *
439 * This is used internally by the "WP_MySQL_On_SQLite_Statement_PHP_Compat" trait,
440 * that is defined conditionally based on the current PHP version.
441 *
442 * @param int $mode The fetch mode to set as the default.
443 * @param mixed $args Additional parameters for the default fetch mode.
444 * @return bool True on success, false on failure.
445 */
446 private function setDefaultFetchMode( $mode, ...$args ): bool {
447 return $this->statement->setFetchMode( $mode, ...$args );
448 }
449 }
450
451 /**
452 * Polyfill ValueError for PHP < 8.0.
453 */
454 if ( PHP_VERSION_ID < 80000 && ! class_exists( ValueError::class ) ) {
455 class ValueError extends Error {
456 }
457 }
458