Skip to content

Commit 535b42a

Browse files
authored
Implement PDO statment's fetchColumn() and fetchObject() methods (#315)
This PR implements two additional PDO statement proxy methods: - `PDOStatement::fetchColumn()` - `PDOStatement::fetchObject()` Both of these methods delegate the calls to the underlying SQLite statement. There are more PDO APIs to cover, but I had these in an in-progress branch, and there is no need to hold it off. Additional PDO API coverage will be done in subsequent PRs.
1 parent bfbd487 commit 535b42a

File tree

2 files changed

+116
-2
lines changed

2 files changed

+116
-2
lines changed

tests/WP_PDO_MySQL_On_SQLite_PDO_API_Tests.php

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
use PHPUnit\Framework\TestCase;
44

5+
// phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound
6+
class FetchObjectTestClass {
7+
public $col1;
8+
public $col2;
9+
public $col3;
10+
public $arg1;
11+
public $arg2;
12+
13+
public function __construct( $arg1 = null, $arg2 = null ) {
14+
$this->arg1 = $arg1;
15+
$this->arg2 = $arg2;
16+
}
17+
}
18+
519
class WP_PDO_MySQL_On_SQLite_PDO_API_Tests extends TestCase {
620
/** @var WP_PDO_MySQL_On_SQLite */
721
private $driver;
@@ -324,6 +338,106 @@ public function test_fetch( $query, $mode, $expected ): void {
324338
}
325339
}
326340

341+
public function test_fetch_column(): void {
342+
$query = "
343+
SELECT 1, 'abc', true
344+
UNION ALL
345+
SELECT 2, 'xyz', false
346+
UNION ALL
347+
SELECT 3, null, null
348+
";
349+
350+
// Fetch first column (default).
351+
$stmt = $this->driver->query( $query );
352+
$this->assertSame( '1', $stmt->fetchColumn() );
353+
$this->assertSame( '2', $stmt->fetchColumn() );
354+
$this->assertSame( '3', $stmt->fetchColumn() );
355+
$this->assertFalse( $stmt->fetchColumn() );
356+
357+
// Fetch second column.
358+
$stmt = $this->driver->query( $query );
359+
$this->assertSame( 'abc', $stmt->fetchColumn( 1 ) );
360+
$this->assertSame( 'xyz', $stmt->fetchColumn( 1 ) );
361+
$this->assertNull( $stmt->fetchColumn( 1 ) );
362+
$this->assertFalse( $stmt->fetchColumn( 1 ) );
363+
364+
// Fetch third column.
365+
$stmt = $this->driver->query( $query );
366+
$this->assertSame( '1', $stmt->fetchColumn( 2 ) );
367+
$this->assertSame( '0', $stmt->fetchColumn( 2 ) );
368+
$this->assertNull( $stmt->fetchColumn( 2 ) );
369+
$this->assertFalse( $stmt->fetchColumn( 2 ) );
370+
371+
// Fetch different columns across rows.
372+
$stmt = $this->driver->query( $query );
373+
$this->assertSame( '1', $stmt->fetchColumn( 0 ) );
374+
$this->assertSame( 'xyz', $stmt->fetchColumn( 1 ) );
375+
$this->assertNull( $stmt->fetchColumn( 2 ) );
376+
$this->assertFalse( $stmt->fetchColumn() );
377+
}
378+
379+
public function test_fetch_column_invalid_index(): void {
380+
$stmt = $this->driver->query( "SELECT 1, 'abc', true" );
381+
382+
if ( PHP_VERSION_ID < 80000 ) {
383+
$this->expectException( PDOException::class );
384+
$this->expectExceptionMessage( 'Invalid column index' );
385+
} else {
386+
$this->expectException( ValueError::class );
387+
$this->expectExceptionMessage( 'Invalid column index' );
388+
}
389+
$stmt->fetchColumn( 3 );
390+
}
391+
392+
public function test_fetch_column_negative_index(): void {
393+
$stmt = $this->driver->query( "SELECT 1, 'abc', true" );
394+
395+
if ( PHP_VERSION_ID < 80000 ) {
396+
$this->expectException( PDOException::class );
397+
$this->expectExceptionMessage( 'Invalid column index' );
398+
} else {
399+
$this->expectException( ValueError::class );
400+
$this->expectExceptionMessage( 'Column index must be greater than or equal to 0' );
401+
}
402+
$stmt->fetchColumn( -1 );
403+
}
404+
405+
public function test_fetch_obj(): void {
406+
// No arguments (stdClass).
407+
$stmt = $this->driver->query( "SELECT 1, 'abc', true" );
408+
$this->assertEquals(
409+
(object) array(
410+
1 => '1',
411+
'abc' => 'abc',
412+
'true' => true,
413+
),
414+
$stmt->fetchObject()
415+
);
416+
$this->assertFalse( $stmt->fetchObject() );
417+
418+
// Custom class.
419+
$stmt = $this->driver->query( "SELECT 1 AS col1, 'abc' AS col2, true AS col3" );
420+
$result = $stmt->fetchObject( FetchObjectTestClass::class );
421+
$this->assertInstanceOf( FetchObjectTestClass::class, $result );
422+
$this->assertSame( '1', $result->col1 );
423+
$this->assertSame( 'abc', $result->col2 );
424+
$this->assertSame( '1', $result->col3 );
425+
$this->assertNull( $result->arg1 );
426+
$this->assertNull( $result->arg2 );
427+
$this->assertFalse( $stmt->fetchObject( FetchObjectTestClass::class ) );
428+
429+
// Custom class with constructor arguments.
430+
$stmt = $this->driver->query( "SELECT 1 AS col1, 'abc' AS col2, true AS col3" );
431+
$result = $stmt->fetchObject( FetchObjectTestClass::class, array( 'val1', 'val2' ) );
432+
$this->assertInstanceOf( FetchObjectTestClass::class, $result );
433+
$this->assertSame( '1', $result->col1 );
434+
$this->assertSame( 'abc', $result->col2 );
435+
$this->assertSame( '1', $result->col3 );
436+
$this->assertSame( 'val1', $result->arg1 );
437+
$this->assertSame( 'val2', $result->arg2 );
438+
$this->assertFalse( $stmt->fetchObject( FetchObjectTestClass::class, array( 'val1', 'val2' ) ) );
439+
}
440+
327441
public function test_attr_default_fetch_mode(): void {
328442
$this->driver->setAttribute( PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_NUM );
329443
$result = $this->driver->query( "SELECT 'a', 'b', 'c'" );

wp-includes/sqlite-ast/class-wp-pdo-proxy-statement.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ public function fetch(
196196
*/
197197
#[ReturnTypeWillChange]
198198
public function fetchColumn( $column = 0 ) {
199-
throw new RuntimeException( 'Not implemented' );
199+
return $this->statement->fetchColumn( $column );
200200
}
201201

202202
/**
@@ -208,7 +208,7 @@ public function fetchColumn( $column = 0 ) {
208208
*/
209209
#[ReturnTypeWillChange]
210210
public function fetchObject( $class = 'stdClass', $constructorArgs = array() ) {
211-
throw new RuntimeException( 'Not implemented' );
211+
return $this->statement->fetchObject( $class, $constructorArgs );
212212
}
213213

214214
/**

0 commit comments

Comments
 (0)