Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c2f0962
ci: use binary pg_upgrade instead of pg_upgradecluster in pg-upgrade-…
jnasbyupgrade Apr 30, 2026
972e550
Fix binary pg_upgrade PG10/11→PG12: exclude relhasoids from pg_class_v
jnasbyupgrade Apr 30, 2026
609176f
Merge branch 'fix-relhasoids-pg12-upgrade' into binary-pg-upgrade-ci
jnasbyupgrade Apr 30, 2026
5e107dc
ci: cat pg_upgrade log on failure for easier diagnosis
jnasbyupgrade Apr 30, 2026
484d690
ci: run pg_upgrade in dedicated dir, dump all logs on failure
jnasbyupgrade Apr 30, 2026
14bd772
ci: fix pg_upgrade checksum mismatch and empty log glob
jnasbyupgrade Apr 30, 2026
59842f3
ci: fix duplicate runs and checksum mismatch
jnasbyupgrade Apr 30, 2026
9aee08f
ci: check data_checksums before stopping old cluster
jnasbyupgrade Apr 30, 2026
b21f9e5
ci: properly handle checksum mismatch across all PG versions
jnasbyupgrade May 1, 2026
19eeed5
ci: always use data checksums on both clusters
jnasbyupgrade May 1, 2026
1940fc7
ci: wait for cluster ready after recreate; drop standard test job
jnasbyupgrade May 1, 2026
07b4769
ci: use trust auth on recreated old cluster
jnasbyupgrade May 1, 2026
1bcc208
Also omit relhaspkey from pg_class_v (removed in PG11)
jnasbyupgrade May 1, 2026
62f9614
Merge branch 'fix-relhasoids-pg12-upgrade' into binary-pg-upgrade-ci
jnasbyupgrade May 1, 2026
dacea53
ci: try pg_createcluster without explicit port
jnasbyupgrade May 1, 2026
3908501
ci: restore -p 5432 on pg_createcluster with explanation
jnasbyupgrade May 1, 2026
53826b7
ci: add --auth trust to new cluster creation
jnasbyupgrade May 1, 2026
d3b2e6e
ci: DRY up repeated options via job-level env vars; fix PG17+ log path
jnasbyupgrade May 1, 2026
677f825
Also omit attcacheoff from pg_attribute_v (removed in PG18)
jnasbyupgrade May 1, 2026
abf3c2a
Merge branch 'fix-relhasoids-pg12-upgrade' into binary-pg-upgrade-ci
jnasbyupgrade May 1, 2026
57256aa
ci: restore standard per-version test job
jnasbyupgrade May 1, 2026
2f69473
ci: move PGUSER to workflow level; use env vars for PGDATABASE and PG…
jnasbyupgrade May 1, 2026
d9cd41a
HISTORY: document pg_upgrade compatibility fixes as re-release of 0.2.2
jnasbyupgrade May 1, 2026
65e6e00
HISTORY: clarify 0.2.2 re-release wording
jnasbyupgrade May 1, 2026
43f3544
ci: move PG_CONFIG to job level; inline PGDATABASE in run scripts
jnasbyupgrade May 1, 2026
de17aac
ci: use -p 5432 on new cluster creation; drop make test from upgrade job
jnasbyupgrade May 1, 2026
b69fb4d
ci: restore make test on upgraded cluster; add TODO for extension upd…
jnasbyupgrade May 1, 2026
fa6d92b
ci: use default database in pg-upgrade-test instead of a separate db
jnasbyupgrade May 1, 2026
443e42c
ci: fix PG_CONFIG - pass as make arg for new cluster only, not job-le…
jnasbyupgrade May 1, 2026
f918480
ci: add comment explaining why PG_CONFIG must be explicit for new clu…
jnasbyupgrade May 1, 2026
db14caf
CLAUDE.md: add CI monitoring and bug-fix comment guidelines
jnasbyupgrade May 1, 2026
4af408e
ci: skip on docs-only changes; add all-checks-passed summary job
jnasbyupgrade May 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 103 additions & 25 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
name: CI
on: [push, pull_request]
on:
push:
branches:
- master
paths-ignore:
- '**.md'
- '**.asc'
pull_request:
paths-ignore:
- '**.md'
- '**.asc'
env:
PGUSER: postgres
jobs:
test:
strategy:
Expand All @@ -16,7 +28,7 @@ jobs:
- name: Install rsync
run: apt-get install -y rsync
- name: Test on PostgreSQL ${{ matrix.pg }}
run: make test PGUSER=postgres
run: make test

