Spaces:
Running on Zero
Running on Zero
| """ | |
| SQL executor for running queries against Spider's SQLite databases. | |
| """ | |
| import sqlite3 | |
| import threading | |
| import time | |
| def execute_sqlite_query(sql: str, db_path: str, timeout: int = 30) -> dict: | |
| """ | |
| Execute a SQL query against a SQLite database file. | |
| Returns a dict with: | |
| - "success": bool | |
| - "columns": list of column names | |
| - "rows": list of tuples | |
| - "row_count": number of rows | |
| - "execution_time_ms": time taken | |
| - "error": error message (if failure) | |
| """ | |
| conn = None | |
| try: | |
| conn = sqlite3.connect(db_path) | |
| conn.execute("PRAGMA foreign_keys = ON") | |
| conn.text_factory = str | |
| cursor = conn.cursor() | |
| # Enforce hard timeout via conn.interrupt() — the timeout parameter | |
| # in sqlite3.connect() only covers lock acquisition, not query execution. | |
| timer = threading.Timer(timeout, conn.interrupt) | |
| timer.start() | |
| start = time.time() | |
| statements = [s.strip() for s in sql.split(";") if s.strip()] | |
| columns = [] | |
| rows = [] | |
| try: | |
| for stmt in statements: | |
| cursor.execute(stmt) | |
| if cursor.description: | |
| columns = [desc[0] for desc in cursor.description] | |
| rows = cursor.fetchall() | |
| finally: | |
| timer.cancel() | |
| elapsed_ms = round((time.time() - start) * 1000, 2) | |
| return { | |
| "success": True, | |
| "columns": columns, | |
| "rows": rows, | |
| "row_count": len(rows), | |
| "execution_time_ms": elapsed_ms, | |
| "error": None, | |
| } | |
| except Exception as e: | |
| return { | |
| "success": False, | |
| "columns": [], | |
| "rows": [], | |
| "row_count": 0, | |
| "execution_time_ms": 0, | |
| "error": str(e), | |
| } | |
| finally: | |
| if conn: | |
| conn.close() | |