From 41e7d9cbbdaac566cf90e52892361c4139e8bc7a Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 8 Jul 2025 09:00:43 +0900 Subject: [PATCH v4 09/15] Introduce global 64-bit TOAST ID counter in control file An 8 byte counter is added to the control file, providing a unique 64-bit-wide source for toast value IDs, with the same guarantees as OIDs in terms of durability. SQL functions and tools looking at the control file are updated. A WAL record is generated every 8k values generated, that can be adjusted if required. Requires a bump of WAL format. Requires a bump of control file version. Requires a catalog version bump. --- src/include/access/toast_counter.h | 34 +++++++ src/include/access/xlog.h | 1 + src/include/catalog/pg_control.h | 4 +- src/include/catalog/pg_proc.dat | 6 +- src/include/storage/lwlocklist.h | 1 + src/backend/access/common/Makefile | 1 + src/backend/access/common/meson.build | 1 + src/backend/access/common/toast_counter.c | 98 +++++++++++++++++++ src/backend/access/rmgrdesc/xlogdesc.c | 10 ++ src/backend/access/transam/xlog.c | 44 +++++++++ src/backend/replication/logical/decode.c | 1 + src/backend/storage/ipc/ipci.c | 5 +- .../utils/activity/wait_event_names.txt | 1 + src/backend/utils/misc/pg_controldata.c | 23 +++-- src/bin/pg_controldata/pg_controldata.c | 2 + src/bin/pg_resetwal/pg_resetwal.c | 2 + doc/src/sgml/func/func-info.sgml | 5 + src/tools/pgindent/typedefs.list | 1 + 18 files changed, 225 insertions(+), 15 deletions(-) create mode 100644 src/include/access/toast_counter.h create mode 100644 src/backend/access/common/toast_counter.c diff --git a/src/include/access/toast_counter.h b/src/include/access/toast_counter.h new file mode 100644 index 000000000000..e2bc79682771 --- /dev/null +++ b/src/include/access/toast_counter.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * toast_counter.h + * Machinery for TOAST value counter. + * + * Copyright (c) 2000-2025, PostgreSQL Global Development Group + * + * src/include/access/toast_counter.h + * + *------------------------------------------------------------------------- + */ +#ifndef TOAST_COUNTER_H +#define TOAST_COUNTER_H + +#define FirstToastId 1 /* First TOAST value ID assigned */ + +/* + * Structure in shared memory to track TOAST value counter activity. + * These are protected by ToastIdGenLock. + */ +typedef struct ToastCounterData +{ + uint64 nextId; /* next TOAST value ID to assign */ + uint32 idCount; /* IDs available before WAL work */ +} ToastCounterData; + +extern PGDLLIMPORT ToastCounterData *ToastCounter; + +/* external declarations */ +extern Size ToastCounterShmemSize(void); +extern void ToastCounterShmemInit(void); +extern uint64 GetNewToastId(void); + +#endif /* TOAST_TYPE_H */ diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index d12798be3d80..6c5e5feb54bb 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -244,6 +244,7 @@ extern bool CreateCheckPoint(int flags); extern bool CreateRestartPoint(int flags); extern WALAvailability GetWALAvailability(XLogRecPtr targetLSN); extern void XLogPutNextOid(Oid nextOid); +extern void XLogPutNextToastId(uint64 nextId); extern XLogRecPtr XLogRestorePoint(const char *rpName); extern void UpdateFullPageWrites(void); extern void GetFullPageWriteInfo(XLogRecPtr *RedoRecPtr_p, bool *doPageWrites_p); diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index 63e834a6ce47..1194b4928155 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -22,7 +22,7 @@ /* Version identifier for this pg_control format */ -#define PG_CONTROL_VERSION 1800 +#define PG_CONTROL_VERSION 1900 /* Nonce key length, see below */ #define MOCK_AUTH_NONCE_LEN 32 @@ -45,6 +45,7 @@ typedef struct CheckPoint Oid nextOid; /* next free OID */ MultiXactId nextMulti; /* next free MultiXactId */ MultiXactOffset nextMultiOffset; /* next free MultiXact offset */ + uint64 nextToastId; /* next free TOAST ID */ TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */ Oid oldestXidDB; /* database with minimum datfrozenxid */ MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */ @@ -80,6 +81,7 @@ typedef struct CheckPoint /* 0xC0 is used in Postgres 9.5-11 */ #define XLOG_OVERWRITE_CONTRECORD 0xD0 #define XLOG_CHECKPOINT_REDO 0xE0 +#define XLOG_NEXT_TOAST_ID 0xF0 /* diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 118d6da1ace0..1f6df80ad312 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12318,9 +12318,9 @@ descr => 'pg_controldata checkpoint state information as a function', proname => 'pg_control_checkpoint', provolatile => 'v', prorettype => 'record', proargtypes => '', - proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,text,oid,xid,xid,xid,oid,xid,xid,oid,xid,xid,timestamptz}', - proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', - proargnames => '{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}', + proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,text,oid,xid,xid,int8,xid,oid,xid,xid,oid,xid,xid,timestamptz}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,next_toast_id,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}', prosrc => 'pg_control_checkpoint' }, { oid => '3443', diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h index 208d2e3a8ed9..81abc58f0810 100644 --- a/src/include/storage/lwlocklist.h +++ b/src/include/storage/lwlocklist.h @@ -85,6 +85,7 @@ PG_LWLOCK(50, DSMRegistry) PG_LWLOCK(51, InjectionPoint) PG_LWLOCK(52, SerialControl) PG_LWLOCK(53, AioWorkerSubmissionQueue) +PG_LWLOCK(54, ToastIdGen) /* * There also exist several built-in LWLock tranches. As with the predefined diff --git a/src/backend/access/common/Makefile b/src/backend/access/common/Makefile index 1ef86a245886..6e9a3a430c19 100644 --- a/src/backend/access/common/Makefile +++ b/src/backend/access/common/Makefile @@ -27,6 +27,7 @@ OBJS = \ syncscan.o \ tidstore.o \ toast_compression.o \ + toast_counter.o \ toast_external.o \ toast_internals.o \ tupconvert.o \ diff --git a/src/backend/access/common/meson.build b/src/backend/access/common/meson.build index c20f2e88921e..4254132c8dfd 100644 --- a/src/backend/access/common/meson.build +++ b/src/backend/access/common/meson.build @@ -15,6 +15,7 @@ backend_sources += files( 'syncscan.c', 'tidstore.c', 'toast_compression.c', + 'toast_counter.c', 'toast_external.c', 'toast_internals.c', 'tupconvert.c', diff --git a/src/backend/access/common/toast_counter.c b/src/backend/access/common/toast_counter.c new file mode 100644 index 000000000000..94d361d0d5c4 --- /dev/null +++ b/src/backend/access/common/toast_counter.c @@ -0,0 +1,98 @@ +/*------------------------------------------------------------------------- + * + * toast_counter.c + * Functions for TOAST value counter. + * + * Copyright (c) 2025, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/backend/access/common/toast_counter.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/toast_counter.h" +#include "access/xlog.h" +#include "miscadmin.h" +#include "storage/lwlock.h" +#include "storage/shmem.h" + +/* Number of TOAST values to preallocate before WAL work */ +#define TOAST_ID_PREFETCH 8192 + +/* pointer to variables struct in shared memory */ +ToastCounterData *ToastCounter = NULL; + +/* + * Initialization of shared memory for ToastCounter. + */ +Size +ToastCounterShmemSize(void) +{ + return sizeof(ToastCounterData); +} + +void +ToastCounterShmemInit(void) +{ + bool found; + + /* Initialize shared state struct */ + ToastCounter = ShmemInitStruct("ToastCounter", + sizeof(ToastCounterData), + &found); + if (!IsUnderPostmaster) + { + Assert(!found); + memset(ToastCounter, 0, sizeof(ToastCounterData)); + } + else + Assert(found); +} + +/* + * GetNewToastId + * + * Toast IDs are generated as a cluster-wide counter. They are 64 bits + * wide, hence wraparound will unlikely happen. + */ +uint64 +GetNewToastId(void) +{ + uint64 result; + + if (RecoveryInProgress()) + elog(ERROR, "cannot assign TOAST IDs during recovery"); + + LWLockAcquire(ToastIdGenLock, LW_EXCLUSIVE); + + /* + * Check for initialization or wraparound of the toast counter ID. + * InvalidToastId (0) should never be returned. We are 64 bit-wide, hence + * wraparound is unlikely going to happen, but this check is cheap so + * let's play it safe. + */ + if (ToastCounter->nextId < ((uint64) FirstToastId)) + { + /* Most-likely first bootstrap or initdb assignment */ + ToastCounter->nextId = FirstToastId; + ToastCounter->idCount = 0; + } + + /* If running out of logged for TOAST IDs, log more */ + if (ToastCounter->idCount == 0) + { + XLogPutNextToastId(ToastCounter->nextId + TOAST_ID_PREFETCH); + ToastCounter->idCount = TOAST_ID_PREFETCH; + } + + result = ToastCounter->nextId; + (ToastCounter->nextId)++; + (ToastCounter->idCount)--; + + LWLockRelease(ToastIdGenLock); + + return result; +} diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index cd6c2a2f650a..6786af4064b8 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -96,6 +96,13 @@ xlog_desc(StringInfo buf, XLogReaderState *record) memcpy(&nextOid, rec, sizeof(Oid)); appendStringInfo(buf, "%u", nextOid); } + else if (info == XLOG_NEXT_TOAST_ID) + { + uint64 nextId; + + memcpy(&nextId, rec, sizeof(uint64)); + appendStringInfo(buf, "%" PRIu64, nextId); + } else if (info == XLOG_RESTORE_POINT) { xl_restore_point *xlrec = (xl_restore_point *) rec; @@ -218,6 +225,9 @@ xlog_identify(uint8 info) case XLOG_CHECKPOINT_REDO: id = "CHECKPOINT_REDO"; break; + case XLOG_NEXT_TOAST_ID: + id = "NEXT_TOAST_ID"; + break; } return id; diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 9a4de1616bcc..172ee27fe4cf 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -53,6 +53,7 @@ #include "access/rewriteheap.h" #include "access/subtrans.h" #include "access/timeline.h" +#include "access/toast_counter.h" #include "access/transam.h" #include "access/twophase.h" #include "access/xact.h" @@ -5259,6 +5260,7 @@ BootStrapXLOG(uint32 data_checksum_version) checkPoint.nextOid = FirstGenbkiObjectId; checkPoint.nextMulti = FirstMultiXactId; checkPoint.nextMultiOffset = 0; + checkPoint.nextToastId = FirstToastId; checkPoint.oldestXid = FirstNormalTransactionId; checkPoint.oldestXidDB = Template1DbOid; checkPoint.oldestMulti = FirstMultiXactId; @@ -5271,6 +5273,10 @@ BootStrapXLOG(uint32 data_checksum_version) TransamVariables->nextXid = checkPoint.nextXid; TransamVariables->nextOid = checkPoint.nextOid; TransamVariables->oidCount = 0; + + ToastCounter->nextId = checkPoint.nextToastId; + ToastCounter->idCount = 0; + MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset); AdvanceOldestClogXid(checkPoint.oldestXid); SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB); @@ -5752,6 +5758,8 @@ StartupXLOG(void) TransamVariables->nextXid = checkPoint.nextXid; TransamVariables->nextOid = checkPoint.nextOid; TransamVariables->oidCount = 0; + ToastCounter->nextId = checkPoint.nextToastId; + ToastCounter->idCount = 0; MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset); AdvanceOldestClogXid(checkPoint.oldestXid); SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB); @@ -7299,6 +7307,12 @@ CreateCheckPoint(int flags) checkPoint.nextOid += TransamVariables->oidCount; LWLockRelease(OidGenLock); + LWLockAcquire(ToastIdGenLock, LW_SHARED); + checkPoint.nextToastId = ToastCounter->nextId; + if (!shutdown) + checkPoint.nextToastId += ToastCounter->idCount; + LWLockRelease(ToastIdGenLock); + MultiXactGetCheckptMulti(shutdown, &checkPoint.nextMulti, &checkPoint.nextMultiOffset, @@ -8234,6 +8248,22 @@ XLogPutNextOid(Oid nextOid) */ } +/* + * Write a NEXT_TOAST_ID log record. + */ +void +XLogPutNextToastId(uint64 nextId) +{ + XLogBeginInsert(); + XLogRegisterData(&nextId, sizeof(uint64)); + (void) XLogInsert(RM_XLOG_ID, XLOG_NEXT_TOAST_ID); + + /* + * The next TOAST value ID is not flushed immediately, for the same reason + * as above for the OIDs in XLogPutNextOid(). + */ +} + /* * Write an XLOG SWITCH record. * @@ -8449,6 +8479,16 @@ xlog_redo(XLogReaderState *record) TransamVariables->oidCount = 0; LWLockRelease(OidGenLock); } + else if (info == XLOG_NEXT_TOAST_ID) + { + uint64 nextToastId; + + memcpy(&nextToastId, XLogRecGetData(record), sizeof(uint64)); + LWLockAcquire(ToastIdGenLock, LW_EXCLUSIVE); + ToastCounter->nextId = nextToastId; + ToastCounter->idCount = 0; + LWLockRelease(ToastIdGenLock); + } else if (info == XLOG_CHECKPOINT_SHUTDOWN) { CheckPoint checkPoint; @@ -8463,6 +8503,10 @@ xlog_redo(XLogReaderState *record) TransamVariables->nextOid = checkPoint.nextOid; TransamVariables->oidCount = 0; LWLockRelease(OidGenLock); + LWLockAcquire(ToastIdGenLock, LW_EXCLUSIVE); + ToastCounter->nextId = checkPoint.nextToastId; + ToastCounter->idCount = 0; + LWLockRelease(ToastIdGenLock); MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset); diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index cc03f0706e9c..bb0337d37201 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -188,6 +188,7 @@ xlog_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) case XLOG_FPI: case XLOG_OVERWRITE_CONTRECORD: case XLOG_CHECKPOINT_REDO: + case XLOG_NEXT_TOAST_ID: break; default: elog(ERROR, "unexpected RM_XLOG_ID record type: %u", info); diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 2fa045e6b0f6..9102c267d7b0 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -20,6 +20,7 @@ #include "access/nbtree.h" #include "access/subtrans.h" #include "access/syncscan.h" +#include "access/toast_counter.h" #include "access/transam.h" #include "access/twophase.h" #include "access/xlogprefetcher.h" @@ -119,6 +120,7 @@ CalculateShmemSize(int *num_semaphores) size = add_size(size, ProcGlobalShmemSize()); size = add_size(size, XLogPrefetchShmemSize()); size = add_size(size, VarsupShmemSize()); + size = add_size(size, ToastCounterShmemSize()); size = add_size(size, XLOGShmemSize()); size = add_size(size, XLogRecoveryShmemSize()); size = add_size(size, CLOGShmemSize()); @@ -280,8 +282,9 @@ CreateOrAttachShmemStructs(void) DSMRegistryShmemInit(); /* - * Set up xlog, clog, and buffers + * Set up TOAST counter, xlog, clog, and buffers */ + ToastCounterShmemInit(); VarsupShmemInit(); XLOGShmemInit(); XLogPrefetchShmemInit(); diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt index 0be307d2ca04..a36969ac6659 100644 --- a/src/backend/utils/activity/wait_event_names.txt +++ b/src/backend/utils/activity/wait_event_names.txt @@ -352,6 +352,7 @@ DSMRegistry "Waiting to read or update the dynamic shared memory registry." InjectionPoint "Waiting to read or update information related to injection points." SerialControl "Waiting to read or update shared pg_serial state." AioWorkerSubmissionQueue "Waiting to access AIO worker submission queue." +ToastIdGen "Waiting to allocate a new TOAST value ID." # # END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE) diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c index 6d036e3bf328..e4abf8593b8d 100644 --- a/src/backend/utils/misc/pg_controldata.c +++ b/src/backend/utils/misc/pg_controldata.c @@ -69,8 +69,8 @@ pg_control_system(PG_FUNCTION_ARGS) Datum pg_control_checkpoint(PG_FUNCTION_ARGS) { - Datum values[18]; - bool nulls[18]; + Datum values[19]; + bool nulls[19]; TupleDesc tupdesc; HeapTuple htup; ControlFileData *ControlFile; @@ -130,30 +130,33 @@ pg_control_checkpoint(PG_FUNCTION_ARGS) values[9] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMultiOffset); nulls[9] = false; - values[10] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestXid); + values[10] = UInt64GetDatum(ControlFile->checkPointCopy.nextToastId); nulls[10] = false; - values[11] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestXidDB); + values[11] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestXid); nulls[11] = false; - values[12] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestActiveXid); + values[12] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestXidDB); nulls[12] = false; - values[13] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestMulti); + values[13] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestActiveXid); nulls[13] = false; - values[14] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestMultiDB); + values[14] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestMulti); nulls[14] = false; - values[15] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestCommitTsXid); + values[15] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestMultiDB); nulls[15] = false; - values[16] = TransactionIdGetDatum(ControlFile->checkPointCopy.newestCommitTsXid); + values[16] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestCommitTsXid); nulls[16] = false; - values[17] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->checkPointCopy.time)); + values[17] = TransactionIdGetDatum(ControlFile->checkPointCopy.newestCommitTsXid); nulls[17] = false; + values[18] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->checkPointCopy.time)); + nulls[18] = false; + htup = heap_form_tuple(tupdesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(htup)); diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c index 10de058ce91f..99200262b57c 100644 --- a/src/bin/pg_controldata/pg_controldata.c +++ b/src/bin/pg_controldata/pg_controldata.c @@ -266,6 +266,8 @@ main(int argc, char *argv[]) ControlFile->checkPointCopy.nextMulti); printf(_("Latest checkpoint's NextMultiOffset: %u\n"), ControlFile->checkPointCopy.nextMultiOffset); + printf(_("Latest checkpoint's NextToastID: %" PRIu64 "\n"), + ControlFile->checkPointCopy.nextToastId); printf(_("Latest checkpoint's oldestXID: %u\n"), ControlFile->checkPointCopy.oldestXid); printf(_("Latest checkpoint's oldestXID's DB: %u\n"), diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index e876f35f38ed..bb324c710911 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -45,6 +45,7 @@ #include "access/heaptoast.h" #include "access/multixact.h" +#include "access/toast_counter.h" #include "access/transam.h" #include "access/xlog.h" #include "access/xlog_internal.h" @@ -686,6 +687,7 @@ GuessControlValues(void) ControlFile.checkPointCopy.nextOid = FirstGenbkiObjectId; ControlFile.checkPointCopy.nextMulti = FirstMultiXactId; ControlFile.checkPointCopy.nextMultiOffset = 0; + ControlFile.checkPointCopy.nextToastId = FirstToastId; ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId; ControlFile.checkPointCopy.oldestXidDB = InvalidOid; ControlFile.checkPointCopy.oldestMulti = FirstMultiXactId; diff --git a/doc/src/sgml/func/func-info.sgml b/doc/src/sgml/func/func-info.sgml index b507bfaf64b1..9d7548825e5a 100644 --- a/doc/src/sgml/func/func-info.sgml +++ b/doc/src/sgml/func/func-info.sgml @@ -3395,6 +3395,11 @@ acl | {postgres=arwdDxtm/postgres,foo=r/postgres} xid + + next_toast_id + bigint + + oldest_xid xid diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 995dc1f28208..d6bf4e47991b 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -3055,6 +3055,7 @@ TmFromChar TmToChar ToastAttrInfo ToastCompressionId +ToastCounterData ToastTupleContext ToastedAttribute TocEntry -- 2.50.0