From 35a0aa0000eac9ec7b5a209b38048d591b73ce3a Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Fri, 24 Jul 2026 18:49:04 +0900 Subject: [PATCH v2 5/6] Begin RI fast-path index scan under the switched user id ri_FastPathCheck() called index_beginscan() before switching to the referenced relation's owner for the permission check and probe. For btree this has no consequence, but starting the scan before the user id switch sets a poor example for code dealing with out-of-tree access methods, whose beginscan could observe the wrong user id. Move index_beginscan() after the SetUserIdAndSecContext() call. Reported-by: Noah Misch Reviewed-by: Ayush Tiwari Discussion: https://postgr.es/m/20260705210533.ee.noahmisch@microsoft.com Backpatch-through: 19 --- src/backend/utils/adt/ri_triggers.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index dc2119cf475..31ecb2d6dca 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -2845,10 +2845,6 @@ ri_FastPathCheck(RI_ConstraintInfo *riinfo, idx_rel = index_open(riinfo->conindid, AccessShareLock); slot = table_slot_create(pk_rel, NULL); - scandesc = index_beginscan(pk_rel, idx_rel, - snapshot, NULL, - riinfo->nkeys, 0, - SO_NONE); GetUserIdAndSecContext(&saved_userid, &saved_sec_context); SetUserIdAndSecContext(RelationGetForm(pk_rel)->relowner, @@ -2857,6 +2853,17 @@ ri_FastPathCheck(RI_ConstraintInfo *riinfo, SECURITY_NOFORCE_RLS); ri_CheckPermissions(pk_rel); + /* + * Begin the scan under the switched user id, so that any access method + * code invoked by index_beginscan() runs as the PK relation's owner. For + * btree this has no functional consequence, but it keeps the ordering + * correct for out-of-tree access methods. + */ + scandesc = index_beginscan(pk_rel, idx_rel, + snapshot, NULL, + riinfo->nkeys, 0, + SO_NONE); + if (riinfo->fpmeta == NULL) { /* Reload to ensure it's valid. */ @@ -2982,9 +2989,6 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel, */ oldcxt = MemoryContextSwitchTo(fpentry->flush_cxt); - scandesc = index_beginscan(pk_rel, idx_rel, snapshot, NULL, - riinfo->nkeys, 0, SO_NONE); - GetUserIdAndSecContext(&saved_userid, &saved_sec_context); SetUserIdAndSecContext(RelationGetForm(pk_rel)->relowner, saved_sec_context | @@ -3000,6 +3004,15 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel, */ ri_CheckPermissions(pk_rel); + /* + * Begin the scan under the switched user id, so that any access method + * code invoked by index_beginscan() runs as the PK relation's owner. For + * btree this has no functional consequence, but it keeps the ordering + * correct for out-of-tree access methods. + */ + scandesc = index_beginscan(pk_rel, idx_rel, snapshot, NULL, + riinfo->nkeys, 0, SO_NONE); + if (riinfo->fpmeta == NULL) { /* Reload to ensure it's valid. */ -- 2.47.3