@@ -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