Engineering NotesDatabase connections and OwlDB
Heavy SQL is judged by OwlDB, which knows the database's state, not by a cost threshold

When AI-written SQL holds a production database for a long time, the order screen and the settlement batch that share that database slow down with it. The usual defense is to run EXPLAIN before execution and reject any SQL whose cost is above some value. But cost is the optimizer's guess from statistics, and it drifts away from real execution time when the statistics are stale or the database is busy. Wherever you put the threshold, it either blocks healthy queries or lets heavy ones through.
So the decision about heavy SQL sits with whatever knows the database's current state. On a direct connection (one where an administrator entered the connection details), the model sees the execution plan with no verdict attached, and the damage after a query starts is bounded by a time budget and a concurrency cap. On a database connected through OwlDB, OwlDB decides before execution, caps resources during execution, and watches sessions. When it blocks a query, it returns the plan nodes that pushed it over the line, and the model fixes the SQL in the next round. This post covers where the decision lives and what shape a rejection takes when it comes back.
Cost is a relative guess from statistics, not a time
A cost threshold has clear advantages. It is simple to build, and it stops a query before it runs. The problem is what cost measures. PostgreSQL's cost is a relative unit in which reading one page sequentially costs 1, and the unit differs from engine to engine. Even within one engine, cost drifts from real time for three reasons:
- Stale statistics give the wrong row counts. For a table that has grown a lot since statistics were last collected, every query that reads it gets a cost lower than reality.
- A misjudged selectivity (the fraction of rows that pass a condition) lets a join that looks light blow up its row count during execution.
- Execution time doesn't depend on the SQL alone. The same SQL runs several times slower while a heavy batch job is running.
All three live outside the SQL text. Without knowing when the statistics were collected and which sessions are running right now, a single cost number cannot separate heavy SQL from light SQL.
Direct connections show the plan and bound the damage while the query runs
On a direct connection, OwlAI sees a single connection. It knows neither the database's current load nor how stale its statistics are. So the execution-plan tool makes no decision. It shows the plan to the model as is, and reports a failure only when the SQL is invalid or the planner returns no plan. The tool refuses EXPLAIN ANALYZE, because that actually runs the SQL. The system prompt tells the model to rewrite the SQL instead of running it when the plan shows a full scan, a Cartesian join, or an exploding row estimate.
In place of a decision, caps apply once execution starts. All of them are installation settings, and the model cannot raise them through tool arguments.
| Cap | Setting key | Default |
|---|---|---|
| Time budget per SQL statement | timeouts.dbQuerySeconds |
600 seconds |
| Concurrent executions against one database, per process | dbConnection.perDbConcurrency |
4 |
| Rows returned per execution | dbConnection.maxRowLimit |
10,000 rows |
| Cumulative cell size per execution | dbConnection.resultMaxBytes |
16 MiB |
Calls over the concurrency cap wait in that database's queue. Even if the model sends several heavy queries at once, a process that serves chat requests or a worker that runs jobs never has more than four executions in flight against one database. When the time budget runs out, a watchdog thread sends the engine's cancel call, and a server-side time limit on the database backs it up in case the cancel doesn't take (“Read-only and query cancellation have to reach the database server”).
Every one of these caps acts after execution has started. A heavy query uses database resources until its budget runs out, and once the engine gets the cancel, the engine decides when it actually stops. For a database where AI queries don't compete with other work, that is enough. For a database shared with production workloads, you need a decision before execution, and that decision needs information from outside the SQL.
OwlDB decides before execution and points at the plan nodes over the line
OwlDB manages the database, so it already knows what a single connection cannot: when each table's statistics were collected, which sessions are running now, and each node's role and load. An OwlDB connection is a connection chosen from the list of databases OwlDB manages, and OwlDB runs its SQL (“OwlDB connections hold a database ID instead of credentials”). That is why the three stages for heavy SQL live in OwlDB.
On an OwlDB connection, when the model calls the execution-plan tool, a decision block comes back with the plan. The block holds four things:
- Whether the query may run
- The threshold used
- The reason
- The plan nodes that pushed it over
OwlAI puts the block into the tool result unchanged. If the model skips the plan and calls the SQL execution tool directly, OwlDB applies the same decision. A query over the threshold doesn't run, and OwlDB returns QUERY_COST_EXCEEDED with the same decision block.
The most useful field in the block is the plan node. A model told only "too heavy" doesn't know what to fix, so it rewrites the whole query or gives up on the answer. A model told "full scan of the order history table" adds a date range or filters on an indexed column. If the culprit is a Cartesian join caused by a missing join condition between two tables, the model that gets that node fills in the missing condition.
The threshold exists in one place, OwlDB. If OwlAI kept a threshold of its own, SQL that passed OwlAI's check could be blocked again at OwlDB, or the other way around. When SQL that passes in one place is blocked in the next, the model can't tell what to fix, and the rounds where it resends slightly altered SQL pile up.
Queries the decision got wrong are stopped during execution
The pre-execution decision is still a guess made from the plan. However well the statistics are maintained, some conditions will have their selectivity misjudged. So OwlDB puts two more controls on queries that pass the decision.
The first is resource caps during execution. Sessions running AI queries are capped on four axes: CPU, I/O, memory, and time. A join that looked light in the plan but blows up its row count during execution is caught here.
The second is session monitoring. OwlDB checks the sessions of AI queries every second and forcibly terminates any session over budget. On a direct connection, what OwlAI sends is a query cancel request, and the engine decides when the query stops. OwlDB ends the database session itself, so no query is left stopped on screen but still running in the database.
The model only sees rejections it can fix with SQL
OwlDB's rejections split two ways, depending on whether the model can resolve them by changing the SQL.
QUERY_COST_EXCEEDED is one the SQL can fix. The decision block goes to the model as a tool result, and the model reads it along with the other tool results from the same round. In the next round, it produces SQL that narrows the conditions, hands the aggregation to the database with GROUP BY, or fills in a missing join condition. The answer the user gets arrives one round later for it.
No readable replica or a busy database is not a problem with the SQL. These reasons are hidden from the model, and OwlAI sends the same request again a little later (“AI queries pick their database node at run time, not at registration”). A model shown an infrastructure reason reads it as a fault in its own SQL, drops healthy conditions or unwinds joins, and produces SQL that runs but returns the wrong answer. A result that hits the row cap is not a rejection: it comes back truncated, with a "more rows" marker. “Two SQL executors, one set of checks and one result format” explains why both paths use the same result shape.
Design choices
We chose OwlDB's decision over a cost threshold. A cost threshold is simple and stops queries before they run, but a single number that knows nothing about statistics freshness or current load cannot separate heavy SQL from light. The decision lives in OwlDB, which has that information. The cost: direct connections get no pre-execution decision, and a heavy query uses database resources until its time budget runs out. The concurrency cap limits how many such queries run at once to four per process.
The threshold lives only in OwlDB. If two places each kept one, each would look safe on its own, but the model would get rejections that contradict each other. In exchange, changing the threshold means changing it in OwlDB; OwlAI cannot tune it per connection.
Instead of only blocking, we return the reason and the plan nodes. What the user wants is an answer, and a blocked query is one round on the way to it. Pointing at what was heavy tells the model where to fix, at the price of an answer that arrives one round later. Reasons unrelated to the SQL go the other way: they are kept from the model, and OwlAI sends the request again.
If AI queries share a database with production workloads and OwlDB manages that database, connect it through OwlDB and leave the decision and session monitoring to OwlDB. For a database where AI queries don't compete with other work for resources, such as an analytics replica, the time budget and concurrency cap on a direct connection are enough.
What problem does this solve?
More in Database connections and OwlDB

Engineering Notes · Database connections and OwlDB
The bastion gets one key line that only forwards to the database, not an account
When a production database sits in a private network behind a bastion host (an SSH server that leads into that…

Engineering Notes · Database connections and OwlDB
Certificate errors are fixed with the right CA and the right name, not by turning off verification
When OwlAI runs on a corporate network and connects over TLS to a cloud LLM or a customer database, certificate errors come from two places.

Engineering Notes · Database connections and OwlDB
Customer RDS lists are read with a 60-minute role, not an access key
To connect a customer's Amazon RDS or Aurora database from OwlAI SaaS, OwlAI needs the endpoint, port and engi…
