1111 * repair and update these tables and metadata in case of database corruption.
1212 */
1313class WP_SQLite_Configurator {
14- /**
15- * The name of the database.
16- *
17- * @var string
18- */
19- private $ db_name ;
20-
2114 /**
2215 * The SQLite driver instance.
2316 *
@@ -42,16 +35,13 @@ class WP_SQLite_Configurator {
4235 /**
4336 * Constructor.
4437 *
45- * @param string $db_name The name of the database.
4638 * @param WP_SQLite_Driver $driver The SQLite driver instance.
4739 * @param WP_SQLite_Information_Schema_Builder $schema_builder The information schema builder instance.
4840 */
4941 public function __construct (
50- string $ db_name ,
5142 WP_SQLite_Driver $ driver ,
5243 WP_SQLite_Information_Schema_Builder $ schema_builder
5344 ) {
54- $ this ->db_name = $ db_name ;
5545 $ this ->driver = $ driver ;
5646 $ this ->schema_builder = $ schema_builder ;
5747 $ this ->schema_reconstructor = new WP_SQLite_Information_Schema_Reconstructor (
@@ -72,20 +62,6 @@ public function ensure_database_configured(): void {
7262 if ( version_compare ( $ version , $ db_version ) > 0 ) {
7363 $ this ->configure_database ();
7464 }
75-
76- // Ensure that the database name used in the current session corresponds
77- // to the database name that is stored in the information schema tables.
78- $ db_name = $ this ->driver ->get_saved_database_name ();
79- if ( $ this ->db_name !== $ db_name ) {
80- throw new WP_SQLite_Driver_Exception (
81- $ this ->driver ,
82- sprintf (
83- "Incorrect database name. The database was created with name '%s', but '%s' is used in the current session. " ,
84- $ db_name ,
85- $ this ->db_name
86- )
87- );
88- }
8965 }
9066
9167 /**
@@ -105,7 +81,7 @@ public function configure_database(): void {
10581 $ this ->schema_builder ->ensure_information_schema_tables ();
10682 $ this ->schema_reconstructor ->ensure_correct_information_schema ();
10783 $ this ->save_current_driver_version ();
108- $ this ->ensure_schemata_data ();
84+ $ this ->ensure_database_data ();
10985 } catch ( Throwable $ e ) {
11086 $ this ->driver ->execute_sqlite_query ( 'ROLLBACK ' );
11187 throw $ e ;
@@ -131,70 +107,142 @@ private function ensure_global_variables_table(): void {
131107 }
132108
133109 /**
134- * Ensure that the "SCHEMATA" table data is correctly populated.
110+ * Ensure that the database data is correctly populated.
135111 *
136112 * This method ensures that the "INFORMATION_SCHEMA.SCHEMATA" table contains
137113 * records for both the "INFORMATION_SCHEMA" database and the user database.
138114 * At the moment, only a single user database is supported.
115+ *
116+ * Additionally, this method ensures that the user database name is stored
117+ * correctly in all the information schema tables.
139118 */
140- public function ensure_schemata_data (): void {
119+ public function ensure_database_data (): void {
120+ // Get all databases from the "SCHEMATA" table.
141121 $ schemata_table = $ this ->schema_builder ->get_table_name ( false , 'schemata ' );
142-
143- // 1. Ensure that the "INFORMATION_SCHEMA" database record exists.
144- $ this ->driver ->execute_sqlite_query (
145- sprintf (
146- 'INSERT INTO %s (SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME)
147- VALUES (?, ?, ?) ON CONFLICT(SCHEMA_NAME) DO NOTHING ' ,
148- $ this ->driver ->get_connection ()->quote_identifier ( $ schemata_table )
149- ),
150- // The "INFORMATION_SCHEMA" database stays on "utf8mb3" even in MySQL 8 and 9.
151- array ( 'information_schema ' , 'utf8mb3 ' , 'utf8mb3_general_ci ' )
152- );
153-
154- // 2. Bail out if a user database record already exists.
155- $ user_db_record_exists = $ this ->driver ->execute_sqlite_query (
122+ $ databases = $ this ->driver ->execute_sqlite_query (
156123 sprintf (
157- " SELECT COUNT(*) FROM %s WHERE SCHEMA_NAME != 'information_schema' " ,
124+ ' SELECT SCHEMA_NAME FROM %s ' ,
158125 $ this ->driver ->get_connection ()->quote_identifier ( $ schemata_table )
159126 )
160- )->fetchColumn () > 0 ;
127+ )->fetchAll ( PDO :: FETCH_COLUMN ); // phpcs:disable WordPress.DB.RestrictedClasses.mysql__PDO
161128
162- if ( $ user_db_record_exists ) {
163- return ;
129+ // Ensure that the "INFORMATION_SCHEMA" database record exists.
130+ if ( ! in_array ( 'information_schema ' , $ databases , true ) ) {
131+ $ this ->driver ->execute_sqlite_query (
132+ sprintf (
133+ 'INSERT INTO %s (SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME) VALUES (?, ?, ?) ' ,
134+ $ this ->driver ->get_connection ()->quote_identifier ( $ schemata_table )
135+ ),
136+ // The "INFORMATION_SCHEMA" database stays on "utf8mb3" even in MySQL 8 and 9.
137+ array ( 'information_schema ' , 'utf8mb3 ' , 'utf8mb3_general_ci ' )
138+ );
164139 }
165140
166- /*
167- * 3. Migrate from older driver versions without the "SCHEMATA" table.
168- *
169- * If a record with an existing database name value is already stored in
170- * "INFORMATION_SCHEMA.TABLES", we need to use that value. This ensures
171- * migration from older driver versions without the "SCHEMATA" table.
172- */
173- $ information_schema_db_name = $ this ->driver ->execute_sqlite_query (
174- sprintf (
175- 'SELECT table_schema FROM %s LIMIT 1 ' ,
176- $ this ->driver ->get_connection ()->quote_identifier (
177- $ this ->schema_builder ->get_table_name ( false , 'tables ' )
178- )
179- )
180- )->fetchColumn ();
141+ // Get the existing user database name.
142+ $ existing_user_db_name = null ;
143+ foreach ( $ databases as $ database ) {
144+ if ( 'information_schema ' !== strtolower ( $ database ) ) {
145+ $ existing_user_db_name = $ database ;
146+ break ;
147+ }
148+ }
181149
182- if ( false !== $ information_schema_db_name ) {
183- $ db_name = $ information_schema_db_name ;
184- } else {
185- $ db_name = $ this ->db_name ;
150+ // Ensure that the user database record exists.
151+ if ( null === $ existing_user_db_name ) {
152+ $ existing_user_db_name = WP_SQLite_Information_Schema_Builder::SAVED_DATABASE_NAME ;
153+ $ this ->driver ->execute_sqlite_query (
154+ sprintf (
155+ 'INSERT INTO %s (SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME) VALUES (?, ?, ?) ' ,
156+ $ this ->driver ->get_connection ()->quote_identifier ( $ schemata_table )
157+ ),
158+ // @TODO: This should probably be version-dependent.
159+ // Before MySQL 8, the default was different.
160+ array ( $ existing_user_db_name , 'utf8mb4 ' , 'utf8mb4_0900_ai_ci ' )
161+ );
186162 }
187163
188- // 4. Create a user database record.
189- $ this ->driver ->execute_sqlite_query (
190- sprintf (
191- 'INSERT INTO %s (SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME) VALUES (?, ?, ?) ' ,
192- $ this ->driver ->get_connection ()->quote_identifier ( $ schemata_table )
193- ),
194- // @TODO: This should probably be version-dependent.
195- // Before MySQL 8, the default was different.
196- array ( $ db_name , 'utf8mb4 ' , 'utf8mb4_0900_ai_ci ' )
197- );
164+ // Migrate from older versions without dynamic database names.
165+ $ saved_database_name = WP_SQLite_Information_Schema_Builder::SAVED_DATABASE_NAME ;
166+ if ( $ saved_database_name !== $ existing_user_db_name ) {
167+ // INFORMATION_SCHEMA.SCHEMATA
168+ $ this ->driver ->execute_sqlite_query (
169+ sprintf (
170+ "UPDATE %s SET SCHEMA_NAME = ? WHERE SCHEMA_NAME != 'information_schema' " ,
171+ $ this ->driver ->get_connection ()->quote_identifier ( $ schemata_table )
172+ ),
173+ array ( $ saved_database_name )
174+ );
175+
176+ // INFORMATION_SCHEMA.TABLES
177+ $ tables_table = $ this ->schema_builder ->get_table_name ( false , 'tables ' );
178+ $ this ->driver ->execute_sqlite_query (
179+ sprintf (
180+ "UPDATE %s SET TABLE_SCHEMA = ? WHERE TABLE_SCHEMA != 'information_schema' " ,
181+ $ this ->driver ->get_connection ()->quote_identifier ( $ tables_table )
182+ ),
183+ array ( $ saved_database_name )
184+ );
185+
186+ // INFORMATION_SCHEMA.COLUMNS
187+ $ columns_table = $ this ->schema_builder ->get_table_name ( false , 'columns ' );
188+ $ this ->driver ->execute_sqlite_query (
189+ sprintf (
190+ "UPDATE %s SET TABLE_SCHEMA = ? WHERE TABLE_SCHEMA != 'information_schema' " ,
191+ $ this ->driver ->get_connection ()->quote_identifier ( $ columns_table )
192+ ),
193+ array ( $ saved_database_name )
194+ );
195+
196+ // INFORMATION_SCHEMA.STATISTICS
197+ $ statistics_table = $ this ->schema_builder ->get_table_name ( false , 'statistics ' );
198+ $ this ->driver ->execute_sqlite_query (
199+ sprintf (
200+ "UPDATE %s SET TABLE_SCHEMA = ?, INDEX_SCHEMA = ? WHERE TABLE_SCHEMA != 'information_schema' " ,
201+ $ this ->driver ->get_connection ()->quote_identifier ( $ statistics_table )
202+ ),
203+ array ( $ saved_database_name , $ saved_database_name )
204+ );
205+
206+ // INFORMATION_SCHEMA.TABLE_CONSTRAINTS
207+ $ table_constraints_table = $ this ->schema_builder ->get_table_name ( false , 'table_constraints ' );
208+ $ this ->driver ->execute_sqlite_query (
209+ sprintf (
210+ "UPDATE %s SET TABLE_SCHEMA = ?, CONSTRAINT_SCHEMA = ? WHERE TABLE_SCHEMA != 'information_schema' " ,
211+ $ this ->driver ->get_connection ()->quote_identifier ( $ table_constraints_table )
212+ ),
213+ array ( $ saved_database_name , $ saved_database_name )
214+ );
215+
216+ // INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
217+ $ referential_constraints_table = $ this ->schema_builder ->get_table_name ( false , 'referential_constraints ' );
218+ $ this ->driver ->execute_sqlite_query (
219+ sprintf (
220+ "UPDATE %s SET CONSTRAINT_SCHEMA = ?, UNIQUE_CONSTRAINT_SCHEMA = ? WHERE CONSTRAINT_SCHEMA != 'information_schema' " ,
221+ $ this ->driver ->get_connection ()->quote_identifier ( $ referential_constraints_table )
222+ ),
223+ array ( $ saved_database_name , $ saved_database_name )
224+ );
225+
226+ // INFORMATION_SCHEMA.KEY_COLUMN_USAGE
227+ $ key_column_usage_table = $ this ->schema_builder ->get_table_name ( false , 'key_column_usage ' );
228+ $ this ->driver ->execute_sqlite_query (
229+ sprintf (
230+ "UPDATE %s SET TABLE_SCHEMA = ?, CONSTRAINT_SCHEMA = ?, REFERENCED_TABLE_SCHEMA = ? WHERE TABLE_SCHEMA != 'information_schema' " ,
231+ $ this ->driver ->get_connection ()->quote_identifier ( $ key_column_usage_table )
232+ ),
233+ array ( $ saved_database_name , $ saved_database_name , $ saved_database_name )
234+ );
235+
236+ // INFORMATION_SCHEMA.CHECK_CONSTRAINTS
237+ $ check_constraints_table = $ this ->schema_builder ->get_table_name ( false , 'check_constraints ' );
238+ $ this ->driver ->execute_sqlite_query (
239+ sprintf (
240+ "UPDATE %s SET CONSTRAINT_SCHEMA = ? WHERE CONSTRAINT_SCHEMA != 'information_schema' " ,
241+ $ this ->driver ->get_connection ()->quote_identifier ( $ check_constraints_table )
242+ ),
243+ array ( $ saved_database_name )
244+ );
245+ }
198246 }
199247
200248 /**
0 commit comments