From 9feb8f33daa47e9d80200ba3a8ecd1af11dc999b Mon Sep 17 00:00:00 2001 From: Tormi Tabor Date: Sun, 18 Oct 2026 21:07:06 +0300 Subject: [PATCH] feat(GH-1): Add hypopg and load pg_stat_statements at startup - Install postgresql-18-hypopg, for hypothetical indexes - Load pg_stat_statements at startup (shared_preload_libraries), so a database can create it and query its statistics - Check both in the publish workflow: a hypothetical index, and a query on pg_stat_statements, which fails unless it's preloaded - List both in the README, with the note for projects that set their own shared_preload_libraries Refs: Dockerfile, .github/workflows/publish.yml, README.md Co-Authored-By: Claude Opus 5.5 --- .github/workflows/publish.yml | 6 +++++- Dockerfile | 7 ++++++- README.md | 5 +++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d3597f0..0c2543d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -44,8 +44,12 @@ jobs: CREATE EXTENSION postgis_tiger_geocoder CASCADE; CREATE EXTENSION vector; CREATE EXTENSION pg_trgm; + CREATE EXTENSION hypopg; + CREATE EXTENSION pg_stat_statements; SELECT extname, extversion FROM pg_extension ORDER BY extname; - SELECT '[1,2,3]'::vector <=> '[1,2,4]'::vector AS cosine_distance, ST_AsText(ST_MakePoint(24.57, 59.34)) AS point;" + SELECT '[1,2,3]'::vector <=> '[1,2,4]'::vector AS cosine_distance, ST_AsText(ST_MakePoint(24.57, 59.34)) AS point; + SELECT indexname AS hypothetical_index FROM hypopg_create_index('CREATE INDEX ON pg_class (relname)'); + SELECT count(*) > 0 AS statements_tracked FROM pg_stat_statements;" - uses: docker/metadata-action@v6 id: meta with: diff --git a/Dockerfile b/Dockerfile index 251ff6e..075dddd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# PostgreSQL 18 with PostGIS 3 and pgvector. The official postgres image is multi-architecture +# PostgreSQL 18 with PostGIS 3, pgvector and hypopg. The official postgres image is multi-architecture # (x86 and Arm) and Debian-based, with the PostgreSQL project's apt repository configured, whose # extension packages follow each release. FROM postgres:18-trixie @@ -8,4 +8,9 @@ RUN apt-get update \ postgresql-18-postgis-3 \ postgresql-18-postgis-3-scripts \ postgresql-18-pgvector \ + postgresql-18-hypopg \ && rm -rf /var/lib/apt/lists/* + +# pg_stat_statements (statistics per query) works only when loaded at startup. A project that sets +# its own command or shared_preload_libraries replaces this and adds it to its own list. +CMD ["postgres", "-c", "shared_preload_libraries=pg_stat_statements"] diff --git a/README.md b/README.md index 384f66d..c0b4935 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # digib/postgres -PostgreSQL 18 with PostGIS 3 and pgvector, the same image locally, in CI and deployed. +PostgreSQL 18 with PostGIS 3, pgvector and hypopg, the same image locally, in CI and deployed. ```bash docker pull ghcr.io/digib/postgres:18 @@ -11,7 +11,8 @@ docker pull ghcr.io/digib/postgres:18 - **[PostgreSQL 18](https://hub.docker.com/_/postgres)**, from the official `postgres:18-trixie` image: Debian, for x86 and Arm - **[PostGIS 3](https://postgis.net/)**, with its topology and Tiger geocoder extensions (`postgresql-18-postgis-3`, `postgresql-18-postgis-3-scripts`) - **[pgvector](https://github.com/pgvector/pgvector)** (`postgresql-18-pgvector`) -- PostgreSQL's own extensions, such as `pg_trgm` and `fuzzystrmatch` +- **[hypopg](https://hypopg.readthedocs.io/)** (`postgresql-18-hypopg`): hypothetical indexes, to see what an index would do without building it +- PostgreSQL's own extensions, such as `pg_trgm`, `fuzzystrmatch` and `pg_stat_statements` (statistics per query), which the image loads at startup (`shared_preload_libraries`). A project that sets its own `command` or `shared_preload_libraries` replaces that and adds `pg_stat_statements` to its own list. Extensions come from the PostgreSQL project's apt repository, which follows each release. A project creates the ones it uses, in a migration or an init script: