From e5eae3786fa0c846a3e01f2758e7dfa481a27410 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <postgres@jeltef.nl>
Date: Thu, 4 Dec 2025 15:39:00 +0100
Subject: [PATCH v2 4/5] Add foreach_hash macro

For lists we've had a new foreach style macros since 14dd0f27d7. This
adds a similar macro for hash tables. This new foreach_hash macro makes
iterating over the items in an HTAB as simple as iterating over the
items in a List. The only additional thing to keep in mind is that when
exiting the loop early you need to call foreach_hash_term.
---
 src/include/utils/hsearch.h | 46 +++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h
index 36b31be7ad6..b3a361d78ad 100644
--- a/src/include/utils/hsearch.h
+++ b/src/include/utils/hsearch.h
@@ -277,6 +277,52 @@ typedef struct
 	uint32		hashvalue;		/* hashvalue to start seqscan over hash */
 } HASH_SEQ_STATUS;
 
+/*
+ * foreach_hash - iterate over all entries in a hash table
+ *
+ * This macro simplifies hash table iteration by combining hash_seq_init
+ * and hash_seq_search into a single for-loop construct.
+ *
+ * Usage:
+ *   foreach_hash(MyEntry, entry, my_hashtable)
+ *   {
+ *       // use entry
+ *   }
+ *
+ * This replaces the more verbose pattern:
+ *   HASH_SEQ_STATUS status;
+ *   MyEntry *entry;
+ *   hash_seq_init(&status, my_hashtable);
+ *   while ((entry = (MyEntry *) hash_seq_search(&status)) != NULL)
+ *   {
+ *       // use entry
+ *   }
+ *
+ * For early termination, use foreach_hash_term() before break:
+ *   foreach_hash(MyEntry, entry, my_hashtable)
+ *   {
+ *       if (found_it)
+ *       {
+ *           foreach_hash_term(entry);
+ *           break;
+ *       }
+ *   }
+ */
+#define foreach_hash(type, var, htab) \
+	for (type *var = 0, *var##__outerloop = (type *) 1; \
+		 var##__outerloop; \
+		 var##__outerloop = 0) \
+		for (HASH_SEQ_STATUS var##__status = (hash_seq_init(&var##__status, (htab)), var##__status); \
+			 (var = (type *) hash_seq_search(&var##__status)) != NULL; \
+			)
+
+/*
+ * foreach_hash_term - terminate a foreach_hash loop early
+ *
+ * Call this before 'break' to properly clean up the hash scan.
+ */
+#define foreach_hash_term(var) hash_seq_term(&var##__status)
+
 /*
  * prototypes for functions in dynahash.c
  */
-- 
2.52.0

