On 20.02.24 08:57, Peter Eisentraut wrote:
On 18.02.24 00:06, Matthias van de Meent wrote:
I'm not sure that the cleanup which is done when changing a RTE's
rtekind is also complete enough for this purpose.
Things like inline_cte_walker change the node->rtekind, which could
leave residual junk data in fields that are currently dropped during
serialization (as the rtekind specifically ignores those fields), but
which would add overhead when the default omission is expected to
handle these fields; as they could then contain junk. It looks like
there is some care about zeroing now unused fields, but I haven't
checked that it covers all cases and fields to the extent required so
that removing this specialized serializer would have zero impact on
size once the default omission patch is committed.

An additional patch with a single function that for this purpose
clears junk fields from RTEs that changed kind would be appreciated:
it is often hand-coded at those locations the kind changes, but that's
more sensitive to programmer error.

Yes, interesting idea.  Or maybe an assert-like function that checks an existing structure for consistency.  Or maybe both.  I'll try this out.

In the meantime, if there are no remaining concerns, I propose to commit the first two patches

Remove custom Constraint node read/write implementations
Remove custom _jumbleRangeTblEntry()

After a few side quests, here is an updated patch set. (I had committed the first of the two patches mentioned above, but not yet the second one.)

v3-0001-Remove-obsolete-comment.patch
v3-0002-Improve-comment.patch

These just update a few comments around the RangeTblEntry definition.

v3-0003-Reformat-some-node-comments.patch
v3-0004-Remove-custom-_jumbleRangeTblEntry.patch

This is pretty much the same patch as before. I have now split it up to first reformat the comments to make room for the node annotations. This patch is now also pgindent-proof. After some side quest discussions, the set of fields to jumble seems correct now, so commit message comments to the contrary have been dropped.

v3-0005-Make-RangeTblEntry-dump-order-consistent.patch

I separated that from the 0008 patch below. I think it useful even if we don't go ahead with 0008 now, for example in dumps from the debugger, and just in general to keep everything more consistent.

v3-0006-WIP-AssertRangeTblEntryIsValid.patch

This is in response to some of the discussions where there was some doubt whether all fields are always filled and cleared correctly when the RTE kind is changed. Seems correct as far as this goes. I didn't know of a good way to hook this in, so I put it into the write/read functions, which is obviously a bit weird if I'm proposing to remove them later. Consider it a proof of concept.

v3-0007-Simplify-range_table_mutator_impl-and-range_table.patch
v3-0008-WIP-Remove-custom-RangeTblEntry-node-read-write-i.patch

At this point, I'm not too stressed about pressing forward with these last two patches. We can look at them again perhaps if we make progress on a more compact node output format. When I started this thread, I had a lot of questions about various details about the RangeTblEntry struct, and we have achieved many answers during the discussions, so I'm happy with the progress. So for PG17, I'd like to just do patches 0001..0005.
From dc53b7ddfc5aa004a0d222b4084a1c580f05a296 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 11 Mar 2024 09:15:33 +0100
Subject: [PATCH v3 1/8] Remove obsolete comment

The idea to use a union in the definition of RangeTblEntry is clearly
not being pursued.

Discussion: 
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org
---
 src/include/nodes/parsenodes.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 2380821600..5113f97363 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1028,12 +1028,6 @@ typedef struct RangeTblEntry
 
        RTEKind         rtekind;                /* see above */
 
-       /*
-        * XXX the fields applicable to only some rte kinds should be merged 
into
-        * a union.  I didn't do this yet because the diffs would impact a lot 
of
-        * code that is being actively worked on.  FIXME someday.
-        */
-
        /*
         * Fields valid for a plain relation RTE (else zero):
         *

base-commit: af0e7deb4a1c369bb8154ac55f085d6a93fe5c35
-- 
2.44.0

From 9fd2ae6a561ea72f627057d922e48d92eaafe099 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 11 Mar 2024 09:15:33 +0100
Subject: [PATCH v3 2/8] Improve comment

Clarify that RangeTblEntry.lateral reflects whether LATERAL was
specified in the statement (as opposed to whether lateralness is
implicit).  Also, the list of applicable entry types was incomplete.

Discussion: 
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org
---
 src/include/nodes/parsenodes.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 5113f97363..346dd5e0e2 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1196,7 +1196,7 @@ typedef struct RangeTblEntry
         */
        Alias      *alias;                      /* user-written alias clause, 
if any */
        Alias      *eref;                       /* expanded reference names */
-       bool            lateral;                /* subquery, function, or 
values is LATERAL? */
+       bool            lateral;                /* was LATERAL specified? */
        bool            inFromCl;               /* present in FROM clause? */
        List       *securityQuals;      /* security barrier quals to apply, if 
any */
 } RangeTblEntry;
-- 
2.44.0

From 77fd2b4cdfdaf90f27a37c966d6aa490c4f6a419 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 11 Mar 2024 09:15:33 +0100
Subject: [PATCH v3 3/8] Reformat some node comments

Reformat some comments in node field definitions to avoid long lines.
This makes room for per-field annotations.  Similar to 835d476fd2.

