Skip to content

Commit e808211

Browse files
committed
Add support for INFORMATION_SCHEMA.SCHEMATA table
This also moves database name handling from a global variable to the INFORMATION_SCHEMA.SCHEMATA table.
1 parent abc48ff commit e808211

File tree

3 files changed

+54
-22
lines changed

3 files changed

+54
-22
lines changed

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

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public function configure_database(): void {
105105
$this->schema_builder->ensure_information_schema_tables();
106106
$this->schema_reconstructor->ensure_correct_information_schema();
107107
$this->save_current_driver_version();
108-
$this->save_current_database_name();
108+
$this->ensure_schemata_data();
109109
} catch ( Throwable $e ) {
110110
$this->driver->execute_sqlite_query( 'ROLLBACK' );
111111
throw $e;
@@ -131,15 +131,43 @@ private function ensure_global_variables_table(): void {
131131
}
132132

133133
/**
134-
* Save the current database name.
134+
* Ensure that the "SCHEMATA" table data is correctly populated.
135135
*
136-
* This method saves the current database name to the database.
136+
* This method ensures that the "INFORMATION_SCHEMA.SCHEMATA" table contains
137+
* records for both the "INFORMATION_SCHEMA" database and the user database.
138+
* At the moment, only a single user database is supported.
137139
*/
138-
public function save_current_database_name(): void {
140+
public function ensure_schemata_data(): void {
141+
$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+
array( 'information_schema', 'utf8mb3', 'utf8mb3_general_ci' )
151+
);
152+
153+
// 2. Check if a user database record exists.
154+
$user_db_record_exists = $this->driver->execute_sqlite_query(
155+
sprintf(
156+
"SELECT COUNT(*) FROM %s WHERE SCHEMA_NAME != 'information_schema'",
157+
$this->driver->get_connection()->quote_identifier( $schemata_table )
158+
),
159+
)->fetchColumn() > 0;
160+
161+
if ( $user_db_record_exists ) {
162+
return;
163+
}
164+
139165
/*
166+
* 3. Migrate from older driver versions without the "SCHEMATA" table.
167+
*
140168
* If a record with an existing database name value is already stored in
141-
* the information schema, we need to use that value. This ensures correct
142-
* migration from older driver versions without the database name variable.
169+
* "INFORMATION_SCHEMA.TABLES", we need to use that value. This ensures
170+
* migration from older driver versions without the "SCHEMATA" table.
143171
*/
144172
$information_schema_db_name = $this->driver->execute_sqlite_query(
145173
sprintf(
@@ -156,14 +184,13 @@ public function save_current_database_name(): void {
156184
$db_name = $this->db_name;
157185
}
158186

187+
// 4. Create a user database record.
159188
$this->driver->execute_sqlite_query(
160189
sprintf(
161-
'INSERT INTO %s (name, value) VALUES (?, ?) ON CONFLICT(name) DO UPDATE SET value = ?',
162-
$this->driver->get_connection()->quote_identifier(
163-
WP_SQLite_Driver::GLOBAL_VARIABLES_TABLE_NAME
164-
)
190+
'INSERT INTO %s (SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME) VALUES (?, ?, ?)',
191+
$this->driver->get_connection()->quote_identifier( $schemata_table )
165192
),
166-
array( WP_SQLite_Driver::DATABASE_NAME_VARIABLE_NAME, $db_name )
193+
array( $db_name, 'utf8mb4', 'utf8mb4_0900_ai_ci' )
167194
);
168195
}
169196

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

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,6 @@ class WP_SQLite_Driver {
5151
*/
5252
const DRIVER_VERSION_VARIABLE_NAME = self::RESERVED_PREFIX . 'driver_version';
5353

54-
/**
55-
* The name of the SQLite database name variable.
56-
*
57-
* This internal variable is used to store the name of the SQLite database.
58-
*/
59-
const DATABASE_NAME_VARIABLE_NAME = self::RESERVED_PREFIX . 'database_name';
60-
6154
/**
6255
* A map of MySQL tokens to SQLite data types.
6356
*
@@ -556,12 +549,12 @@ public function get_saved_driver_version(): string {
556549
*/
557550
public function get_saved_database_name(): string {
558551
try {
552+
$schemata_table = $this->information_schema_builder->get_table_name( false, 'schemata' );
559553
return $this->execute_sqlite_query(
560554
sprintf(
561-
'SELECT value FROM %s WHERE name = ?',
562-
$this->quote_sqlite_identifier( self::GLOBAL_VARIABLES_TABLE_NAME )
563-
),
564-
array( self::DATABASE_NAME_VARIABLE_NAME )
555+
'SELECT SCHEMA_NAME FROM %s WHERE SCHEMA_NAME != "information_schema" LIMIT 1',
556+
$this->quote_sqlite_identifier( $schemata_table )
557+
)
565558
)->fetchColumn() ?? '';
566559
} catch ( PDOException $e ) {
567560
if ( str_contains( $e->getMessage(), 'no such table' ) ) {

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class WP_SQLite_Information_Schema_Builder {
1717
* We only implement a limited subset that is necessary for a database schema
1818
* introspection and representation, currently covering the following tables:
1919
*
20+
* - SCHEMATA
2021
* - TABLES
2122
* - COLUMNS
2223
* - STATISTICS (indexes)
@@ -30,6 +31,17 @@ class WP_SQLite_Information_Schema_Builder {
3031
* - TRIGGERS
3132
*/
3233
const INFORMATION_SCHEMA_TABLE_DEFINITIONS = array(
34+
// INFORMATION_SCHEMA.SCHEMATA
35+
'schemata' => "
36+
CATALOG_NAME TEXT NOT NULL DEFAULT 'def' COLLATE NOCASE, -- always 'def'
37+
SCHEMA_NAME TEXT NOT NULL COLLATE NOCASE, -- database name
38+
DEFAULT_CHARACTER_SET_NAME TEXT NOT NULL COLLATE NOCASE, -- default character set
39+
DEFAULT_COLLATION_NAME TEXT NOT NULL COLLATE NOCASE, -- default collation
40+
SQL_PATH TEXT NULL COLLATE NOCASE, -- always NULL
41+
DEFAULT_ENCRYPTION TEXT NOT NULL DEFAULT 'NO' COLLATE NOCASE, -- not implemented
42+
PRIMARY KEY (SCHEMA_NAME)
43+
",
44+
3345
// INFORMATION_SCHEMA.TABLES
3446
'tables' => "
3547
TABLE_CATALOG TEXT NOT NULL DEFAULT 'def' COLLATE NOCASE, -- always 'def'

0 commit comments

Comments
 (0)