Skip to content

Commit fd55809

Browse files
committed
Extract WP schema to a method, improve naming and docs
1 parent be2841d commit fd55809

3 files changed

Lines changed: 84 additions & 67 deletions

File tree

tests/WP_SQLite_Information_Schema_Reconstructor_Tests.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function setUp(): void {
7575
);
7676
}
7777

78-
public function testReconstructInformationSchemaTable(): void {
78+
public function testReconstructTable(): void {
7979
$this->engine->get_pdo()->exec(
8080
'
8181
CREATE TABLE t (
@@ -124,7 +124,7 @@ public function testReconstructInformationSchemaTable(): void {
124124
);
125125
}
126126

127-
public function testReconstructInformationSchemaTableWithWpTables(): void {
127+
public function testReconstructWpTable(): void {
128128
// Create a WP table with any columns.
129129
$this->engine->get_pdo()->exec( 'CREATE TABLE wp_posts ( id INTEGER )' );
130130

@@ -175,7 +175,7 @@ public function testReconstructInformationSchemaTableWithWpTables(): void {
175175
);
176176
}
177177

178-
public function testReconstructInformationSchemaFromMysqlDataTypesCache(): void {
178+
public function testReconstructTableFromMysqlDataTypesCache(): void {
179179
$pdo = $this->engine->get_pdo();
180180

181181
$pdo->exec( self::CREATE_DATA_TYPES_CACHE_TABLE_SQL );

wp-includes/sqlite-ast/class-wp-sqlite-configurator.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,30 @@ class WP_SQLite_Configurator {
2323
*
2424
* @var WP_SQLite_Information_Schema_Builder
2525
*/
26-
private $information_schema_builder;
26+
private $schema_builder;
2727

2828
/**
2929
* A service for reconstructing the MySQL INFORMATION_SCHEMA tables in SQLite.
3030
*
3131
* @var WP_SQLite_Information_Schema_Reconstructor
3232
*/
33-
private $information_schema_reconstructor;
33+
private $schema_reconstructor;
3434

3535
/**
3636
* Constructor.
3737
*
38-
* @param WP_SQLite_Driver $driver The SQLite driver instance.
39-
* @param WP_SQLite_Information_Schema_Builder $information_schema_builder The information schema builder instance.
38+
* @param WP_SQLite_Driver $driver The SQLite driver instance.
39+
* @param WP_SQLite_Information_Schema_Builder $schema_builder The information schema builder instance.
4040
*/
4141
public function __construct(
4242
WP_SQLite_Driver $driver,
43-
WP_SQLite_Information_Schema_Builder $information_schema_builder
43+
WP_SQLite_Information_Schema_Builder $schema_builder
4444
) {
45-
$this->driver = $driver;
46-
$this->information_schema_builder = $information_schema_builder;
47-
$this->information_schema_reconstructor = new WP_SQLite_Information_Schema_Reconstructor(
45+
$this->driver = $driver;
46+
$this->schema_builder = $schema_builder;
47+
$this->schema_reconstructor = new WP_SQLite_Information_Schema_Reconstructor(
4848
$driver,
49-
$information_schema_builder
49+
$schema_builder
5050
);
5151
}
5252

@@ -78,8 +78,8 @@ public function configure_database(): void {
7878
$this->driver->execute_sqlite_query( 'BEGIN EXCLUSIVE TRANSACTION' );
7979
try {
8080
$this->ensure_global_variables_table();
81-
$this->information_schema_builder->ensure_information_schema_tables();
82-
$this->information_schema_reconstructor->ensure_correct_information_schema();
81+
$this->schema_builder->ensure_information_schema_tables();
82+
$this->schema_reconstructor->ensure_correct_information_schema();
8383
$this->save_current_driver_version();
8484
} catch ( Throwable $e ) {
8585
$this->driver->execute_sqlite_query( 'ROLLBACK' );

wp-includes/sqlite-ast/class-wp-sqlite-information-schema-reconstructor.php

Lines changed: 70 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -28,63 +28,37 @@ class WP_SQLite_Information_Schema_Reconstructor {
2828
*
2929
* @var WP_SQLite_Information_Schema_Builder
3030
*/
31-
private $information_schema_builder;
31+
private $schema_builder;
3232

3333
/**
3434
* Constructor.
3535
*
36-
* @param WP_SQLite_Driver $driver The SQLite driver instance.
37-
* @param WP_SQLite_Information_Schema_Builder $information_schema_builder The information schema builder instance.
36+
* @param WP_SQLite_Driver $driver The SQLite driver instance.
37+
* @param WP_SQLite_Information_Schema_Builder $schema_builder The information schema builder instance.
3838
*/
3939
public function __construct(
4040
WP_SQLite_Driver $driver,
41-
WP_SQLite_Information_Schema_Builder $information_schema_builder
41+
WP_SQLite_Information_Schema_Builder $schema_builder
4242
) {
43-
$this->driver = $driver;
44-
$this->information_schema_builder = $information_schema_builder;
43+
$this->driver = $driver;
44+
$this->schema_builder = $schema_builder;
4545
}
4646

4747
/**
4848
* Ensure that the MySQL INFORMATION_SCHEMA data in SQLite is correct.
4949
*
5050
* This method checks if the MySQL INFORMATION_SCHEMA data in SQLite is correct,
51-
* and if it is not, it will reconstruct the data.
51+
* and if it is not, it will reconstruct missing data and remove stale values.
5252
*/
5353
public function ensure_correct_information_schema(): void {
54-
$tables = $this->get_existing_table_names();
54+
$sqlite_tables = $this->get_sqlite_table_names();
5555
$information_schema_tables = $this->get_information_schema_table_names();
5656

5757
// In WordPress, use "wp_get_db_schema()" to reconstruct WordPress tables.
58-
$wp_tables = array();
59-
if ( defined( 'ABSPATH' ) ) {
60-
if ( file_exists( ABSPATH . 'wp-admin/includes/schema.php' ) ) {
61-
require_once ABSPATH . 'wp-admin/includes/schema.php';
62-
}
63-
if ( ! function_exists( 'wp_get_db_schema' ) ) {
64-
throw new Exception( 'The "wp_get_db_schema()" function was not defined.' );
65-
}
66-
$schema = wp_get_db_schema();
67-
$parser = $this->driver->create_parser( $schema );
68-
while ( $parser->next_query() ) {
69-
$ast = $parser->get_query_ast();
70-
if ( null === $ast ) {
71-
throw new WP_SQLite_Driver_Exception( $this->driver, 'Failed to parse the MySQL query.' );
72-
}
73-
74-
$create_node = $ast->get_first_descendant_node( 'createStatement' );
75-
if ( $create_node && $create_node->has_child_node( 'createTable' ) ) {
76-
$name_node = $create_node->get_first_descendant_node( 'tableName' );
77-
$name = $this->unquote_mysql_identifier(
78-
substr( $schema, $name_node->get_start(), $name_node->get_length() )
79-
);
80-
81-
$wp_tables[ $name ] = $create_node;
82-
}
83-
}
84-
}
58+
$wp_tables = $this->get_wp_create_table_statements();
8559

8660
// Reconstruct information schema records for tables that don't have them.
87-
foreach ( $tables as $table ) {
61+
foreach ( $sqlite_tables as $table ) {
8862
if ( ! in_array( $table, $information_schema_tables, true ) ) {
8963
if ( isset( $wp_tables[ $table ] ) ) {
9064
// WordPress core table (as returned by "wp_get_db_schema()").
@@ -97,19 +71,19 @@ public function ensure_correct_information_schema(): void {
9771
throw new WP_SQLite_Driver_Exception( $this->driver, 'Failed to parse the MySQL query.' );
9872
}
9973
}
100-
$this->information_schema_builder->record_create_table( $ast );
74+
$this->schema_builder->record_create_table( $ast );
10175
}
10276
}
10377

10478
// Remove information schema records for tables that don't exist.
10579
foreach ( $information_schema_tables as $table ) {
106-
if ( ! in_array( $table, $tables, true ) ) {
80+
if ( ! in_array( $table, $sqlite_tables, true ) ) {
10781
$sql = sprintf( 'DROP %s', $this->quote_sqlite_identifier( $table ) );
10882
$ast = $this->driver->create_parser( $sql )->parse();
10983
if ( null === $ast ) {
11084
throw new WP_SQLite_Driver_Exception( $this->driver, 'Failed to parse the MySQL query.' );
11185
}
112-
$this->information_schema_builder->record_drop_table( $ast );
86+
$this->schema_builder->record_drop_table( $ast );
11387
}
11488
}
11589
}
@@ -119,7 +93,7 @@ public function ensure_correct_information_schema(): void {
11993
*
12094
* @return string[] The names of tables in the SQLite database.
12195
*/
122-
private function get_existing_table_names(): array {
96+
private function get_sqlite_table_names(): array {
12397
return $this->driver->execute_sqlite_query(
12498
"
12599
SELECT name
@@ -144,12 +118,55 @@ private function get_existing_table_names(): array {
144118
* @return string[] The names of tables in the information schema.
145119
*/
146120
private function get_information_schema_table_names(): array {
147-
$tables_table = $this->information_schema_builder->get_table_name( false, 'tables' );
121+
$tables_table = $this->schema_builder->get_table_name( false, 'tables' );
148122
return $this->driver->execute_sqlite_query(
149123
"SELECT table_name FROM $tables_table ORDER BY table_name"
150124
)->fetchAll( PDO::FETCH_COLUMN );
151125
}
152126

127+
/**
128+
* Get a map of parsed CREATE TABLE statements for WordPress tables.
129+
*
130+
* When reconstructing the information schema data for WordPress tables, we
131+
* can use the "wp_get_db_schema()" function to get accurate CREATE TABLE
132+
* statements. This method parses the result of "wp_get_db_schema()" into
133+
* an array of parsed CREATE TABLE statements indexed by the table names.
134+
*
135+
* @return array<string, WP_Parser_Node> The WordPress CREATE TABLE statements.
136+
*/
137+
private function get_wp_create_table_statements(): array {
138+
if ( ! defined( 'ABSPATH' ) ) {
139+
return array();
140+
}
141+
if ( file_exists( ABSPATH . 'wp-admin/includes/schema.php' ) ) {
142+
require_once ABSPATH . 'wp-admin/includes/schema.php';
143+
}
144+
if ( ! function_exists( 'wp_get_db_schema' ) ) {
145+
throw new Exception( 'The "wp_get_db_schema()" function was not defined.' );
146+
}
147+
148+
$schema = wp_get_db_schema();
149+
$parser = $this->driver->create_parser( $schema );
150+
$wp_tables = array();
151+
while ( $parser->next_query() ) {
152+
$ast = $parser->get_query_ast();
153+
if ( null === $ast ) {
154+
throw new WP_SQLite_Driver_Exception( $this->driver, 'Failed to parse the MySQL query.' );
155+
}
156+
157+
$create_node = $ast->get_first_descendant_node( 'createStatement' );
158+
if ( $create_node && $create_node->has_child_node( 'createTable' ) ) {
159+
$name_node = $create_node->get_first_descendant_node( 'tableName' );
160+
$name = $this->unquote_mysql_identifier(
161+
substr( $schema, $name_node->get_start(), $name_node->get_length() )
162+
);
163+
164+
$wp_tables[ $name ] = $create_node;
165+
}
166+
}
167+
return $wp_tables;
168+
}
169+
153170
/**
154171
* Generate a MySQL CREATE TABLE statement from an SQLite table definition.
155172
*
@@ -167,9 +184,9 @@ private function generate_create_table_statement( string $table_name ): string {
167184
foreach ( $columns as $column ) {
168185
$mysql_type = $this->get_cached_mysql_data_type( $table_name, $column['name'] );
169186
if ( null === $mysql_type ) {
170-
$mysql_type = $this->get_mysql_data_type( $column['type'] );
187+
$mysql_type = $this->get_mysql_column_type( $column['type'] );
171188
}
172-
$definitions[] = $this->get_column_definition( $table_name, $column );
189+
$definitions[] = $this->generate_column_definition( $table_name, $column );
173190
$column_types[ $column['name'] ] = $mysql_type;
174191
}
175192

@@ -206,7 +223,7 @@ private function generate_create_table_statement( string $table_name ): string {
206223
if ( 'pk' === $key['origin'] ) {
207224
continue;
208225
}
209-
$definitions[] = $this->get_key_definition( $table_name, $key, $column_types );
226+
$definitions[] = $this->generate_key_definition( $table_name, $key, $column_types );
210227
}
211228

212229
return sprintf(
@@ -225,14 +242,14 @@ private function generate_create_table_statement( string $table_name ): string {
225242
* @param array $column_info The SQLite column information.
226243
* @return string The MySQL column definition.
227244
*/
228-
private function get_column_definition( string $table_name, array $column_info ): string {
245+
private function generate_column_definition( string $table_name, array $column_info ): string {
229246
$definition = array();
230247
$definition[] = $this->quote_sqlite_identifier( $column_info['name'] );
231248

232249
// Data type.
233250
$mysql_type = $this->get_cached_mysql_data_type( $table_name, $column_info['name'] );
234251
if ( null === $mysql_type ) {
235-
$mysql_type = $this->get_mysql_data_type( $column_info['type'] );
252+
$mysql_type = $this->get_mysql_column_type( $column_info['type'] );
236253
}
237254
$definition[] = $mysql_type;
238255

@@ -268,27 +285,27 @@ private function get_column_definition( string $table_name, array $column_info )
268285
* This method generates a MySQL key definition from SQLite key data.
269286
*
270287
* @param string $table_name The name of the table.
271-
* @param array $key The SQLite key information.
288+
* @param array $key_info The SQLite key information.
272289
* @param array $column_types The MySQL data types of the columns.
273290
* @return string The MySQL key definition.
274291
*/
275-
private function get_key_definition( string $table_name, array $key, array $column_types ): string {
292+
private function generate_key_definition( string $table_name, array $key_info, array $column_types ): string {
276293
$definition = array();
277294

278295
// Key type.
279-
$cached_type = $this->get_cached_mysql_data_type( $table_name, $key['name'] );
296+
$cached_type = $this->get_cached_mysql_data_type( $table_name, $key_info['name'] );
280297
if ( 'FULLTEXT' === $cached_type ) {
281298
$definition[] = 'FULLTEXT KEY';
282299
} elseif ( 'SPATIAL' === $cached_type ) {
283300
$definition[] = 'SPATIAL KEY';
284-
} elseif ( 'UNIQUE' === $cached_type || '1' === $key['unique'] ) {
301+
} elseif ( 'UNIQUE' === $cached_type || '1' === $key_info['unique'] ) {
285302
$definition[] = 'UNIQUE KEY';
286303
} else {
287304
$definition[] = 'KEY';
288305
}
289306

290307
// Key name.
291-
$name = $key['name'];
308+
$name = $key_info['name'];
292309

293310
/*
294311
* The SQLite driver prefixes index names with "{$table_name}__" to avoid
@@ -310,7 +327,7 @@ private function get_key_definition( string $table_name, array $key, array $colu
310327

311328
// Key columns.
312329
$key_columns = $this->driver->execute_sqlite_query(
313-
'SELECT * FROM pragma_index_info("' . $key['name'] . '")'
330+
'SELECT * FROM pragma_index_info("' . $key_info['name'] . '")'
314331
)->fetchAll( PDO::FETCH_ASSOC );
315332
$cols = array();
316333
foreach ( $key_columns as $column ) {
@@ -445,7 +462,7 @@ private function get_cached_mysql_data_type( string $table_name, string $column_
445462
* @param string $column_type The SQLite column type.
446463
* @return string The MySQL column type.
447464
*/
448-
private function get_mysql_data_type( string $column_type ): string {
465+
private function get_mysql_column_type( string $column_type ): string {
449466
$type = strtoupper( $column_type );
450467

451468
/*

0 commit comments

Comments
 (0)