Discussion: 
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org
---
 src/include/nodes/parsenodes.h | 86 ++++++++++++++++++++++------------
 1 file changed, 57 insertions(+), 29 deletions(-)

diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 346dd5e0e2..a3c4e86f4c 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1066,18 +1066,26 @@ typedef struct RangeTblEntry
         * relation.  This allows plans referencing AFTER trigger transition
         * tables to be invalidated if the underlying table is altered.
         */
-       Oid                     relid;                  /* OID of the relation 
*/
-       bool            inh;                    /* inheritance requested? */
-       char            relkind;                /* relation kind (see 
pg_class.relkind) */
-       int                     rellockmode;    /* lock level that query 
requires on the rel */
-       Index           perminfoindex;  /* index of RTEPermissionInfo entry, or 
0 */
-       struct TableSampleClause *tablesample;  /* sampling info, or NULL */
+       /* OID of the relation */
+       Oid                     relid;
+       /* inheritance requested? */
+       bool            inh;
+       /* relation kind (see pg_class.relkind) */
+       char            relkind;
+       /* lock level that query requires on the rel */
+       int                     rellockmode;
+       /* index of RTEPermissionInfo entry, or 0 */
+       Index           perminfoindex;
+       /* sampling info, or NULL */
+       struct TableSampleClause *tablesample;
 
        /*
         * Fields valid for a subquery RTE (else NULL):
         */
-       Query      *subquery;           /* the sub-query */
-       bool            security_barrier;       /* is from security_barrier 
view? */
+       /* the sub-query */
+       Query      *subquery;
+       /* is from security_barrier view? */
+       bool            security_barrier;
 
        /*
         * Fields valid for a join RTE (else NULL/zero):
@@ -1122,11 +1130,15 @@ typedef struct RangeTblEntry
         * merged columns could not be dropped); this is not accounted for in
         * joinleftcols/joinrighttcols.
         */
-       JoinType        jointype;               /* type of join */
-       int                     joinmergedcols; /* number of merged (JOIN 
USING) columns */
-       List       *joinaliasvars;      /* list of alias-var expansions */
-       List       *joinleftcols;       /* left-side input column numbers */
-       List       *joinrightcols;      /* right-side input column numbers */
+       JoinType        jointype;
+       /* number of merged (JOIN USING) columns */
+       int                     joinmergedcols;
+       /* list of alias-var expansions */
+       List       *joinaliasvars;
+       /* left-side input column numbers */
+       List       *joinleftcols;
+       /* right-side input column numbers */
+       List       *joinrightcols;
 
        /*
         * join_using_alias is an alias clause attached directly to JOIN/USING. 
It
@@ -1143,8 +1155,10 @@ typedef struct RangeTblEntry
         * implicit, and must be accounted for "by hand" in places such as
         * expandRTE().
         */
-       List       *functions;          /* list of RangeTblFunction nodes */
-       bool            funcordinality; /* is this called WITH ORDINALITY? */
+       /* list of RangeTblFunction nodes */
+       List       *functions;
+       /* is this called WITH ORDINALITY? */
+       bool            funcordinality;
 
        /*
         * Fields valid for a TableFunc RTE (else NULL):
@@ -1154,14 +1168,18 @@ typedef struct RangeTblEntry
        /*
         * Fields valid for a values RTE (else NIL):
         */
-       List       *values_lists;       /* list of expression lists */
+       /* list of expression lists */
+       List       *values_lists;
 
        /*
         * Fields valid for a CTE RTE (else NULL/zero):
         */
-       char       *ctename;            /* name of the WITH list item */
-       Index           ctelevelsup;    /* number of query levels up */
-       bool            self_reference; /* is this a recursive self-reference? 
*/
+       /* name of the WITH list item */
+       char       *ctename;
+       /* number of query levels up */
+       Index           ctelevelsup;
+       /* is this a recursive self-reference? */
+       bool            self_reference;
 
        /*
         * Fields valid for CTE, VALUES, ENR, and TableFunc RTEs (else NIL):
@@ -1181,24 +1199,34 @@ typedef struct RangeTblEntry
         * all three lists (as well as an empty-string entry in eref).  Testing
         * for zero coltype is the standard way to detect a dropped column.
         */
-       List       *coltypes;           /* OID list of column type OIDs */
-       List       *coltypmods;         /* integer list of column typmods */
-       List       *colcollations;      /* OID list of column collation OIDs */
+       /* OID list of column type OIDs */
+       List       *coltypes;
+       /* integer list of column typmods */
+       List       *coltypmods;
+       /* OID list of column collation OIDs */
+       List       *colcollations;
 
        /*
         * Fields valid for ENR RTEs (else NULL/zero):
         */
-       char       *enrname;            /* name of ephemeral named relation */
-       Cardinality enrtuples;          /* estimated or actual from caller */
+       /* name of ephemeral named relation */
+       char       *enrname;
+       /* estimated or actual from caller */
+       Cardinality enrtuples;
 
        /*
         * Fields valid in all RTEs:
         */
