From d6a0b2259089c4f0afeb4c3f0efaf2994e85f3cd Mon Sep 17 00:00:00 2001
From: Tatsuo Ishii <ishii@postgresql.org>
Date: Fri, 20 Mar 2026 10:59:04 +0900
Subject: [PATCH v1] Fix session local relation cache case bug.

pool_search_relcache did not consider the session local cache case
such as temp table search. It created the search result in shared
relation cache even if the relation cache is session local. As a
result subsequent query against the session local cache is returned
from the shared relation cache. This could cause wrong
result. Example:

create table t1(i int);
select * from t1; -- info "t1 is not a temp table" is registered in shared cache
drop table t1;
create temp table t1(i int);
select * from t1; -- shared cache tells that t1 is not temp table and it could be load balanced,
       	      	  -- it could access non existent table from standby nodes.

Fix is, to not register a temp table to shared relation cache if it's
a session local cache.

Discussion: https://github.com/pgpool/pgpool2/issues/154
Backpatch-through: v4.4
---
 src/utils/pool_relcache.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/src/utils/pool_relcache.c b/src/utils/pool_relcache.c
index 0eef6b182..170e9a617 100644
--- a/src/utils/pool_relcache.c
+++ b/src/utils/pool_relcache.c
@@ -205,6 +205,7 @@ pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, cha
 					(errmsg("hit local relation cache"),
 					 errdetail("query:%s", relcache->sql)));
 
+			/* data found in local cache */
 			return relcache->cache[i].data;
 		}
 	}
@@ -225,9 +226,11 @@ pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, cha
 	locked_by_others = pool_is_shmem_lock();
 
 	/*
-	 * if enable_shared_relcache is true, search query cache.
+	 * if enable_shared_relcache is true and cach is not session local ,
+	 * search query cache.
 	 */
-	if (pool_config->enable_shared_relcache)
+	if (!relcache->cache_is_session_local &&
+		pool_config->enable_shared_relcache)
 	{
 		/* if shmem is not locked by this process, get the lock */
 		if (!locked_by_others)
@@ -248,7 +251,8 @@ pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, cha
 		}
 		PG_END_TRY();
 	}
-	/* If not in query cache or not used, send query for backend. */
+
+	/* target data was not found in neither local nor shared query cache */
 	if (query_cache_not_found)
 	{
 		ereport(DEBUG1,
@@ -260,8 +264,10 @@ pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, cha
 
 		/* Register cache */
 		result = (*relcache->register_func) (res);
-		/* save local catalog cache in query cache */
-		if (pool_config->enable_shared_relcache)
+
+		/* save local catalog cache in shared query cache */
+		if (!relcache->cache_is_session_local &&
+			pool_config->enable_shared_relcache)
 		{
 			query_cache_data = relation_cache_to_query_cache(res, &query_cache_len);
 
@@ -282,7 +288,7 @@ pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, cha
 			pool_catalog_commit_cache(backend, query, query_cache_data, query_cache_len);
 		}
 	}
-	else
+	else	/* hit shared relation cache */
 	{
 		ereport(DEBUG1,
 				(errmsg("hit query cache"),
@@ -293,7 +299,8 @@ pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, cha
 		result = (*relcache->register_func) (res);
 	}
 	/* if shmem is locked by this function, unlock it */
-	if (pool_config->enable_shared_relcache && !locked_by_others)
+	if (!relcache->cache_is_session_local &&
+		pool_config->enable_shared_relcache && !locked_by_others)
 	{
 		pool_shmem_unlock();
 		POOL_SETMASK(&oldmask);
-- 
2.43.0

