Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php
Original file line number Diff line number Diff line change
Expand Up @@ -2301,7 +2301,10 @@ private function execute_transaction_or_locking_statement( WP_Parser_Node $node
* can handle persistent and temporary tables in one query.
*/
$this->execute_sqlite_query(
sprintf( 'SELECT 1 FROM %s LIMIT 0', $table_name )
sprintf(
'SELECT 1 FROM %s LIMIT 0',
$this->quote_sqlite_identifier( $table_name )
)
);
} catch ( PDOException $e ) {
throw $this->new_table_not_found_exception(
Expand Down Expand Up @@ -3722,19 +3725,20 @@ private function execute_show_tables_statement( WP_Parser_Node $node ): void {
$is_full = $command_type && $command_type->has_child_token( WP_MySQL_Lexer::FULL_SYMBOL );

// Fetch table information.
$table_tables = $this->information_schema_builder->get_table_name(
$table_tables = $this->information_schema_builder->get_table_name(
false, // SHOW TABLES lists only non-temporary tables.
'tables'
);
$query = sprintf(
$tables_column_alias = $this->quote_sqlite_identifier( 'Tables_in_' . $database );
$query = sprintf(
'SELECT %s FROM %s WHERE table_schema = ? %s ORDER BY table_name',
$is_full
? sprintf( 'table_name AS `Tables_in_%s`, table_type AS `Table_type`', $database )
: sprintf( 'table_name AS `Tables_in_%s`', $database ),
? sprintf( 'table_name AS %s, table_type AS `Table_type`', $tables_column_alias )
: sprintf( 'table_name AS %s', $tables_column_alias ),
$this->quote_sqlite_identifier( $table_tables ),
$condition ?? ''
);
$params = array(
$params = array(
$this->get_saved_db_name( $database ),
);

Expand Down Expand Up @@ -7451,7 +7455,7 @@ function ( $column ) {
$sqlite_index_name = $this->get_sqlite_index_name( $table_name, 'primary' );
$create_index_queries[] = sprintf(
'CREATE UNIQUE INDEX %s ON %s (%s)',
self::RESERVED_PREFIX . $sqlite_index_name,
$this->quote_sqlite_identifier( self::RESERVED_PREFIX . $sqlite_index_name ),
$this->quote_sqlite_identifier( $table_name ),
implode( ', ', $column_list )
);
Expand Down
98 changes: 98 additions & 0 deletions packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,44 @@ public function testShowTablesLike() {
);
}

public function testShowTablesWithQuotedDatabaseIdentifier(): void {
$pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class;
$this->sqlite = new $pdo_class( 'sqlite::memory:' );
$this->engine = new WP_MySQL_On_SQLite(
'mysql-on-sqlite:dbname=db`name',
null,
null,
array( 'sqlite_pdo' => $this->sqlite )
);
$this->engine->setAttribute( PDO::ATTR_STRINGIFY_FETCHES, true );

$this->assertQuery( 'CREATE TABLE `table name` (id INT)' );

$result = $this->assertQuery( 'SHOW TABLES' );
$this->assertSame( 'Tables_in_db`name', $this->last_statement->getColumnMeta( 0 )['name'] );
$this->assertEquals(
array(
(object) array(
'Tables_in_db`name' => 'table name',
),
),
$result
);

$result = $this->assertQuery( 'SHOW FULL TABLES FROM `db``name`' );
$this->assertSame( 'Tables_in_db`name', $this->last_statement->getColumnMeta( 0 )['name'] );
$this->assertSame( 'Table_type', $this->last_statement->getColumnMeta( 1 )['name'] );
$this->assertEquals(
array(
(object) array(
'Tables_in_db`name' => 'table name',
'Table_type' => 'BASE TABLE',
),
),
$result
);
}

public function testShowTableStatusFrom() {
// Created in setUp() function
$this->assertQuery( 'DROP TABLE _options' );
Expand Down Expand Up @@ -8161,6 +8199,44 @@ public function testCompoundPrimaryKeyWithAutoincrement(): void {
);
}

public function testCompoundPrimaryKeyWithAutoincrementAndQuotedIdentifiers(): void {
$this->assertQuery(
'CREATE TABLE `table ``name` (`id ``col` INT AUTO_INCREMENT, `name ``col` VARCHAR(32), PRIMARY KEY(`id ``col`, `name ``col`))'
);

$this->assertQuery( "INSERT INTO `table ``name` (`name ``col`) VALUES ('A'), ('B')" );

// Rebuilding the table via ALTER TABLE must also quote the generated index identifier.
$this->assertQuery( 'ALTER TABLE `table ``name` ADD COLUMN extra INT DEFAULT 0' );
$this->assertQuery( "INSERT INTO `table ``name` (`name ``col`) VALUES ('C')" );

$results = $this->assertQuery( 'SELECT `id ``col`, `name ``col` FROM `table ``name` ORDER BY `id ``col`' );
$this->assertEquals(
array(
(object) array(
'id `col' => '1',
'name `col' => 'A',
),
(object) array(
'id `col' => '2',
'name `col' => 'B',
),
(object) array(
'id `col' => '3',
'name `col' => 'C',
),
),
$results
);

$result = $this->engine
->execute_sqlite_query( "SELECT * FROM pragma_index_list('table `name')" )
->fetchAll( PDO::FETCH_ASSOC );
$this->assertCount( 1, $result );
$this->assertSame( '_wp_sqlite_table `name__primary', $result[0]['name'] );
$this->assertSame( '1', (string) $result[0]['unique'] );
}

/**
* @dataProvider getReservedPrefixTestData
*/
Expand Down Expand Up @@ -10546,6 +10622,28 @@ public function testLockTemporaryTables(): void {
$this->assertQuery( 'UNLOCK TABLES' );
}

public function testLockTablesWithQuotedIdentifiers(): void {
$this->assertQuery( 'CREATE TABLE `table name` (id INT)' );
$this->assertQuery( 'CREATE TABLE `select` (id INT)' );
$this->assertQuery( 'CREATE TEMPORARY TABLE `temp``table` (id INT)' );

$this->assertQuery( 'LOCK TABLES `table name` READ, `select` WRITE, `temp``table` WRITE' );
$this->assertQuery( 'UNLOCK TABLES' );

$this->expectException( 'WP_MySQL_On_SQLite_Exception' );
$this->expectExceptionMessage( "Table 'wp.missing table' doesn't exist" );
$this->assertQuery( 'LOCK TABLES `missing table` READ' );
}

public function testLockTableWithDotInName(): void {
// "main.t" is a table name, not table "t" in the SQLite "main" schema.
$this->assertQuery( 'CREATE TABLE t (id INT)' );

$this->expectException( 'WP_MySQL_On_SQLite_Exception' );
$this->expectExceptionMessage( "Table 'wp.main.t' doesn't exist" );
$this->assertQuery( 'LOCK TABLES `main.t` READ' );
}

public function testTransactionSavepoints(): void {
$this->assertQuery( 'CREATE TABLE t (id INT)' );

Expand Down
Loading