We didn't have any use of TransactionId as members of List, until
RelationSyncEntry->streamed_txns was introduced (464824323e57, pg14).
It's currently implemented as a list of int.  This is not wrong at
present, but it may soon be, and I'm sure it rubs some people the wrong
way.

But is the rubbing way wrong enough to add support for TransactionId in
pg_list.h, including, say, T_XidList?

The minimal patch (attached) is quite small AFAICS.

-- 
Álvaro Herrera               48°01'N 7°57'E  —  https://www.EnterpriseDB.com/
>From 19f165f556a3cee7226a7b22b9bdf7ad9bce9fb0 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvhe...@alvh.no-ip.org>
Date: Fri, 29 Apr 2022 17:42:17 +0200
Subject: [PATCH] Implement List support for TransactionId

Use it for RelationSyncEntry->streamed_txns, which is currently using an
integer list.
---
 src/backend/nodes/list.c                    | 42 ++++++++++++++++++++-
 src/backend/nodes/outfuncs.c                |  4 ++
 src/backend/replication/pgoutput/pgoutput.c | 13 ++-----
 src/include/nodes/nodes.h                   |  1 +
 src/include/nodes/pg_list.h                 |  6 +++
 5 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c
index f843f861ef..9d8f4fd5c7 100644
--- a/src/backend/nodes/list.c
+++ b/src/backend/nodes/list.c
@@ -54,6 +54,7 @@
 #define IsPointerList(l)		((l) == NIL || IsA((l), List))
 #define IsIntegerList(l)		((l) == NIL || IsA((l), IntList))
 #define IsOidList(l)			((l) == NIL || IsA((l), OidList))
