A text-to-SQL assistant must only ever run read-only queries. Checking sql.startswith("SELECT") isn't enough: SELECT 1; DROP TABLE users would pass.
Implement check_sql(sql) returning (ok, reason):
-- … to end of line and /* … */) and replace the contents of string literals ('…', where '' is an escaped quote) with nothing, so keywords inside strings don't count. An unterminated string or comment → (False, "unterminated").;. Allow one trailing semicolon. More than one non-empty statement → (False, "multiple statements").SELECT or WITH (case-insensitive) → otherwise (False, "not a query").INSERT UPDATE DELETE DROP ALTER CREATE ATTACH PRAGMA REPLACE TRUNCATE GRANT → (False, "forbidden: <KEYWORD>") for the first one found in that list order.(True, "ok").Then implement enforce_limit(sql, max_rows): if the cleaned query has no LIMIT keyword, return the original SQL (without a trailing semicolon) plus LIMIT <max_rows>. Otherwise return it unchanged.