Skip to content

db.pg #

Description

pg is a wrapper for the PostgreSQL client library. It provides access to a PostgreSQL database server.

Before you can use this module, you must first have PostgreSQL installed on your system. To do this, find your OS and perform the actions listed.

Note
These instructions are meant only as a convenience. If your OS is not listed
or you need extra help, go here.

Fedora 31

sudo dnf install postgresql-server postgresql-contrib
sudo systemctl enable postgresql # to autostart on startup
sudo systemctl start  postgresql

Ubuntu/Debian

sudo apt install postgresql postgresql-client
sudo systemctl enable postgresql # to autostart on startup
sudo systemctl start  postgresql

MacOSX (Homebrew)

brew install postgresql
brew services start postgresql

On newer Homebrew setups the formula and service name may be versioned instead, for example postgresql@18. Use the exact name reported by brew info postgresql.

MacOSX (MacPorts)

gem install pg -- --with-pg-config=/opt/local/lib/postgresql[version number]/bin/pg_config

Installing libpq-dev or its equivalent for your OS

Ubuntu/Debian: sudo apt install libpq-dev

Red Hat Linux (RHEL): yum install postgresql-devel

OpenSuse: zypper in postgresql-devel

ArchLinux: pacman -S postgresql-libs

FreeBSD: pkg install postgresql18-client

OpenBSD: pkg_add postgresql-client

Windows:

The directory structure of the @VEXEROOT/thirdparty/pg folder will look like the following after following all instructions. Create the pg folder yourself if it does not exist yet.

@VEXEROOT/thirdparty/pg
├───libpq
│       libpq-fe.h
│       pg_config.h
│       postgres_ext.h
│
└───win64
    └───msvc
            libpq.lib

Installation instructions are as follows

