From 9815596aaecaec254c638e1a150cac7860954f1c Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 11 May 2025 13:44:22 -0400
Subject: [PATCH v1 10/11] Silence complaints about leaks in
 load_domaintype_info().

This code intentionally leaks some intermediate cruft into the
long-lived DomainConstraintCache's memory context, reasoning that the
amount of leakage will typically not be much so it's not worth doing
a copyObject() of the final tree to avoid that.  But Valgrind knows
nothing of engineering tradeoffs and complains anyway.  So modify the
code to do it the slow clean way when USE_VALGRIND.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/285483.1746756246@sss.pgh.pa.us
---
 src/backend/utils/cache/typcache.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index f9aec38a11f..bf0e362eae6 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -1189,8 +1189,20 @@ load_domaintype_info(TypeCacheEntry *typentry)
 				dcc->dccRefCount = 0;
 			}
 
-			/* Create node trees in DomainConstraintCache's context */
+			/*
+			 * The clean way to do the next bit is to run stringToNode() and
+			 * expression_planner() in the short-lived caller's context, then
+			 * copy the result into the DomainConstraintCache's dccContext.
+			 * Under Valgrind, we do it that way to silence complaints about
+			 * leaking cruft into dccContext.  However, the amount of stuff
+			 * leaked is usually pretty minimal, and the cost of the extra
+			 * copyObject() call is not negligible.  So when not catering to
+			 * Valgrind, we do it all in dccContext and accept some leakage.
+			 */
+#ifndef USE_VALGRIND
+			/* Do all this work in DomainConstraintCache's context */
 			oldcxt = MemoryContextSwitchTo(dcc->dccContext);
+#endif
 
 			check_expr = (Expr *) stringToNode(constring);
 
@@ -1206,10 +1218,19 @@ load_domaintype_info(TypeCacheEntry *typentry)
 			 */
 			check_expr = expression_planner(check_expr);
 
+#ifdef USE_VALGRIND
+			/* Create only the minimally needed stuff in dccContext */
+			oldcxt = MemoryContextSwitchTo(dcc->dccContext);
+#endif
+
 			r = makeNode(DomainConstraintState);
 			r->constrainttype = DOM_CONSTRAINT_CHECK;
 			r->name = pstrdup(NameStr(c->conname));
+#ifdef USE_VALGRIND
+			r->check_expr = copyObject(check_expr);
+#else
 			r->check_expr = check_expr;
+#endif
 			r->check_exprstate = NULL;
 
 			MemoryContextSwitchTo(oldcxt);
-- 
2.43.5