-       Alias      *alias;                      /* user-written alias clause, 
if any */
-       Alias      *eref;                       /* expanded reference names */
-       bool            lateral;                /* was LATERAL specified? */
-       bool            inFromCl;               /* present in FROM clause? */
-       List       *securityQuals;      /* security barrier quals to apply, if 
any */
+       /* user-written alias clause, if any */
+       Alias      *alias;
+       /* expanded reference names */
+       Alias      *eref;
+       /* was LATERAL specified? */
+       bool            lateral;
+       /* present in FROM clause? */
+       bool            inFromCl;
+       /* security barrier quals to apply, if any */
+       List       *securityQuals;
 } RangeTblEntry;
 
 /*
-- 
2.44.0

From 70f2efa0d15d6533594814041dac2651efe78e8e Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 11 Mar 2024 09:15:33 +0100
Subject: [PATCH v3 4/8] Remove custom _jumbleRangeTblEntry()

This is part of an effort to reduce the number of special cases in the
automatically generated node support functions.

This patch removes _jumbleRangeTblEntry() and instead adds per-field
query_jumble_ignore annotations to match the behavior of the previous
custom code.  The pg_stat_statements test suite has some coverage of
this.  It gets rid of switch on rtekind; this should be technically
correct, since we do the equal and copy functions like this also.

The list of fields to jumble has been checked and corrected as of
8b29a119fd.

Discussion: 
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org
---
 src/backend/nodes/queryjumblefuncs.c | 49 ----------------------------
 src/include/nodes/parsenodes.h       | 40 +++++++++++------------
 2 files changed, 20 insertions(+), 69 deletions(-)

diff --git a/src/backend/nodes/queryjumblefuncs.c 
b/src/backend/nodes/queryjumblefuncs.c
index 2c116c8728..be823a7f8f 100644
--- a/src/backend/nodes/queryjumblefuncs.c
+++ b/src/backend/nodes/queryjumblefuncs.c
@@ -353,52 +353,3 @@ _jumbleA_Const(JumbleState *jstate, Node *node)
                }
        }
 }
-
-static void
-_jumbleRangeTblEntry(JumbleState *jstate, Node *node)
-{
-       RangeTblEntry *expr = (RangeTblEntry *) node;
-
-       JUMBLE_FIELD(rtekind);
-       switch (expr->rtekind)
-       {
-               case RTE_RELATION:
-                       JUMBLE_FIELD(relid);
-                       JUMBLE_FIELD(inh);
-                       JUMBLE_NODE(tablesample);
-                       break;
-               case RTE_SUBQUERY:
-                       JUMBLE_NODE(subquery);
-                       break;
-               case RTE_JOIN:
-                       JUMBLE_FIELD(jointype);
-                       break;
-               case RTE_FUNCTION:
-                       JUMBLE_NODE(functions);
-                       JUMBLE_FIELD(funcordinality);
-                       break;
-               case RTE_TABLEFUNC:
-                       JUMBLE_NODE(tablefunc);
-                       break;
-               case RTE_VALUES:
-                       JUMBLE_NODE(values_lists);
-                       break;
-               case RTE_CTE:
-
-                       /*
-                        * Depending on the CTE name here isn't ideal, but it's 
the only
-                        * info we have to identify the referenced WITH item.
-                        */
-                       JUMBLE_STRING(ctename);
-                       JUMBLE_FIELD(ctelevelsup);
-                       break;
-               case RTE_NAMEDTUPLESTORE:
-                       JUMBLE_STRING(enrname);
-                       break;
-               case RTE_RESULT:
-                       break;
-               default:
-                       elog(ERROR, "unrecognized RTE kind: %d", (int) 
expr->rtekind);
-                       break;
-       }
-}
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a3c4e86f4c..aae50abdb0 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1022,7 +1022,7 @@ typedef enum RTEKind
 
 typedef struct RangeTblEntry
 {
-       pg_node_attr(custom_read_write, custom_query_jumble)
+       pg_node_attr(custom_read_write)
 
        NodeTag         type;
 
@@ -1071,11 +1071,11 @@ typedef struct RangeTblEntry
        /* inheritance requested? */
        bool            inh;
        /* relation kind (see pg_class.relkind) */
-       char            relkind;
+       char            relkind pg_node_attr(query_jumble_ignore);
        /* lock level that query requires on the rel */
-       int                     rellockmode;
+       int                     rellockmode pg_node_attr(query_jumble_ignore);
        /* index of RTEPermissionInfo entry, or 0 */
-       Index           perminfoindex;
+       Index           perminfoindex pg_node_attr(query_jumble_ignore);
        /* sampling info, or NULL */
        struct TableSampleClause *tablesample;
 
@@ -1085,7 +1085,7 @@ typedef struct RangeTblEntry
        /* the sub-query */
        Query      *subquery;
        /* is from security_barrier view? */
-       bool            security_barrier;
+       bool            security_barrier pg_node_attr(query_jumble_ignore);
 
        /*
         * Fields valid for a join RTE (else NULL/zero):
@@ -1132,20 +1132,20 @@ typedef struct RangeTblEntry
         */
        JoinType        jointype;
        /* number of merged (JOIN USING) columns */
-       int                     joinmergedcols;
+       int                     joinmergedcols 
pg_node_attr(query_jumble_ignore);
        /* list of alias-var expansions */
-       List       *joinaliasvars;
+       List       *joinaliasvars pg_node_attr(query_jumble_ignore);
        /* left-side input column numbers */
-       List       *joinleftcols;
+       List       *joinleftcols pg_node_attr(query_jumble_ignore);
        /* right-side input column numbers */
-       List       *joinrightcols;
+       List       *joinrightcols pg_node_attr(query_jumble_ignore);
 
        /*
         * join_using_alias is an alias clause attached directly to JOIN/USING. 
It
         * is different from the alias field (below) in that it does not hide 
the
         * range variables of the tables being joined.
         */
-       Alias      *join_using_alias;
+       Alias      *join_using_alias pg_node_attr(query_jumble_ignore);
 
        /*
         * Fields valid for a function RTE (else NIL/zero):
@@ -1179,7 +1179,7 @@ typedef struct RangeTblEntry
        /* number of query levels up */
        Index           ctelevelsup;
        /* is this a recursive self-reference? */
-       bool            self_reference;
+       bool            self_reference pg_node_attr(query_jumble_ignore);
 
        /*
         * Fields valid for CTE, VALUES, ENR, and TableFunc RTEs (else NIL):
@@ -1200,11 +1200,11 @@ typedef struct RangeTblEntry
         * for zero coltype is the standard way to detect a dropped column.
         */
        /* OID list of column type OIDs */
-       List       *coltypes;
+       List       *coltypes pg_node_attr(query_jumble_ignore);
        /* integer list of column typmods */
-       List       *coltypmods;
+       List       *coltypmods pg_node_attr(query_jumble_ignore);
        /* OID list of column collation OIDs */
-       List       *colcollations;
+       List       *colcollations pg_node_attr(query_jumble_ignore);
 
        /*
         * Fields valid for ENR RTEs (else NULL/zero):
@@ -1212,21 +1212,21 @@ typedef struct RangeTblEntry
        /* name of ephemeral named relation */
        char       *enrname;
        /* estimated or actual from caller */
-       Cardinality enrtuples;
+       Cardinality enrtuples pg_node_attr(query_jumble_ignore);
 
        /*
         * Fields valid in all RTEs:
         */
        /* user-written alias clause, if any */
-       Alias      *alias;
+       Alias      *alias pg_node_attr(query_jumble_ignore);
        /* expanded reference names */
-       Alias      *eref;
+       Alias      *eref pg_node_attr(query_jumble_ignore);
        /* was LATERAL specified? */
-       bool            lateral;
+       bool            lateral pg_node_attr(query_jumble_ignore);
        /* present in FROM clause? */
-       bool            inFromCl;
+       bool            inFromCl pg_node_attr(query_jumble_ignore);
        /* security barrier quals to apply, if any */
-       List       *securityQuals;
+       List       *securityQuals pg_node_attr(query_jumble_ignore);
 } RangeTblEntry;
 
 /*
-- 
2.44.0

From e0412cdbd0d84b39a40355042b3c99fd88273b8d Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 11 Mar 2024 09:15:33 +0100
Subject: [PATCH v3 5/8] Make RangeTblEntry dump order consistent

Put the fields alias and eref earlier in the struct, so that it
matches the order in _outRangeTblEntry()/_readRangeTblEntry().  This
helps if we ever want to fully automate out/read of RangeTblEntry.
Also, it makes dumps in the debugger easier to read in the same way.
Internally, this makes no difference.

Discussion: 
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org

TODO: catversion
---
 src/backend/nodes/outfuncs.c   |  1 -
 src/backend/nodes/readfuncs.c  |  1 -
 src/include/nodes/parsenodes.h | 14 ++++++++++----
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 29cbc83bd9..c55375e7f9 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -494,7 +494,6 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
 {
        WRITE_NODE_TYPE("RANGETBLENTRY");
 
-       /* put alias + eref first to make dump more legible */
        WRITE_NODE_FIELD(alias);
        WRITE_NODE_FIELD(eref);
        WRITE_ENUM_FIELD(rtekind, RTEKind);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index a122407c88..c4d01a441a 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -348,7 +348,6 @@ _readRangeTblEntry(void)
 {
        READ_LOCALS(RangeTblEntry);
 
-       /* put alias + eref first to make dump more legible */
        READ_NODE_FIELD(alias);
        READ_NODE_FIELD(eref);
        READ_ENUM_FIELD(rtekind, RTEKind);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index aae50abdb0..6192492df8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1026,6 +1026,16 @@ typedef struct RangeTblEntry
 
        NodeTag         type;
 
+       /*
+        * Fields valid in all RTEs:
+        *
+        * put alias + eref first to make dump more legible
+        */
+       /* user-written alias clause, if any */
+       Alias      *alias pg_node_attr(query_jumble_ignore);
+       /* expanded reference names */
+       Alias      *eref pg_node_attr(query_jumble_ignore);
+
        RTEKind         rtekind;                /* see above */
 
        /*
@@ -1217,10 +1227,6 @@ typedef struct RangeTblEntry
        /*
         * Fields valid in all RTEs:
         */
-       /* user-written alias clause, if any */
-       Alias      *alias pg_node_attr(query_jumble_ignore);
-       /* expanded reference names */
-       Alias      *eref pg_node_attr(query_jumble_ignore);
        /* was LATERAL specified? */
        bool            lateral pg_node_attr(query_jumble_ignore);
        /* present in FROM clause? */
-- 
2.44.0

From 357cfbc2622480abf6a041dc3715f439b74c789f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 11 Mar 2024 09:15:33 +0100
Subject: [PATCH v3 6/8] WIP: AssertRangeTblEntryIsValid()

This provides a function AssertRangeTblEntryIsValid() that checks that
a RangeTblEntry node is filled with a valid combination of fields.
This is hooked into the write/read functions so that it is executed by
WRITE_READ_PARSE_PLAN_TREES.

Discussion: 
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org
---
 src/backend/nodes/nodeFuncs.c | 59 +++++++++++++++++++++++++++++++++++
 src/backend/nodes/outfuncs.c  |  2 ++
 src/backend/nodes/readfuncs.c |  2 ++
 src/include/nodes/nodeFuncs.h |  6 ++++
 4 files changed, 69 insertions(+)

diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 6ba8e73256..db1b9bec13 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -4571,3 +4571,62 @@ planstate_walk_members(PlanState **planstates, int 
nplans,
 
        return false;
 }
+
+#ifdef USE_ASSERT_CHECKING
+
+/*
+ * Assertion check that a RangeTblEntry node is filled with a valid
+ * combination of fields.
+ *
+ * Best used together with WRITE_READ_PARSE_PLAN_TREES.
+ */
+void
+AssertRangeTblEntryIsValid(const RangeTblEntry *rte)
+{
+       Assert(rte->rtekind == RTE_RELATION ||
+                  rte->rtekind == RTE_SUBQUERY ||
+                  rte->rtekind == RTE_JOIN ||
+                  rte->rtekind == RTE_FUNCTION ||
+                  rte->rtekind == RTE_TABLEFUNC ||
+                  rte->rtekind == RTE_VALUES ||
+                  rte->rtekind == RTE_CTE ||
+                  rte->rtekind == RTE_NAMEDTUPLESTORE ||
+                  rte->rtekind == RTE_RESULT);
+
+       Assert(rte->eref);
+
+       if (rte->relid)
+               Assert(rte->rtekind == RTE_RELATION || rte->rtekind == 
RTE_SUBQUERY || rte->rtekind == RTE_NAMEDTUPLESTORE);
+       if (rte->inh)
+               Assert(rte->rtekind == RTE_RELATION || rte->rtekind == 
RTE_SUBQUERY);
+       if (rte->relkind)
+               Assert(rte->rtekind == RTE_RELATION || rte->rtekind == 
RTE_SUBQUERY);
+       if (rte->rellockmode)
+               Assert(rte->rtekind == RTE_RELATION || rte->rtekind == 
RTE_SUBQUERY);
+       if (rte->tablesample)
+               Assert(rte->rtekind == RTE_RELATION);
+       if (rte->perminfoindex)
+               Assert(rte->rtekind == RTE_RELATION || rte->rtekind == 
RTE_SUBQUERY);
+       if (rte->subquery)
+               Assert(rte->rtekind == RTE_SUBQUERY);
+       if (rte->security_barrier)
+               Assert(rte->rtekind == RTE_SUBQUERY);
+       if (rte->joinmergedcols || rte->joinaliasvars || rte->joinleftcols || 
rte->joinrightcols || rte->join_using_alias)
+               Assert(rte->rtekind == RTE_JOIN);
+       if (rte->functions || rte->funcordinality)
+               Assert(rte->rtekind == RTE_FUNCTION);
+       if (rte->tablefunc)
+               Assert(rte->rtekind == RTE_TABLEFUNC);
+       if (rte->values_lists)
+               Assert(rte->rtekind == RTE_VALUES);
+       if (rte->ctename || rte->ctelevelsup || rte->self_reference)
+               Assert(rte->rtekind == RTE_CTE);
+       if (rte->coltypes || rte->coltypmods || rte->colcollations)
+               Assert(rte->rtekind == RTE_TABLEFUNC || rte->rtekind == 
RTE_VALUES || rte->rtekind == RTE_CTE || rte->rtekind == RTE_NAMEDTUPLESTORE);
+       if (rte->enrname || rte->enrtuples)
+               Assert(rte->rtekind == RTE_NAMEDTUPLESTORE);
+       if (rte->lateral)
+               Assert(rte->rtekind == RTE_RELATION || rte->rtekind == 
RTE_SUBQUERY || rte->rtekind == RTE_FUNCTION || rte->rtekind == RTE_TABLEFUNC 
|| rte->rtekind == RTE_VALUES);
+}
+
+#endif
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c55375e7f9..5e34584c55 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -21,6 +21,7 @@
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
 #include "nodes/bitmapset.h"
+#include "nodes/nodeFuncs.h"
 #include "nodes/nodes.h"
 #include "nodes/pg_list.h"
 #include "utils/datum.h"
@@ -492,6 +493,7 @@ _outExtensibleNode(StringInfo str, const ExtensibleNode 
*node)
 static void
 _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
 {
+       AssertRangeTblEntryIsValid(node);
        WRITE_NODE_TYPE("RANGETBLENTRY");
 
        WRITE_NODE_FIELD(alias);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index c4d01a441a..217d81041a 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -30,6 +30,7 @@
 
 #include "miscadmin.h"
 #include "nodes/bitmapset.h"
+#include "nodes/nodeFuncs.h"
 #include "nodes/readfuncs.h"
 
 
@@ -432,6 +433,7 @@ _readRangeTblEntry(void)
        READ_BOOL_FIELD(inFromCl);
        READ_NODE_FIELD(securityQuals);
 
+       AssertRangeTblEntryIsValid(local_node);
        READ_DONE();
 }
 
diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h
index eaba59bed8..873ed9e9b7 100644
--- a/src/include/nodes/nodeFuncs.h
+++ b/src/include/nodes/nodeFuncs.h
@@ -219,4 +219,10 @@ extern bool planstate_tree_walker_impl(struct PlanState 
*planstate,
                                                                           
planstate_tree_walker_callback walker,
                                                                           void 
*context);
 
+#ifdef USE_ASSERT_CHECKING
+extern void AssertRangeTblEntryIsValid(const RangeTblEntry *rte);
+#else
+#define AssertRangeTblEntryIsValid(rte) ((void)true)
+#endif
+
 #endif                                                 /* NODEFUNCS_H */
-- 
2.44.0

From b2332f2ea03307ee6bc0e2e62fa5f364f7340039 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 11 Mar 2024 09:15:33 +0100
Subject: [PATCH v3 7/8] Simplify range_table_mutator_impl() and
 range_table_entry_walker_impl()

This is part of an effort to reduce the number of special cases in the
node support functions.

This patch removes the switch on rtekind from
range_table_mutator_impl() and range_table_entry_walker_impl().  This
should be fine because all the subroutines can handle unset/NULL
fields.  And it removes one more place that needs to track knowledge
about which fields are valid when.

Discussion: 
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org
---
 src/backend/nodes/nodeFuncs.c | 110 ++++++++++++----------------------
 1 file changed, 37 insertions(+), 73 deletions(-)

diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index db1b9bec13..410f700ee5 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -2699,41 +2699,20 @@ range_table_entry_walker_impl(RangeTblEntry *rte,
                if (WALK(rte))
                        return true;
 
-       switch (rte->rtekind)
-       {
-               case RTE_RELATION:
-                       if (WALK(rte->tablesample))
-                               return true;
-                       break;
-               case RTE_SUBQUERY:
-                       if (!(flags & QTW_IGNORE_RT_SUBQUERIES))
-                               if (WALK(rte->subquery))
-                                       return true;
-                       break;
-               case RTE_JOIN:
-                       if (!(flags & QTW_IGNORE_JOINALIASES))
-                               if (WALK(rte->joinaliasvars))
-                                       return true;
-                       break;
-               case RTE_FUNCTION:
-                       if (WALK(rte->functions))
-                               return true;
-                       break;
-               case RTE_TABLEFUNC:
-                       if (WALK(rte->tablefunc))
-                               return true;
-                       break;
-               case RTE_VALUES:
-                       if (WALK(rte->values_lists))
-                               return true;
-                       break;
-               case RTE_CTE:
-               case RTE_NAMEDTUPLESTORE:
-               case RTE_RESULT:
-                       /* nothing to do */
-                       break;
-       }
-
+       if (WALK(rte->tablesample))
+               return true;
+       if (!(flags & QTW_IGNORE_RT_SUBQUERIES))
+               if (WALK(rte->subquery))
+                       return true;
+       if (!(flags & QTW_IGNORE_JOINALIASES))
+               if (WALK(rte->joinaliasvars))
+                       return true;
+       if (WALK(rte->functions))
+               return true;
+       if (WALK(rte->tablefunc))
+               return true;
+       if (WALK(rte->values_lists))
+               return true;
        if (WALK(rte->securityQuals))
                return true;
 
@@ -3693,47 +3672,32 @@ range_table_mutator_impl(List *rtable,
                RangeTblEntry *newrte;
 
                FLATCOPY(newrte, rte, RangeTblEntry);
-               switch (rte->rtekind)
+
+               MUTATE(newrte->tablesample, rte->tablesample, TableSampleClause 
*);
+
+               if (!(flags & QTW_IGNORE_RT_SUBQUERIES))
+                       MUTATE(newrte->subquery, rte->subquery, Query *);
+               else
                {
-                       case RTE_RELATION:
-                               MUTATE(newrte->tablesample, rte->tablesample,
-                                          TableSampleClause *);
-                               /* we don't bother to copy eref, aliases, etc; 
OK? */
-                               break;
-                       case RTE_SUBQUERY:
-                               if (!(flags & QTW_IGNORE_RT_SUBQUERIES))
-                                       MUTATE(newrte->subquery, rte->subquery, 
Query *);
-                               else
-                               {
-                                       /* else, copy RT subqueries as-is */
-                                       newrte->subquery = 
copyObject(rte->subquery);
-                               }
-                               break;
-                       case RTE_JOIN:
-                               if (!(flags & QTW_IGNORE_JOINALIASES))
-                                       MUTATE(newrte->joinaliasvars, 
rte->joinaliasvars, List *);
-                               else
-                               {
-                                       /* else, copy join aliases as-is */
-                                       newrte->joinaliasvars = 
copyObject(rte->joinaliasvars);
-                               }
-                               break;
-                       case RTE_FUNCTION:
-                               MUTATE(newrte->functions, rte->functions, List 
*);
-                               break;
-                       case RTE_TABLEFUNC:
-                               MUTATE(newrte->tablefunc, rte->tablefunc, 
TableFunc *);
-                               break;
-                       case RTE_VALUES:
-                               MUTATE(newrte->values_lists, rte->values_lists, 
List *);
-                               break;
-                       case RTE_CTE:
-                       case RTE_NAMEDTUPLESTORE:
-                       case RTE_RESULT:
-                               /* nothing to do */
-                               break;
+                       /* else, copy RT subqueries as-is */
+                       newrte->subquery = copyObject(rte->subquery);
                }
+
+               if (!(flags & QTW_IGNORE_JOINALIASES))
+                       MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List 
*);
+               else
+               {
+                       /* else, copy join aliases as-is */
+                       newrte->joinaliasvars = copyObject(rte->joinaliasvars);
+               }
+
+               MUTATE(newrte->functions, rte->functions, List *);
+               MUTATE(newrte->tablefunc, rte->tablefunc, TableFunc *);
+               MUTATE(newrte->values_lists, rte->values_lists, List *);
                MUTATE(newrte->securityQuals, rte->securityQuals, List *);
+
+               /* we don't bother to copy eref, aliases, etc; OK? */
+
                newrt = lappend(newrt, newrte);
        }
        return newrt;
-- 
2.44.0

From ef4c35a8aa6e6e855814629545cacc97fbcb9066 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 11 Mar 2024 09:15:33 +0100
Subject: [PATCH v3 8/8] WIP: Remove custom RangeTblEntry node read/write
 implementations

This is part of an effort to reduce the number of special cases in the
automatically generated node support functions.

This patch removes the custom read/write functions for RangeTblEntry.

Discussion: 
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org

TODO: check how much this bloats stored rules
TODO: catversion
---
 src/backend/nodes/outfuncs.c   | 81 -----------------------------
 src/backend/nodes/readfuncs.c  | 93 ----------------------------------
 src/include/nodes/parsenodes.h |  2 -
 3 files changed, 176 deletions(-)

diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 5e34584c55..dbc316ed32 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -490,87 +490,6 @@ _outExtensibleNode(StringInfo str, const ExtensibleNode 
*node)
        methods->nodeOut(str, node);
 }
 