Download the latest PostgreSQL version from the official website
(currently https://www.enterprisedb.com/downloads/postgres-postgresql-downloads)

In one of the steps in the installer, tick the following boxes:
[X] PostgreSQL Server
[ ] pgAdmin 4
[ ] Stack Builder
[X] Command Line Tools

We need PostgreSQL Server because it brings with it the C header files
needed for building programs that link to `libpq.dll`.

After finishing installation, add the folder `C:/Program Files/PostgreSQL/<version>/bin` to PATH.
Any program that wants to use postgres client functionality require these DLLs found in `/bin`:
- libcrypto-3-x64.dll
- libiconv-2.dll
- libintl-9.dll
- libpq.dll
- libssl-3-x64.dll
- libwinpthread-1.dll

If you want to compile with MSVC, you will need to copy `C:/Program Files/PostgreSQL/<version>/bin/libpq.lib`
into the `@VEXEROOT/thirdparty/pg/win64/msvc` directory.

Navigate to `C:/Program Files/PostgreSQL/<version>/include`. There you will find the files:
- `libpq-fe.h`
- `pg_config.h`
- `postgres_ext.h`

Copy the header files into `@VEXEROOT/thirdparty/pg/libpq`. You can now compile programs using the `db.pg` module.

---

After building an executable that uses `db.pg`, you may want to distribute it to others
who might not have the postgres DLLs installed on their machine. All you need to do is to
make sure a copy of all the required DLLs are in the same folder as your executable.

Getting Started with PostgreSQL

Read this section to learn how to install and connect to PostgreSQL Windows; Linux; macOS.

When you use pg.connect(pg.Config{ ... }), empty Config fields are omitted from the generated libpq connection string. That lets libpq defaults, PGPASSWORD, and .pgpass apply when you do not set those fields in code.

Thread Safety & Connection Pool

pg.connect() returns a &DB that is safe to share across V threads. Internally DB holds a pool of Conn objects (one libpq PGconn* each); every method on DB transparently checks a Conn out of the pool for the duration of the call and returns it when done. This matches Go's database/sql.DB model.

mut db := pg.connect(pg.Config{ ... })!
defer { db.close() or {} }

// Pool defaults: unlimited open conns, 2 idle conns kept warm, no lifetime cap.
// Tune them like Go:
db.set_max_open_conns(50)
db.set_max_idle_conns(10)
db.set_conn_max_lifetime(30 * time.minute)

For operations that must run on the same physical connection — LISTEN/NOTIFY, session-scoped prepared statements, manual transactions — pin a conn with db.conn() or open a transaction with db.begin():

// Pinned connection: returned to the pool when conn.close() is called.
mut c := db.conn()!
defer { c.close() or {} }
c.listen('my_channel')!

// Transaction: the conn is pinned for the lifetime of the Tx and released on
// commit() or rollback().
mut tx := db.begin()!
tx.exec('UPDATE accounts SET balance = balance - 100 WHERE id = 1')!
tx.exec('UPDATE accounts SET balance = balance + 100 WHERE id = 2')!
tx.commit()!

Using Parameterized Queries

Parameterized queries (exec_param, etc.) in V require the use of the following syntax: ($n).

The number following the $ specifies which parameter from the argument array to use.

db.exec_param_many('INSERT INTO users (username, password) VALUES ($1, $2)', ['tom', 'securePassword'])!
db.exec_param('SELECT * FROM users WHERE username = ($1) limit 1', 'tom')!

Using LISTEN/NOTIFY

PostgreSQL's LISTEN/NOTIFY mechanism allows you to build event-driven applications. One connection can send notifications on a channel, and all connections listening on that channel will receive them.

Basic Usage

LISTEN/NOTIFY is session-scoped, so you must pin a Conn from the pool — calling db.listen() would only listen on whichever pooled conn happens to serve that one call.

import db.pg

fn main() {
    mut db := pg.connect(pg.Config{ user: 'postgres', password: 'password', dbname: 'mydb' })!
    defer { db.close() or {} }

    mut c := db.conn()!
    defer { c.close() or {} }

    // Start listening on a channel
    c.listen('my_channel')!

    // From another connection or session, send a notification
    c.notify('my_channel', 'Hello, World!')!

    // Process incoming data from the server
    c.consume_input()!

    // Check for notifications
    if notification := c.get_notification() {
        println('Received notification on channel: ${notification.channel}')
        println('Payload: ${notification.payload}')
        println('From server process: ${notification.pid}')
    }

    // Stop listening
    c.unlisten('my_channel')!
    // Or unlisten from all channels
    c.unlisten_all()!
}

Event Loop with Polling

For real-time applications, you can use the socket file descriptor with select/poll:

import db.pg
import time

fn main() {
    mut db := pg.connect(pg.Config{ user: 'postgres', password: 'password', dbname: 'mydb' })!
    defer { db.close() or {} }

    mut c := db.conn()!
    defer { c.close() or {} }

    c.listen('events')!

    // Get socket fd for polling (useful with select/epoll)
    socket_fd := c.socket()
    println('Socket FD: ${socket_fd}')

    // Simple polling loop
    for {
        c.consume_input()!
        for {
            notification := c.get_notification() or { break }
            println('Event: ${notification.channel} - ${notification.payload}')
        }
        time.sleep(100 * time.millisecond)
    }
}

Available Methods

  • listen(channel string) - Register to receive notifications on a channel
  • unlisten(channel string) - Unregister from a specific channel
  • unlisten_all() - Unregister from all channels
  • notify(channel string, payload string) - Send a notification (payload can be empty)
  • consume_input() - Read pending data from server (call before get_notification)
  • get_notification() - Returns the next pending notification, or none for no notifications.
  • socket() - Returns the connection's socket file descriptor for use with select/poll

fn connect #

fn connect(config Config, pcfg PoolConfig) !&DB

connect creates a new pool and opens an initial connection to verify the config works. The returned &DB is safe to share between threads.

fn connect_with_conninfo #

fn connect_with_conninfo(conninfo string, pcfg PoolConfig) !&DB

connect_with_conninfo is the conninfo-string variant of connect.

fn ConnStatusType.from #

fn ConnStatusType.from[W](input W) !ConnStatusType

fn ExecStatusType.from #

fn ExecStatusType.from[W](input W) !ExecStatusType

fn Oid.from #

fn Oid.from[W](input W) !Oid

fn PQTransactionLevel.from #

fn PQTransactionLevel.from[W](input W) !PQTransactionLevel

fn (db.pg.Result) as_structs #

fn (res Result) as_structs[T](mapper fn (Result, Row) !T) ![]T

as_structs is a Result method that maps the results' rows based on the provided mapping function

fn (db.pg.Row) val #

fn (row Row) val(index int) string

val returns the value at index, flattening SQL NULL to an empty string.

fn (db.pg.Row) values #

fn (row Row) values() []string

values returns all row values, flattening SQL NULL to empty strings.

fn (db.pg.Row) val_opt #

fn (row Row) val_opt(index int) ?string

val_opt returns the raw optional value at index.

enum ConnStatusType #

enum ConnStatusType {
	ok  = C.CONNECTION_OK
	bad = C.CONNECTION_BAD
	// Non-blocking mode only below here
	// The existence of these should never be relied upon - they should only be used for user feedback or similar purposes.
	started           = C.CONNECTION_STARTED           // Waiting for connection to be made.
	made              = C.CONNECTION_MADE              // Connection OK; waiting to send.
	awaiting_response = C.CONNECTION_AWAITING_RESPONSE // Waiting for a response from the postmaster.
	auth_ok           = C.CONNECTION_AUTH_OK           // Received authentication; waiting for backend startup.
	setenv            = C.CONNECTION_SETENV            // Negotiating environment.
	ssl_startup       = C.CONNECTION_SSL_STARTUP       // Negotiating SSL.
	needed            = C.CONNECTION_NEEDED            // Internal state: connect() needed . Available in PG 8
	check_writable    = C.CONNECTION_CHECK_WRITABLE    // Check if we could make a writable connection. Available since PG 10
	consume           = C.CONNECTION_CONSUME           // Wait for any pending message and consume them. Available since PG 10
	gss_startup       = C.CONNECTION_GSS_STARTUP       // Negotiating GSSAPI; available since PG 12
}

enum ExecStatusType #

@[typedef]
enum ExecStatusType {
	empty_query    = C.PGRES_EMPTY_QUERY    // empty query string was executed
	command_ok     = C.PGRES_COMMAND_OK     // a query command that doesn't return anything was executed properly by the backend
	tuples_ok      = C.PGRES_TUPLES_OK      // a query command that returns tuples was executed properly by the backend, PGresult contains the result tuples
	copy_out       = C.PGRES_COPY_OUT       // Copy Out data transfer in progress
	copy_in        = C.PGRES_COPY_IN        // Copy In data transfer in progress
	bad_response   = C.PGRES_BAD_RESPONSE   // an unexpected response was recv'd from the backend
	nonfatal_error = C.PGRES_NONFATAL_ERROR // notice or warning message
	fatal_error    = C.PGRES_FATAL_ERROR    // query failed
	copy_both      = C.PGRES_COPY_BOTH      // Copy In/Out data transfer in progress
	single_tuple   = C.PGRES_SINGLE_TUPLE   // single tuple from larger resultset
}

enum Oid #

enum Oid {
	t_bool             = 16
	t_bytea            = 17
	t_char             = 18
	t_name             = 19
	t_int8             = 20
	t_int2             = 21
	t_int2vector       = 22
	t_int4             = 23
	t_regproc          = 24
	t_text             = 25
	t_oid              = 26
	t_tid              = 27
	t_xid              = 28
	t_cid              = 29
	t_vector           = 30
	t_pg_ddl_command   = 32
	t_pg_type          = 71
	t_pg_attribute     = 75
	t_pg_proc          = 81
	t_pg_class         = 83
	t_json             = 114
	t_xml              = 142
	t__xml             = 143
	t_pg_node_tree     = 194
	t__json            = 199
	t_smgr             = 210
	t_index_am_handler = 325
	t_point            = 600
	t_lseg             = 601
	t_path             = 602
	t_box              = 603
	t_polygon          = 604
	t_line             = 628
	t__line            = 629
	t_cidr             = 650
	t__cidr            = 651
	t_float4           = 700
	t_float8           = 701
	t_abstime          = 702
	t_reltime          = 703
	t_tinterval        = 704
	t_unknown          = 705
	t_circle           = 718
	t__circle          = 719
	t_money            = 790
	t__money           = 791
	t_macaddr          = 829
	t_inet             = 869
	t__bool            = 1000
	t__bytea           = 1001
	t__char            = 1002
	t__name            = 1003
	t__int2            = 1005
	t__int2vector      = 1006
	t__int4            = 1007
	t__regproc         = 1008
	t__text            = 1009
	t__tid             = 1010
	t__xid             = 1011
	t__cid             = 1012
	t__vector          = 1013
	t__bpchar          = 1014
	t__varchar         = 1015
	t__int8            = 1016
	t__point           = 1017
	t__lseg            = 1018
	t__path            = 1019
	t__box             = 1020
	t__float4          = 1021
	t__float8          = 1022
	t__abstime         = 1023
	t__reltime         = 1024
	t__tinterval       = 1025
	t__polygon         = 1027
	t__                = 1028
	t_aclitem          = 1033
	t__aclitem         = 1034
	t__macaddr         = 1040
	t__inet            = 1041
	t_bpchar           = 1042
	t_varchar          = 1043
	t_date             = 1082
	t_time             = 1083
	t_timestamp        = 1114
	t__timestamp       = 1115
	t__date            = 1182
	t__time            = 1183
	t_timestamptz      = 1184
	t__timestamptz     = 1185
	t_interval         = 1186
	t__interval        = 1187
	t__numeric         = 1231
	t_pg_database      = 1248
	t__cstring         = 1263
	t_timetz           = 1266
	t__timetz          = 1270
	t_bit              = 1560
	t__bit             = 1561
	t_varbit           = 1562
	t__varbit          = 1563
	t_numeric          = 1700
	t_refcursor        = 1790
	t__refcursor       = 2201
	t_regprocedure     = 2202
	t_regoper          = 2203
	t_regoperator      = 2204
	t_regclass         = 2205
	t_regtype          = 2206
	t__regprocedure    = 2207
	t__regoper         = 2208
	t__regoperator     = 2209
	t__regclass        = 2210
	t__regtype         = 2211
	t_record           = 2249
	t_cstring          = 2275
	t_any              = 2276
	t_anyarray         = 2277
	t_v                = 2278
	t_trigger          = 2279
	t_language_handler = 2280
	t_internal         = 2281
	t_opaque           = 2282
	t_anyelement       = 2283
	t__record          = 2287
	t_anynonarray      = 2776
	t_pg_authid        = 2842
	t_pg_auth_members  = 2843
	t__txid_snapshot   = 2949
	t_uuid             = 2950
	t__uuid            = 2951
	t_txid_snapshot    = 2970
	t_fdw_handler      = 3115
	t_pg_lsn           = 3220
	t__pg_lsn          = 3221
	t_tsm_handler      = 3310
	t_anyenum          = 3500
	t_tsvector         = 3614
	t_tsquery          = 3615
	t_gtsvector        = 3642
	t__tsvector        = 3643
	t__gtsvector       = 3644
	t__tsquery         = 3645
	t_regconfig        = 3734
	t__regconfig       = 3735
	t_regdictionary    = 3769
	t__regdictionary   = 3770
	t_jsonb            = 3802
	t__jsonb           = 3807
	t_anyrange         = 3831
	t_event_trigger    = 3838
	t_int4range        = 3904
	t__int4range       = 3905
	t_numrange         = 3906
	t__numrange        = 3907
	t_tsrange          = 3908
	t__tsrange         = 3909
	t_tstzrange        = 3910
	t__tstzrange       = 3911
	t_daterange        = 3912
	t__daterange       = 3913
	t_int8range        = 3926
	t__int8range       = 3927
	t_pg_shseclabel    = 4066
	t_regnamespace     = 4089
	t__regnamespace    = 4090
	t_regrole          = 4096
	t__regrole         = 4097
}

enum PQTransactionLevel #

enum PQTransactionLevel {
	read_uncommitted
	read_committed
	repeatable_read
	serializable
}

struct C.PGconn #

@[typedef]
struct C.PGconn {}

struct C.PGnotify #

@[typedef]
struct C.PGnotify {
	relname &char // notification channel name
	be_pid  int   // process ID of notifying server process
	extra   &char // notification payload string
}

PGnotify represents a notification received from the server via LISTEN/NOTIFY

struct C.PGresult #

@[typedef]
struct C.PGresult {}

struct C.pg_conn #

struct C.pg_conn {}

struct C.pg_result #

struct C.pg_result {}

struct Config #

struct Config {
pub:
	host     string = 'localhost'
	port     int    = 5432
	user     string
	username string
	password string
	dbname   string
}

fn (Config) connection_user #

fn (config Config) connection_user() !string

connection_user returns the configured username, accepting both user and username.

struct Conn #

@[heap]
struct Conn {
mut:
	conn       voidptr = unsafe { nil }
	pool       &Pool   = unsafe { nil }
	created_at time.Time
	bad        bool
}

Conn is a single libpq connection. It is NOT safe for concurrent use by multiple V threads (libpq enforces serial use of PGconn*). Use it pinned for operations that require a specific connection (LISTEN/NOTIFY, prepared statements scoped to the session, manual transactions). For pooled, thread-safe access prefer DB, which checks out a Conn per call.

fn (Conn) begin_on_conn #

fn (c &Conn) begin_on_conn(param PQTransactionParam) !

begin_on_conn begins a transaction on this single connection. Most callers should use DB.begin() instead, which returns a Tx that owns the underlying conn for the lifetime of the transaction.

fn (Conn) close #

fn (mut c Conn) close() !

close releases this conn back to its pool. Safe to call more than once: release detaches the wrapper from the underlying handle on the first call (nils c.conn), so any subsequent close or method invocation on the same &Conn is a no-op or a benign error rather than a use-after-free.

fn (Conn) commit #

fn (c &Conn) commit() !

commit commits the current transaction on this connection.

fn (Conn) consume_input #

fn (c &Conn) consume_input() !bool

consume_input reads any available input from the server. This must be called before get_notification() to ensure pending notifications are processed. Returns true on success, false if there was an error reading from the connection.

fn (Conn) copy_expert #

fn (c &Conn) copy_expert(query string, mut file io.ReaderWriter) !int

copy_expert executes COPY command https://www.postgresql.org/docs/9.5/libpq-copy.html

fn (Conn) create #

fn (c &Conn) create(table orm.Table, fields []orm.TableField) !

create is used internally by V's ORM for processing table creation queries (DDL).

fn (Conn) delete #

fn (c &Conn) delete(table orm.Table, where orm.QueryData) !

delete is used internally by V's ORM for processing DELETE queries.

fn (Conn) drop #

fn (c &Conn) drop(table orm.Table) !

drop is used internally by V's ORM for processing table destroying queries (DDL).

fn (Conn) exec #

fn (c &Conn) exec(query string) ![]db.pg.Row

exec submits a command to the database server and wait for the result, returning an error on failure and a row set on success

fn (Conn) exec_no_null #

fn (c &Conn) exec_no_null(query string) ![]RowNoNull

exec_no_null works like exec, but the fields can't be NULL, no optionals

fn (Conn) exec_one #

fn (c &Conn) exec_one(query string) !Row

exec_one executes a query and returns its first row as a result, or an error on failure

fn (Conn) exec_param #

fn (c &Conn) exec_param(query string, param string) ![]db.pg.Row

exec_param executes a query with 1 parameter ($1), and returns either an error on failure, or the full result set on success

fn (Conn) exec_param2 #

fn (c &Conn) exec_param2(query string, param string, param2 string) ![]db.pg.Row

exec_param2 executes a query with 2 parameters ($1) and ($2), and returns either an error on failure, or the full result set on success

fn (Conn) exec_param_many #

fn (c &Conn) exec_param_many(query string, params []string) ![]db.pg.Row

exec_param_many executes a query with the parameters provided as ($1), ($2), ($n)

fn (Conn) exec_param_many_result #

fn (c &Conn) exec_param_many_result(query string, params []string) !Result

exec_param_many executes a query with the parameters provided as ($1), ($2), ($n) and returns a Result

fn (Conn) exec_prepared #

fn (c &Conn) exec_prepared(name string, params []string) ![]db.pg.Row

exec_prepared sends a request to execute a prepared statement with given parameters, and waits for the result. The number of parameters must match with the parameters declared in the prepared statement.

fn (Conn) exec_prepared_result #

fn (c &Conn) exec_prepared_result(name string, params []string) !Result

exec_prepared sends a request to execute a prepared statement with given parameters, and waits for the result. The number of parameters must match with the parameters declared in the prepared statement. returns Result

fn (Conn) exec_result #

fn (c &Conn) exec_result(query string) !Result

exec_result submits a command to the database server and wait for the result, returning an error on failure and a Result set on success

fn (Conn) get_notification #

fn (c &Conn) get_notification() ?Notification

get_notification returns the next pending notification from the server, if any. Returns none if there are no pending notifications. You should call consume_input() before this to ensure all pending notifications are available.

fn (Conn) insert #

fn (c &Conn) insert(table orm.Table, data orm.QueryData) !

insert is used internally by V's ORM for processing INSERT queries.

fn (Conn) is_bad #

fn (c &Conn) is_bad() bool

is_bad reports whether the underlying libpq connection has gone bad (e.g. dropped TCP, server idle-timeout).

fn (Conn) is_expired #

fn (c &Conn) is_expired(max_lifetime time.Duration) bool

is_expired reports whether the conn has lived longer than max_lifetime. A max_lifetime of zero means "no limit".

fn (Conn) last_id #

fn (c &Conn) last_id() int

last_id is used internally by V's ORM for post-processing INSERT queries.

fn (Conn) listen #

fn (c &Conn) listen(channel string) !

listen registers the connection to receive notifications on the specified channel. After calling this, use consume_input() and get_notification() to receive notifications.

fn (Conn) notify #

fn (c &Conn) notify(channel string, payload string) !

notify sends a notification on the specified channel with an optional payload. All connections currently listening on that channel will receive the notification.

fn (Conn) orm_begin #

fn (c &Conn) orm_begin() !

orm_begin starts a transaction on this conn.

fn (Conn) orm_commit #

fn (c &Conn) orm_commit() !

orm_commit commits the transaction on this conn.

fn (Conn) orm_release_savepoint #

fn (c &Conn) orm_release_savepoint(name string) !

orm_release_savepoint releases a savepoint on this conn.

fn (Conn) orm_rollback #

fn (c &Conn) orm_rollback() !

orm_rollback rolls back the transaction on this conn.

fn (Conn) orm_rollback_to #

fn (c &Conn) orm_rollback_to(name string) !

orm_rollback_to rolls back to a savepoint on this conn.

fn (Conn) orm_savepoint #

fn (c &Conn) orm_savepoint(name string) !

orm_savepoint creates a savepoint on this conn.

fn (Conn) prepare #

fn (c &Conn) prepare(name string, query string, num_params int) !

prepare submits a request to create a prepared statement with the given parameters, and waits for completion. You must provide the number of parameters ($1, $2, $3 ...) used in the statement

fn (Conn) q_int #

fn (c &Conn) q_int(query string) !int

q_int submit a command to the database server and returns an the first field in the first tuple converted to an int. If no row is found or on command failure, an error is returned

fn (Conn) q_string #

fn (c &Conn) q_string(query string) !string

q_string submit a command to the database server and returns an the first field in the first tuple as a string. If no row is found or on command failure, an error is returned

fn (Conn) q_strings #

fn (c &Conn) q_strings(query string) ![]db.pg.Row

q_strings submit a command to the database server and returns the resulting row set. Alias of exec

fn (Conn) release_savepoint #

fn (c &Conn) release_savepoint(savepoint string) !

release_savepoint releases a specified savepoint on this connection.

fn (Conn) reset #

fn (c &Conn) reset() !

reset returns the connection to initial state for reuse

fn (Conn) rollback #

fn (c &Conn) rollback() !

rollback rolls back the current transaction on this connection.

fn (Conn) rollback_to #

fn (c &Conn) rollback_to(savepoint string) !

rollback_to rolls back to a specified savepoint on this connection.

fn (Conn) savepoint #

fn (c &Conn) savepoint(savepoint string) !

savepoint creates a new savepoint on this connection.

fn (Conn) select #

fn (c &Conn) select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ![][]orm.Primitive

select is used internally by V's ORM for processing SELECT queries.

fn (Conn) socket #

fn (c &Conn) socket() int

socket returns the file descriptor of the connection socket to the server. This is useful for applications that want to use select() or poll() to wait for notifications without blocking. Returns -1 if no valid socket.

fn (Conn) unlisten #

fn (c &Conn) unlisten(channel string) !

unlisten unregisters the connection from receiving notifications on the specified channel. Use unlisten_all() to unregister from all channels.

fn (Conn) unlisten_all #

fn (c &Conn) unlisten_all() !

unlisten_all unregisters the connection from all notification channels.

fn (Conn) update #

fn (c &Conn) update(table orm.Table, data orm.QueryData, where orm.QueryData) !

update is used internally by V's ORM for processing UPDATE queries.

fn (Conn) validate #

fn (c &Conn) validate() !bool

validate checks if the connection is still usable

struct DB #

struct DB {
mut:
	pool &Pool = unsafe { nil }
}

DB is a thread-safe handle to a PostgreSQL database, backed by a pool of Conn objects. It mirrors Go's database/sql.DB design: methods on DB transparently acquire a conn for the call, then release it back to the pool. For operations that must run on the same physical connection (LISTEN/NOTIFY, session-scoped prepared statements, manual transactions), use db.conn() to pin a conn or db.begin() to start a transaction.

fn (DB) begin #

fn (mut db DB) begin(param PQTransactionParam) !&Tx

begin starts a new transaction and returns a Tx that pins a conn from the pool. The conn is released when Tx.commit() or Tx.rollback() is called. The default isolation level is REPEATABLE READ (matching the old single-conn API); pass PQTransactionParam{ transaction_level: ... } to override.

fn (DB) close #

fn (mut db DB) close() !

close shuts down the pool and tears down all idle connections. In-flight conns will be closed when released.

fn (DB) conn #

fn (mut db DB) conn() !&Conn

conn checks a conn out of the pool. The caller is responsible for calling conn.close() when done; failing to do so leaks the conn. Use this when you need session-bound operations like LISTEN/NOTIFY.

fn (DB) copy_expert #

fn (mut db DB) copy_expert(query string, mut file io.ReaderWriter) !int

copy_expert runs a COPY command on a pooled conn.

fn (DB) create #

fn (mut db DB) create(table orm.Table, fields []orm.TableField) !

create acquires a conn from the pool and runs CREATE TABLE on it.

fn (DB) delete #

fn (mut db DB) delete(table orm.Table, where orm.QueryData) !

delete acquires a conn from the pool and runs the ORM DELETE on it.

fn (DB) drop #

fn (mut db DB) drop(table orm.Table) !

drop acquires a conn from the pool and runs DROP TABLE on it.

fn (DB) exec #

fn (mut db DB) exec(query string) ![]db.pg.Row

exec runs query on a pooled conn and returns the rows.

fn (DB) exec_no_null #

fn (mut db DB) exec_no_null(query string) ![]RowNoNull

exec_no_null runs query and returns rows with no nullable fields.

fn (DB) exec_one #

fn (mut db DB) exec_one(query string) !Row

exec_one runs query and returns its first row.

fn (DB) exec_param #

fn (mut db DB) exec_param(query string, param string) ![]db.pg.Row

exec_param runs query with a single $1 parameter.

fn (DB) exec_param2 #

fn (mut db DB) exec_param2(query string, param string, param2 string) ![]db.pg.Row

exec_param2 runs query with two parameters ($1, $2).

fn (DB) exec_param_many #

fn (mut db DB) exec_param_many(query string, params []string) ![]db.pg.Row

exec_param_many runs query with the given parameters.

fn (DB) exec_param_many_result #

fn (mut db DB) exec_param_many_result(query string, params []string) !Result

exec_param_many_result runs query with parameters and returns a Result.

fn (DB) exec_prepared #

fn (mut db DB) exec_prepared(name string, params []string) ![]db.pg.Row

exec_prepared runs a previously-prepared statement.

fn (DB) exec_prepared_result #

fn (mut db DB) exec_prepared_result(name string, params []string) !Result

exec_prepared_result runs a previously-prepared statement and returns a Result.

fn (DB) exec_result #

fn (mut db DB) exec_result(query string) !Result

exec_result runs query and returns a Result (rows + column index).

fn (DB) insert #

fn (mut db DB) insert(table orm.Table, data orm.QueryData) !

insert acquires a conn from the pool, runs the ORM INSERT on it, and stashes LASTVAL() captured on the same session for the calling thread. V's sql db { insert ... } macro emits a follow-up db.last_id() call; stashing here lets that read return the correct id even though the pool may hand out a different conn for the second call.

fn (DB) last_id #

fn (mut db DB) last_id() int

last_id returns the id stashed by this thread's most recent DB.insert (or 0 if there is none). LASTVAL() itself is session-scoped, so calling it on a freshly-checked-out pool conn would return the wrong value or 0; DB.insert captures it on the same conn that ran the INSERT and stashes it per-thread, which is what V's ORM macro expects.

fn (DB) prepare #

fn (mut db DB) prepare(name string, query string, num_params int) !

prepare registers a prepared statement on a transient conn. For repeated use, pin a conn via db.conn().

fn (DB) q_int #

fn (mut db DB) q_int(query string) !int

q_int runs query and returns the first column of the first row as int.

fn (DB) q_string #

fn (mut db DB) q_string(query string) !string

q_string runs query and returns the first column of the first row as string.

fn (DB) q_strings #

fn (mut db DB) q_strings(query string) ![]db.pg.Row

q_strings runs query and returns the full row set (alias of exec).

fn (DB) reset #

fn (mut db DB) reset() !

reset is a no-op kept for ORM compatibility.

fn (DB) select #

fn (mut db DB) select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ![][]orm.Primitive

select acquires a conn from the pool and runs the ORM SELECT on it.

fn (DB) set_conn_max_lifetime #

fn (mut db DB) set_conn_max_lifetime(d time.Duration)

set_conn_max_lifetime sets the maximum amount of time a conn may be reused. A value of zero means conns are reused indefinitely.

fn (DB) set_max_idle_conns #

fn (mut db DB) set_max_idle_conns(n int)

set_max_idle_conns caps the number of idle connections kept warm.

fn (DB) set_max_open_conns #

fn (mut db DB) set_max_open_conns(n int)

set_max_open_conns caps the total number of open connections. A value of 0 means unlimited (the default, like Go).

fn (DB) stats #

fn (mut db DB) stats() PoolStats

stats returns a snapshot of the pool state.

fn (DB) update #

fn (mut db DB) update(table orm.Table, data orm.QueryData, where orm.QueryData) !

update acquires a conn from the pool and runs the ORM UPDATE on it.

fn (DB) validate #

fn (mut db DB) validate() !bool

validate borrows a conn from the pool and checks it is alive.

struct Notification #

struct Notification {
pub:
	channel string // notification channel name
	pid     int    // process ID of notifying server process
	payload string // notification payload string (may be empty)
}

Notification represents a notification received from the server via LISTEN/NOTIFY

struct PQTransactionParam #

@[params]
struct PQTransactionParam {
pub:
	transaction_level PQTransactionLevel = .repeatable_read
}

struct PoolConfig #

@[params]
struct PoolConfig {
pub:
	max_open_conns    int // 0 = unlimited
	max_idle_conns    int = 2 // 0 = keep no idle conns
	conn_max_lifetime time.Duration // 0 = unlimited
}

PoolConfig configures pool behavior at construction time.

struct PoolStats #

struct PoolStats {
pub:
	max_open_connections int // configured limit (0 = unlimited)
	open_connections     int // total in-use + idle conns
	in_use               int // conns currently checked out
	idle                 int // conns parked as idle
	wait_count           int // number of callers currently blocked on acquire
}

PoolStats reports the current state of a DB's connection pool.

struct Result #

struct Result {
pub:
	cols map[string]int
	rows []Row
}

struct Row #

struct Row {
pub mut:
	vals []?string
}

struct RowNoNull #

struct RowNoNull {
pub mut:
	vals []string
}

struct Tx #

@[heap]
struct Tx {
mut:
	conn &Conn = unsafe { nil }
	done bool
}

Tx is a database transaction. It pins a single Conn from the pool for the lifetime of the transaction, so all queries run on the same physical connection. The pinned conn is returned to the pool when commit() or rollback() is called; failing to call either leaks the conn.

fn (Tx) commit #

fn (mut tx Tx) commit() !

commit commits the transaction and returns the pinned conn to the pool.

fn (Tx) copy_expert #

fn (mut tx Tx) copy_expert(query string, mut file io.ReaderWriter) !int

copy_expert runs a COPY command on the pinned conn.

fn (Tx) create #

fn (mut tx Tx) create(table orm.Table, fields []orm.TableField) !

create runs CREATE TABLE on the pinned transaction conn.

fn (Tx) delete #

fn (mut tx Tx) delete(table orm.Table, where orm.QueryData) !

delete runs the ORM DELETE on the pinned transaction conn.

fn (Tx) drop #

fn (mut tx Tx) drop(table orm.Table) !

drop runs DROP TABLE on the pinned transaction conn.

fn (Tx) exec #

fn (mut tx Tx) exec(query string) ![]db.pg.Row

exec runs query on the pinned conn.

fn (Tx) exec_no_null #

fn (mut tx Tx) exec_no_null(query string) ![]RowNoNull

exec_no_null runs query and returns rows with no nullable fields.

fn (Tx) exec_one #

fn (mut tx Tx) exec_one(query string) !Row

exec_one runs query and returns its first row.

fn (Tx) exec_param #

fn (mut tx Tx) exec_param(query string, param string) ![]db.pg.Row

exec_param runs query with one $1 parameter.

fn (Tx) exec_param2 #

fn (mut tx Tx) exec_param2(query string, param string, param2 string) ![]db.pg.Row

exec_param2 runs query with two parameters.

fn (Tx) exec_param_many #

fn (mut tx Tx) exec_param_many(query string, params []string) ![]db.pg.Row

exec_param_many runs query with the given parameters.

fn (Tx) exec_param_many_result #

fn (mut tx Tx) exec_param_many_result(query string, params []string) !Result

exec_param_many_result runs query with parameters and returns a Result.

fn (Tx) exec_prepared #

fn (mut tx Tx) exec_prepared(name string, params []string) ![]db.pg.Row

exec_prepared runs a previously-prepared statement on the pinned conn.

fn (Tx) exec_prepared_result #

fn (mut tx Tx) exec_prepared_result(name string, params []string) !Result

exec_prepared_result runs a previously-prepared statement on the pinned conn.

fn (Tx) exec_result #

fn (mut tx Tx) exec_result(query string) !Result

exec_result runs query and returns a Result.

fn (Tx) insert #

fn (mut tx Tx) insert(table orm.Table, data orm.QueryData) !

insert runs the ORM INSERT on the pinned transaction conn.

fn (Tx) last_id #

fn (mut tx Tx) last_id() int

last_id returns the last inserted id on the pinned conn.

fn (Tx) orm_begin #

fn (mut tx Tx) orm_begin() !

orm_begin is a no-op on Tx (begin already ran when the Tx was created). It exists so Tx satisfies orm.TransactionalConnection for nested savepoints.

fn (Tx) orm_commit #

fn (mut tx Tx) orm_commit() !

orm_commit commits the Tx.

fn (Tx) orm_release_savepoint #

fn (mut tx Tx) orm_release_savepoint(name string) !

orm_release_savepoint releases a savepoint inside the Tx.

fn (Tx) orm_rollback #

fn (mut tx Tx) orm_rollback() !

orm_rollback rolls back the Tx.

fn (Tx) orm_rollback_to #

fn (mut tx Tx) orm_rollback_to(name string) !

orm_rollback_to rolls back to a savepoint inside the Tx.

fn (Tx) orm_savepoint #

fn (mut tx Tx) orm_savepoint(name string) !

orm_savepoint creates a savepoint inside the Tx.

fn (Tx) prepare #

fn (mut tx Tx) prepare(name string, query string, num_params int) !

prepare registers a prepared statement on the pinned conn.

fn (Tx) q_int #

fn (mut tx Tx) q_int(query string) !int

q_int runs query and returns the first column of the first row as int.

fn (Tx) q_string #

fn (mut tx Tx) q_string(query string) !string

q_string runs query and returns the first column of the first row as string.

fn (Tx) q_strings #

fn (mut tx Tx) q_strings(query string) ![]db.pg.Row

q_strings runs query and returns the full row set (alias of exec).

fn (Tx) raw #

fn (mut tx Tx) raw() !&Conn

raw returns the pinned conn for advanced use cases. The caller MUST NOT call close() on it; the conn is owned by the transaction.

fn (Tx) release_savepoint #

fn (mut tx Tx) release_savepoint(name string) !

release_savepoint releases the savepoint named name.

fn (Tx) rollback #

fn (mut tx Tx) rollback() !

rollback rolls back the transaction and returns the pinned conn to the pool.

fn (Tx) rollback_to #

fn (mut tx Tx) rollback_to(name string) !

rollback_to rolls the transaction back to the savepoint named name.

fn (Tx) savepoint #

fn (mut tx Tx) savepoint(name string) !

savepoint creates a savepoint named name.

fn (Tx) select #

fn (mut tx Tx) select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ![][]orm.Primitive

select runs the ORM SELECT on the pinned transaction conn.

fn (Tx) update #

fn (mut tx Tx) update(table orm.Table, data orm.QueryData, where orm.QueryData) !

update runs the ORM UPDATE on the pinned transaction conn.