From 50a1f91639d16d291ea4f95756a82007bf3849df Mon Sep 17 00:00:00 2001 From: Dean Rasheed Date: Fri, 26 Jun 2026 18:19:33 +0100 Subject: [PATCH v9 01/10] Save temporary table ON COMMIT actions to pg_class. This adds a new column reloncommit to pg_class and uses it to save the ON COMMIT actions of temporary tables. This is then used by psql's \d meta-command to display the table's ON COMMIT action. This will be required by global temporary tables in future commits. --- doc/src/sgml/catalogs.sgml | 16 +++++++++++++ src/backend/bootstrap/bootparse.y | 1 + src/backend/catalog/heap.c | 6 ++++- src/backend/catalog/index.c | 1 + src/backend/utils/cache/relcache.c | 21 ++++++++++++++++- src/bin/psql/describe.c | 36 +++++++++++++++++++++++++++++- src/include/catalog/heap.h | 1 + src/include/catalog/pg_class.h | 9 ++++++++ src/include/utils/relcache.h | 4 +++- src/test/regress/expected/temp.out | 27 ++++++++++++++++++++++ src/test/regress/sql/temp.sql | 8 +++++++ 11 files changed, 126 insertions(+), 4 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 4b474c13917..a6f74f3e861 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -2171,6 +2171,22 @@ SCRAM-SHA-256$<iteration count>:&l + + + reloncommit char + + + The relation's ON COMMIT action: + n = none, + p = preserve rows, + d = delete rows, + D = drop. + Values other than n are only supported for + temporary tables; see + CREATE TABLE. + + + relnatts int2 diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 943ff4733d3..305a5654ff3 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -214,6 +214,7 @@ Boot_CreateStmt: RELPERSISTENCE_PERMANENT, shared_relation, mapped_relation, + ONCOMMIT_NOOP, true, &relfrozenxid, &relminmxid, diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 88087654de9..684a44946fc 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -294,6 +294,7 @@ heap_create(const char *relname, char relpersistence, bool shared_relation, bool mapped_relation, + OnCommitAction oncommit, bool allow_system_table_mods, TransactionId *relfrozenxid, MultiXactId *relminmxid, @@ -371,7 +372,8 @@ heap_create(const char *relname, shared_relation, mapped_relation, relpersistence, - relkind); + relkind, + oncommit); /* * Have the storage manager create the relation's disk file, if needed. @@ -958,6 +960,7 @@ InsertPgClassTuple(Relation pg_class_desc, values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared); values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence); values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind); + values[Anum_pg_class_reloncommit - 1] = CharGetDatum(rd_rel->reloncommit); values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts); values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks); values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules); @@ -1339,6 +1342,7 @@ heap_create_with_catalog(const char *relname, relpersistence, shared_relation, mapped_relation, + oncommit, allow_system_table_mods, &relfrozenxid, &relminmxid, diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 81bba4beac7..da4a7454f22 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -989,6 +989,7 @@ index_create(Relation heapRelation, relpersistence, shared_relation, mapped_relation, + ONCOMMIT_NOOP, allow_system_table_mods, &relfrozenxid, &relminmxid, diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index fb4e042be8a..7df64ac9486 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1952,6 +1952,7 @@ formrdesc(const char *relationName, Oid relationReltype, relation->rd_rel->relallvisible = 0; relation->rd_rel->relallfrozen = 0; relation->rd_rel->relkind = RELKIND_RELATION; + relation->rd_rel->reloncommit = RELONCOMMIT_NONE; relation->rd_rel->relnatts = (int16) natts; /* @@ -3524,7 +3525,8 @@ RelationBuildLocalRelation(const char *relname, bool shared_relation, bool mapped_relation, char relpersistence, - char relkind) + char relkind, + OnCommitAction oncommit) { Relation rel; MemoryContext oldcxt; @@ -3668,6 +3670,23 @@ RelationBuildLocalRelation(const char *relname, break; } + /* set up oncommit action */ + switch (oncommit) + { + case ONCOMMIT_NOOP: + rel->rd_rel->reloncommit = RELONCOMMIT_NONE; + break; + case ONCOMMIT_PRESERVE_ROWS: + rel->rd_rel->reloncommit = RELONCOMMIT_PRESERVE_ROWS; + break; + case ONCOMMIT_DELETE_ROWS: + rel->rd_rel->reloncommit = RELONCOMMIT_DELETE_ROWS; + break; + case ONCOMMIT_DROP: + rel->rd_rel->reloncommit = RELONCOMMIT_DROP; + break; + } + /* if it's a materialized view, it's not populated initially */ if (relkind == RELKIND_MATVIEW) rel->rd_rel->relispopulated = false; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index a2f09c26369..44d81ee4cce 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -1580,6 +1580,7 @@ describeOneTableDetails(const char *schemaname, char relpersistence; char relreplident; char *relam; + char reloncommit; } tableinfo; bool show_column_details = false; @@ -1594,7 +1595,25 @@ describeOneTableDetails(const char *schemaname, /* Get general table info */ printfPQExpBuffer(&buf, "/* %s */\n", _("Get general information about one relation")); - if (pset.sversion >= 120000) + if (pset.sversion >= 200000) + { + appendPQExpBuffer(&buf, + "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, " + "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, " + "false AS relhasoids, c.relispartition, %s, c.reltablespace, " + "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, " + "c.relpersistence, c.relreplident, am.amname, c.reloncommit\n" + "FROM pg_catalog.pg_class c\n " + "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n" + "LEFT JOIN pg_catalog.pg_am am ON (c.relam = am.oid)\n" + "WHERE c.oid = '%s';", + (verbose ? + "pg_catalog.array_to_string(c.reloptions || " + "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n" + : "''"), + oid); + } + else if (pset.sversion >= 120000) { appendPQExpBuffer(&buf, "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, " @@ -1662,6 +1681,10 @@ describeOneTableDetails(const char *schemaname, NULL : pg_strdup(PQgetvalue(res, 0, 14)); else tableinfo.relam = NULL; + if (pset.sversion >= 200000) + tableinfo.reloncommit = *(PQgetvalue(res, 0, 15)); + else + tableinfo.reloncommit = RELONCOMMIT_NONE; PQclear(res); res = NULL; @@ -3680,6 +3703,17 @@ describeOneTableDetails(const char *schemaname, printfPQExpBuffer(&buf, _("Access method: %s"), tableinfo.relam); printTableAddFooter(&cont, buf.data); } + + /* On-commit action */ + if (verbose && tableinfo.reloncommit != RELONCOMMIT_NONE) + { + printfPQExpBuffer(&buf, _("On-commit action: %s"), + tableinfo.reloncommit == RELONCOMMIT_PRESERVE_ROWS ? "PRESERVE ROWS" : + tableinfo.reloncommit == RELONCOMMIT_DELETE_ROWS ? "DELETE ROWS" : + tableinfo.reloncommit == RELONCOMMIT_DROP ? "DROP" : + "???"); + printTableAddFooter(&cont, buf.data); + } } /* reloptions, if verbose */ diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 6c9ac812aa0..a622d703e97 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -59,6 +59,7 @@ extern Relation heap_create(const char *relname, char relpersistence, bool shared_relation, bool mapped_relation, + OnCommitAction oncommit, bool allow_system_table_mods, TransactionId *relfrozenxid, MultiXactId *relminmxid, diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index c4af599dc90..c5e84816127 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -88,6 +88,9 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat /* see RELKIND_xxx constants below */ char relkind BKI_DEFAULT(r); + /* see RELONCOMMIT_xxx constants below */ + char reloncommit BKI_DEFAULT(n); + /* number of user attributes */ int16 relnatts BKI_DEFAULT(0); /* genbki.pl will fill this in */ @@ -184,6 +187,12 @@ MAKE_SYSCACHE(RELNAMENSP, pg_class_relname_nsp_index, 128); #define RELPERSISTENCE_UNLOGGED 'u' /* unlogged permanent table */ #define RELPERSISTENCE_TEMP 't' /* temporary table */ +/* on-commit action; only temporary tables support values other than 'n' */ +#define RELONCOMMIT_NONE 'n' /* default: no action */ +#define RELONCOMMIT_PRESERVE_ROWS 'p' /* keep table rows on commit */ +#define RELONCOMMIT_DELETE_ROWS 'd' /* delete table rows on commit */ +#define RELONCOMMIT_DROP 'D' /* drop table on commit */ + /* default selection for replica identity (primary key or nothing) */ #define REPLICA_IDENTITY_DEFAULT 'd' /* no replica identity is logged for this relation */ diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 89c27aa1529..ed09a699e8b 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -17,6 +17,7 @@ #include "access/tupdesc.h" #include "common/relpath.h" #include "nodes/bitmapset.h" +#include "nodes/primnodes.h" /* @@ -121,7 +122,8 @@ extern Relation RelationBuildLocalRelation(const char *relname, bool shared_relation, bool mapped_relation, char relpersistence, - char relkind); + char relkind, + OnCommitAction oncommit); /* * Routines to manage assignment of new relfilenumber to a relation diff --git a/src/test/regress/expected/temp.out b/src/test/regress/expected/temp.out index a50c7ae88a9..77c9bbf7364 100644 --- a/src/test/regress/expected/temp.out +++ b/src/test/regress/expected/temp.out @@ -42,6 +42,12 @@ SELECT * FROM temptest; DROP TABLE temptest; -- test temp table deletion CREATE TEMP TABLE temptest(col int); +SELECT reloncommit FROM pg_class WHERE oid = 'temptest'::regclass; + reloncommit +------------- + n +(1 row) + \c SELECT * FROM temptest; ERROR: relation "temptest" does not exist @@ -49,6 +55,12 @@ LINE 1: SELECT * FROM temptest; ^ -- Test ON COMMIT DELETE ROWS CREATE TEMP TABLE temptest(col int) ON COMMIT DELETE ROWS; +SELECT reloncommit FROM pg_class WHERE oid = 'temptest'::regclass; + reloncommit +------------- + d +(1 row) + -- while we're here, verify successful truncation of index with SQL function CREATE INDEX ON temptest(bit_length('')); BEGIN; @@ -86,6 +98,12 @@ DROP TABLE temptest; -- Test ON COMMIT DROP BEGIN; CREATE TEMP TABLE temptest(col int) ON COMMIT DROP; +SELECT reloncommit FROM pg_class WHERE oid = 'temptest'::regclass; + reloncommit +------------- + D +(1 row) + INSERT INTO temptest VALUES (1); INSERT INTO temptest VALUES (2); SELECT * FROM temptest; @@ -284,6 +302,15 @@ create temp table temp_parted_oncommit_test1 create temp table temp_parted_oncommit_test2 partition of temp_parted_oncommit_test for values in (2) on commit drop; +select relname, reloncommit from pg_class + where relname ~ 'temp_parted_oncommit_test' order by relname; + relname | reloncommit +----------------------------+------------- + temp_parted_oncommit_test | d + temp_parted_oncommit_test1 | p + temp_parted_oncommit_test2 | D +(3 rows) + insert into temp_parted_oncommit_test values (1), (2); commit; -- Data from the remaining partition is still here as its rows are diff --git a/src/test/regress/sql/temp.sql b/src/test/regress/sql/temp.sql index d50472ddced..c8801c7ef5f 100644 --- a/src/test/regress/sql/temp.sql +++ b/src/test/regress/sql/temp.sql @@ -47,6 +47,8 @@ DROP TABLE temptest; CREATE TEMP TABLE temptest(col int); +SELECT reloncommit FROM pg_class WHERE oid = 'temptest'::regclass; + \c SELECT * FROM temptest; @@ -55,6 +57,8 @@ SELECT * FROM temptest; CREATE TEMP TABLE temptest(col int) ON COMMIT DELETE ROWS; +SELECT reloncommit FROM pg_class WHERE oid = 'temptest'::regclass; + -- while we're here, verify successful truncation of index with SQL function CREATE INDEX ON temptest(bit_length('')); @@ -85,6 +89,8 @@ BEGIN; CREATE TEMP TABLE temptest(col int) ON COMMIT DROP; +SELECT reloncommit FROM pg_class WHERE oid = 'temptest'::regclass; + INSERT INTO temptest VALUES (1); INSERT INTO temptest VALUES (2); @@ -223,6 +229,8 @@ create temp table temp_parted_oncommit_test1 create temp table temp_parted_oncommit_test2 partition of temp_parted_oncommit_test for values in (2) on commit drop; +select relname, reloncommit from pg_class + where relname ~ 'temp_parted_oncommit_test' order by relname; insert into temp_parted_oncommit_test values (1), (2); commit; -- Data from the remaining partition is still here as its rows are -- 2.51.0