115 lines
3.5 KiB
Python
115 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import fdb
|
|
from datetime import datetime
|
|
|
|
# === CONFIG ===
|
|
DB_PATH = r"U:\Medicus 3\data\MEDICUS.FDB"
|
|
USER = "sysdba"
|
|
PASSWORD = "masterkey"
|
|
|
|
# output file (timestamped)
|
|
OUTFILE = f"firebird_schema_{datetime.now():%Y%m%d_%H%M%S}.txt"
|
|
|
|
# === CONNECT ===
|
|
con = fdb.connect(
|
|
dsn=DB_PATH,
|
|
user=USER,
|
|
password=PASSWORD,
|
|
charset='WIN1250'
|
|
)
|
|
cur = con.cursor()
|
|
|
|
with open(OUTFILE, "w", encoding="utf-8") as f:
|
|
f.write(f"Firebird schema overview for: {DB_PATH}\n\n")
|
|
|
|
# === GET ALL USER TABLES ===
|
|
cur.execute("""
|
|
SELECT r.rdb$relation_name
|
|
FROM rdb$relations r
|
|
WHERE r.rdb$system_flag = 0
|
|
AND r.rdb$view_blr IS NULL
|
|
ORDER BY r.rdb$relation_name
|
|
""")
|
|
tables = [t[0].strip() for t in cur.fetchall()]
|
|
|
|
for table in tables:
|
|
f.write("=" * 80 + "\n")
|
|
f.write(f"TABLE: {table}\n")
|
|
f.write("-" * 80 + "\n")
|
|
|
|
# --- COLUMNS ---
|
|
cur.execute(f"""
|
|
SELECT
|
|
rf.rdb$field_name,
|
|
f.rdb$field_type,
|
|
f.rdb$field_sub_type,
|
|
f.rdb$field_length,
|
|
f.rdb$field_scale,
|
|
coalesce(rf.rdb$null_flag, 0),
|
|
rf.rdb$default_source,
|
|
rf.rdb$description
|
|
FROM rdb$relation_fields rf
|
|
JOIN rdb$fields f ON rf.rdb$field_source = f.rdb$field_name
|
|
WHERE rf.rdb$relation_name = '{table}'
|
|
ORDER BY rf.rdb$field_position
|
|
""")
|
|
|
|
f.write("Columns:\n")
|
|
for row in cur.fetchall():
|
|
name = row[0].strip()
|
|
dtype = row[1]
|
|
subtype = row[2]
|
|
length = row[3]
|
|
scale = row[4]
|
|
notnull = bool(row[5])
|
|
default = (row[6] or "").strip() if row[6] else ""
|
|
desc = (row[7] or "").strip() if row[7] else ""
|
|
f.write(f" - {name:<20} type={dtype} sub={subtype} len={length} "
|
|
f"scale={scale} notnull={notnull} default={default} desc={desc}\n")
|
|
|
|
# --- INDEXES ---
|
|
cur.execute(f"""
|
|
SELECT
|
|
i.rdb$index_name,
|
|
i.rdb$unique_flag,
|
|
i.rdb$index_type,
|
|
s.rdb$field_name
|
|
FROM rdb$indices i
|
|
JOIN rdb$index_segments s ON i.rdb$index_name = s.rdb$index_name
|
|
WHERE i.rdb$relation_name = '{table}'
|
|
ORDER BY i.rdb$index_name, s.rdb$field_position
|
|
""")
|
|
idx = cur.fetchall()
|
|
if idx:
|
|
f.write("Indexes:\n")
|
|
for row in idx:
|
|
f.write(f" - {row[0].strip():<30} field={row[3].strip()} unique={bool(row[1])} type={row[2]}\n")
|
|
else:
|
|
f.write("Indexes: none\n")
|
|
|
|
# --- PRIMARY & FOREIGN KEYS ---
|
|
cur.execute(f"""
|
|
SELECT
|
|
rc.rdb$constraint_name,
|
|
rc.rdb$constraint_type,
|
|
seg.rdb$field_name
|
|
FROM rdb$relation_constraints rc
|
|
JOIN rdb$index_segments seg ON rc.rdb$index_name = seg.rdb$index_name
|
|
WHERE rc.rdb$relation_name = '{table}'
|
|
ORDER BY rc.rdb$constraint_name
|
|
""")
|
|
cons = cur.fetchall()
|
|
if cons:
|
|
f.write("Constraints:\n")
|
|
for row in cons:
|
|
f.write(f" - {row[1].strip():<15} {row[0].strip()} → {row[2].strip()}\n")
|
|
else:
|
|
f.write("Constraints: none\n")
|
|
|
|
f.write("\n")
|
|
|
|
con.close()
|
|
print(f"✅ Schema saved to: {OUTFILE}")
|