pg-upgrade-test:
strategy:
Expand All @@ -34,37 +46,71 @@ jobs:
new_pg: "13"
- old_pg: "12"
new_pg: "18"
name: 🔄 pg_upgrade ${{ matrix.old_pg }} → ${{ matrix.new_pg }}
name: 🔄 Binary pg_upgrade ${{ matrix.old_pg }} → ${{ matrix.new_pg }}
runs-on: ubuntu-latest
container: pgxn/pgxn-tools
env:
# Both clusters must use the same initdb options so pg_upgrade sees
# consistent settings (checksums, auth) on old and new clusters.
INITDB_OPTS: --data-checksums --auth trust
steps:
- name: Start PostgreSQL ${{ matrix.old_pg }}
run: pg-start ${{ matrix.old_pg }}
- name: Recreate old cluster with data checksums enabled
run: |
pg_ctlcluster ${{ matrix.old_pg }} test stop
pg_dropcluster ${{ matrix.old_pg }} test
# -p 5432: pg_createcluster assigns the next available port, which
# may not be 5432 after pg-start has claimed and released it. Force
# 5432 so subsequent psql/createdb calls connect without -p.
pg_createcluster -p 5432 ${{ matrix.old_pg }} test -- $INITDB_OPTS
pg_ctlcluster ${{ matrix.old_pg }} test start
pg_isready -t 30
- name: Check out the repo
uses: actions/checkout@v4
- name: Install rsync
run: apt-get install -y rsync
- name: Install cat_tools into old cluster
run: make install PGUSER=postgres
- name: Test cat_tools on old cluster
run: make test PGUSER=postgres
- name: Prepare upgrade test database
run: |
createdb -U postgres cat_tools_upgrade_test
psql -U postgres -d cat_tools_upgrade_test -c "CREATE EXTENSION cat_tools"
run: make install
- name: Install cat_tools extension into upgrade test database
run: psql -c "CREATE EXTENSION cat_tools"
- name: Install PostgreSQL ${{ matrix.new_pg }}
run: apt-get install -y postgresql-${{ matrix.new_pg }} postgresql-server-dev-${{ matrix.new_pg }}
- name: Install cat_tools into new cluster
run: make install PGUSER=postgres PG_CONFIG=/usr/lib/postgresql/${{ matrix.new_pg }}/bin/pg_config
- name: Upgrade cluster to PostgreSQL ${{ matrix.new_pg }}
run: pg_upgradecluster -v ${{ matrix.new_pg }} ${{ matrix.old_pg }} test
# PG_CONFIG must be specified explicitly: at this point both old and new
# PostgreSQL are installed, and the default pg_config on PATH may not be
# the new version's.
run: make install PG_CONFIG=/usr/lib/postgresql/${{ matrix.new_pg }}/bin/pg_config
- name: Stop old cluster, binary pg_upgrade to PostgreSQL ${{ matrix.new_pg }}, start new cluster
run: |
pg_ctlcluster ${{ matrix.old_pg }} test stop
pg_createcluster -p 5432 ${{ matrix.new_pg }} test -- $INITDB_OPTS
# PG17+ writes logs to $new_datadir/pg_upgrade_output.d/; older
# versions write to CWD. Search both on failure.
mkdir -p /tmp/pg_upgrade_logs
chown postgres:postgres /tmp/pg_upgrade_logs
su -c "cd /tmp/pg_upgrade_logs && /usr/lib/postgresql/${{ matrix.new_pg }}/bin/pg_upgrade \
-b /usr/lib/postgresql/${{ matrix.old_pg }}/bin \
-B /usr/lib/postgresql/${{ matrix.new_pg }}/bin \
-d /var/lib/postgresql/${{ matrix.old_pg }}/test \
-D /var/lib/postgresql/${{ matrix.new_pg }}/test \
-o '-c config_file=/etc/postgresql/${{ matrix.old_pg }}/test/postgresql.conf' \
-O '-c config_file=/etc/postgresql/${{ matrix.new_pg }}/test/postgresql.conf'" postgres \
|| { find /tmp/pg_upgrade_logs \
/var/lib/postgresql/${{ matrix.new_pg }}/test/pg_upgrade_output.d \
-name '*.log' 2>/dev/null | sort | xargs -r tail -n +1; exit 1; }
pg_ctlcluster ${{ matrix.new_pg }} test start
- name: Verify extension version after upgrade
run: |
VERSION=$(psql -U postgres -d cat_tools_upgrade_test -tAc "SELECT extversion FROM pg_extension WHERE extname = 'cat_tools'")
VERSION=$(psql -tAc "SELECT extversion FROM pg_extension WHERE extname = 'cat_tools'")
echo "Extension version: ${VERSION:-<not found>}"
echo "$VERSION" | grep -q "0.2.2"
- name: Run test suite on new cluster
run: make test PGUSER=postgres
- name: Run test suite on upgraded cluster
run: make test
# TODO: also test ALTER EXTENSION cat_tools UPDATE here, once the
# pg_upgrade source versions (e.g. 0.2.0) can install on the new_pg
# version. Currently the pre-0.2.2 install scripts fail on PG11+ so
# we cannot pg_upgrade from a cluster that has them installed.

