@@ -222,24 +222,80 @@ protected function getTablesToDrop(Connection $connection): array
222222 protected function dropTables (Connection $ connection , array $ tables , ConsoleIo $ io ): void
223223 {
224224 $ driver = $ connection ->getDriver ();
225+ $ driverClass = get_class ($ driver );
225226
226- // Disable foreign key checks temporarily
227- $ this ->setForeignKeyChecks ($ connection , false );
227+ // For PostgreSQL and SQL Server, we need to drop foreign keys first
228+ // or use CASCADE in the drop statement
229+ if (str_contains ($ driverClass , 'Postgres ' )) {
230+ foreach ($ tables as $ table ) {
231+ $ quotedTable = $ driver ->quoteIdentifier ($ table );
232+ $ io ->verbose ("Dropping table: {$ table }" );
233+ $ connection ->execute ("DROP TABLE IF EXISTS {$ quotedTable } CASCADE " );
234+ }
235+ } elseif (str_contains ($ driverClass , 'Sqlserver ' )) {
236+ // Drop all foreign key constraints first
237+ $ this ->dropForeignKeyConstraints ($ connection , $ tables , $ io );
228238
229- try {
239+ // Then drop tables
230240 foreach ($ tables as $ table ) {
231241 $ quotedTable = $ driver ->quoteIdentifier ($ table );
232242 $ io ->verbose ("Dropping table: {$ table }" );
233243 $ connection ->execute ("DROP TABLE IF EXISTS {$ quotedTable }" );
234244 }
235- } finally {
236- // Re-enable foreign key checks
237- $ this ->setForeignKeyChecks ($ connection , true );
245+ } else {
246+ // MySQL and SQLite support disabling foreign key checks
247+ $ this ->setForeignKeyChecks ($ connection , false );
248+
249+ try {
250+ foreach ($ tables as $ table ) {
251+ $ quotedTable = $ driver ->quoteIdentifier ($ table );
252+ $ io ->verbose ("Dropping table: {$ table }" );
253+ $ connection ->execute ("DROP TABLE IF EXISTS {$ quotedTable }" );
254+ }
255+ } finally {
256+ $ this ->setForeignKeyChecks ($ connection , true );
257+ }
238258 }
239259
240260 $ io ->success ('Dropped ' . count ($ tables ) . ' table(s). ' );
241261 }
242262
263+ /**
264+ * Drop all foreign key constraints from the given tables.
265+ *
266+ * @param \Cake\Database\Connection $connection Database connection
267+ * @param array<string> $tables Tables to process
268+ * @param \Cake\Console\ConsoleIo $io Console IO
269+ * @return void
270+ */
271+ protected function dropForeignKeyConstraints (Connection $ connection , array $ tables , ConsoleIo $ io ): void
272+ {
273+ $ driver = $ connection ->getDriver ();
274+ $ driverClass = get_class ($ driver );
275+
276+ if (!str_contains ($ driverClass , 'Sqlserver ' )) {
277+ return ;
278+ }
279+
280+ // Query to find all foreign key constraints on the specified tables
281+ $ tableList = implode ("',' " , array_map (fn ($ t ) => addslashes ($ t ), $ tables ));
282+
283+ $ sql = "SELECT
284+ fk.name AS constraint_name,
285+ OBJECT_NAME(fk.parent_object_id) AS table_name
286+ FROM sys.foreign_keys fk
287+ WHERE OBJECT_NAME(fk.parent_object_id) IN (' {$ tableList }') " ;
288+
289+ $ result = $ connection ->execute ($ sql )->fetchAll ('assoc ' );
290+
291+ foreach ($ result as $ row ) {
292+ $ constraintName = $ driver ->quoteIdentifier ($ row ['constraint_name ' ]);
293+ $ tableName = $ driver ->quoteIdentifier ($ row ['table_name ' ]);
294+ $ io ->verbose ("Dropping foreign key: {$ row ['constraint_name ' ]} on {$ row ['table_name ' ]}" );
295+ $ connection ->execute ("ALTER TABLE {$ tableName } DROP CONSTRAINT {$ constraintName }" );
296+ }
297+ }
298+
243299 /**
244300 * Enable or disable foreign key checks.
245301 *
@@ -254,13 +310,8 @@ protected function setForeignKeyChecks(Connection $connection, bool $enable): vo
254310
255311 if (str_contains ($ driverClass , 'Mysql ' )) {
256312 $ connection ->execute ('SET FOREIGN_KEY_CHECKS = ' . ($ enable ? '1 ' : '0 ' ));
257- } elseif (str_contains ($ driverClass , 'Postgres ' )) {
258- // PostgreSQL handles this per-session via constraints
259- // We'll use CASCADE in the DROP statement instead
260313 } elseif (str_contains ($ driverClass , 'Sqlite ' )) {
261314 $ connection ->execute ('PRAGMA foreign_keys = ' . ($ enable ? 'ON ' : 'OFF ' ));
262- } elseif (str_contains ($ driverClass , 'Sqlserver ' )) {
263- // SQL Server doesn't have a global toggle, handled differently
264315 }
265316 }
266317
0 commit comments