Files
reporty/drop_all_empty_tables_aggressive.py
2025-10-06 17:49:09 +02:00

162 lines
5.0 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()}")