extension-update-test:
strategy:
Expand All @@ -91,21 +137,53 @@ jobs:
- name: Install rsync
run: apt-get install -y rsync
- name: Install cat_tools (all versions)
run: make install PGUSER=postgres
run: make install
- name: Test upgrade from 0.2.0 (direct 0.2.0→0.2.2 path)
run: |
psql -U postgres -c "CREATE EXTENSION cat_tools VERSION '0.2.0'"
psql -U postgres -c "ALTER EXTENSION cat_tools UPDATE"
VERSION=$(psql -U postgres -tAc "SELECT extversion FROM pg_extension WHERE extname = 'cat_tools'")
psql -c "CREATE EXTENSION cat_tools VERSION '0.2.0'"
psql -c "ALTER EXTENSION cat_tools UPDATE"
VERSION=$(psql -tAc "SELECT extversion FROM pg_extension WHERE extname = 'cat_tools'")
echo "Version after 0.2.0 upgrade: ${VERSION:-<not found>}"
echo "$VERSION" | grep -q "0.2.2"
- name: Test upgrade from 0.2.1 (0.2.1→0.2.2 path)
run: |
createdb -U postgres cat_tools_from_021
psql -U postgres -d cat_tools_from_021 -c "CREATE EXTENSION cat_tools VERSION '0.2.1'"
psql -U postgres -d cat_tools_from_021 -c "ALTER EXTENSION cat_tools UPDATE"
VERSION=$(psql -U postgres -d cat_tools_from_021 -tAc "SELECT extversion FROM pg_extension WHERE extname = 'cat_tools'")
createdb cat_tools_from_021
psql -d cat_tools_from_021 -c "CREATE EXTENSION cat_tools VERSION '0.2.1'"
psql -d cat_tools_from_021 -c "ALTER EXTENSION cat_tools UPDATE"
VERSION=$(psql -d cat_tools_from_021 -tAc "SELECT extversion FROM pg_extension WHERE extname = 'cat_tools'")
echo "Version after 0.2.1 upgrade: ${VERSION:-<not found>}"
echo "$VERSION" | grep -q "0.2.2"
- name: Run test suite on updated extension
run: make test PGUSER=postgres
run: make test