+#define IsXidList(l)			((l) == NIL || IsA((l), XidList))
 
 #ifdef USE_ASSERT_CHECKING
 /*
@@ -71,7 +72,8 @@ check_list_invariants(const List *list)
 
 	Assert(list->type == T_List ||
 		   list->type == T_IntList ||
-		   list->type == T_OidList);
+		   list->type == T_OidList ||
+		   list->type == T_XidList);
 }
 #else
 #define check_list_invariants(l)  ((void) 0)
@@ -383,6 +385,24 @@ lappend_oid(List *list, Oid datum)
 	return list;
 }
 
+/*
+ * Append a TransactionId to the specified list. See lappend()
+ */
+List *
+lappend_xid(List *list, TransactionId datum)
+{
+	Assert(IsXidList(list));
+
+	if (list == NIL)
+		list = new_list(T_XidList, 1);
+	else
+		new_tail_cell(list);
+
+	llast_xid(list) = datum;
+	check_list_invariants(list);
+	return list;
+}
+
 /*
  * Make room for a new cell at position 'pos' (measured from 0).
  * The data in the cell is left undefined, and must be filled in by the
@@ -714,6 +734,26 @@ list_member_oid(const List *list, Oid datum)
 	return false;
 }
 
+/*
+ * Return true iff the TransactionId 'datum' is a member of the list.
+ */
+bool
+list_member_xid(const List *list, TransactionId datum)
+{
+	const ListCell *cell;
+
+	Assert(IsXidList(list));
+	check_list_invariants(list);
+
+	foreach(cell, list)
+	{
+		if (lfirst_oid(cell) == datum)
+			return true;
+	}
+
+	return false;
+}
+
 /*
  * Delete the n'th cell (counting from 0) in list.
  *
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 0271ea9d78..0f257ed0ce 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -221,6 +221,8 @@ _outList(StringInfo str, const List *node)
 		appendStringInfoChar(str, 'i');
 	else if (IsA(node, OidList))
 		appendStringInfoChar(str, 'o');
+	else if (IsA(node, XidList))
+		appendStringInfoChar(str, 'x');
 
 	foreach(lc, node)
 	{
@@ -239,6 +241,8 @@ _outList(StringInfo str, const List *node)
 			appendStringInfo(str, " %d", lfirst_int(lc));
 		else if (IsA(node, OidList))
 			appendStringInfo(str, " %u", lfirst_oid(lc));
+		else if (IsA(node, XidList))
+			appendStringInfo(str, " %u", lfirst_xid(lc));
 		else
 			elog(ERROR, "unrecognized list node type: %d",
 				 (int) node->type);
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 42c06af239..d4a84631c7 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -1923,13 +1923,8 @@ init_rel_sync_cache(MemoryContext cachectx)
 static bool
 get_schema_sent_in_streamed_txn(RelationSyncEntry *entry, TransactionId xid)
 {
-	ListCell   *lc;
-
-	foreach(lc, entry->streamed_txns)
-	{
-		if (xid == (uint32) lfirst_int(lc))
-			return true;
-	}
+	if (list_member_xid(entry->streamed_txns, xid))
+		return true;
 
 	return false;
 }
@@ -1945,7 +1940,7 @@ set_schema_sent_in_streamed_txn(RelationSyncEntry *entry, TransactionId xid)
 
 	oldctx = MemoryContextSwitchTo(CacheMemoryContext);
 
-	entry->streamed_txns = lappend_int(entry->streamed_txns, xid);
+	entry->streamed_txns = lappend_xid(entry->streamed_txns, xid);
 
 	MemoryContextSwitchTo(oldctx);
 }
@@ -2248,7 +2243,7 @@ cleanup_rel_sync_cache(TransactionId xid, bool is_commit)
 		 */
 		foreach(lc, entry->streamed_txns)
 		{
-			if (xid == (uint32) lfirst_int(lc))
+			if (xid == lfirst_xid(lc))
 			{
 				if (is_commit)
 					entry->schema_sent = true;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index b3b407579b..7ce1fc4deb 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -317,6 +317,7 @@ typedef enum NodeTag
 	T_List,
 	T_IntList,
 	T_OidList,
+	T_XidList,
 
 	/*
 	 * TAGS FOR EXTENSIBLE NODES (extensible.h)
diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index 2cb9d1371d..2ba2346c3a 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -45,6 +45,7 @@ typedef union ListCell
 	void	   *ptr_value;
 	int			int_value;
 	Oid			oid_value;
+	TransactionId xid_value;
 } ListCell;
 
 typedef struct List
@@ -169,6 +170,7 @@ list_length(const List *l)
 #define lfirst(lc)				((lc)->ptr_value)
 #define lfirst_int(lc)			((lc)->int_value)
 #define lfirst_oid(lc)			((lc)->oid_value)
+#define lfirst_xid(lc)			((lc)->xid_value)
 #define lfirst_node(type,lc)	castNode(type, lfirst(lc))
 
 #define linitial(l)				lfirst(list_nth_cell(l, 0))
@@ -194,6 +196,7 @@ list_length(const List *l)
 #define llast(l)				lfirst(list_last_cell(l))
 #define llast_int(l)			lfirst_int(list_last_cell(l))
 #define llast_oid(l)			lfirst_oid(list_last_cell(l))
+#define llast_xid(l)			lfirst_xid(list_last_cell(l))
 #define llast_node(type,l)		castNode(type, llast(l))
 
 /*
@@ -202,6 +205,7 @@ list_length(const List *l)
 #define list_make_ptr_cell(v)	((ListCell) {.ptr_value = (v)})
 #define list_make_int_cell(v)	((ListCell) {.int_value = (v)})
 #define list_make_oid_cell(v)	((ListCell) {.oid_value = (v)})
+#define list_make_xid_cell(v)	((ListCell) {.xid_value = (v)})
 
 #define list_make1(x1) \
 	list_make1_impl(T_List, list_make_ptr_cell(x1))
@@ -539,6 +543,7 @@ extern List *list_make5_impl(NodeTag t, ListCell datum1, ListCell datum2,
 extern pg_nodiscard List *lappend(List *list, void *datum);
 extern pg_nodiscard List *lappend_int(List *list, int datum);
 extern pg_nodiscard List *lappend_oid(List *list, Oid datum);
+extern pg_nodiscard List *lappend_xid(List *list, TransactionId datum);
 
 extern pg_nodiscard List *list_insert_nth(List *list, int pos, void *datum);
 extern pg_nodiscard List *list_insert_nth_int(List *list, int pos, int datum);
@@ -557,6 +562,7 @@ extern bool list_member(const List *list, const void *datum);
 extern bool list_member_ptr(const List *list, const void *datum);
 extern bool list_member_int(const List *list, int datum);
 extern bool list_member_oid(const List *list, Oid datum);
+extern bool list_member_xid(const List *list, TransactionId datum);
 
 extern pg_nodiscard List *list_delete(List *list, void *datum);
 extern pg_nodiscard List *list_delete_ptr(List *list, void *datum);
-- 
2.30.2

Reply via email to