sql.pool
import sql.pool
sqllifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledsql.pool.*needsimport sql.pool.
Keeping connections open and lending them out.
Opening a connection is expensive: for PostgreSQL it is a TCP connection, a TLS handshake and an authentication exchange before the first statement runs. A server that opened one per request would spend most of its time connecting. A pool opens a few and lends them out.
var db = sql.pool('postgres://localhost/app', { max: 10 })
var posts = db.fetch_all('select * from posts')
Used that way the pool takes a connection, runs the statement and gives
it back. Where several statements have to run on the same connection,
which a transaction requires, acquire() holds one until it is released
and with_connection() does the releasing.
Sizing
A pool wants to be as small as the work allows. Connections are not free at the other end either, and a pool larger than the database can usefully serve turns a queue in the application into a queue in the database, where it is harder to see.
SQLite wants a smaller pool than a server engine does. Readers are concurrent but writers are not, so past a handful of connections the writes queue on the database’s own lock rather than running. An in-memory SQLite database goes further: it belongs to the connection that opened it, so a pool of several would be several different empty databases. The pool clamps that case to one connection.
Isolates
A pool belongs to the isolate that made it. An isolate that needs database access makes its own.
Constants
DEFAULT_MAX
sql.pool.DEFAULT_MAX = 10
How many connections a pool opens at most, when it is not told.
DEFAULT_IDLE_TIMEOUT
sql.pool.DEFAULT_IDLE_TIMEOUT = 300000
How long an idle connection is kept before being closed, in milliseconds. Zero keeps them indefinitely.
DEFAULT_MAX_LIFETIME
sql.pool.DEFAULT_MAX_LIFETIME = 1800000
How long any connection is kept before being replaced, in milliseconds. Zero keeps them indefinitely.
Recycling connections on a schedule is what stops a pool holding one that a database restart, a failover or a firewall has quietly invalidated.
Classes
Pool
class sql.Pool
A pool of connections to one database.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
sql.Pool(driver, options, settings)
Parameters
driver(Driver)options(dict) — The adapter’s connection options.settings(dict) — The pool’s own settings:min,max,idle_timeout,max_lifetime,validate_on_acquireandon_connect.
Pool.size()
sql.Pool.size() -> number
How many connections exist, lent out or not.
Returns number
Pool.available()
sql.Pool.available() -> number
How many are available right now.
Returns number
Pool.in_use()
sql.Pool.in_use() -> number
How many are currently lent out.
Returns number
Pool.stats()
sql.Pool.stats() -> dict
A snapshot of the pool: { size, idle, in_use, max }.
Returns dict
Pool.acquire()
sql.Pool.acquire() -> Connection
Takes a connection, waiting for one if they are all busy.
The caller has to give it back. close() on the connection does that,
which is what makes a pooled connection a drop-in for one that is not
pooled, and with_connection() does it whatever happens.
There is no waiting when the pool is empty, and no timeout to set. A pool belongs to one isolate, so nothing else can release a connection while this call is running; blocking would never end. Running out means the pool is too small for the work or a connection is being held longer than it should be, and both of those are better reported than waited on.
Returns Connection
Raises PoolExhaustedError if every connection is in use.
Raises ClosedError if the pool has been closed.
Pool.release()
sql.Pool.release(connection)
Gives a connection back.
Called for you by Connection.close() on a pooled connection, so there
is rarely a reason to call it directly.
A connection that has been closed for real, or that has outlived
max_lifetime, is discarded rather than kept.
Parameters
connection(Connection)
Pool.with_connection()
sql.Pool.with_connection(body: function) -> any
Runs body with a connection, giving it back whatever happens.
db.with_connection(@(connection) {
connection.transaction(@(tx) {
tx.exec('...')
})
})
Parameters
body(function) — Called with aConnection.
Returns any — Whatever body returned.
Pool.transaction()
sql.Pool.transaction(body: function, isolation) -> any
Runs body in a transaction on a connection of its own.
Parameters
body(function) — Called with aTransaction.isolation(string|nil)
Returns any — Whatever body returned.
Pool.query()
sql.Pool.query(sql: string, params) -> ResultSet
Runs a query on a connection from the pool.
Parameters
sql(string)params(list|dict|nil)
Returns ResultSet
Pool.exec()
sql.Pool.exec(sql: string, params) -> ExecResult
Runs a statement for its effect on a connection from the pool.
Parameters
sql(string)params(list|dict|nil)
Returns ExecResult
Pool.fetch_one()
sql.Pool.fetch_one(sql: string, params) -> dict|nil
The first row of a query, or nil.
Parameters
sql(string)params(list|dict|nil)
Returns dict|nil
Pool.fetch_all()
sql.Pool.fetch_all(sql: string, params) -> list[dict]
Every row of a query.
Parameters
sql(string)params(list|dict|nil)
Returns list[dict]
Pool.fetch_value()
sql.Pool.fetch_value(sql: string, params, fallback) -> any
The first column of the first row.
Parameters
sql(string)params(list|dict|nil)fallback(any)
Returns any
Pool.close()
sql.Pool.close()
Closes every connection and refuses further use.
Connections currently lent out are closed as they come back.
Safe to call more than once.
Pool.is_closed()
sql.Pool.is_closed() -> bool
Whether this pool has been closed.
Returns bool
Pool.to_string()
sql.Pool.to_string()
2026, Richard Ore and Zuri contributors