Skip to content

Commit c6074c6

Browse files
committed
Allow AUTOINCREMENT with compound PRIMARY KEY
1 parent d9cb007 commit c6074c6

File tree

2 files changed

+81
-10
lines changed

2 files changed

+81
-10
lines changed

tests/WP_SQLite_Driver_Tests.php

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4125,11 +4125,62 @@ public function testTimestampColumnNamedTimestamp() {
41254125
);
41264126
}
41274127

4128-
public function testCompoundPrimaryKeyAndAutoincrementNotSupported(): void {
4129-
$this->expectException( WP_SQLite_Driver_Exception::class );
4130-
$this->expectExceptionMessage( 'Cannot combine AUTOINCREMENT and multiple primary keys in SQLite' );
4128+
public function testCompoundPrimaryKeyWithAutoincrement(): void {
41314129
$this->assertQuery(
4132-
'CREATE TABLE t1 (id1 INT AUTO_INCREMENT, id2 INT, PRIMARY KEY(id1, id2))'
4130+
'CREATE TABLE t1 (id INT AUTO_INCREMENT, name VARCHAR(32), PRIMARY KEY(id, name))'
4131+
);
4132+
4133+
// Ensure auto-increment is working.
4134+
$this->assertQuery( "INSERT INTO t1 (name) VALUES ('A'), ('B'), ('C')" );
4135+
$results = $this->assertQuery( 'SELECT * FROM t1' );
4136+
$this->assertEquals(
4137+
array(
4138+
(object) array(
4139+
'id' => 1,
4140+
'name' => 'A',
4141+
),
4142+
(object) array(
4143+
'id' => 2,
4144+
'name' => 'B',
4145+
),
4146+
(object) array(
4147+
'id' => 3,
4148+
'name' => 'C',
4149+
),
4150+
),
4151+
$results
4152+
);
4153+
4154+
// Verify the table schema.
4155+
$results = $this->assertQuery( 'SHOW CREATE TABLE t1' );
4156+
$this->assertEquals(
4157+
implode(
4158+
"\n",
4159+
array(
4160+
'CREATE TABLE `t1` (',
4161+
' `id` int NOT NULL AUTO_INCREMENT,',
4162+
' `name` varchar(32) NOT NULL,',
4163+
' PRIMARY KEY (`id`, `name`)',
4164+
') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci',
4165+
)
4166+
),
4167+
$results[0]->{'Create Table'}
4168+
);
4169+
4170+
// Ensure an SQLite index was created for the compound key columns.
4171+
$result = $this->engine
4172+
->execute_sqlite_query( "SELECT * FROM pragma_index_list('t1')" )
4173+
->fetchAll( PDO::FETCH_ASSOC );
4174+
$this->assertCount( 1, $result );
4175+
$this->assertEquals(
4176+
array(
4177+
'seq' => '0',
4178+
'name' => '_wp_sqlite_t1__primary',
4179+
'unique' => '1',
4180+
'origin' => 'c',
4181+
'partial' => '0',
4182+
),
4183+
$result[0]
41334184
);
41344185
}
41354186

wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5618,13 +5618,33 @@ function ( $column ) {
56185618

56195619
if ( 'PRIMARY' === $info['INDEX_NAME'] ) {
56205620
if ( $has_autoincrement ) {
5621-
if ( $has_autoincrement ) {
5622-
if ( count( $constraint ) > 1 ) {
5623-
throw $this->new_driver_exception(
5624-
'Cannot combine AUTOINCREMENT and multiple primary keys in SQLite'
5625-
);
5626-
}
5621+
/*
5622+
* In MySQL, a compound PRIMARY KEY can have an AUTOINCREMENT
5623+
* column, when it is the first column in the key.
5624+
*
5625+
* SQLite doesn't support this, but we can emulate it as follows:
5626+
* 1. Keep only the first column as a PRIMARY KEY.
5627+
* Since this is the column that also has AUTOINCREMENT,
5628+
* it reasonable to assume that its values are unique.
5629+
* 2. Create a UNIQUE key for all the PRIMARY KEY columns.
5630+
* This is to preserve the index of the compound key.
5631+
*/
5632+
if ( count( $constraint ) > 1 ) {
5633+
$sqlite_index_name = $this->get_sqlite_index_name( $table_name, 'primary' );
5634+
$create_index_queries[] = sprintf(
5635+
'CREATE UNIQUE INDEX %s ON %s (%s)',
5636+
self::RESERVED_PREFIX . $sqlite_index_name,
5637+
$this->quote_sqlite_identifier( $table_name ),
5638+
implode( ', ', $column_list )
5639+
);
56275640
}
5641+
5642+
/*
5643+
* The PRIMARY KEY was already generated with AUTOINCREMENT,
5644+
* as required by SQLite column constraint syntax.
5645+
*
5646+
* @see https://www.sqlite.org/syntax/column-constraint.html
5647+
*/
56285648
continue;
56295649
}
56305650
$rows[] = sprintf( ' PRIMARY KEY (%s)', implode( ', ', $column_list ) );

0 commit comments

Comments
 (0)