all-checks-passed:
needs: [test, pg-upgrade-test, extension-update-test]
if: always()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify all jobs are listed in needs
# Ensures this job won't silently ignore a newly-added job that was
# omitted from the needs list above.
run: |
DEFINED=$(python3 -c "
import yaml
with open('.github/workflows/ci.yml') as f:
w = yaml.safe_load(f)
print('\n'.join(sorted(j for j in w['jobs'] if j != 'all-checks-passed')))
")
NEEDED=$(echo '${{ toJson(needs) }}' | python3 -c "
import json, sys
print('\n'.join(sorted(json.load(sys.stdin))))
")
if [ "$DEFINED" != "$NEEDED" ]; then
echo "Some jobs are missing from all-checks-passed needs:"
diff <(echo "$DEFINED") <(echo "$NEEDED")
exit 1
fi
- name: Check all jobs passed or were skipped
run: |
if [[ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
echo "One or more jobs failed or were cancelled"
exit 1
fi
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Claude Code Instructions for cat_tools

## GitHub CI

After pushing to a branch with an open PR, monitor CI using `gh pr checks --watch` in a background subagent until all jobs pass or a failure is confirmed. Investigate and fix failures immediately rather than leaving them for the user to notice.

## Bug Fixes

When fixing a bug, add a comment at the fix site explaining what the bug was and why the fix works. The goal is to prevent re-introducing the bug later.

## Git

**Never delete a branch without explicit user approval.** This includes `git push origin --delete`, `git branch -d`, and `git branch -D`. Always ask first.
Expand Down
23 changes: 23 additions & 0 deletions HISTORY.asc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Compatibility release: fixes broken installs on PostgreSQL 11 and 12+, and
provides an upgrade path from 0.2.0 and 0.2.1.


### PostgreSQL Version Support

cat_tools 0.2.1 (and earlier) only installs correctly on **PostgreSQL 9.2 – 10**.
Expand Down Expand Up @@ -35,6 +36,24 @@ afterward.** The upgrade will fail with an error if any such dependent objects
exist — this is intentional, to avoid silently breaking user-defined objects.
After dropping your dependent objects, run `ALTER EXTENSION cat_tools UPDATE` again.

### `pg_upgrade` Compatibility (Re-release)

`pg_upgrade` physically copies data files and re-applies schema definitions on
the new cluster. Any view that references a catalog column removed in the new
PostgreSQL version will cause the upgrade to fail. The initial 0.2.2 release
omitted `oid` and `attmissingval` from the catalog views, but missed several
columns that were later removed from PostgreSQL:

* `relhasoids` was removed from `pg_catalog.pg_class` in PG12.
* `relhaspkey` was removed from `pg_catalog.pg_class` in PG17.
* `attcacheoff` was removed from `pg_catalog.pg_attribute` in PG17.

Without this fix, running `pg_upgrade` across any of these version boundaries
with cat_tools installed would fail.

**You must have the re-release of 0.2.2 installed before running `pg_upgrade`
to PostgreSQL 12 or later.**

### Changes

* `sql/cat_tools--0.1.4--0.1.5.sql` was empty; added `-- empty upgrade` placeholder so
Expand All @@ -48,6 +67,10 @@ After dropping your dependent objects, run `ALTER EXTENSION cat_tools UPDATE` ag
which also applies all 0.2.1 function additions in a single step.
* `GRANT SELECT ON cat_tools.pg_extension_v TO cat_tools__usage` is now applied on the
upgrade path from 0.2.0 (it was absent in 0.2.0 and only added via the 0.2.1 upgrade).
* (Re-release) `_cat_tools.pg_class_v` now explicitly omits `relhasoids` (removed in PG12)
and `relhaspkey` (removed in PG17) to prevent `pg_upgrade` failures.
* (Re-release) `_cat_tools.pg_attribute_v` now explicitly omits `attcacheoff` (removed in
PG17) to prevent `pg_upgrade` failures.

0.2.1
-----
Expand Down
10 changes: 10 additions & 0 deletions README.asc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ tables/views/functions. They are meant for use by code, not by people.

To make use of them, you need to grant `cat_tools__usage` to any roles that need access.

[WARNING]
====
Any function or view in this extension that exposes raw PostgreSQL catalog
information does *not* provide a stable API. The PostgreSQL system catalogs
change between major versions — columns are added, removed, and change type.
If your code depends on the specific columns returned by objects such as
`cat_tools.pg_class_v`, `cat_tools.column`, or `cat_tools.pg_attribute_v`,
it may break when you upgrade PostgreSQL.
====

== Current Status

image:https://badge.fury.io/pg/cat_tools.svg["PGXN version",link="https://badge.fury.io/pg/cat_tools"]
Expand Down
4 changes: 2 additions & 2 deletions sql/cat_tools--0.2.0--0.2.2.sql.in
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS
LEFT JOIN pg_namespace n ON( n.oid = c.relnamespace )
;
$fmt$
, __cat_tools.omit_column('pg_catalog.pg_class')
, __cat_tools.omit_column('pg_catalog.pg_class', array['oid', 'relhasoids', 'relhaspkey'])
));
REVOKE ALL ON _cat_tools.pg_class_v FROM public;

Expand Down Expand Up @@ -531,7 +531,7 @@ $fmt$
* attmissingval is explicitly included above (cast to text[] via SED markers).
* Omit it here so it doesn't appear twice, and omit oid to avoid conflicts on PG12+.
*/
, __cat_tools.omit_column('pg_catalog.pg_attribute', array['oid', 'attmissingval'])
, __cat_tools.omit_column('pg_catalog.pg_attribute', array['oid', 'attmissingval', 'attcacheoff'])
, __cat_tools.omit_column('pg_catalog.pg_type')
));
REVOKE ALL ON _cat_tools.pg_attribute_v FROM public;
Expand Down
4 changes: 2 additions & 2 deletions sql/cat_tools--0.2.1--0.2.2.sql.in
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS
LEFT JOIN pg_namespace n ON( n.oid = c.relnamespace )
;
$fmt$
, __cat_tools.omit_column('pg_catalog.pg_class')
, __cat_tools.omit_column('pg_catalog.pg_class', array['oid', 'relhasoids', 'relhaspkey'])
));
REVOKE ALL ON _cat_tools.pg_class_v FROM public;

