A thin Vlang layer that boots PostgreSQL 18.1 in standalone (single‑user) mode and exposes a simple API to run arbitrary SQL queries and collect result rows.
- Uses the PostgreSQL source as a git submodule at
./postgresql(REL_18_1). - Calls the initialization sequence from
PostgresSingleUserMainbut replaces the interactive stdin/stdout with in‑memory buffers. - Executes queries via SPI (
SPI_execute) and returns results as UTF‑8 strings. - No external postmaster or separate processes – everything runs in the same OS process.
- Install V (>=0.4) and a C compiler.
- Initialize submodules:
git submodule update --init --recursive. - Build PostgreSQL in the submodule (for example
./configure --prefix=$(pwd)/installed && make -j4 installinside./postgresql). - Ensure a PostgreSQL data directory exists at
./data(created by./postgresql/installed/bin/initdb).
The Python package uses uv with setuptools build hooks. A wheel build runs
make python-lib, packages the generated libvpg_python.so inside vpg/, and
tags the wheel for the current Python/platform ABI.
uv build --wheel
uv publish dist/*.whlFor PyPI publishing, set UV_PUBLISH_TOKEN to a PyPI API token before running
uv publish, or pass the token with uv publish --token ....
mut pg := vpg.NewPGEmbedded{
data_dir: './data',
user: 'embed_user',
db: 'embed_db',
} or { err => eprintln(err) }
defer pg.Close()
result := pg.Query('SELECT version();') or { err => eprintln(err) }
println(result) // e.g. [{version: 'PostgreSQL 18.1 on ...'}]- The wrapper follows the exact startup order from
PostgresSingleUserMain:InitStandaloneProcess → InitializeGUCOptions → process_postgres_switches → SelectConfigFiles → checkDataDir → ChangeToDataDir → CreateDataDirLockFile → LocalProcessControlFile → process_shared_preload_libraries → InitializeMaxBackends → InitPostmasterChildSlots → InitializeFastPathLocks → process_shmem_requests → InitializeShmemGUCs → InitializeWalConsistencyChecking → CreateSharedMemoryAndSemaphores → set_max_safe_fds → InitProcess → PostgresMain. whereToSendOutputis set toDestNone; query results are captured via a customDestReceiverthat appends tuples to a string buffer.- Error handling propagates
elog/ereportas V errors viaerrnoandPG_TRY/PG_CATCHblocks wrapped in C functions. - All memory is allocated in PostgreSQL memory contexts; V only owns the final UTF‑8 strings.
- Runs with the privileges of the calling process; ensure the data directory is owned by a non‑root user.
- Signal handlers are installed as in the original backend (SIGINT, SIGTERM, SIGQUIT → die).
- No network listeners are opened; the backend stays in standalone mode.