From 6b21a0da96967bf94a7569e0a1c89bf13cf38868 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Wed, 25 Oct 2023 14:20:07 +0200
Subject: [PATCH v5 3/3] Introduce for_each_object

Add new for_each_object helper that does not require var argument to be
declared before hand.
---
 src/backend/replication/logical/tablesync.c |  3 +--
 src/include/nodes/pg_list.h                 | 23 +++++++++++++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c82d05a642e..ed27181c2a9 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -416,7 +416,6 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
 		TimestampTz last_start_time;
 	};
 	static HTAB *last_start_times = NULL;
-	SubscriptionRelState *rstate;
 	bool		started_tx = false;
 	bool		should_exit = false;
 
@@ -453,7 +452,7 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
 	/*
 	 * Process all tables that are being synchronized.
 	 */
-	for_each_ptr(rstate, table_states_not_ready)
+	for_each_object(SubscriptionRelState, rstate, table_states_not_ready)
 	{
 		if (rstate->state == SUBREL_STATE_SYNCDONE)
 		{
diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index e09116e8fdb..0748d36536b 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -473,6 +473,29 @@ for_each_cell_setup(const List *lst, const ListCell *initcell)
 		  (var = lfirst(&var##__state.l->elements[var##__state.i]), true));\
 		 var##__state.i++)
 
+/*
+ * for_each_object -
+ *	  a convenience macro which loops through a list of pointers without
+ *	  needing a "ListCell *" only a type and variable name. It automatically
+ *	  declares a loop variable with the given name and type;
+ *
+ * Unlike with foreach() it's not possible to detect if an early "break"
+ * occured by checking the value of the loop variable at the end of the loop.
+ * If you need this, it's recommended to use foreach() instead or manually keep
+ * track of a break occured using a boolean flag variable called e.g. "found".
+ *
+ * The caveats for foreach() apply equally here.
+ */
+#define for_each_object(type, var, lst) \
+	for (type * var = NULL, *var##__outerloop = (type *) 1; \
+		 var##__outerloop; \
+		 var##__outerloop = NULL) \
+		for (ForEachState var##__state = {(lst), 0}; \
+			 (var##__state.l != NIL && \
+			  var##__state.i < var##__state.l->length && \
+			  (var = lfirst(&var##__state.l->elements[var##__state.i]), true));\
+			 var##__state.i++)
+
 /*
  * for_each_int -
  *	  a convenience macro which loops through a list of ints without needing a
-- 
2.34.1

