#!/usr/bin/env python3 # -*- coding: utf-8 -*- import fdb from pathlib import Path # ================== CONFIG ================== DB_PATH = r"u:\MEDICUS 3\data\medicus.FDB" HOST = "localhost" USER = "sysdba" PASSWORD = "masterkey" LOG_FILE = Path("dropped_tables_full.txt") # ============================================ con = fdb.connect( host=HOST, database=DB_PATH, user=USER, password=PASSWORD, charset="WIN1250", ) cur = con.cursor() print("💣 Aggressively removing all empty tables and their dependencies...") # --------------------------------------------------------------------- # Helper functions # --------------------------------------------------------------------- def commit_safe(): try: con.commit() except Exception as e: print(f" ⚠️ Commit failed: {e}") con.rollback() def drop_objects(sql_query: str, drop_sql_template: str, obj_type: str, table_name: str): """Generic dropper for dependent objects (views, triggers, procedures).""" cur.execute(sql_query) objs = [r[0].strip() for r in cur.fetchall()] for name in objs: stmt = drop_sql_template.format(name=name) try: print(f" 🔧 Dropping {obj_type}: {name}") con.execute_immediate(stmt) commit_safe() except Exception as e: print(f" ⚠️ Could not drop {obj_type} {name}: {e}") con.rollback() def drop_fk_constraints_referring_to(table_name: str): cur.execute(f""" SELECT TRIM(rc.rdb$relation_name), TRIM(rc.rdb$constraint_name) FROM rdb$relation_constraints rc JOIN rdb$ref_constraints ref ON ref.rdb$constraint_name = rc.rdb$constraint_name JOIN rdb$relation_constraints pk ON pk.rdb$constraint_name = ref.rdb$const_name_uq WHERE rc.rdb$constraint_type = 'FOREIGN KEY' AND UPPER(pk.rdb$relation_name) = '{table_name.upper()}' """) for fk_table, fk_name in cur.fetchall(): stmt = f'ALTER TABLE {fk_table} DROP CONSTRAINT {fk_name}' try: print(f" 🔧 Dropping FK {fk_name} in {fk_table}") con.execute_immediate(stmt) commit_safe() except Exception as e: print(f" ⚠️ Could not drop FK {fk_name} in {fk_table}: {e}") con.rollback() # --------------------------------------------------------------------- # Collect all user tables # --------------------------------------------------------------------- cur.execute(""" SELECT TRIM(rdb$relation_name) FROM rdb$relations WHERE rdb$system_flag = 0 ORDER BY 1 """) tables = [r[0] for r in cur.fetchall()] dropped, skipped = [], [] # --------------------------------------------------------------------- # Main loop # --------------------------------------------------------------------- for t in tables: try: cur.execute(f"SELECT COUNT(*) FROM {t}") count = cur.fetchone()[0] except Exception as e: print(f"⚠️ Skipping {t}: {e}") continue if count > 0: continue print(f"\n🧹 {t} → empty, removing dependencies and dropping...") # 1️⃣ Drop foreign keys referencing this table drop_fk_constraints_referring_to(t) # 2️⃣ Drop views referencing this table drop_objects( sql_query=f""" SELECT TRIM(rdb$view_name) FROM rdb$view_relations WHERE UPPER(rdb$relation_name) = '{t.upper()}' """, drop_sql_template="DROP VIEW {name}", obj_type="view", table_name=t ) # 3️⃣ Drop triggers whose source mentions this table drop_objects( sql_query=f""" SELECT TRIM(rdb$trigger_name) FROM rdb$triggers WHERE rdb$trigger_source CONTAINING '{t.upper()}' """, drop_sql_template="DROP TRIGGER {name}", obj_type="trigger", table_name=t ) # 4️⃣ Drop stored procedures referencing this table drop_objects( sql_query=f""" SELECT TRIM(rdb$procedure_name) FROM rdb$procedures WHERE rdb$procedure_source CONTAINING '{t.upper()}' """, drop_sql_template="DROP PROCEDURE {name}", obj_type="procedure", table_name=t ) # 5️⃣ Finally, drop the table itself try: con.execute_immediate(f"DROP TABLE {t}") commit_safe() dropped.append(t) print(f" ✅ Dropped table {t}") except Exception as e: print(f" ⚠️ Could not drop {t}: {e}") con.rollback() skipped.append(t) con.close() # --------------------------------------------------------------------- # Log results # --------------------------------------------------------------------- LOG_FILE.write_text( "=== DROPPED TABLES ===\n" + "\n".join(dropped) + "\n\n=== SKIPPED TABLES ===\n" + "\n".join(skipped), encoding="utf-8" ) print("\n✅ Done.") print(f"Total dropped: {len(dropped)}") print(f"Skipped: {len(skipped)}") print(f"Log saved to {LOG_FILE.resolve()}")