Skip to content

Commit 5d79372

Browse files
committed
Implement ALTER TABLE ... DROP FOREIGN KEY
1 parent 026a602 commit 5d79372

2 files changed

Lines changed: 197 additions & 0 deletions

File tree

tests/WP_SQLite_Driver_Metadata_Tests.php

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,4 +1567,152 @@ public function testInformationSchemaAlterTableAddForeignKeys(): void {
15671567
$result
15681568
);
15691569
}
1570+
1571+
public function testInformationSchemaAlterTableDropForeignKeys(): void {
1572+
$this->assertQuery( 'CREATE TABLE t1 (id INT PRIMARY KEY, name VARCHAR(255))' );
1573+
$this->assertQuery(
1574+
'CREATE TABLE t2 (
1575+
id INT,
1576+
t1_id INT REFERENCES t1 (id),
1577+
FOREIGN KEY (t1_id) REFERENCES t1 (id),
1578+
CONSTRAINT fk1 FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE
1579+
)'
1580+
);
1581+
1582+
// INFORMATION_SCHEMA.TABLE_CONSTRAINTS
1583+
$result = $this->assertQuery( "SELECT * FROM information_schema.table_constraints WHERE table_name = 't2'" );
1584+
$this->assertCount( 3, $result );
1585+
1586+
// INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
1587+
$result = $this->assertQuery( "SELECT * FROM information_schema.referential_constraints WHERE table_name = 't2'" );
1588+
$this->assertCount( 3, $result );
1589+
1590+
// INFORMATION_SCHEMA.KEY_COLUMN_USAGE
1591+
$result = $this->assertQuery( "SELECT * FROM information_schema.key_column_usage WHERE table_name = 't2'" );
1592+
$this->assertCount( 3, $result );
1593+
1594+
// SHOW CREATE TABLE
1595+
$result = $this->assertQuery( 'SHOW CREATE TABLE t2' );
1596+
$this->assertEquals(
1597+
array(
1598+
(object) array(
1599+
'Create Table' => implode(
1600+
"\n",
1601+
array(
1602+
'CREATE TABLE `t2` (',
1603+
' `id` int DEFAULT NULL,',
1604+
' `t1_id` int DEFAULT NULL,',
1605+
' CONSTRAINT `fk1` FOREIGN KEY (`t1_id`) REFERENCES `t1` (`id`) ON DELETE CASCADE,',
1606+
' CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`t1_id`) REFERENCES `t1` (`id`),',
1607+
' CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`t1_id`) REFERENCES `t1` (`id`)',
1608+
') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci',
1609+
)
1610+
),
1611+
),
1612+
),
1613+
$result
1614+
);
1615+
1616+
// DROP the first foreign key.
1617+
$this->assertQuery( 'ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1' );
1618+
1619+
$result = $this->assertQuery( "SELECT * FROM information_schema.table_constraints WHERE table_name = 't2'" );
1620+
$this->assertCount( 2, $result );
1621+
$this->assertEquals( 't2_ibfk_2', $result[0]->CONSTRAINT_NAME );
1622+
$this->assertEquals( 'fk1', $result[1]->CONSTRAINT_NAME );
1623+
1624+
$result = $this->assertQuery( "SELECT * FROM information_schema.referential_constraints WHERE table_name = 't2'" );
1625+
$this->assertCount( 2, $result );
1626+
$this->assertEquals( 't2_ibfk_2', $result[0]->CONSTRAINT_NAME );
1627+
$this->assertEquals( 'fk1', $result[1]->CONSTRAINT_NAME );
1628+
1629+
$result = $this->assertQuery( "SELECT * FROM information_schema.key_column_usage WHERE table_name = 't2'" );
1630+
$this->assertCount( 2, $result );
1631+
$this->assertEquals( 't2_ibfk_2', $result[0]->CONSTRAINT_NAME );
1632+
$this->assertEquals( 'fk1', $result[1]->CONSTRAINT_NAME );
1633+
1634+
$result = $this->assertQuery( 'SHOW CREATE TABLE t2' );
1635+
$this->assertEquals(
1636+
array(
1637+
(object) array(
1638+
'Create Table' => implode(
1639+
"\n",
1640+
array(
1641+
'CREATE TABLE `t2` (',
1642+
' `id` int DEFAULT NULL,',
1643+
' `t1_id` int DEFAULT NULL,',
1644+
' CONSTRAINT `fk1` FOREIGN KEY (`t1_id`) REFERENCES `t1` (`id`) ON DELETE CASCADE,',
1645+
' CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`t1_id`) REFERENCES `t1` (`id`)',
1646+
') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci',
1647+
)
1648+
),
1649+
),
1650+
),
1651+
$result
1652+
);
1653+
1654+
// DROP the second foreign key.
1655+
$this->assertQuery( 'ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_2' );
1656+
1657+
$result = $this->assertQuery( "SELECT * FROM information_schema.table_constraints WHERE table_name = 't2'" );
1658+
$this->assertCount( 1, $result );
1659+
$this->assertEquals( 'fk1', $result[0]->CONSTRAINT_NAME );
1660+
1661+
$result = $this->assertQuery( "SELECT * FROM information_schema.referential_constraints WHERE table_name = 't2'" );
1662+
$this->assertCount( 1, $result );
1663+
$this->assertEquals( 'fk1', $result[0]->CONSTRAINT_NAME );
1664+
1665+
$result = $this->assertQuery( "SELECT * FROM information_schema.key_column_usage WHERE table_name = 't2'" );
1666+
$this->assertCount( 1, $result );
1667+
$this->assertEquals( 'fk1', $result[0]->CONSTRAINT_NAME );
1668+
1669+
$result = $this->assertQuery( 'SHOW CREATE TABLE t2' );
1670+
$this->assertEquals(
1671+
array(
1672+
(object) array(
1673+
'Create Table' => implode(
1674+
"\n",
1675+
array(
1676+
'CREATE TABLE `t2` (',
1677+
' `id` int DEFAULT NULL,',
1678+
' `t1_id` int DEFAULT NULL,',
1679+
' CONSTRAINT `fk1` FOREIGN KEY (`t1_id`) REFERENCES `t1` (`id`) ON DELETE CASCADE',
1680+
') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci',
1681+
)
1682+
),
1683+
),
1684+
),
1685+
$result
1686+
);
1687+
1688+
// DROP the third foreign key.
1689+
$this->assertQuery( 'ALTER TABLE t2 DROP FOREIGN KEY fk1' );
1690+
1691+
$result = $this->assertQuery( "SELECT * FROM information_schema.table_constraints WHERE table_name = 't2'" );
1692+
$this->assertCount( 0, $result );
1693+
1694+
$result = $this->assertQuery( "SELECT * FROM information_schema.referential_constraints WHERE table_name = 't2'" );
1695+
$this->assertCount( 0, $result );
1696+
1697+
$result = $this->assertQuery( "SELECT * FROM information_schema.key_column_usage WHERE table_name = 't2'" );
1698+
$this->assertCount( 0, $result );
1699+
1700+
$result = $this->assertQuery( 'SHOW CREATE TABLE t2' );
1701+
$this->assertEquals(
1702+
array(
1703+
(object) array(
1704+
'Create Table' => implode(
1705+
"\n",
1706+
array(
1707+
'CREATE TABLE `t2` (',
1708+
' `id` int DEFAULT NULL,',
1709+
' `t1_id` int DEFAULT NULL',
1710+
') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci',
1711+
)
1712+
),
1713+
),
1714+
),
1715+
$result
1716+
);
1717+
}
15701718
}

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,15 @@ public function record_alter_table( WP_Parser_Node $node ): void {
640640

641641
// DROP
642642
if ( WP_MySQL_Lexer::DROP_SYMBOL === $first_token->id ) {
643+
// DROP FOREIGN KEY
644+
if ( $action->has_child_token( WP_MySQL_Lexer::FOREIGN_SYMBOL ) ) {
645+
$field_identifier = $action->get_first_child_node( 'fieldIdentifier' );
646+
$identifiers = $field_identifier->get_descendant_nodes( 'identifier' );
647+
$name = $this->get_value( end( $identifiers ) );
648+
$this->record_drop_foreign_key( $table_is_temporary, $table_name, $name );
649+
continue;
650+
}
651+
643652
// DROP [COLUMN]
644653
$column_ref = $action->get_first_child_node( 'fieldIdentifier' );
645654
if ( null !== $column_ref ) {
@@ -1209,6 +1218,46 @@ private function record_add_constraint(
12091218
}
12101219
}
12111220

1221+
/**
1222+
* Analyze DROP FOREIGN KEY statement and record data in the information schema.
1223+
*
1224+
* @param bool $table_is_temporary Whether the table is temporary.
1225+
* @param string $table_name The table name.
1226+
* @param string $name The foreign key name.
1227+
*/
1228+
private function record_drop_foreign_key(
1229+
bool $table_is_temporary,
1230+
string $table_name,
1231+
string $name
1232+
): void {
1233+
$this->delete_values(
1234+
$this->get_table_name( $table_is_temporary, 'table_constraints' ),
1235+
array(
1236+
'TABLE_SCHEMA' => $this->db_name,
1237+
'TABLE_NAME' => $table_name,
1238+
'CONSTRAINT_NAME' => $name,
1239+
)
1240+
);
1241+
1242+
$this->delete_values(
1243+
$this->get_table_name( $table_is_temporary, 'referential_constraints' ),
1244+
array(
1245+
'CONSTRAINT_SCHEMA' => $this->db_name,
1246+
'TABLE_NAME' => $table_name,
1247+
'CONSTRAINT_NAME' => $name,
1248+
)
1249+
);
1250+
1251+
$this->delete_values(
1252+
$this->get_table_name( $table_is_temporary, 'key_column_usage' ),
1253+
array(
1254+
'TABLE_SCHEMA' => $this->db_name,
1255+
'TABLE_NAME' => $table_name,
1256+
'CONSTRAINT_NAME' => $name,
1257+
)
1258+
);
1259+
}
1260+
12121261
/**
12131262
* Analyze "columnDefinition" or "fieldDefinition" AST node and extract column data.
12141263
*

0 commit comments

Comments
 (0)