Run read-only SQL
pg_readonlyRun SQL without changing data. Executes every statement in a BEGIN READ ONLY transaction, so Postgres rejects writes and rolls back, and is safe for SELECT, EXPLAIN, and SHOW.
Instructions
Run a SQL statement with no persistent data changes. Always executes inside a BEGIN READ ONLY transaction regardless of ALLOW_WRITES, so postgres itself rejects any INSERT/UPDATE/DELETE/DDL and the transaction is always rolled back. Use this whenever the goal is to read - SELECT, EXPLAIN, SHOW, VALUES, WITH ... SELECT, etc. Scope caveat for hosts that auto-allow this tool: READ ONLY constrains writes to the DATABASE, not every side effect. Functions whose effect is outside the table data - pg_cancel_backend / pg_terminate_backend, pg_read_file, lo_export, COPY ... TO PROGRAM - are NOT blocked here and are NOT behind the ALLOW_WRITES gate that pg_kill sits behind. They still require the privileges the DATABASE_URL role holds, so a least-privileged role (e.g. pg_read_all_data) is what actually bounds this tool. Use params for parameterized queries to avoid SQL injection. Params can be strings, numbers, booleans, null, arrays (for postgres arrays / ANY), or objects (for json/jsonb columns). Large result sets are truncated to POSTGRES_MAX_ROWS (default 1000) with a truncated: true flag.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | The SQL statement to execute. Hard cap of 1 MB. | |
| params | No | Positional parameters referenced as $1, $2, ... in the SQL. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| rows | Yes | Result rows, capped at POSTGRES_MAX_ROWS. Values are whatever JSON type pg parsed the column into. | |
| fields | Yes | Result column descriptors, in select-list order. | |
| command | No | Postgres command tag (`INSERT`, `CREATE TABLE`, ...). Absent on the cursor path -- read absence as 'row-returning statement, command unknown'. | |
| rowCount | Yes | Rows AFFECTED for DML -- not necessarily rows.length -- and rows returned on the cursor path. Null when pg reported no count. | |
| truncated | No | Present and true only when the result hit POSTGRES_MAX_ROWS and rows were dropped. |