Re: GUC parameter ACLs and physical walsender - Mailing list pgsql-hackers

From Mark Dilger
Subject Re: GUC parameter ACLs and physical walsender
Date
Msg-id CAHgHdKsciwDvZkyUi+=i-tjK3CdD3DCccLgA2wT5AEzXdM0aHg@mail.gmail.com
Whole thread
In response to Re: GUC parameter ACLs and physical walsender  (John Naylor <johncnaylorls@gmail.com>)
Responses Re: GUC parameter ACLs and physical walsender
List pgsql-hackers


On Wed, Apr 22, 2026 at 8:27 PM John Naylor <johncnaylorls@gmail.com> wrote:
On Thu, Apr 23, 2026 at 2:19 AM Jeff Davis <pgsql@j-davis.com> wrote:
> It seems to be because pg_parameter_acl is not nailed in cache. I
> attached a quick patch to do so (which turns it into the "expected
> permission denied" error). But I'm not sure if that's the right fix, or
> if it would be a complete fix. I also don't think that would be
> backportable, but perhaps?

I think in existing installations AddNewRelationType() would have
picked some oid already, so fixing rowtype_oid at initdb time would
only work in the master branch.

John is right that the hardcoded BKI_ROWTYPE_OID(2173) makes this
non-backportable as-is.
                                                                                                                                                           
On existing installations (PG 15-18), AddNewRelationType() assigned rowtype OID
10097 to pg_parameter_acl during initdb. Jeff's patch has formrdesc set
rd_att->tdtypeid = 2173, but that field is never corrected — Phase3 overwrites
rd_rel (including reltype) via memcpy, but rd_att->tdtypeid stays at the
formrdesc value. The comment in formrdesc says as much: "this data had better
be right because it will never be replaced."
                                   
On assert-enabled builds, every backend crashes on the first connection:                                                                                  
 
TRAP: failed Assert("relation->rd_att->tdtypeid == relp->reltype"),  
  File: "relcache.c", Line: 4294                                                                                                                            
                                                                                   
On non-assert builds, the mismatch has no observable effect. The wrong typeId
gets stamped into pg_parameter_acl tuple headers by heap_form_tuple, but
nothing reads it back -- all consumers of HeapTupleHeaderGetTypeId are in the
executor, PL/pgSQL, and record-type processing, not catalog operations.
                                         
For backports, formrdesc would need to use something other than the hardcoded
OID -- either look up the real rowtype OID, or pass InvalidOid and teach the
Assert to tolerate it for late-nailed relations.
                                                                                                                                                           
To demonstrate, using an existing cluster whose initdb was done without the
nailing patch (rowtype 10097), then started with patched binaries:  after applying
Jeff's v1-0001-Nail-pg_parameter_acl-in-relcache.patch to master, which has
dbf217c1c7 already applied:

--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1965,6 +1965,12 @@ formrdesc(const char *relationName, Oid relationReltype,
    relation->rd_att->tdtypeid = relationReltype;
    relation->rd_att->tdtypmod = -1;    /* just to be sure */

+   elog(LOG, "formrdesc \"%s\": relid=%u reltype=%u tdtypeid=%u",
+        relationName,
+        TupleDescAttr(relation->rd_att, 0)->attrelid,
+        relationReltype,
+        relation->rd_att->tdtypeid);
+
    /*
     * initialize tuple desc info
     */
@@ -4283,6 +4289,14 @@ RelationCacheInitializePhase3(void)
             * data correctly to start with, because it may already have been
             * copied into one or more catcache entries.)
             */
+           elog(LOG, "RelationCacheInitializePhase3 \"%s\": relid=%u "
+                "formrdesc tdtypeid=%u, pg_class reltype=%u%s",
+                RelationGetRelationName(relation),
+                RelationGetRelid(relation),
+                relation->rd_att->tdtypeid,
+                relp->reltype,
+                (relation->rd_att->tdtypeid != relp->reltype)
+                ? " MISMATCH" : "");
            Assert(relation->rd_att->tdtypeid == relp->reltype);
            Assert(relation->rd_att->tdtypmod == -1);

On an existing cluster with patched binaries it shows:
                                                                                                                                                           
  formrdesc "pg_parameter_acl": relid=0 reltype=2173 tdtypeid=2173
  RelationCacheInitializePhase3 "pg_parameter_acl": relid=6243
    formrdesc tdtypeid=2173, pg_class reltype=10097 MISMATCH

--

Mark Dilger

pgsql-hackers by date:

Previous
From: Jacob Champion
Date:
Subject: Re: oauth integer overflow
Next
From: Bharath Rupireddy
Date:
Subject: Re: Introduce XID age based replication slot invalidation