class PG::Connection
A session with the server: one task's at a time. Moving it to another
task goes through a PG::Lease.
Constants
STATEMENT_CACHE_SIZE: Int
How many prepared statements #query keeps by default.
QUOTED: Array[Bytes]
The bytes that make an array element quoted.
Class methods
def self.open(config: PG::Config) -> PG::Connection
Connects with config and authenticates (see PG.connect).
def self.where(config: PG::Config) -> String
Where config points, for messages.
def self.md5_password(user: String, password: String, salt: Bytes) -> String
What md5 authentication sends: md5 and the hex digest of the hex
digest of password and user, then salt.
def self.new(config: PG::Config, io: IO) -> PG::Connection
A connection over io, not started: PG.connect makes them.
def self.new(lease: PG::Lease) -> PG::Connection
The connection lease describes (see .adopt).
def self.adopt(lease: PG::Lease) -> PG::Connection
Makes a connection of lease in the calling task: the session goes on
where #release left it (idle, its prepared statements kept). A lease
is used once.
def self.quote_ident(name: String) -> String
name as an SQL identifier: double-quoted, a " in it doubled.
Raises ArgumentError for an empty name, one holding a NUL, or one of
64 bytes or more (the server cuts an identifier to 63 bytes).
PG::Connection.quote_ident("jobs") # => "\"jobs\""
PG::Connection.quote_ident("a\"b c") # => "\"a\"\"b c\""
def self.encode(value: Object?) -> Bytes?
A parameter's text, as the server reads it (nil for NULL). A Time is
sent in UTC, so that a timestamp column (without zone), which drops
the offset, keeps the instant as PG::Row#time reads it back. An
Array is a one-dimensional PostgreSQL array (encode_array).
PG::Connection.encode(true) # => b"t"
PG::Connection.encode(b"\x01\xff") # => b"\\x01ff"
PG::Connection.encode(-Float::INFINITY) # => b"-Infinity"
PG::Connection.encode([1, nil, 3]) # => b"{1,NULL,3}"
def self.encode_array(xs: Array[Object?]) -> Bytes
An array parameter's text: {1,2,3}, each element as encode gives
it, double-quoted when it is empty, spells NULL or holds ,, {,
}, ", \ or white space (" and \ escaped with \); a nil
element is NULL, the empty array {}. Raises ArgumentError for
elements of different classes or a nested array (one dimension for
now).
PG::Connection.encode_array(["a", "b,c", "d\"e", ""]) # => b"{a,\"b,c\",\"d\\\"e\",\"\"}"
PG::Connection.encode_array(Array[Int].new) # => b"{}"
def self.element_class(xs: Array[Object?]) -> Type[Object]?
The class of an array parameter's elements, nil when it has none but
nils; ArgumentError for mixed classes or a nested array.
def self.types(params: Array[Object?]) -> Array[Int]
The type OIDs the Parse message gives for params, up to the last
one that is not 0: the array's type for an array of Ints (int8[]
1016), Bools (bool[] 1000) or Bytes (bytea[] 1001), so that a
bare unnest($1) resolves without a cast; 0 for the rest, as for
every scalar: the server infers the type from the context, so that
the column decides (a float8[] would compare a numeric or real
column as double precision, a text[] would not meet a uuid,
date, enum or citext column, a timestamptz[] would shift a
timestamp column's values by the session's time zone). An empty
array or one of nils is 0 too.
PG::Connection.types([1, [1, 2], "a"]) # => [0, 1016]
PG::Connection.types([Array[Int].new]) # => []
Methods
def release -> PG::Lease?
Gives the session up as a PG::Lease, for another task to .adopt;
this object is closed for use afterwards (its socket stays open). Only
an idle session is given up: one in a transaction is rolled back
first. Returns nil, closing the socket, when the session cannot go on:
it is closed or broken, or the rollback failed. Never raises.
def parameters -> Hash[String, String]
The run-time parameters the server reported (server_version, TimeZone, client_encoding, standard_conforming_strings, ...), kept up to date.
def server_version -> String
The server's version, as server_version reports it ("17.11 (Debian 17.11-0+deb13u1)").
def process_id -> Int
The server process serving this session.
def transaction_status -> Symbol
:idle, :in_transaction or :failed (a transaction an error
aborted), as of the last time the server was ready.
def listen(channel: String) -> Void
Listens to channel (LISTEN, the name quoted as an identifier, so
that any name of 1 to 63 bytes works, case kept): the server then
sends this session every NOTIFY on it, which #wait_for_notify and
#notifications give. Listening again to a channel does nothing. A
LISTEN takes effect when its transaction commits (at once outside
one). Raises ArgumentError for an empty name, one holding a NUL, or
one of 64 bytes or more (the server would cut it to 63).
Listen through this method rather than exec("LISTEN ..."): only it
is tracked (#listening?), which PG::Pool relies on.
def unlisten(channel: String) -> Void
Stops listening to channel (UNLISTEN). Notifications already
received stay queued. Raises ArgumentError for a name #listen
refuses.
def unlisten_all -> Void
Stops listening to every channel (UNLISTEN *), whichever way it was
listened to. Notifications already received stay queued.
def listening? -> Bool
Whether a LISTEN through #listen may be in force on this session: a
channel listened to and not unlistened, or an #unlisten in a
transaction (a rollback would undo it). A LISTEN sent with #exec
is not seen.
def notify(channel: String, payload: String = …) -> Void
Sends a notification on channel with payload (pg_notify, as a
query with parameters: no quoting). Inside a transaction it is
delivered when the transaction commits, and not at all if it rolls
back. Raises ArgumentError for a channel name #listen refuses,
and PG::ServerError for what the server refuses (a payload of 8000
bytes or more).
def notifications -> Array[PG::Notification]
The notifications received so far and not yet taken, oldest first,
taking them: those that arrived while the connection ran queries, or
read by #wait_for_notify along with others. Does not read the
socket.
def wait_for_notify(timeout: Duration? = …) -> PG::Notification?
The next notification: a queued one (see #notifications), else one
read from the socket, waiting up to timeout (nil: without limit).
Returns nil when timeout passes first. Only the calling task waits;
Task.timeout and cancel interrupt the wait. An interrupted wait
leaves the connection usable when it was waiting between messages, as
it nearly always is; one interrupted in the middle of a message (the
rest of it not arrived yet) closes the connection, as #exec says.
The server delivers notifications only between transactions: inside
one (#transaction), this waits for its timeout.
Raises PG::ConnectionError when the connection is closed or breaks,
PG::ServerError when the server ends the session (an administrator's
pg_terminate_backend, a shutdown).
def on_notice(&handler: (Hash[String, String]) -> Void) -> Void
Calls the block with each notice or warning the server sends (its
fields, as PG::ServerError#fields); without a handler they are dropped.
def exec(sql: String) -> PG::Result
Runs sql (one statement or several, separated by ;) with the
simple protocol, and returns the last statement's result. Raises
PG::ServerError for the first statement that fails, after which the
statements after it do not run (and, outside a transaction block, the
ones before it stay done). Takes no parameters: use #query for
values.
A call that does not read the server's whole answer (its task was cancelled or timed out, or a notice handler raised) closes the connection: what is left of the answer would be taken for the next one's.
def exec_all(sql: String) -> Array[PG::Result]
As #exec, but returns every statement's result, in order.
def query(sql: String, params: Array[Object?] = …) -> PG::Result
Runs one statement with the extended protocol, params standing for
$1, $2, ...: each is sent apart from the SQL, so no value needs
quoting. A parameter may be nil (NULL), an Int, a Float, a String, a
Bool, Bytes (bytea), a Time (sent in UTC) or a Symbol (its name);
another raises ArgumentError. Raises PG::ServerError when the
statement fails. A call cut short closes the connection, as #exec
says.
The statement is prepared once and kept, by its SQL text, among the
connection's statement_cache_size most recently used. One the server
no longer has (SQLSTATE 26000), or says changed under it (0A000, a
table altered) outside a transaction, is prepared again and the call
retried once; inside a transaction the 0A000 is raised (the
transaction is aborted), and the next call prepares it again.
def prepared_statements -> Int
How many prepared statements the connection keeps.
def transaction[R](&: (PG::Connection) -> R) -> R
Runs the block in a transaction: BEGIN, then COMMIT when the block
returns, or ROLLBACK when it raises (the exception goes on) or leaves
otherwise (return, break). When a statement in the block failed
and the block went on after rescuing it, the server rolls the
transaction back at COMMIT; this raises PG::ServerError (SQLSTATE 25P02)
then, rather than returning as if it had been committed. Returns the
block's value. Raises PG::TransactionError when the connection is in
a transaction already: there are no nested transactions (no
savepoints) yet.
def closed? -> Bool
Whether #close was called, or the connection broke.
def tls? -> Bool
Whether the session goes over TLS (see sslmode in PG.connect).
def close -> Void
Ends the session: tells the server, and closes the socket. Closing a closed connection does nothing.
def startup -> Void
The startup exchange: authentication, then the session's parameters,
up to the first ReadyForQuery. Called by PG.connect.