#!/usr/bin/env python3
"""
查找并杀掉数据库端的僵尸连接，释放 knowledge 表的锁
"""
import os, psycopg2
from dotenv import load_dotenv

_dir = os.path.dirname(os.path.abspath(__file__))
_root = os.path.normpath(os.path.join(_dir, '..', '..'))
load_dotenv(os.path.join(_root, '.env'))

conn = psycopg2.connect(
    host=os.getenv('KNOWHUB_DB'),
    port=int(os.getenv('KNOWHUB_PORT', 5432)),
    user=os.getenv('KNOWHUB_USER'),
    password=os.getenv('KNOWHUB_PASSWORD'),
    database=os.getenv('KNOWHUB_DB_NAME'),
    connect_timeout=10
)
conn.autocommit = True
cur = conn.cursor()

print("Connected.\n")

# 1. 查所有非 idle 的活跃连接
print("=== Active connections (non-idle) ===")
cur.execute("""
    SELECT pid, state, now() - query_start as duration, query
    FROM pg_stat_activity
    WHERE state != 'idle' AND pid != pg_backend_pid()
    ORDER BY query_start
""")
rows = cur.fetchall()
print(f"Found {len(rows)} active connections.\n")
for r in rows:
    print(f"  PID={r[0]}  state={r[1]}  duration={r[2]}")
    print(f"    query: {str(r[3])[:150]}")
    print()

# 2. 查所有 idle in transaction 的连接（这些最可能持有锁）
print("=== Idle-in-transaction connections ===")
cur.execute("""
    SELECT pid, state, now() - query_start as duration, query
    FROM pg_stat_activity
    WHERE state = 'idle in transaction' AND pid != pg_backend_pid()
    ORDER BY query_start
""")
idle_tx = cur.fetchall()
print(f"Found {len(idle_tx)} idle-in-transaction connections.\n")
for r in idle_tx:
    print(f"  PID={r[0]}  duration={r[2]}")
    print(f"    last query: {str(r[3])[:150]}")
    print()

# 3. 杀掉所有非当前的 非idle 和 idle-in-transaction 连接
cur.execute("""
    SELECT pid FROM pg_stat_activity
    WHERE pid != pg_backend_pid()
      AND (state != 'idle' OR state = 'idle in transaction')
""")
pids = [r[0] for r in cur.fetchall()]
print(f"=== Terminating {len(pids)} backend connections ===")
for pid in pids:
    try:
        cur.execute("SELECT pg_terminate_backend(%s)", (pid,))
        print(f"  Killed PID {pid}")
    except Exception as e:
        print(f"  Failed PID {pid}: {e}")

print("\nDone. Try opening knowledge table in Navicat now.")
cur.close()
conn.close()
