From: David Rowley Date: Sun, 15 Mar 2026 22:45:49 +0000 (+1300) Subject: Add all required calls to TupleDescFinalize() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=503620311e3fc127708b00d4cd7eff6fd3154753;p=thirdparty%2Fpostgresql.git Add all required calls to TupleDescFinalize() As of this commit all TupleDescs must have TupleDescFinalize() called on them once the TupleDesc is set up and before BlessTupleDesc() is called. In this commit, TupleDescFinalize() does nothing. This change has only been separated out from the commit that properly implements this function to make the change more obvious. Any extension which makes its own TupleDesc will need to be modified to call the new function. The follow-up commit which properly implements TupleDescFinalize() will cause any code which forgets to do this to fail in assert-enabled builds in BlessTupleDesc(). It may still be worth mentioning this change in the release notes so that extension authors update their code. Author: David Rowley Reviewed-by: Chao Li Reviewed-by: Andres Freund Reviewed-by: John Naylor Reviewed-by: Amit Langote Reviewed-by: Zsolt Parragi Reviewed-by: Álvaro Herrera Reviewed-by: Junwang Zhao Discussion: https://postgr.es/m/CAApHDvpoFjaj3%2Bw_jD5uPnGazaw41A71tVJokLDJg2zfcigpMQ%40mail.gmail.com --- diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 2498d80c8e7..4038950a6ef 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -881,6 +881,7 @@ materializeResult(FunctionCallInfo fcinfo, PGconn *conn, PGresult *res) tupdesc = CreateTemplateTupleDesc(1); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status", TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); ntuples = 1; nfields = 1; } @@ -1044,6 +1045,7 @@ materializeQueryResult(FunctionCallInfo fcinfo, tupdesc = CreateTemplateTupleDesc(1); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status", TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); attinmeta = TupleDescGetAttInMetadata(tupdesc); oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); @@ -1529,6 +1531,8 @@ dblink_get_pkey(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 2, "colname", TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); + /* * Generate attribute metadata needed later to produce tuples from raw * C strings diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 89b86855243..a6b4fb5252b 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -174,6 +174,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) TupleDescInitEntry(tupledesc, (AttrNumber) 9, "pinning_backends", INT4OID, -1, 0); + TupleDescFinalize(tupledesc); fctx->tupdesc = BlessTupleDesc(tupledesc); /* Allocate NBuffers worth of BufferCachePagesRec records. */ @@ -442,6 +443,7 @@ pg_buffercache_os_pages_internal(FunctionCallInfo fcinfo, bool include_numa) TupleDescInitEntry(tupledesc, (AttrNumber) 3, "numa_node", INT4OID, -1, 0); + TupleDescFinalize(tupledesc); fctx->tupdesc = BlessTupleDesc(tupledesc); fctx->include_numa = include_numa; diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index 9bc3a784bf7..dfab0b64cf5 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -469,6 +469,8 @@ pg_visibility_tupdesc(bool include_blkno, bool include_pd) TupleDescInitEntry(tupdesc, ++a, "pd_all_visible", BOOLOID, -1, 0); Assert(a == maxattr); + TupleDescFinalize(tupdesc); + return BlessTupleDesc(tupdesc); } diff --git a/src/backend/access/brin/brin_tuple.c b/src/backend/access/brin/brin_tuple.c index 69c233c62eb..742ac089a28 100644 --- a/src/backend/access/brin/brin_tuple.c +++ b/src/backend/access/brin/brin_tuple.c @@ -84,6 +84,7 @@ brtuple_disk_tupdesc(BrinDesc *brdesc) MemoryContextSwitchTo(oldcxt); + TupleDescFinalize(tupdesc); brdesc->bd_disktdesc = tupdesc; } diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index b69d10f0a45..2137385a833 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -221,6 +221,9 @@ CreateTupleDesc(int natts, Form_pg_attribute *attrs) memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE); populate_compact_attribute(desc, i); } + + TupleDescFinalize(desc); + return desc; } @@ -265,6 +268,8 @@ CreateTupleDescCopy(TupleDesc tupdesc) desc->tdtypeid = tupdesc->tdtypeid; desc->tdtypmod = tupdesc->tdtypmod; + TupleDescFinalize(desc); + return desc; } @@ -311,6 +316,8 @@ CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts) desc->tdtypeid = tupdesc->tdtypeid; desc->tdtypmod = tupdesc->tdtypmod; + TupleDescFinalize(desc); + return desc; } @@ -396,6 +403,8 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) desc->tdtypeid = tupdesc->tdtypeid; desc->tdtypmod = tupdesc->tdtypmod; + TupleDescFinalize(desc); + return desc; } @@ -438,6 +447,8 @@ TupleDescCopy(TupleDesc dst, TupleDesc src) * source's refcount would be wrong in any case.) */ dst->tdrefcount = -1; + + TupleDescFinalize(dst); } /* @@ -1065,6 +1076,8 @@ BuildDescFromLists(const List *names, const List *types, const List *typmods, co TupleDescInitEntryCollation(desc, attnum, attcollation); } + TupleDescFinalize(desc); + return desc; } diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index ff927279cc3..fe7b984ff32 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -129,6 +129,7 @@ initGinState(GinState *state, Relation index) attr->attndims); TupleDescInitEntryCollation(state->tupdesc[i], (AttrNumber) 2, attr->attcollation); + TupleDescFinalize(state->tupdesc[i]); } /* diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c index f23bc4a6757..c65f93abdae 100644 --- a/src/backend/access/gist/gistscan.c +++ b/src/backend/access/gist/gistscan.c @@ -201,6 +201,7 @@ gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, attno - 1)->atttypid, -1, 0); } + TupleDescFinalize(so->giststate->fetchTupdesc); scan->xs_hitupdesc = so->giststate->fetchTupdesc; /* Also create a memory context that will hold the returned tuples */ diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 9f5379b87ac..b246e8127db 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -340,6 +340,7 @@ getSpGistTupleDesc(Relation index, SpGistTypeDesc *keyType) TupleDescCompactAttr(outTupDesc, i)->attcacheoff = -1; populate_compact_attribute(outTupDesc, spgKeyColumn); + TupleDescFinalize(outTupDesc); } return outTupDesc; } diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 55b9f38927d..d468c9774b3 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -745,6 +745,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 5, "dbid", OIDOID, -1, 0); + TupleDescFinalize(tupdesc); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index ecb3c8c0820..4e35311b2f3 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -430,6 +430,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS) TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset", INT4OID, -1, 0); + TupleDescFinalize(resultTupleDesc); resultTupleDesc = BlessTupleDesc(resultTupleDesc); /* diff --git a/src/backend/backup/basebackup_copy.c b/src/backend/backup/basebackup_copy.c index 07f58b39d8c..6c3453efd80 100644 --- a/src/backend/backup/basebackup_copy.c +++ b/src/backend/backup/basebackup_copy.c @@ -357,6 +357,8 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli) */ TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "tli", INT8OID, -1, 0); + TupleDescFinalize(tupdesc); + /* send RowDescription */ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); @@ -388,6 +390,7 @@ SendTablespaceList(List *tablespaces) TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "spcoid", OIDOID, -1, 0); TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "spclocation", TEXTOID, -1, 0); TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "size", INT8OID, -1, 0); + TupleDescFinalize(tupdesc); /* send RowDescription */ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 5ee6389d39c..0e93ababa87 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -481,6 +481,8 @@ ConstructTupleDescriptor(Relation heapRelation, populate_compact_attribute(indexTupDesc, i); } + TupleDescFinalize(indexTupDesc); + return indexTupDesc; } diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index aadc7c202c6..a79157c43bf 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -1322,6 +1322,7 @@ pg_get_publication_tables(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 4, "qual", PG_NODE_TREEOID, -1, 0); + TupleDescFinalize(tupdesc); funcctx->tuple_desc = BlessTupleDesc(tupdesc); funcctx->user_fctx = table_infos; diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index c78dcea98c1..078a1cf5127 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -229,6 +229,12 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, TupleDescAttr(tupdesc, 1)->attcompression = InvalidCompressionMethod; TupleDescAttr(tupdesc, 2)->attcompression = InvalidCompressionMethod; + populate_compact_attribute(tupdesc, 0); + populate_compact_attribute(tupdesc, 1); + populate_compact_attribute(tupdesc, 2); + + TupleDescFinalize(tupdesc); + /* * Toast tables for regular relations go in pg_toast; those for temp * relations go into the per-backend temp-toast-table namespace. diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 93918a223b8..5f922c3f5c2 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -281,6 +281,7 @@ ExplainResultDesc(ExplainStmt *stmt) tupdesc = CreateTemplateTupleDesc(1); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN", result_type, -1, 0); + TupleDescFinalize(tupdesc); return tupdesc; } diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 242372b1e68..3afd762e9dc 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -2424,6 +2424,7 @@ CallStmtResultDesc(CallStmt *stmt) -1, 0); } + TupleDescFinalize(tupdesc); } return tupdesc; diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index e1b808bbb60..551667650ba 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -1808,6 +1808,7 @@ pg_get_sequence_data(PG_FUNCTION_ARGS) BOOLOID, -1, 0); TupleDescInitEntry(resultTupleDesc, (AttrNumber) 3, "page_lsn", LSNOID, -1, 0); + TupleDescFinalize(resultTupleDesc); resultTupleDesc = BlessTupleDesc(resultTupleDesc); seqrel = try_relation_open(relid, AccessShareLock); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index cd6d720386f..a2e3b72f156 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1038,6 +1038,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, } } + TupleDescFinalize(descriptor); + /* * For relations with table AM and partitioned tables, select access * method to use: an explicitly indicated one, or (in the case of a @@ -1466,6 +1468,8 @@ BuildDescForRelation(const List *columns) populate_compact_attribute(desc, attnum - 1); } + TupleDescFinalize(desc); + return desc; } diff --git a/src/backend/commands/wait.c b/src/backend/commands/wait.c index 1290df10c6f..8e920a72372 100644 --- a/src/backend/commands/wait.c +++ b/src/backend/commands/wait.c @@ -338,5 +338,6 @@ WaitStmtResultDesc(WaitStmt *stmt) tupdesc = CreateTemplateTupleDesc(1); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status", TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); return tupdesc; } diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c index a0b111dc0e4..b481e50acfb 100644 --- a/src/backend/executor/execSRF.c +++ b/src/backend/executor/execSRF.c @@ -272,6 +272,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, funcrettype, -1, 0); + TupleDescFinalize(tupdesc); rsinfo.setDesc = tupdesc; } MemoryContextSwitchTo(oldcontext); @@ -776,6 +777,7 @@ init_sexpr(Oid foid, Oid input_collation, Expr *node, funcrettype, -1, 0); + TupleDescFinalize(tupdesc); sexpr->funcResultDesc = tupdesc; sexpr->funcReturnsTuple = false; } diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 7effe954286..07b248aa5f3 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -2175,6 +2175,8 @@ ExecTypeFromTLInternal(List *targetList, bool skipjunk) cur_resno++; } + TupleDescFinalize(typeInfo); + return typeInfo; } @@ -2209,6 +2211,8 @@ ExecTypeFromExprList(List *exprList) cur_resno++; } + TupleDescFinalize(typeInfo); + return typeInfo; } diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index 63e605e1f81..feb82d64967 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -414,6 +414,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) TupleDescInitEntryCollation(tupdesc, (AttrNumber) 1, exprCollation(funcexpr)); + TupleDescFinalize(tupdesc); } else { @@ -485,6 +486,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) 0); } + TupleDescFinalize(scan_tupdesc); Assert(attno == natts); } diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index e003db520de..9c415e166ee 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -1883,6 +1883,7 @@ addRangeTableEntryForFunction(ParseState *pstate, TupleDescInitEntryCollation(tupdesc, (AttrNumber) 1, exprCollation(funcexpr)); + TupleDescFinalize(tupdesc); } else if (functypclass == TYPEFUNC_RECORD) { @@ -1940,6 +1941,7 @@ addRangeTableEntryForFunction(ParseState *pstate, i++; } + TupleDescFinalize(tupdesc); /* * Ensure that the coldeflist defines a legal set of names (no @@ -2008,7 +2010,7 @@ addRangeTableEntryForFunction(ParseState *pstate, 0); /* no need to set collation */ } - + TupleDescFinalize(tupdesc); Assert(natts == totalatts); } else diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 3bcfc1f5e3d..f57c4d41080 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -1572,6 +1572,8 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup) } Assert(lname == NULL && lvar == NULL); /* lists same length? */ + TupleDescFinalize(tupleDesc); + return tupleDesc; } diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c index 7c8639b32e9..9f04c9ed25d 100644 --- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c +++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c @@ -1073,6 +1073,7 @@ libpqrcv_processTuples(PGresult *pgres, WalRcvExecResult *walres, for (coln = 0; coln < nRetTypes; coln++) TupleDescInitEntry(walres->tupledesc, (AttrNumber) coln + 1, PQfname(pgres, coln), retTypes[coln], -1, 0); + TupleDescFinalize(walres->tupledesc); attinmeta = TupleDescGetAttInMetadata(walres->tupledesc); /* No point in doing more here if there were no tuples returned. */ diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 79fc192b171..376ff46340d 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -452,6 +452,7 @@ IdentifySystem(void) TEXTOID, -1, 0); TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 4, "dbname", TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); /* prepare for projection of tuples */ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); @@ -497,6 +498,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd) /* TimeLineID is unsigned, so int4 is not wide enough. */ TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "restart_tli", INT8OID, -1, 0); + TupleDescFinalize(tupdesc); memset(nulls, true, READ_REPLICATION_SLOT_COLS * sizeof(bool)); @@ -599,6 +601,7 @@ SendTimeLineHistory(TimeLineHistoryCmd *cmd) tupdesc = CreateTemplateTupleDesc(2); TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "filename", TEXTOID, -1, 0); TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "content", TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); TLHistoryFileName(histfname, cmd->timeline); TLHistoryFilePath(path, cmd->timeline); @@ -1016,6 +1019,7 @@ StartReplication(StartReplicationCmd *cmd) INT8OID, -1, 0); TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "next_tli_startpos", TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); /* prepare for projection of tuple */ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); @@ -1370,6 +1374,7 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd) TEXTOID, -1, 0); TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 4, "output_plugin", TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); /* prepare for projection of tuples */ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 9e82c1fc1a1..fc2e9f6686a 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -1841,6 +1841,7 @@ aclexplode(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable", BOOLOID, -1, 0); + TupleDescFinalize(tupdesc); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* allocate memory for user context */ diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index c083608b1d5..bfb949401d0 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -454,6 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS) "creation", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "isdir", BOOLOID, -1, 0); + TupleDescFinalize(tupdesc); BlessTupleDesc(tupdesc); memset(isnull, false, sizeof(isnull)); diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 9dadd6da672..4481c354fd6 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -146,6 +146,7 @@ pg_lock_status(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart", TIMESTAMPTZOID, -1, 0); + TupleDescFinalize(tupdesc); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* diff --git a/src/backend/utils/adt/orderedsetaggs.c b/src/backend/utils/adt/orderedsetaggs.c index 3b6da8e36ac..fd8b8676470 100644 --- a/src/backend/utils/adt/orderedsetaggs.c +++ b/src/backend/utils/adt/orderedsetaggs.c @@ -233,6 +233,7 @@ ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples) -1, 0); + TupleDescFinalize(newdesc); FreeTupleDesc(qstate->tupdesc); qstate->tupdesc = newdesc; } diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 5ac022274a7..bad5642d9c9 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -770,6 +770,7 @@ pg_stat_get_backend_subxact(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 2, "subxact_overflow", BOOLOID, -1, 0); + TupleDescFinalize(tupdesc); BlessTupleDesc(tupdesc); if ((local_beentry = pgstat_get_local_beentry_by_proc_number(procNumber)) != NULL) @@ -1671,6 +1672,7 @@ pg_stat_wal_build_tuple(PgStat_WalCounters wal_counters, TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stats_reset", TIMESTAMPTZOID, -1, 0); + TupleDescFinalize(tupdesc); BlessTupleDesc(tupdesc); /* Fill values and NULLs */ @@ -2098,6 +2100,7 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset", TIMESTAMPTZOID, -1, 0); + TupleDescFinalize(tupdesc); BlessTupleDesc(tupdesc); /* Get statistics about the archiver process */ @@ -2179,6 +2182,7 @@ pg_stat_get_replication_slot(PG_FUNCTION_ARGS) TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 13, "stats_reset", TIMESTAMPTZOID, -1, 0); + TupleDescFinalize(tupdesc); BlessTupleDesc(tupdesc); namestrcpy(&slotname, text_to_cstring(slotname_text)); @@ -2266,6 +2270,7 @@ pg_stat_get_subscription_stats(PG_FUNCTION_ARGS) INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 13, "stats_reset", TIMESTAMPTZOID, -1, 0); + TupleDescFinalize(tupdesc); BlessTupleDesc(tupdesc); if (!subentry) diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c index 71c7c7d3b3c..d8dece42b9b 100644 --- a/src/backend/utils/adt/tsvector_op.c +++ b/src/backend/utils/adt/tsvector_op.c @@ -651,6 +651,7 @@ tsvector_unnest(PG_FUNCTION_ARGS) TEXTARRAYOID, -1, 0); if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); + TupleDescFinalize(tupdesc); funcctx->tuple_desc = tupdesc; funcctx->user_fctx = PG_GETARG_TSVECTOR_COPY(0); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index a1c88c6b1b6..d27ac216e6d 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -729,6 +729,8 @@ RelationBuildTupleDesc(Relation relation) pfree(constr); relation->rd_att->constr = NULL; } + + TupleDescFinalize(relation->rd_att); } /* @@ -1985,6 +1987,7 @@ formrdesc(const char *relationName, Oid relationReltype, /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ TupleDescCompactAttr(relation->rd_att, 0)->attcacheoff = 0; + TupleDescFinalize(relation->rd_att); /* mark not-null status */ if (has_not_null) @@ -3688,6 +3691,8 @@ RelationBuildLocalRelation(const char *relname, for (i = 0; i < natts; i++) TupleDescAttr(rel->rd_att, i)->attrelid = relid; + TupleDescFinalize(rel->rd_att); + rel->rd_rel->reltablespace = reltablespace; if (mapped_relation) @@ -4443,6 +4448,7 @@ BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs) /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ TupleDescCompactAttr(result, 0)->attcacheoff = 0; + TupleDescFinalize(result); /* Note: we don't bother to set up a TupleConstr entry */ @@ -6291,6 +6297,8 @@ load_relcache_init_file(bool shared) populate_compact_attribute(rel->rd_att, i); } + TupleDescFinalize(rel->rd_att); + /* next read the access method specific field */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index 8a934ea8dca..516d02cfb82 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -340,6 +340,8 @@ get_expr_result_type(Node *expr, exprCollation(col)); i++; } + TupleDescFinalize(tupdesc); + if (resultTypeId) *resultTypeId = rexpr->row_typeid; if (resultTupleDesc) @@ -1044,6 +1046,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, } } + TupleDescFinalize(tupdesc); return true; } @@ -1853,6 +1856,8 @@ build_function_result_tupdesc_d(char prokind, 0); } + TupleDescFinalize(desc); + return desc; } @@ -1970,6 +1975,7 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases) typeoid, -1, 0); + TupleDescFinalize(tupdesc); } else if (functypclass == TYPEFUNC_RECORD) { diff --git a/src/backend/utils/misc/guc_funcs.c b/src/backend/utils/misc/guc_funcs.c index 8524dd3a981..472cb5393ce 100644 --- a/src/backend/utils/misc/guc_funcs.c +++ b/src/backend/utils/misc/guc_funcs.c @@ -444,6 +444,7 @@ GetPGVariableResultDesc(const char *name) TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, TEXTOID, -1, 0); } + TupleDescFinalize(tupdesc); return tupdesc; } @@ -465,6 +466,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest) tupdesc = CreateTemplateTupleDesc(1); TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, varname, TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); /* prepare for projection of tuples */ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); @@ -499,6 +501,7 @@ ShowAllGUCConfig(DestReceiver *dest) TEXTOID, -1, 0); TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "description", TEXTOID, -1, 0); + TupleDescFinalize(tupdesc); /* prepare for projection of tuples */ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); @@ -934,6 +937,8 @@ show_all_settings(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 17, "pending_restart", BOOLOID, -1, 0); + TupleDescFinalize(tupdesc); + /* * Generate attribute metadata needed later to produce tuples from raw * C strings diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index d46cdbf7a3c..595413dbbc5 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -195,6 +195,7 @@ extern TupleDesc CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts); extern TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc); +#define TupleDescFinalize(d) ((void) 0) #define TupleDescSize(src) \ (offsetof(struct TupleDescData, compact_attrs) + \ (src)->natts * sizeof(CompactAttribute) + \ diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 5ecc7766757..b72c963b3be 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -1912,6 +1912,8 @@ build_row_from_vars(PLpgSQL_variable **vars, int numvars) TupleDescInitEntryCollation(row->rowtupdesc, i + 1, typcoll); } + TupleDescFinalize(row->rowtupdesc); + return row; } diff --git a/src/test/modules/test_custom_stats/test_custom_fixed_stats.c b/src/test/modules/test_custom_stats/test_custom_fixed_stats.c index 485e08e5c19..f9e7c717280 100644 --- a/src/test/modules/test_custom_stats/test_custom_fixed_stats.c +++ b/src/test/modules/test_custom_stats/test_custom_fixed_stats.c @@ -206,6 +206,7 @@ test_custom_stats_fixed_report(PG_FUNCTION_ARGS) INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "stats_reset", TIMESTAMPTZOID, -1, 0); + TupleDescFinalize(tupdesc); BlessTupleDesc(tupdesc); values[0] = Int64GetDatum(stats->numcalls); diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c index 679a5de456d..48ca2a4ea70 100644 --- a/src/test/modules/test_predtest/test_predtest.c +++ b/src/test/modules/test_predtest/test_predtest.c @@ -230,6 +230,7 @@ test_predtest(PG_FUNCTION_ARGS) "s_r_holds", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 8, "w_r_holds", BOOLOID, -1, 0); + TupleDescFinalize(tupdesc); tupdesc = BlessTupleDesc(tupdesc); values[0] = BoolGetDatum(strong_implied_by);