Skip to content

Commit e56b913

Browse files
committed
Implement and use PDOStatement fetch() and fetchAll() with basic fetch modes
1 parent d47bb69 commit e56b913

4 files changed

Lines changed: 264 additions & 21 deletions

File tree

tests/WP_PDO_MySQL_On_SQLite_PDO_API_Tests.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ public function test_connection(): void {
1818
public function test_query(): void {
1919
$result = $this->driver->query( "SELECT 1, 'abc'" );
2020
$this->assertInstanceOf( PDOStatement::class, $result );
21+
$this->assertSame(
22+
array(
23+
1 => 1,
24+
0 => 1,
25+
'abc' => 'abc',
26+
),
27+
$result->fetch()
28+
);
2129
}
2230

2331
public function test_exec(): void {
@@ -91,4 +99,87 @@ public function test_rollback_no_active_transaction(): void {
9199
$this->expectExceptionCode( 0 );
92100
$this->driver->rollBack();
93101
}
102+
103+
public function test_fetch_default(): void {
104+
// Default fetch mode is PDO::FETCH_BOTH.
105+
$result = $this->driver->query( "SELECT 1, 'abc', 2" );
106+
$this->assertSame(
107+
array(
108+
1 => 1,
109+
0 => 1,
110+
'abc' => 'abc',
111+
'2' => 2,
112+
),
113+
$result->fetch()
114+
);
115+
}
116+
117+
/**
118+
* @dataProvider data_pdo_fetch_methods
119+
*/
120+
public function test_fetch( $query, $mode, $expected ): void {
121+
$stmt = $this->driver->query( $query );
122+
$result = $stmt->fetch( $mode );
123+
if ( is_object( $expected ) ) {
124+
$this->assertInstanceOf( get_class( $expected ), $result );
125+
$this->assertEquals( $expected, $result );
126+
} else {
127+
$this->assertSame( $expected, $result );
128+
}
129+
}
130+
131+
public function data_pdo_fetch_methods(): Generator {
132+
// PDO::FETCH_BOTH
133+
yield 'PDO::FETCH_BOTH' => array(
134+
"SELECT 1, 'abc', 2, 'two' as `2`",
135+
PDO::FETCH_BOTH,
136+
array(
137+
1 => 1,
138+
0 => 1,
139+
'abc' => 'abc',
140+
'2' => 'two',
141+
'3' => 'two',
142+
),
143+
);
144+
145+
// PDO::FETCH_NUM
146+
yield 'PDO::FETCH_NUM' => array(
147+
"SELECT 1, 'abc', 2, 'two' as `2`",
148+
PDO::FETCH_NUM,
149+
array( 1, 'abc', 2, 'two' ),
150+
);
151+
152+
// PDO::FETCH_ASSOC
153+
yield 'PDO::FETCH_ASSOC' => array(
154+
"SELECT 1, 'abc', 2, 'two' as `2`",
155+
PDO::FETCH_ASSOC,
156+
array(
157+
'1' => 1,
158+
'abc' => 'abc',
159+
'2' => 'two',
160+
),
161+
);
162+
163+
// PDO::FETCH_NAMED
164+
yield 'PDO::FETCH_NAMED' => array(
165+
"SELECT 1, 'abc', 2, 'two' as `2`",
166+
PDO::FETCH_NAMED,
167+
array(
168+
'1' => 1,
169+
'abc' => 'abc',
170+
'2' => array( 2, 'two' ),
171+
),
172+
);
173+
174+
// PDO::FETCH_OBJ
175+
yield 'PDO::FETCH_OBJ' => array(
176+
"SELECT 1, 'abc', 2, 'two' as `2`",
177+
PDO::FETCH_OBJ,
178+
(object) array(
179+
'1' => 1,
180+
'abc' => 'abc',
181+
'2' => 'two',
182+
),
183+
);
184+
}
94185
}

wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -727,9 +727,17 @@ function ( string $sql, array $params ) {
727727
#[ReturnTypeWillChange]
728728
public function query( string $query, ?int $fetch_mode = PDO::FETCH_COLUMN, ...$fetch_mode_args ) {
729729
$this->flush();
730-
$this->pdo_fetch_mode = $fetch_mode;
731730
$this->last_mysql_query = $query;
732731

732+
/**
733+
* Use "PDO::FETCH_NUM" fetch mode, as the "WP_PDO_Synthetic_Statement"
734+
* expects the row data to be passed as an array of values.
735+
*
736+
* @TODO: We can remove this when we use the SQLite PDOStatements directly,
737+
* likely via a proxy, and will stop fetching the results eagerly.
738+
*/
739+
$this->pdo_fetch_mode = PDO::FETCH_NUM;
740+
733741
try {
734742
// Parse the MySQL query.
735743
$parser = $this->create_parser( $query );
@@ -772,8 +780,10 @@ public function query( string $query, ?int $fetch_mode = PDO::FETCH_COLUMN, ...$
772780
$this->commit_wrapper_transaction();
773781
}
774782

783+
$columns = is_array( $this->last_column_meta ) ? $this->last_column_meta : array();
784+
$rows = is_array( $this->last_result ) ? $this->last_result : array();
775785
$affected_rows = is_int( $this->last_return_value ) ? $this->last_return_value : 0;
776-
return new WP_PDO_Synthetic_Statement( $affected_rows );
786+
return new WP_PDO_Synthetic_Statement( $columns, $rows, $affected_rows );
777787
} catch ( Throwable $e ) {
778788
try {
779789
$this->rollback_user_transaction();
@@ -2518,7 +2528,7 @@ private function execute_show_statement( WP_Parser_Node $node ): void {
25182528
} else {
25192529
$this->set_results_from_fetched_data(
25202530
array(
2521-
(object) array(
2531+
array(
25222532
'Table' => $table_name,
25232533
'Create Table' => $sql,
25242534
),
@@ -2557,7 +2567,7 @@ private function execute_show_statement( WP_Parser_Node $node ): void {
25572567
case WP_MySQL_Lexer::GRANTS_SYMBOL:
25582568
$this->set_results_from_fetched_data(
25592569
array(
2560-
(object) array(
2570+
array(
25612571
'Grants for root@%' => 'GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, CREATE ROLE, DROP ROLE ON *.* TO `root`@`localhost` WITH GRANT OPTION',
25622572
),
25632573
)
@@ -2646,7 +2656,7 @@ private function execute_show_collation_statement( WP_Parser_Node $node ): void
26462656
)
26472657
);
26482658
$this->store_last_column_meta_from_statement( $stmt );
2649-
$this->set_results_from_fetched_data( $stmt->fetchAll( PDO::FETCH_OBJ ) );
2659+
$this->set_results_from_fetched_data( $stmt->fetchAll( $this->pdo_fetch_mode ) );
26502660
}
26512661

26522662
/**
@@ -2680,7 +2690,7 @@ private function execute_show_databases_statement( WP_Parser_Node $node ): void
26802690
);
26812691

26822692
$this->store_last_column_meta_from_statement( $stmt );
2683-
$databases = $stmt->fetchAll( PDO::FETCH_OBJ );
2693+
$databases = $stmt->fetchAll( $this->pdo_fetch_mode );
26842694
$this->set_results_from_fetched_data( $databases );
26852695
}
26862696

@@ -2766,7 +2776,7 @@ private function execute_show_index_statement( WP_Parser_Node $node ): void {
27662776
);
27672777

27682778
$this->store_last_column_meta_from_statement( $stmt );
2769-
$index_info = $stmt->fetchAll( PDO::FETCH_OBJ );
2779+
$index_info = $stmt->fetchAll( $this->pdo_fetch_mode );
27702780
$this->set_results_from_fetched_data( $index_info );
27712781
}
27722782

@@ -2829,7 +2839,7 @@ private function execute_show_table_status_statement( WP_Parser_Node $node ): vo
28292839
);
28302840

28312841
$this->store_last_column_meta_from_statement( $stmt );
2832-
$table_info = $stmt->fetchAll( PDO::FETCH_OBJ );
2842+
$table_info = $stmt->fetchAll( $this->pdo_fetch_mode );
28332843
if ( false === $table_info ) {
28342844
$this->set_results_from_fetched_data( array() );
28352845
}
@@ -2881,7 +2891,7 @@ private function execute_show_tables_statement( WP_Parser_Node $node ): void {
28812891
);
28822892

28832893
$this->store_last_column_meta_from_statement( $stmt );
2884-
$table_info = $stmt->fetchAll( PDO::FETCH_OBJ );
2894+
$table_info = $stmt->fetchAll( $this->pdo_fetch_mode );
28852895
if ( false === $table_info ) {
28862896
$this->set_results_from_fetched_data( array() );
28872897
}
@@ -2954,7 +2964,7 @@ private function execute_show_columns_statement( WP_Parser_Node $node ): void {
29542964
);
29552965

29562966
$this->store_last_column_meta_from_statement( $stmt );
2957-
$column_info = $stmt->fetchAll( PDO::FETCH_OBJ );
2967+
$column_info = $stmt->fetchAll( $this->pdo_fetch_mode );
29582968
if ( false === $column_info ) {
29592969
$this->set_results_from_fetched_data( array() );
29602970
}
@@ -2993,7 +3003,7 @@ private function execute_describe_statement( WP_Parser_Node $node ): void {
29933003
);
29943004

29953005
$this->store_last_column_meta_from_statement( $stmt );
2996-
$column_info = $stmt->fetchAll( PDO::FETCH_OBJ );
3006+
$column_info = $stmt->fetchAll( $this->pdo_fetch_mode );
29973007
$this->set_results_from_fetched_data( $column_info );
29983008
}
29993009

@@ -3315,14 +3325,14 @@ private function execute_administration_statement( WP_Parser_Node $node ): void
33153325

33163326
$operation = strtolower( $first_token->get_value() );
33173327
foreach ( $errors as $error ) {
3318-
$results[] = (object) array(
3328+
$results[] = array(
33193329
'Table' => $this->db_name . '.' . $table_name,
33203330
'Op' => $operation,
33213331
'Msg_type' => 'Error',
33223332
'Msg_text' => $error,
33233333
);
33243334
}
3325-
$results[] = (object) array(
3335+
$results[] = array(
33263336
'Table' => $this->db_name . '.' . $table_name,
33273337
'Op' => $operation,
33283338
'Msg_type' => 'status',

0 commit comments

Comments
 (0)