From 9bba83e8c9e19e442c0e8ad2f90a4fd1d14fe4f1 Mon Sep 17 00:00:00 2001
From: Jeff Davis <jeff@j-davis.com>
Date: Wed, 7 Aug 2024 13:03:32 -0700
Subject: [PATCH v2 6/6] Invalidate collation cache when appropriate.

Previously, DROP COLLATION could leave a cache entry around. That's
not normally a problem, but can be if oid wraparound causes the same
oid to be reused for a different collation.
---
 src/backend/utils/adt/pg_locale.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index 47f902b8f59..f5f45f72a13 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -63,6 +63,7 @@
 #include "utils/builtins.h"
 #include "utils/formatting.h"
 #include "utils/guc_hooks.h"
+#include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
@@ -1453,6 +1454,18 @@ pg_locale_deterministic(pg_locale_t locale)
 	return locale->deterministic;
 }
 
+static void
+CollationCacheInvalidate(Datum arg, int cacheid, uint32 hashvalue)
+{
+	ResourceOwnerReleaseAllOfKind(CollationCacheOwner,
+								  &PGLocaleResourceKind);
+
+	/* free all memory and reset hash table */
+	MemoryContextReset(CollationCacheContext);
+	CollationCache = collation_cache_create(CollationCacheContext,
+											16, NULL);
+}
+
 /*
  * Initialize default_locale with database locale settings.
  */
@@ -1722,14 +1735,7 @@ pg_newlocale_from_collation(Oid collid)
 	if (collid == DEFAULT_COLLATION_OID)
 		return &default_locale;
 
-	/*
-	 * Cache mechanism for collation information.
-	 *
-	 * Note that we currently lack any way to flush the cache.  Since we don't
-	 * support ALTER COLLATION, this is OK.  The worst case is that someone
-	 * drops a collation, and a useless cache entry hangs around in existing
-	 * backends.
-	 */
+	/* cache mechanism for collation information */
 	if (CollationCache == NULL)
 	{
 		CollationCacheOwner = ResourceOwnerCreate(NULL, "collation cache");
@@ -1738,6 +1744,9 @@ pg_newlocale_from_collation(Oid collid)
 													  ALLOCSET_DEFAULT_SIZES);
 		CollationCache = collation_cache_create(CollationCacheContext,
 												16, NULL);
+		CacheRegisterSyscacheCallback(COLLOID,
+									  CollationCacheInvalidate,
+									  (Datum) 0);
 	}
 
 	cache_entry = collation_cache_insert(CollationCache, collid, &found);
-- 
2.34.1

