From 5d805eb10bfe996cafaa51f274486b4410e00497 Mon Sep 17 00:00:00 2001 From: Mehmet YILMAZ Date: Thu, 17 Jul 2025 15:15:43 +0300 Subject: [PATCH] PG18 - Adapt columnar stripe metadata updates (#8030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #8019 **Background / Problem** - PostgreSQL 18 (commit [a07e03f…](https://github.com/postgres/postgres/commit/a07e03fd8fa7daf4d1356f7cb501ffe784ea6257)) removed `heap_inplace_update()` and related helpers. - Citus’ columnar writer relied on that API in `UpdateStripeMetadataRow()` to patch the `columnar_stripe` catalog row with the stripe file-offset, size, and row-count. - Building the extension against PG 18 therefore failed at link-time and, if stubbed out, left `file_offset = 0`, causing every insert to abort with `ERROR: attempted columnar write … to invalid logical offset: 0` **Scope of This PR** - Keep the fast-path on PG 12–17 (`heap_inplace_update()` unchanged). - Switch to `CatalogTupleUpdate()` on PG 18+, matching core’s new catalog-update API. - Bump the lock level from `AccessShareLock` → `RowExclusiveLock` when the normal heap-update path is taken. - No behavioral changes for users on PG ≤ 17 --- src/backend/columnar/columnar_metadata.c | 47 ++++++++++++++---------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/backend/columnar/columnar_metadata.c b/src/backend/columnar/columnar_metadata.c index 301596b26..8c252a906 100644 --- a/src/backend/columnar/columnar_metadata.c +++ b/src/backend/columnar/columnar_metadata.c @@ -1391,7 +1391,17 @@ UpdateStripeMetadataRow(uint64 storageId, uint64 stripeId, bool *update, Oid columnarStripesOid = ColumnarStripeRelationId(); - Relation columnarStripes = table_open(columnarStripesOid, AccessShareLock); +#if PG_VERSION_NUM >= 180000 + + /* CatalogTupleUpdate performs a normal heap UPDATE → RowExclusiveLock */ + const LOCKMODE openLockMode = RowExclusiveLock; +#else + + /* In‑place update never changed tuple length → AccessShareLock was enough */ + const LOCKMODE openLockMode = AccessShareLock; +#endif + + Relation columnarStripes = table_open(columnarStripesOid, openLockMode); Oid indexId = ColumnarStripePKeyIndexRelationId(); bool indexOk = OidIsValid(indexId); @@ -1414,17 +1424,6 @@ UpdateStripeMetadataRow(uint64 storageId, uint64 stripeId, bool *update, storageId, stripeId))); } - -/* - * heap_modify_tuple + heap_inplace_update only exist on PG < 18; - * on PG18 the in-place helper was removed upstream, so we skip the whole block. - */ -#if PG_VERSION_NUM < PG_VERSION_18 - - /* - * heap_inplace_update already doesn't allow changing size of the original - * tuple, so we don't allow setting any Datum's to NULL values. - */ bool newNulls[Natts_columnar_stripe] = { false }; TupleDesc tupleDescriptor = RelationGetDescr(columnarStripes); HeapTuple modifiedTuple = heap_modify_tuple(oldTuple, @@ -1433,27 +1432,37 @@ UpdateStripeMetadataRow(uint64 storageId, uint64 stripeId, bool *update, newNulls, update); - heap_inplace_update(columnarStripes, modifiedTuple); -#endif +#if PG_VERSION_NUM < PG_VERSION_18 + /* + * heap_inplace_update already doesn't allow changing size of the original + * tuple, so we don't allow setting any Datum's to NULL values. + */ + heap_inplace_update(columnarStripes, modifiedTuple); /* * Existing tuple now contains modifications, because we used * heap_inplace_update(). */ HeapTuple newTuple = oldTuple; +#else + + /* Regular catalog UPDATE keeps indexes in sync */ + CatalogTupleUpdate(columnarStripes, &oldTuple->t_self, modifiedTuple); + HeapTuple newTuple = modifiedTuple; +#endif + + CommandCounterIncrement(); /* * Must not pass modifiedTuple, because BuildStripeMetadata expects a real * heap tuple with MVCC fields. */ - StripeMetadata *modifiedStripeMetadata = BuildStripeMetadata(columnarStripes, - newTuple); - - CommandCounterIncrement(); + StripeMetadata *modifiedStripeMetadata = + BuildStripeMetadata(columnarStripes, newTuple); systable_endscan(scanDescriptor); - table_close(columnarStripes, AccessShareLock); + table_close(columnarStripes, openLockMode); /* return StripeMetadata object built from modified tuple */ return modifiedStripeMetadata;