162 lines
5.0 KiB
Python
162 lines
5.0 KiB
Python
#!/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()}")
|