Re: Global temporary tables

From: Haibo Yan <tristan(dot)yim(at)gmail(dot)com>
To: Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com>
Cc: Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org, Japin Li <japinli(at)hotmail(dot)com>, Kirk Wolak <wolakk(at)gmail(dot)com>
Subject: Re: Global temporary tables
Date: 2026-09-09 02:18:13
Message-ID: CABXr29FsL7FF7A8n07MpM_7fs5vou4GuKCjitQaZoVTrDxBbeg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Wed, Sep 2, 2026 at 1:09 AM Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com> wrote:
>
> On Wed, 15 Jul 2026 at 08:57, Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com> wrote:
> >
> > I'll put the patch back to WoA, until I've had a chance to look at these issues.
> >
>
> It looks like I'm not going to have any time for Postgres work for at
> least the first week of this commitfest, and when I do get back to it,
> my focus will probably be on v19 open items, so I might just move this
> patch to the next commitfest.
>
> I did, however, do some work on it after the last commitfest, so I'm
> attaching that, just as a record of where I got to. As far as I can
> remember, I fixed all the outstanding issues, and I also added a few
> new tests and documentation, and a new patch implementing DISCARD
> GLOBAL TEMP.
>
> The biggest change I made was refactoring the pending inserts queue
> into a new cache, which eliminated a lot of code duplication. However,
> I'm not happy with where that ended up -- in particular, the flushing
> code feels like a fragile hack. Having convinced myself that the
> contents of pg_temp_class and pg_temp_index have to be kept in memory
> for the duration of the session (or at least, beyond a single
> transaction, to support things like rollback of sequence
> initialization), I'm now inclined to think that it would be better to
> just get rid of pg_temp_class and pg_temp_index, and have SQL-callable
> functions to allow users to retrieve that data, if they need it. By
> contrast, I still think having pg_temp_statistic and
> pg_temp_statistic_ext_data is valuable, because (a) they're likely to
> contain much more data (e.g., MCV lists), (b) I think they're much
> more likely to be queried by users, and (c) having them in their
> current form makes the backend code that uses stats for GTTs very
> simple.

Hi Dean,

I followed up on your comment in v10 that pg_temp_class and
pg_temp_index might be better removed, with the session-local state kept
in memory instead.

I traced the lifetime and transaction semantics of the two catalogs in the
v10 code, and then tried implementing that direction. The attached two
patches are incremental review patches on top of your v10 series; they are
not intended to replace or renumber the GTT series.

The first patch removes pg_temp_class and stores the backend-local
physical/statistics/freeze state directly in GtrUsageEntry.

The main reason I think this is a cleaner representation is that, in the v10
implementation, the lifetime of a pg_temp_class row and the lifetime of
the corresponding GtrUsageEntry are effectively identical. They are
created from the same relation-tracking paths and removed from the same
drop/invalidation/DISCARD paths. I could not find a case where the
pg_temp_class state has an independent lifetime.

So keeping a second catalog row, plus the machinery required to cache and
flush it, seems to duplicate state that the backend already owns for exactly
the same lifetime.

The physical state moved into GtrUsageEntry includes the fields that were
previously supplied by pg_temp_class, such as relpages, reltuples,
visibility/freeze information, reltablespace, and relfilenode.

There are two update paths:

* transactional updates, used by DDL, with subtransaction history so that
SAVEPOINT rollback restores the previous state; and
* in-place updates for VACUUM/ANALYZE-style statistics changes, matching
the non-transactional behavior of the corresponding ordinary-table
catalog updates.

The second patch removes pg_temp_index and the remaining gtcatcache
machinery.

Although the only session-local value in pg_temp_index is indisvalid,
I don’t think it can safely be represented as just an Oid -> bool map.
All of the writers are transactional DDL paths. In particular, an
indisvalid change made inside a subtransaction has to be undone if that
subtransaction aborts.

The patch therefore keeps the current value together with the
SubTransactionId that last changed it and a small history chain for
rollback. For example, an ALTER INDEX ... ATTACH PARTITION that changes
a partitioned index from invalid to valid inside a SAVEPOINT will restore
the previous validity state on rollback.

I also tried to keep the change centralized rather than adding GTT-specific
branches to planner or executor code.

ScanPgRelation() overlays the backend-local physical state when building
rd_rel, and RelationInitIndexAccessInfo() /
RelationGetIndexList() overlay the local indisvalid state. For the
few places that need a catalog tuple without opening a Relation, the
patches provide effective pg_class / pg_index tuple helpers.

I audited the raw RELOID syscache callers that could potentially bypass
the pg_class overlay, and the indisvalid consumers and writers. I
didn’t find an in-backend consumer that still reads one of these
session-local values through an un-overlaid path.

psql’s same-session \d / \di behavior is preserved using
pg_gtt_index_isvalid(). The existing direct pg_index reads in tools
such as pg_dump, pg_upgrade, and pg_amcheck remain as they were in v10;
those tools were not using pg_temp_index in v10 either.

I left pg_temp_statistic and pg_temp_statistic_ext_data unchanged.
They carry substantially more data and fit the existing statistics tuple
interfaces much better, so I don’t think the same argument automatically
applies to them.

I tested the two patches both separately and together.

On an assertion/debug build:

patch 1 applies and builds independently, with 244/244 regression tests;
patch 1 + patch 2 applies and builds cleanly;
full Meson test: 403 total, 363 passed, 0 failed, 40 skipped;
regression: 244/244;
isolation: 134/134;
GTT subscription TAP test: 4/4;
GTT checksum TAP test: 6/6;
targeted tests with debug_discard_caches = 1 passed;
nested SAVEPOINT rollback tests for relation physical state passed
through multiple subtransaction levels;
transactional indisvalid rollback was tested using partitioned-index
ATTACH;
a cross-backend DROP while another backend had pending local state was
also tested;
an ASAN+UBSAN build and the relevant targeted tests completed without
sanitizer reports.

The patches were also run through pgindent and git diff --check.

There are a few things I deliberately did not address in these patches.

First, while testing I found a pre-existing v10 issue where creating a
global temporary sequence and then rolling the creation back can leave a
local usage entry behind. I have a small separate fix for that, but I
left it out of these patches so that this series remains only about
removing pg_temp_class / pg_temp_index.

I also did not try to address the previously discussed GTT inheritance
case, the broader frozen-XID/autovacuum policy questions, or the missing
Meson wiring for the two existing GTT TAP tests.

So, as far as I can tell, the two attached patches change the
representation of the backend-local relation/index state without changing
the intended v10 semantics.

I’d be interested in whether this matches the direction you had in mind
when you mentioned removing pg_temp_class and pg_temp_index, and in
particular whether you see any reason to keep either of those catalogs
rather than folding this state into the existing backend-local GTT state.

>
> Regards,
> Dean

Regards,
Haibo

Attachment Content-Type Size
gtt-v10-review-0001-Remove-pg_temp_class-in-favor-of-backend-local-GTT-state.patch application/octet-stream 155.2 KB
gtt-v10-review-0002-Remove-pg_temp_index-and-gtcatcache-in-favor-of-backend-local-state.patch application/octet-stream 90.0 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Ayoub Kazar 2026-09-09 02:37:54 Re: Add pg_stat_vfdcache view for VFD cache statistics
Previous Message shihao zhong 2026-09-09 02:05:31 Re: pgbench: \gset and \aset should store SQL NULL as the null value