8 moduli leaf portati verbatim da ChironeWp3 con rename psdwp3→tht: - vendor/thoth_lsh (MinHash/LSH, leaf puro datasketch+tqdm) + VENDORED.md - lshindex/ (build/save/load/query, dipende vendor + LshConfig) - sqlcheck/ (validate_sql, leaf ExecutionConfig+mschema) - execute/ + execute/warnings (run_controlled/explain, leaf sqlglot+sqlalchemy) - rest/execute + rest/explain (REST variants, dipendono execute+rest.client) - ctetest (CTE test records, leaf sqlglot+pydantic) - report (validation report rendering, dipende execute+sqlcheck) - datamart (stub NotImplementedError) Verifica: import smoke catena completa OK, pytest 109 passed. Deps (datasketch, sqlglot, sqlalchemy, pydantic, requests, tqdm) già in pyproject. VENDORED.md neutralizzato (riferimenti PsdWp3→Thoth).
41 lines
1.4 KiB
Python
41 lines
1.4 KiB
Python
from sqlglot import exp
|
|
|
|
from tht.config import ExecutionConfig
|
|
from tht.execute import ExecResult, PlanSummary
|
|
|
|
|
|
def runtime_warnings(result: ExecResult, cfg: ExecutionConfig) -> list[str]:
|
|
warnings: list[str] = []
|
|
if not result.rows:
|
|
warnings.append("risultato vuoto: verificare filtri e join")
|
|
if result.truncated:
|
|
warnings.append("righe = limit: risultato troncato dalla preview")
|
|
if result.execution_ms > cfg.warn_execution_ms:
|
|
warnings.append(
|
|
f"tempo di esecuzione elevato: {result.execution_ms} ms "
|
|
f"(soglia {cfg.warn_execution_ms} ms)"
|
|
)
|
|
return warnings
|
|
|
|
|
|
def plan_warnings(plan: PlanSummary, cfg: ExecutionConfig) -> list[str]:
|
|
warnings: list[str] = []
|
|
if plan.plan_rows > cfg.warn_plan_rows:
|
|
warnings.append(
|
|
f"righe stimate dal piano: {plan.plan_rows} (soglia {cfg.warn_plan_rows}) — "
|
|
f"possibile join molto ampio o cardinalita' anomala"
|
|
)
|
|
return warnings
|
|
|
|
|
|
def static_warnings(ast: exp.Expression) -> list[str]:
|
|
"""Euristica cast sospetti: CAST su colonne dentro WHERE (non-sargable)."""
|
|
warnings: list[str] = []
|
|
for where in ast.find_all(exp.Where):
|
|
for cast in where.find_all(exp.Cast):
|
|
if cast.find(exp.Column) is not None:
|
|
warnings.append(
|
|
f"cast su colonna nel WHERE (possibile non-sargable): {cast.sql()}"
|
|
)
|
|
return warnings
|