-static void
-_outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
-{
-       AssertRangeTblEntryIsValid(node);
-       WRITE_NODE_TYPE("RANGETBLENTRY");
-
-       WRITE_NODE_FIELD(alias);
-       WRITE_NODE_FIELD(eref);
-       WRITE_ENUM_FIELD(rtekind, RTEKind);
-
-       switch (node->rtekind)
-       {
-               case RTE_RELATION:
-                       WRITE_OID_FIELD(relid);
-                       WRITE_BOOL_FIELD(inh);
-                       WRITE_CHAR_FIELD(relkind);
-                       WRITE_INT_FIELD(rellockmode);
-                       WRITE_UINT_FIELD(perminfoindex);
-                       WRITE_NODE_FIELD(tablesample);
-                       break;
-               case RTE_SUBQUERY:
-                       WRITE_NODE_FIELD(subquery);
-                       WRITE_BOOL_FIELD(security_barrier);
-                       /* we re-use these RELATION fields, too: */
-                       WRITE_OID_FIELD(relid);
-                       WRITE_BOOL_FIELD(inh);
-                       WRITE_CHAR_FIELD(relkind);
-                       WRITE_INT_FIELD(rellockmode);
-                       WRITE_UINT_FIELD(perminfoindex);
-                       break;
-               case RTE_JOIN:
-                       WRITE_ENUM_FIELD(jointype, JoinType);
-                       WRITE_INT_FIELD(joinmergedcols);
-                       WRITE_NODE_FIELD(joinaliasvars);
-                       WRITE_NODE_FIELD(joinleftcols);
-                       WRITE_NODE_FIELD(joinrightcols);
-                       WRITE_NODE_FIELD(join_using_alias);
-                       break;
-               case RTE_FUNCTION:
-                       WRITE_NODE_FIELD(functions);
-                       WRITE_BOOL_FIELD(funcordinality);
-                       break;
-               case RTE_TABLEFUNC:
-                       WRITE_NODE_FIELD(tablefunc);
-                       break;
-               case RTE_VALUES:
-                       WRITE_NODE_FIELD(values_lists);
-                       WRITE_NODE_FIELD(coltypes);
-                       WRITE_NODE_FIELD(coltypmods);
-                       WRITE_NODE_FIELD(colcollations);
-                       break;
-               case RTE_CTE:
-                       WRITE_STRING_FIELD(ctename);
-                       WRITE_UINT_FIELD(ctelevelsup);
-                       WRITE_BOOL_FIELD(self_reference);
-                       WRITE_NODE_FIELD(coltypes);
-                       WRITE_NODE_FIELD(coltypmods);
-                       WRITE_NODE_FIELD(colcollations);
-                       break;
-               case RTE_NAMEDTUPLESTORE:
-                       WRITE_STRING_FIELD(enrname);
-                       WRITE_FLOAT_FIELD(enrtuples);
-                       WRITE_NODE_FIELD(coltypes);
-                       WRITE_NODE_FIELD(coltypmods);
-                       WRITE_NODE_FIELD(colcollations);
-                       /* we re-use these RELATION fields, too: */
-                       WRITE_OID_FIELD(relid);
-                       break;
-               case RTE_RESULT:
-                       /* no extra fields */
-                       break;
-               default:
-                       elog(ERROR, "unrecognized RTE kind: %d", (int) 
node->rtekind);
-                       break;
-       }
-
-       WRITE_BOOL_FIELD(lateral);
-       WRITE_BOOL_FIELD(inFromCl);
-       WRITE_NODE_FIELD(securityQuals);
-}
-
 static void
 _outA_Expr(StringInfo str, const A_Expr *node)
 {
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 217d81041a..1a322659be 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -344,99 +344,6 @@ _readA_Const(void)
        READ_DONE();
 }
 