Expand Down Expand Up @@ -75,7 +75,7 @@ $fmt$
* attmissingval is explicitly included above (cast to text[] via SED markers).
* Omit it here so it doesn't appear twice, and omit oid to avoid conflicts on PG12+.
*/
, __cat_tools.omit_column('pg_catalog.pg_attribute', array['oid', 'attmissingval'])
, __cat_tools.omit_column('pg_catalog.pg_attribute', array['oid', 'attmissingval', 'attcacheoff'])
, __cat_tools.omit_column('pg_catalog.pg_type')
));
REVOKE ALL ON _cat_tools.pg_attribute_v FROM public;
Expand Down
4 changes: 2 additions & 2 deletions sql/cat_tools--0.2.2.sql.in
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS
LEFT JOIN pg_namespace n ON( n.oid = c.relnamespace )
;
$fmt$
, __cat_tools.omit_column('pg_catalog.pg_class')
, __cat_tools.omit_column('pg_catalog.pg_class', array['oid', 'relhasoids', 'relhaspkey'])
));
REVOKE ALL ON _cat_tools.pg_class_v FROM public;

Expand Down Expand Up @@ -766,7 +766,7 @@ $fmt$
* attmissingval is explicitly included above (cast to text[] via SED markers).
* Omit it here so it doesn't appear twice, and omit oid to avoid conflicts on PG12+.
*/
, __cat_tools.omit_column('pg_catalog.pg_attribute', array['oid', 'attmissingval'])
, __cat_tools.omit_column('pg_catalog.pg_attribute', array['oid', 'attmissingval', 'attcacheoff'])
, __cat_tools.omit_column('pg_catalog.pg_type')
));
REVOKE ALL ON _cat_tools.pg_attribute_v FROM public;
Expand Down
Loading