SQL Safety Reference
SQL Safety Reference
Section titled “SQL Safety Reference”dbward processes every SQL statement through three safety layers before execution:
- Classification — determines the operation type
- Review — checks for risky patterns
- Risk scoring — calculates overall risk level for auto-approve decisions
SQL Classification
Section titled “SQL Classification”Every statement is classified into one of three categories:
ExecuteSelect (read-only)
Section titled “ExecuteSelect (read-only)”SELECTSHOWEXPLAIN(without ANALYZE)EXPLAIN ANALYZEon SELECT statementsSET(safe session variables only)
ExecuteDml (write operations)
Section titled “ExecuteDml (write operations)”INSERT,UPDATE,DELETE,MERGETRUNCATECOPYCALL(stored procedures)CREATE TABLE,CREATE VIEW,CREATE INDEXALTER TABLESELECTwith writable CTE (WITH ... INSERT/UPDATE/DELETE)SELECTwith dangerous functions (24 known functions)EXPLAIN ANALYZEon DML statements (actually executes the inner statement)SELECT INTO
Rejected (blocked by default)
Section titled “Rejected (blocked by default)”DROP TABLE/VIEW/INDEX/SEQUENCE¹CREATE SEQUENCE¹DROP SCHEMA/DATABASE/FUNCTION/ROLECREATE FUNCTION/PROCEDURE/TRIGGER/ROLE/DATABASEGRANT,REVOKEBEGIN,COMMIT,ROLLBACK,SAVEPOINTLOCK TABLELOAD DATASET(unsafe variables)
¹ Can be bypassed with --emergency --allow-ddl for schema repair. Requires request.break_glass_ddl permission. See Break-Glass.
Special rules
Section titled “Special rules”| Condition | Result |
|---|---|
| Parse failure | Classified as ExecuteDml (fail-closed: requires approval) |
| Unknown statement type | Classified as ExecuteDml |
| Input > 1 MB | Rejected |
| > 100 statements | Rejected |
| Multiple SELECT statements | Rejected (use single SELECT) |
SET + SELECT combo | Allowed |
| NULL bytes in input | Rejected |
SQL Review (10 rules)
Section titled “SQL Review (10 rules)”Each rule has a configurable severity: warn, block, or off.
warn(default) — adds a finding to the risk assessmentblock— 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"Rule descriptions
Section titled “Rule descriptions”| Rule | Fires when | Risk |
|---|---|---|
no_where_delete | DELETE without WHERE clause | Entire table deletion |
no_where_update | UPDATE without WHERE clause | Entire table overwrite |
drop_table | DROP TABLE detected | Permanent data loss |
drop_column | ALTER TABLE DROP COLUMN | Column data loss |
not_null_without_default | ALTER TABLE ADD COLUMN NOT NULL without DEFAULT | Fails on existing rows |
create_index_not_concurrently | CREATE INDEX without CONCURRENTLY (PostgreSQL) | Table lock during build |
alter_column_type | ALTER COLUMN ... TYPE | Table rewrite, potential data loss |
truncate | TRUNCATE TABLE | All data removed |
mixed_ddl_dml | DDL and DML in same request | Complex rollback |
large_in_list | IN (...) with > 100 values | Performance 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
Section titled “Risk Scoring”Risk scoring determines whether a request qualifies for auto-approve.
Levels
Section titled “Levels”| Level | Numeric | Meaning |
|---|---|---|
| Low | 1 | Safe (SELECT, safe DDL, small tables) |
| Medium | 2 | Moderate concern |
| High | 3 | Significant risk |
| Critical | 4 | Reserved |
| Unknown | 5 | Cannot assess (schema not synced) |
| Unavailable | 6 | Parse failure |
Scoring rules
Section titled “Scoring rules”| Condition | Level |
|---|---|
SELECT + allow_read_only | Low |
Safe DDL (CREATE TABLE/VIEW/INDEX) + allow_safe_ddl | Low |
| Schema not synced | Unknown |
| Multi-statement DML (>1 DML) | High |
| DROP or TRUNCATE detected | High |
| ≥ 3 review warnings | High |
| CASCADE FK + large table (> max_estimated_rows) | High |
| CASCADE FK + small table | Medium |
| Large table without cascade | Medium |
| 1-2 review warnings | Medium |
| None of the above | Low |
Safe DDL
Section titled “Safe DDL”These CREATE/ALTER statements are considered safe regardless of table size:
CREATE TABLE(new table, no existing data)CREATE VIEWCREATE INDEX CONCURRENTLY(PostgreSQL only)ALTER TABLE ... ADD COLUMN(PostgreSQL only, no lock on existing rows)
Dangerous functions (24)
Section titled “Dangerous functions (24)”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
See also
Section titled “See also”- Auto-Approve — how risk scoring drives auto-approve
- Policies Overview — fail-closed principle
- Configuration Reference — full config fields