]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
catcache.c: use C_COLLATION_OID for texteqfast/texthashfast.
authorJeff Davis <jdavis@postgresql.org>
Wed, 22 Apr 2026 17:22:44 +0000 (10:22 -0700)
committerJeff Davis <jdavis@postgresql.org>
Wed, 22 Apr 2026 17:22:44 +0000 (10:22 -0700)
The problem report was about setting GUCs in the startup packet for a
physical replication connection. Setting the GUC required an ACL
check, which performed a lookup on pg_parameter_acl.parname. The
catalog cache was hardwired to use DEFAULT_COLLATION_OID for
texteqfast() and texthashfast(), but the database default collation
was uninitialized because it's a physical walsender and never connects
to a database. In versions 18 and later, this resulted in a NULL
pointer dereference, while in version 17 it resulted in an ERROR.

As the comments stated, using DEFAULT_COLLATION_OID was arbitrary
anyway: if the collation actually mattered, it should have used the
column's actual collation. (In the catalog, some text columns are the
default collation and some are "C".)

Fix by using C_COLLATION_OID, which doesn't require any initialization
and is always available. When any deterministic collation will do,
it's best to consistently use the simplest and fastest one, so this is
a good idea anyway.

Another problem was raised in the thread, which this commit doesn't
fix (see second discussion link).

Reported-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/D18AD72A-5004-4EF8-AF80-10732AF677FA@yandex-team.ru
Discussion: https://postgr.es/m/4524ed61a015d3496fc008644dcb999bb31916a7.camel%40j-davis.com
Backpatch-through: 17

src/backend/utils/cache/catcache.c

index 87ed55064604a0b2fa579a83399d4914ad9b833e..a8e7bf649d23f6a7839acdbb5cdd3d89306f02b8 100644 (file)
@@ -205,6 +205,10 @@ nameeqfast(Datum a, Datum b)
        char       *ca = NameStr(*DatumGetName(a));
        char       *cb = NameStr(*DatumGetName(b));
 
+       /*
+        * Catalogs only use deterministic collations, so ignore column collation
+        * and use fast path.
+        */
        return strncmp(ca, cb, NAMEDATALEN) == 0;
 }
 
@@ -213,6 +217,10 @@ namehashfast(Datum datum)
 {
        char       *key = NameStr(*DatumGetName(datum));
 
+       /*
+        * Catalogs only use deterministic collations, so ignore column collation
+        * and use fast path.
+        */
        return hash_bytes((unsigned char *) key, strlen(key));
 }
 
@@ -244,17 +252,20 @@ static bool
 texteqfast(Datum a, Datum b)
 {
        /*
-        * The use of DEFAULT_COLLATION_OID is fairly arbitrary here.  We just
-        * want to take the fast "deterministic" path in texteq().
+        * Catalogs only use deterministic collations, so ignore column collation
+        * and use "C" locale for efficiency.
         */
-       return DatumGetBool(DirectFunctionCall2Coll(texteq, DEFAULT_COLLATION_OID, a, b));
+       return DatumGetBool(DirectFunctionCall2Coll(texteq, C_COLLATION_OID, a, b));
 }
 
 static uint32
 texthashfast(Datum datum)
 {
-       /* analogously here as in texteqfast() */
-       return DatumGetInt32(DirectFunctionCall1Coll(hashtext, DEFAULT_COLLATION_OID, datum));
+       /*
+        * Catalogs only use deterministic collations, so ignore column collation
+        * and use "C" locale for efficiency.
+        */
+       return DatumGetInt32(DirectFunctionCall1Coll(hashtext, C_COLLATION_OID, datum));
 }
 
 static bool