Skip to content

Commit 2ceb315

Browse files
authored
Fix length of index names for a create table statement (#133)
Fixes: #124 This PR introduces some changes to how we determine the name of an index. SQLite requires that each index is uniquely named across the database (not just the table). This causes issues when multiple tables have the same key names when importing from MySQL. To avoid these issues, the index name is prefixed with the table name when it is created. This however results in the indexes having names that are too long for MySQL so when we run `show create table` the create statements have these prefixed keys that are too long. To solve this, we keep adding the table name as a prefix but we remove it when we generate the create statement. Furthermore, we ensure that the table name itself has no double underscores in it so we can be sure that we can split on `__` safely. The result is that each create table statement will have the original index name and prevents it from being too long.
1 parent 3dfb82e commit 2ceb315

2 files changed

Lines changed: 47 additions & 9 deletions

File tree

tests/WP_SQLite_Translator_Tests.php

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,8 @@ public function testShowCreateTable1() {
283283
`option_name` varchar(255) DEFAULT '',
284284
`option_value` text NOT NULL DEFAULT '',
285285
PRIMARY KEY (`ID`),
286-
KEY `_tmp_table__composite` (`option_name`, `option_value`),
287-
UNIQUE KEY `_tmp_table__option_name` (`option_name`)
286+
KEY `composite` (`option_name`, `option_value`),
287+
UNIQUE KEY `option_name` (`option_name`)
288288
);",
289289
$results[0]->{'Create Table'}
290290
);
@@ -312,8 +312,8 @@ public function testShowCreateTableQuoted() {
312312
`option_name` varchar(255) DEFAULT '',
313313
`option_value` text NOT NULL DEFAULT '',
314314
PRIMARY KEY (`ID`),
315-
KEY `_tmp_table__composite` (`option_name`, `option_value`),
316-
UNIQUE KEY `_tmp_table__option_name` (`option_name`)
315+
KEY `composite` (`option_name`, `option_value`),
316+
UNIQUE KEY `option_name` (`option_name`)
317317
);",
318318
$results[0]->{'Create Table'}
319319
);
@@ -365,12 +365,32 @@ public function testShowCreateTableWithAlterAndCreateIndex() {
365365
`option_name` smallint NOT NULL DEFAULT 14,
366366
`option_value` text NOT NULL DEFAULT \'\',
367367
PRIMARY KEY (`ID`),
368-
KEY `_tmp_table__option_name` (`option_name`)
368+
KEY `option_name` (`option_name`)
369369
);',
370370
$results[0]->{'Create Table'}
371371
);
372372
}
373373

374+
public function testCreateTablseWithIdenticalIndexNames() {
375+
$this->assertQuery(
376+
"CREATE TABLE _tmp_table_a (
377+
ID BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL,
378+
option_name VARCHAR(255) default '',
379+
option_value TEXT NOT NULL,
380+
KEY `option_name` (`option_name`)
381+
);"
382+
);
383+
384+
$this->assertQuery(
385+
"CREATE TABLE _tmp_table_b (
386+
ID BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL,
387+
option_name VARCHAR(255) default '',
388+
option_value TEXT NOT NULL,
389+
KEY `option_name` (`option_name`)
390+
);"
391+
);
392+
}
393+
374394
public function testShowCreateTableWithPrimaryKeyColumnsReverseOrdered() {
375395
$this->assertQuery(
376396
'CREATE TABLE `_tmp_table` (

wp-includes/sqlite/class-wp-sqlite-translator.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,8 +900,7 @@ private function execute_create_table() {
900900
if ( 'UNIQUE INDEX' === $index_type ) {
901901
$unique = 'UNIQUE ';
902902
}
903-
$index_name = "{$table->name}__{$constraint->name}";
904-
903+
$index_name = $this->generate_index_name( $table->name, $constraint->name );
905904
$this->execute_sqlite_query(
906905
"CREATE $unique INDEX \"$index_name\" ON \"{$table->name}\" (\"" . implode( '", "', $constraint->columns ) . '")'
907906
);
@@ -3086,7 +3085,7 @@ private function execute_alter() {
30863085
} elseif ( 'ADD' === $op_type && $is_index_op ) {
30873086
$key_name = $this->rewriter->consume()->value;
30883087
$sqlite_index_type = $this->mysql_index_type_to_sqlite_type( $mysql_index_type );
3089-
$sqlite_index_name = "{$this->table_name}__$key_name";
3088+
$sqlite_index_name = $this->generate_index_name( $this->table_name, $key_name );
30903089
$this->rewriter->replace_all(
30913090
array(
30923091
new WP_SQLite_Token( 'CREATE', WP_SQLite_Token::TYPE_KEYWORD, WP_SQLite_Token::FLAG_KEYWORD_RESERVED ),
@@ -3570,7 +3569,12 @@ private function get_key_definitions( $table_name, $columns ) {
35703569

35713570
$key_definition[] = 'KEY';
35723571

3573-
$key_definition[] = sprintf( '`%s`', $key['index']['name'] );
3572+
// Remove the prefix from the index name if there is any. We use __ as a separator.
3573+
$index_name = strstr( $key['index']['name'], '__' )
3574+
? explode( '__', $key['index']['name'] )[1]
3575+
: $key['index']['name'];
3576+
3577+
$key_definition[] = sprintf( '`%s`', $index_name );
35743578

35753579
$cols = array_map(
35763580
function ( $column ) {
@@ -4199,4 +4203,18 @@ public function rollback() {
41994203
}
42004204
return $this->last_exec_returned;
42014205
}
4206+
4207+
/**
4208+
* Create an index name consisting of table name and original index name.
4209+
* This is to avoid duplicate index names in SQLite.
4210+
*
4211+
* @param $table
4212+
* @param $original_index_name
4213+
*
4214+
* @return string
4215+
*/
4216+
private function generate_index_name( $table, $original_index_name ) {
4217+
// Strip the occurrences of 2 or more consecutive underscores to allow easier splitting on __ later.
4218+
return preg_replace( '/_{2,}/', '_', $table ) . '__' . $original_index_name;
4219+
}
42024220
}

0 commit comments

Comments
 (0)