Summary
Add a readonly_session_sql field to [[sources]] holding session-setting statements that DBHub runs
before every read-only execution on that source.
[[sources]]
id = "production"
dsn = "mysql://user:pass@localhost:3306/mydb"
readonly_session_sql = """
SET SESSION max_execution_time = 30000;
SET SESSION innodb_lock_wait_timeout = 5;
"""
Problem
DBHub exposes a few guardrails as named options (query_timeout, search_path,
pool_max_connections), but there is no way to set anything else the database can enforce
on its own:
| Setting |
What it protects against |
max_execution_time (MySQL) |
No server-side statement deadline on MySQL |
innodb_lock_wait_timeout (MySQL), lock_timeout (Postgres) |
A read query waiting on a lock indefinitely |
work_mem (Postgres) |
One query consuming unbounded memory |
MySQL is where this matters most. The MariaDB connector applies query_timeout server-side as
max_statement_time, while the MySQL connector relies on a client-side deadline plus
KILL QUERY (#386). Mapping query_timeout to max_execution_time would cover the deadline
alone; readonly_session_sql also covers lock waits and the other settings above, without a new option
for each.
Why per execution rather than at connect time
A setting applied at connect time can be changed mid-session, and the change stays on the
pooled connection (#448 shows this on PostgreSQL). Every connector already opens a read-only
transaction for each read-only execution, so running the statements right after it puts the
configured values back before every statement.
Why not role-level settings
Per-role defaults (ALTER ROLE dbhub SET lock_timeout = '5s') are an option, and I agree a
least-privilege account is the real boundary. DBHub-side settings still help because:
Dialects
| Database |
Statement form |
Scope |
| MySQL / MariaDB |
SET SESSION name = value |
Overwritten per execution |
| PostgreSQL |
SET LOCAL name = value |
Reverts at the end of each execution |
Anything else fails at config load, so this does not become a general SQL execution path.
SQL Server, Oracle and SQLite are left out for now: SQLite has no server-side deadline to set,
and the SQL Server and Oracle containers would make the integration job heavier. They can follow
the same pattern if there is demand.
It applies to every read-only execution (execute_sql, explain_sql, read-only custom tools);
writable executions are untouched.
#450 implements this for MySQL/MariaDB with tests and docs. PostgreSQL support is ready on top
of it in a follow-up branch,
which I will open once the first PR settles. Happy to adjust the field name or scope.
Summary
Add a
readonly_session_sqlfield to[[sources]]holding session-setting statements that DBHub runsbefore every read-only execution on that source.
Problem
DBHub exposes a few guardrails as named options (
query_timeout,search_path,pool_max_connections), but there is no way to set anything else the database can enforceon its own:
max_execution_time(MySQL)innodb_lock_wait_timeout(MySQL),lock_timeout(Postgres)work_mem(Postgres)MySQL is where this matters most. The MariaDB connector applies
query_timeoutserver-side asmax_statement_time, while the MySQL connector relies on a client-side deadline plusKILL QUERY(#386). Mappingquery_timeouttomax_execution_timewould cover the deadlinealone;
readonly_session_sqlalso covers lock waits and the other settings above, without a new optionfor each.
Why per execution rather than at connect time
A setting applied at connect time can be changed mid-session, and the change stays on the
pooled connection (#448 shows this on PostgreSQL). Every connector already opens a read-only
transaction for each read-only execution, so running the statements right after it puts the
configured values back before every statement.
Why not role-level settings
Per-role defaults (
ALTER ROLE dbhub SET lock_timeout = '5s') are an option, and I agree aleast-privilege account is the real boundary. DBHub-side settings still help because:
max_execution_timeor other session variables;Dialects
SET SESSION name = valueSET LOCAL name = valueAnything else fails at config load, so this does not become a general SQL execution path.
SQL Server, Oracle and SQLite are left out for now: SQLite has no server-side deadline to set,
and the SQL Server and Oracle containers would make the integration job heavier. They can follow
the same pattern if there is demand.
It applies to every read-only execution (
execute_sql,explain_sql, read-only custom tools);writable executions are untouched.
#450 implements this for MySQL/MariaDB with tests and docs. PostgreSQL support is ready on top
of it in a follow-up branch,
which I will open once the first PR settles. Happy to adjust the field name or scope.