Skip to content

Commit d21076b

Browse files
Fix SQLiteAdapter when changing primary key (#954)
* Fix SQLiteAdapter when changing primary key * Update src/Db/Adapter/SqliteAdapter.php * Simplify --------- Co-authored-by: Mark Story <[email protected]>
1 parent 6d2569a commit d21076b

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

src/Db/Adapter/SqliteAdapter.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,13 +1343,16 @@ protected function getAddPrimaryKeyInstructions(TableMetadata $table, string $co
13431343
$instructions->addPostStep(function ($state) use ($column) {
13441344
$quotedColumn = preg_quote($column);
13451345
$columnPattern = "`{$quotedColumn}`|\"{$quotedColumn}\"|\[{$quotedColumn}\]";
1346-
$matchPattern = "/($columnPattern)\s+(\w+(\(\d+\))?)(\s+(NOT )?NULL)?/";
1346+
$matchPattern = "/($columnPattern)\s+(\w+(\(\d+\))?)(\s+(NOT )?NULL)?(\s+(?:PRIMARY KEY\s+)?AUTOINCREMENT)?/i";
13471347

13481348
$sql = $state['createSQL'];
13491349

13501350
if (preg_match($matchPattern, $state['createSQL'], $matches)) {
13511351
if (isset($matches[2])) {
1352-
if ($matches[2] === 'INTEGER') {
1352+
$hasAutoIncrement = isset($matches[6]) && stripos($matches[6], 'AUTOINCREMENT') !== false;
1353+
1354+
if ($matches[2] === 'INTEGER' && $hasAutoIncrement) {
1355+
// Only add AUTOINCREMENT if the column already had it
13531356
$replace = '$1 INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT';
13541357
} else {
13551358
$replace = '$1 $2 NOT NULL PRIMARY KEY';

tests/TestCase/Db/Adapter/SqliteAdapterTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,51 @@ public function testChangePrimaryKeyNonInteger()
428428
$this->assertTrue($this->adapter->hasPrimaryKey('table1', ['column2']));
429429
}
430430

431+
public function testChangePrimaryKeyWithoutAutoIncrement()
432+
{
433+
// Create table with id_1 as PK without AUTOINCREMENT keyword
434+
$this->adapter->execute('CREATE TABLE table1 (id_1 INTEGER NOT NULL PRIMARY KEY, id_2 INTEGER NOT NULL)');
435+
436+
// Verify initial SQL does not have AUTOINCREMENT
437+
$result = $this->adapter->fetchRow("SELECT sql FROM sqlite_master WHERE type='table' AND name='table1'");
438+
$this->assertStringNotContainsString('AUTOINCREMENT', $result['sql']);
439+
440+
// Change primary key to id_2
441+
$table = new Table('table1', [], $this->adapter);
442+
$table->changePrimaryKey('id_2')->save();
443+
444+
// Verify primary key changed
445+
$this->assertFalse($this->adapter->hasPrimaryKey('table1', ['id_1']));
446+
$this->assertTrue($this->adapter->hasPrimaryKey('table1', ['id_2']));
447+
448+
// Verify the SQL does NOT have AUTOINCREMENT added to id_2
449+
$result = $this->adapter->fetchRow("SELECT sql FROM sqlite_master WHERE type='table' AND name='table1'");
450+
$this->assertStringNotContainsString('AUTOINCREMENT', $result['sql'], 'AUTOINCREMENT should not be added when changing PK to a column that did not have it');
451+
}
452+
453+
public function testChangePrimaryKeyFromAutoIncrementColumn()
454+
{
455+
// Create table with id_1 as PK with AUTOINCREMENT
456+
$this->adapter->execute('CREATE TABLE table1 (id_1 INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id_2 INTEGER NOT NULL)');
457+
458+
// Verify initial SQL has AUTOINCREMENT
459+
$result = $this->adapter->fetchRow("SELECT sql FROM sqlite_master WHERE type='table' AND name='table1'");
460+
$this->assertStringContainsString('AUTOINCREMENT', $result['sql']);
461+
462+
// Change primary key to id_2 (should NOT get AUTOINCREMENT since id_2 doesn't have it)
463+
$table = new Table('table1', [], $this->adapter);
464+
$table->changePrimaryKey('id_2')->save();
465+
466+
// Verify primary key changed
467+
$this->assertFalse($this->adapter->hasPrimaryKey('table1', ['id_1']));
468+
$this->assertTrue($this->adapter->hasPrimaryKey('table1', ['id_2']));
469+
470+
// Verify the SQL does NOT have AUTOINCREMENT on id_2
471+
// (id_1 lost its AUTOINCREMENT when PK was dropped, and id_2 never had it)
472+
$result = $this->adapter->fetchRow("SELECT sql FROM sqlite_master WHERE type='table' AND name='table1'");
473+
$this->assertStringNotContainsString('AUTOINCREMENT', $result['sql'], 'AUTOINCREMENT should not be added when changing PK to a column that never had it');
474+
}
475+
431476
public function testDropPrimaryKey()
432477
{
433478
$table = new Table('table1', ['id' => false, 'primary_key' => 'column1'], $this->adapter);

0 commit comments

Comments
 (0)