-static RangeTblEntry *
-_readRangeTblEntry(void)
-{
-       READ_LOCALS(RangeTblEntry);
-
-       READ_NODE_FIELD(alias);
-       READ_NODE_FIELD(eref);
-       READ_ENUM_FIELD(rtekind, RTEKind);
-
-       switch (local_node->rtekind)
-       {
-               case RTE_RELATION:
-                       READ_OID_FIELD(relid);
-                       READ_BOOL_FIELD(inh);
-                       READ_CHAR_FIELD(relkind);
-                       READ_INT_FIELD(rellockmode);
-                       READ_UINT_FIELD(perminfoindex);
-                       READ_NODE_FIELD(tablesample);
-                       break;
-               case RTE_SUBQUERY:
-                       READ_NODE_FIELD(subquery);
-                       READ_BOOL_FIELD(security_barrier);
-                       /* we re-use these RELATION fields, too: */
-                       READ_OID_FIELD(relid);
-                       READ_BOOL_FIELD(inh);
-                       READ_CHAR_FIELD(relkind);
-                       READ_INT_FIELD(rellockmode);
-                       READ_UINT_FIELD(perminfoindex);
-                       break;
-               case RTE_JOIN:
-                       READ_ENUM_FIELD(jointype, JoinType);
-                       READ_INT_FIELD(joinmergedcols);
-                       READ_NODE_FIELD(joinaliasvars);
-                       READ_NODE_FIELD(joinleftcols);
-                       READ_NODE_FIELD(joinrightcols);
-                       READ_NODE_FIELD(join_using_alias);
-                       break;
-               case RTE_FUNCTION:
-                       READ_NODE_FIELD(functions);
-                       READ_BOOL_FIELD(funcordinality);
-                       break;
-               case RTE_TABLEFUNC:
-                       READ_NODE_FIELD(tablefunc);
-                       /* The RTE must have a copy of the column type info, if 
any */
-                       if (local_node->tablefunc)
-                       {
-                               TableFunc  *tf = local_node->tablefunc;
-
-                               local_node->coltypes = tf->coltypes;
-                               local_node->coltypmods = tf->coltypmods;
-                               local_node->colcollations = tf->colcollations;
-                       }
-                       break;
-               case RTE_VALUES:
-                       READ_NODE_FIELD(values_lists);
-                       READ_NODE_FIELD(coltypes);
-                       READ_NODE_FIELD(coltypmods);
-                       READ_NODE_FIELD(colcollations);
-                       break;
-               case RTE_CTE:
-                       READ_STRING_FIELD(ctename);
-                       READ_UINT_FIELD(ctelevelsup);
-                       READ_BOOL_FIELD(self_reference);
-                       READ_NODE_FIELD(coltypes);
-                       READ_NODE_FIELD(coltypmods);
-                       READ_NODE_FIELD(colcollations);
-                       break;
-               case RTE_NAMEDTUPLESTORE:
-                       READ_STRING_FIELD(enrname);
-                       READ_FLOAT_FIELD(enrtuples);
-                       READ_NODE_FIELD(coltypes);
-                       READ_NODE_FIELD(coltypmods);
-                       READ_NODE_FIELD(colcollations);
-                       /* we re-use these RELATION fields, too: */
-                       READ_OID_FIELD(relid);
-                       break;
-               case RTE_RESULT:
-                       /* no extra fields */
-                       break;
-               default:
-                       elog(ERROR, "unrecognized RTE kind: %d",
-                                (int) local_node->rtekind);
-                       break;
-       }
-
-       READ_BOOL_FIELD(lateral);
-       READ_BOOL_FIELD(inFromCl);
-       READ_NODE_FIELD(securityQuals);
-
-       AssertRangeTblEntryIsValid(local_node);
-       READ_DONE();
-}
-
 static A_Expr *
 _readA_Expr(void)
 {
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 6192492df8..b3b5a6cdf1 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1022,8 +1022,6 @@ typedef enum RTEKind
 
 typedef struct RangeTblEntry
 {
-       pg_node_attr(custom_read_write)
-
        NodeTag         type;
 
        /*
-- 
2.44.0

Reply via email to