Skip to content

SQL Safety Reference

dbward processes every SQL statement through three safety layers before execution:

  1. Classification — determines the operation type
  2. Review — checks for risky patterns
  3. Risk scoring — calculates overall risk level for auto-approve decisions

Every statement is classified into one of three categories:

  • SELECT
  • SHOW
  • EXPLAIN (without ANALYZE)
  • EXPLAIN ANALYZE on SELECT statements
  • SET (safe session variables only)
  • INSERT, UPDATE, DELETE, MERGE
  • TRUNCATE
  • COPY
  • CALL (stored procedures)
  • CREATE TABLE, CREATE VIEW, CREATE INDEX
  • ALTER TABLE
  • SELECT with writable CTE (WITH ... INSERT/UPDATE/DELETE)
  • SELECT with dangerous functions (24 known functions)
  • EXPLAIN ANALYZE on DML statements (actually executes the inner statement)
  • SELECT INTO
  • DROP TABLE/VIEW/INDEX/SEQUENCE ¹
  • CREATE SEQUENCE ¹
  • DROP SCHEMA/DATABASE/FUNCTION/ROLE
  • CREATE FUNCTION/PROCEDURE/TRIGGER/ROLE/DATABASE
  • GRANT, REVOKE
  • BEGIN, COMMIT, ROLLBACK, SAVEPOINT
  • LOCK TABLE
  • LOAD DATA
  • SET (unsafe variables)

¹ Can be bypassed with --emergency --allow-ddl for schema repair. Requires request.break_glass_ddl permission. See Break-Glass.

ConditionResult
Parse failureClassified as ExecuteDml (fail-closed: requires approval)
Unknown statement typeClassified as ExecuteDml
Input > 1 MBRejected
> 100 statementsRejected
Multiple SELECT statementsRejected (use single SELECT)
SET + SELECT comboAllowed
NULL bytes in inputRejected

Each rule has a configurable severity: warn, block, or off.

  • warn (default) — adds a finding to the risk assessment
  • block — rejects the request regardless of workflow (DDL rules ² can be bypassed with --emergency --allow-ddl)
  • off — rule is disabled
[sql_review]
no_where_delete = "warn"
no_where_update = "warn"
drop_table = "warn"
drop_column = "warn"
not_null_without_default = "warn"
create_index_not_concurrently = "warn"
alter_column_type = "warn"
truncate = "warn"
mixed_ddl_dml = "warn"
large_in_list = "warn"
RuleFires whenRisk
no_where_deleteDELETE without WHERE clauseEntire table deletion
no_where_updateUPDATE without WHERE clauseEntire table overwrite
drop_tableDROP TABLE detectedPermanent data loss
drop_columnALTER TABLE DROP COLUMNColumn data loss
not_null_without_defaultALTER TABLE ADD COLUMN NOT NULL without DEFAULTFails on existing rows
create_index_not_concurrentlyCREATE INDEX without CONCURRENTLY (PostgreSQL)Table lock during build
alter_column_typeALTER COLUMN ... TYPETable rewrite, potential data loss
truncateTRUNCATE TABLEAll data removed
mixed_ddl_dmlDDL and DML in same requestComplex rollback
large_in_listIN (...) with > 100 valuesPerformance concern

² DDL rules (drop_table, drop_column, truncate, create_index_not_concurrently, alter_column_type, not_null_without_default) can be bypassed with --emergency --allow-ddl. DML safety rules (no_where_delete, no_where_update, large_in_list) and mixed_ddl_dml are never bypassable.


Risk scoring determines whether a request qualifies for auto-approve.

LevelNumericMeaning
Low1Safe (SELECT, safe DDL, small tables)
Medium2Moderate concern
High3Significant risk
Critical4Reserved
Unknown5Cannot assess (schema not synced)
Unavailable6Parse failure
ConditionLevel
SELECT + allow_read_onlyLow
Safe DDL (CREATE TABLE/VIEW/INDEX) + allow_safe_ddlLow
Schema not syncedUnknown
Multi-statement DML (>1 DML)High
DROP or TRUNCATE detectedHigh
≥ 3 review warningsHigh
CASCADE FK + large table (> max_estimated_rows)High
CASCADE FK + small tableMedium
Large table without cascadeMedium
1-2 review warningsMedium
None of the aboveLow

These CREATE/ALTER statements are considered safe regardless of table size:

  • CREATE TABLE (new table, no existing data)
  • CREATE VIEW
  • CREATE INDEX CONCURRENTLY (PostgreSQL only)
  • ALTER TABLE ... ADD COLUMN (PostgreSQL only, no lock on existing rows)

Functions that promote a SELECT to ExecuteDml:

dblink, dblink_exec, dblink_connect, lo_export, lo_import, lo_unlink, pg_read_file, pg_read_binary_file, pg_ls_dir, pg_execute_server_program, copy_to, copy_from, set_config, pg_cancel_backend, pg_terminate_backend, pg_sleep, pg_advisory_lock, pg_advisory_xact_lock, pg_notify, sys_exec, sys_eval, load_file, sleep, benchmark