Skip to content

Commit 67dece9

Browse files
committed
Implement and use PDOStatement fetch() and fetchAll() with basic fetch modes
1 parent ca9dd2a commit 67dece9

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();
@@ -2444,7 +2454,7 @@ private function execute_show_statement( WP_Parser_Node $node ): void {
24442454
} else {
24452455
$this->set_results_from_fetched_data(
24462456
array(
2447-
(object) array(
2457+
array(
24482458
'Table' => $table_name,
24492459
'Create Table' => $sql,
24502460
),
@@ -2483,7 +2493,7 @@ private function execute_show_statement( WP_Parser_Node $node ): void {
24832493
case WP_MySQL_Lexer::GRANTS_SYMBOL:
24842494
$this->set_results_from_fetched_data(
24852495
array(
2486-
(object) array(
2496+
array(
24872497
'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',
24882498
),
24892499
)
@@ -2572,7 +2582,7 @@ private function execute_show_collation_statement( WP_Parser_Node $node ): void
25722582
)
25732583
);
25742584
$this->store_last_column_meta_from_statement( $stmt );
2575-
$this->set_results_from_fetched_data( $stmt->fetchAll( PDO::FETCH_OBJ ) );
2585+
$this->set_results_from_fetched_data( $stmt->fetchAll( $this->pdo_fetch_mode ) );
25762586
}
25772587

25782588
/**
@@ -2604,7 +2614,7 @@ private function execute_show_databases_statement( WP_Parser_Node $node ): void
26042614
);
26052615

26062616
$this->store_last_column_meta_from_statement( $stmt );
2607-
$databases = $stmt->fetchAll( PDO::FETCH_OBJ );
2617+
$databases = $stmt->fetchAll( $this->pdo_fetch_mode );
26082618
$this->set_results_from_fetched_data( $databases );
26092619
}
26102620

@@ -2690,7 +2700,7 @@ private function execute_show_index_statement( WP_Parser_Node $node ): void {
26902700
);
26912701

26922702
$this->store_last_column_meta_from_statement( $stmt );
2693-
$index_info = $stmt->fetchAll( PDO::FETCH_OBJ );
2703+
$index_info = $stmt->fetchAll( $this->pdo_fetch_mode );
26942704
$this->set_results_from_fetched_data( $index_info );
26952705
}
26962706

@@ -2753,7 +2763,7 @@ private function execute_show_table_status_statement( WP_Parser_Node $node ): vo
27532763
);
27542764

27552765
$this->store_last_column_meta_from_statement( $stmt );
2756-
$table_info = $stmt->fetchAll( PDO::FETCH_OBJ );
2766+
$table_info = $stmt->fetchAll( $this->pdo_fetch_mode );
27572767
if ( false === $table_info ) {
27582768
$this->set_results_from_fetched_data( array() );
27592769
}
@@ -2805,7 +2815,7 @@ private function execute_show_tables_statement( WP_Parser_Node $node ): void {
28052815
);
28062816

28072817
$this->store_last_column_meta_from_statement( $stmt );
2808-
$table_info = $stmt->fetchAll( PDO::FETCH_OBJ );
2818+
$table_info = $stmt->fetchAll( $this->pdo_fetch_mode );
28092819
if ( false === $table_info ) {
28102820
$this->set_results_from_fetched_data( array() );
28112821
}
@@ -2878,7 +2888,7 @@ private function execute_show_columns_statement( WP_Parser_Node $node ): void {
28782888
);
28792889

28802890
$this->store_last_column_meta_from_statement( $stmt );
2881-
$column_info = $stmt->fetchAll( PDO::FETCH_OBJ );
2891+
$column_info = $stmt->fetchAll( $this->pdo_fetch_mode );
28822892
if ( false === $column_info ) {
28832893
$this->set_results_from_fetched_data( array() );
28842894
}
@@ -2917,7 +2927,7 @@ private function execute_describe_statement( WP_Parser_Node $node ): void {
29172927
);
29182928

29192929
$this->store_last_column_meta_from_statement( $stmt );
2920-
$column_info = $stmt->fetchAll( PDO::FETCH_OBJ );
2930+
$column_info = $stmt->fetchAll( $this->pdo_fetch_mode );
29212931
$this->set_results_from_fetched_data( $column_info );
29222932
}
29232933

@@ -3239,14 +3249,14 @@ private function execute_administration_statement( WP_Parser_Node $node ): void
32393249

32403250
$operation = strtolower( $first_token->get_value() );
32413251
foreach ( $errors as $error ) {
3242-
$results[] = (object) array(
3252+
$results[] = array(
32433253
'Table' => $this->db_name . '.' . $table_name,
32443254
'Op' => $operation,
32453255
'Msg_type' => 'Error',
32463256
'Msg_text' => $error,
32473257
);
32483258
}
3249-
$results[] = (object) array(
3259+
$results[] = array(
32503260
'Table' => $this->db_name . '.' . $table_name,
32513261
'Op' => $operation,
32523262
'Msg_type' => 'status',

0 commit comments

Comments
 (0)