From 5f1a5b9e12c3b8fa85bf29c725d7f1bc38be9bdc Mon Sep 17 00:00:00 2001 From: Ayush7614 Date: Tue, 3 Nov 2026 02:00:00 +0530 Subject: [PATCH] fix(retrieval): support PostgreSQL 17+ checkpoint stats in capacity probe pg_stat_bgwriter lost checkpoints_timed/checkpoints_req in PostgreSQL 17 (moved to pg_stat_checkpointer as num_timed/num_requested), so the publication-capacity resource probe raised UndefinedColumn on modern PostgreSQL and the capacity-batch contract test failed on main. Detect the server version and read checkpoint counts from the view that actually exposes them on each version. --- .../capacity_execution.py | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/scripts/publication_benchmark/capacity_execution.py b/scripts/publication_benchmark/capacity_execution.py index 6fce6091b..17d88a9f3 100644 --- a/scripts/publication_benchmark/capacity_execution.py +++ b/scripts/publication_benchmark/capacity_execution.py @@ -47,9 +47,28 @@ class CapacityBatch: container_name: str | None = None +def _pg_checkpoints_fragment(engine) -> str: + """Return the checkpoint-count subselect for this PostgreSQL version. + + PostgreSQL 17 moved checkpoint stats out of ``pg_stat_bgwriter`` into + ``pg_stat_checkpointer`` (columns renamed to ``num_timed``/ + ``num_requested``), and pre-17 PostgreSQL keeps them in + ``pg_stat_bgwriter`` (``checkpoints_timed``/``checkpoints_req``). + Detect the server version so the capacity probe works on both. + """ + with engine.connect() as connection: + version_number = int( + connection.execute(text("SHOW server_version_num")).scalar_one() + ) + if version_number >= 170000: + return "(SELECT num_timed + num_requested FROM pg_stat_checkpointer)" + return "(SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter)" + + def _database_resources(database_url: str, spec: RetrievalProbeSpec) -> dict[str, int]: engine = create_engine(database_url_for_owner(database_url, owner="sync")) try: + checkpoints_fragment = _pg_checkpoints_fragment(engine) with engine.connect() as connection: row = ( connection.execute( @@ -58,8 +77,8 @@ def _database_resources(database_url: str, spec: RetrievalProbeSpec) -> dict[str "(SELECT temp_bytes FROM pg_stat_database WHERE datname = current_database()) " "AS temp_bytes, (SELECT deadlocks FROM pg_stat_database " "WHERE datname = current_database()) AS deadlocks, " - "(SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter) " - "AS checkpoints, pg_database_size(current_database()) AS database_bytes, " + + checkpoints_fragment + + " AS checkpoints, pg_database_size(current_database()) AS database_bytes, " "(SELECT coalesce(sum(pg_relation_size(c.oid)), 0) FROM pg_class c " "WHERE c.relkind IN ('r', 'm') AND c.relnamespace IN " "(SELECT oid FROM pg_namespace WHERE nspname = 'public')) AS table_bytes, "