Skip to content
This repository was archived by the owner on Jun 2, 2025. It is now read-only.

Commit 03d8ee5

Browse files
committed
Implement implicit index naming
1 parent ad3f600 commit 03d8ee5

File tree

3 files changed

+75
-6
lines changed

3 files changed

+75
-6
lines changed

tests/WP_SQLite_Driver_Tests.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4739,6 +4739,36 @@ public function testIndexNamePrecedesConstraintName(): void {
47394739
);
47404740
}
47414741

4742+
public function testImplicitIndexNames(): void {
4743+
$this->assertQuery(
4744+
'CREATE TABLE t (
4745+
id INT UNIQUE,
4746+
id_2 INT UNIQUE,
4747+
value INT,
4748+
UNIQUE (id),
4749+
UNIQUE (id, value)
4750+
)'
4751+
);
4752+
4753+
$result = $this->assertQuery( 'SHOW INDEX FROM t' );
4754+
$this->assertCount( 5, $result );
4755+
4756+
$this->assertSame( 'id', $result[0]->Key_name );
4757+
$this->assertSame( 'id', $result[0]->Column_name );
4758+
4759+
$this->assertSame( 'id_2', $result[1]->Key_name );
4760+
$this->assertSame( 'id_2', $result[1]->Column_name );
4761+
4762+
$this->assertSame( 'id_3', $result[2]->Key_name );
4763+
$this->assertSame( 'id', $result[2]->Column_name );
4764+
4765+
$this->assertSame( 'id_4', $result[3]->Key_name );
4766+
$this->assertSame( 'id', $result[3]->Column_name );
4767+
4768+
$this->assertSame( 'id_4', $result[4]->Key_name );
4769+
$this->assertSame( 'value', $result[4]->Column_name );
4770+
}
4771+
47424772
public function testValidDuplicateConstraintNames(): void {
47434773
$this->assertQuery(
47444774
'CREATE TABLE t (

tests/WP_SQLite_Driver_Translation_Tests.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,14 @@ public function testCreateTableWithStandaloneUniqueIndexes(): void {
457457
'INSERT INTO `_wp_sqlite_mysql_information_schema_columns` (`table_schema`, `table_name`, `column_name`, `ordinal_position`, `column_default`, `is_nullable`, `data_type`, `character_maximum_length`, `character_octet_length`, `numeric_precision`, `numeric_scale`, `datetime_precision`, `character_set_name`, `collation_name`, `column_type`, `column_key`, `extra`, `privileges`, `column_comment`, `generation_expression`, `srs_id`)'
458458
. " VALUES ('wp', 't', 'name', 2, null, 'YES', 'varchar', 100, 400, null, null, null, 'utf8mb4', 'utf8mb4_general_ci', 'varchar(100)', '', '', 'select,insert,update,references', '', '', null)",
459459
"SELECT column_name, data_type, is_nullable, character_maximum_length FROM `_wp_sqlite_mysql_information_schema_columns` WHERE table_schema = 'wp' AND table_name = 't' AND column_name IN ('id')",
460+
"SELECT DISTINCT index_name FROM `_wp_sqlite_mysql_information_schema_statistics` WHERE table_schema = 'wp' AND table_name = 't' AND (index_name = 'id' OR index_name LIKE 'id\_%' ESCAPE '\\')",
460461
'INSERT INTO `_wp_sqlite_mysql_information_schema_statistics` (`table_schema`, `table_name`, `non_unique`, `index_schema`, `index_name`, `seq_in_index`, `column_name`, `collation`, `cardinality`, `sub_part`, `packed`, `nullable`, `index_type`, `comment`, `index_comment`, `is_visible`, `expression`)'
461462
. " VALUES ('wp', 't', 0, 'wp', 'id', 1, 'id', 'A', 0, null, null, 'YES', 'BTREE', '', '', 'YES', null)",
462463
'INSERT INTO `_wp_sqlite_mysql_information_schema_table_constraints` (`table_schema`, `table_name`, `constraint_schema`, `constraint_name`, `constraint_type`)'
463464
. " VALUES ('wp', 't', 'wp', 'id', 'UNIQUE')",
464465
"UPDATE `_wp_sqlite_mysql_information_schema_columns` AS c SET (column_key, is_nullable) = ( SELECT CASE WHEN MAX(s.index_name = 'PRIMARY') THEN 'PRI' WHEN MAX(s.non_unique = 0 AND s.seq_in_index = 1) THEN 'UNI' WHEN MAX(s.seq_in_index = 1) THEN 'MUL' ELSE '' END, CASE WHEN MAX(s.index_name = 'PRIMARY') THEN 'NO' ELSE c.is_nullable END FROM `_wp_sqlite_mysql_information_schema_statistics` AS s WHERE s.table_schema = c.table_schema AND s.table_name = c.table_name AND s.column_name = c.column_name ) WHERE c.table_schema = 'wp' AND c.table_name = 't'",
465466
"SELECT column_name, data_type, is_nullable, character_maximum_length FROM `_wp_sqlite_mysql_information_schema_columns` WHERE table_schema = 'wp' AND table_name = 't' AND column_name IN ('name')",
467+
"SELECT DISTINCT index_name FROM `_wp_sqlite_mysql_information_schema_statistics` WHERE table_schema = 'wp' AND table_name = 't' AND (index_name = 'name' OR index_name LIKE 'name\_%' ESCAPE '\\')",
466468
'INSERT INTO `_wp_sqlite_mysql_information_schema_statistics` (`table_schema`, `table_name`, `non_unique`, `index_schema`, `index_name`, `seq_in_index`, `column_name`, `collation`, `cardinality`, `sub_part`, `packed`, `nullable`, `index_type`, `comment`, `index_comment`, `is_visible`, `expression`)'
467469
. " VALUES ('wp', 't', 0, 'wp', 'name', 1, 'name', 'A', 0, null, null, 'YES', 'BTREE', '', '', 'YES', null)",
468470
'INSERT INTO `_wp_sqlite_mysql_information_schema_table_constraints` (`table_schema`, `table_name`, `constraint_schema`, `constraint_name`, `constraint_type`)'

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

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ private function record_add_constraint(
10341034
$has_spatial_column = null !== $first_column_type && $this->is_spatial_data_type( $first_column_type );
10351035

10361036
$non_unique = $this->get_index_non_unique( $keyword );
1037-
$index_name = $this->get_index_name( $node );
1037+
$index_name = $this->get_index_name( $node, $table_name );
10381038
$index_type = $this->get_index_type( $node, $keyword, $has_spatial_column );
10391039
$index_comment = $this->get_index_comment( $node );
10401040
$seq_in_index = 1;
@@ -1899,10 +1899,11 @@ private function get_table_constraint_type( WP_Parser_Node $node ): ?string {
18991899
/**
19001900
* Extract index name from the "tableConstraintDef" AST node.
19011901
*
1902-
* @param WP_Parser_Node $node The "tableConstraintDef" AST node.
1903-
* @return string The index name as stored in information schema.
1902+
* @param WP_Parser_Node $node The "tableConstraintDef" AST node.
1903+
* @param string $table_name The table name.
1904+
* @return string The index name as stored in information schema.
19041905
*/
1905-
private function get_index_name( WP_Parser_Node $node ): string {
1906+
private function get_index_name( WP_Parser_Node $node, string $table_name ): string {
19061907
if ( $node->get_first_descendant_token( WP_MySQL_Lexer::PRIMARY_SYMBOL ) ) {
19071908
return 'PRIMARY';
19081909
}
@@ -1933,8 +1934,44 @@ private function get_index_name( WP_Parser_Node $node ): string {
19331934
$name = $this->get_value( $subnode->get_first_descendant_node( 'identifier' ) );
19341935
}
19351936

1936-
// @TODO: Check if the name is already used.
1937-
return $name;
1937+
// Check if the name is already used.
1938+
$existing_indices = $this->connection->query(
1939+
sprintf(
1940+
"SELECT DISTINCT index_name
1941+
FROM %s
1942+
WHERE table_schema = ?
1943+
AND table_name = ?
1944+
AND (index_name = ? OR index_name LIKE ? ESCAPE '\\')",
1945+
$this->connection->quote_identifier(
1946+
$this->get_table_name(
1947+
$this->temporary_table_exists( $table_name ),
1948+
'statistics'
1949+
)
1950+
)
1951+
),
1952+
array(
1953+
$this->db_name,
1954+
$table_name,
1955+
$name,
1956+
str_replace( array( '_', '%' ), array( '\\_', '\\%' ), $name ) . '\\_%',
1957+
)
1958+
)->fetchAll(
1959+
PDO::FETCH_COLUMN // phpcs:ignore WordPress.DB.RestrictedClasses.mysql__PDO
1960+
);
1961+
1962+
// The name is not used - we can use it as-is.
1963+
if ( count( $existing_indices ) === 0 ) {
1964+
return $name;
1965+
}
1966+
1967+
// The name is used - find the first unused name.
1968+
$new_name = $name;
1969+
$suffix = 2;
1970+
while ( in_array( $new_name, $existing_indices, true ) ) {
1971+
$new_name = $name . '_' . $suffix;
1972+
$suffix += 1;
1973+
}
1974+
return $new_name;
19381975
}
19391976
return $this->get_value( $name_node );
19401977
}

0 commit comments

Comments
 (0)