On 06.12.23 21:02, Peter Eisentraut wrote:
I have been looking into what it would take to get rid of the
custom_read_write and custom_query_jumble for the RangeTblEntry node
type. This is one of the larger and more complex exceptions left.
(Similar considerations would also apply to the Constraint node type.)
In this updated patch set, I have also added the treatment of the
Constraint type. (I also noted that the manual read/write functions for
the Constraint type are out-of-sync again, so simplifying this would be
really helpful.) I have also added commit messages to each patch.
The way I have re-ordered the patch series now, I think patches 0001
through 0003 are candidates for inclusion after review, patch 0004 still
needs a bit more analysis and testing, as described therein.
From f0e896a201367a639be9d08d070066867c46d7cf Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 15 Jan 2024 11:23:39 +0100
Subject: [PATCH v2 1/4] Remove custom Constraint node read/write
implementations
This is part of an effort to reduce the number of special cases in the
automatically generated node support functions.
Allegedly, only certain fields of the Constraint node are valid based
on contype. But this has historically not been kept up to date in the
read/write functions. The Constraint node is only used for debugging
DDL statements, so there are no strong requirements for its output,
and there is no enforcement for its correctness. (There was no read
support before a6bc3301925.) Commits e7a552f303c and abf46ad9c7b are
examples of where omissions were fixed. And the current output is
again incorrect, because the recently added "inhcount" field is not
included.
This patch just removes the custom read/write implementations for the
Constraint node type. Now we just output all the fields, which is a
bit more than before, but at least we don't have to maintain these
functions anymore. Also, we lose the string representation of the
contype field, but for this marginal use case that seems tolerable.
This patch also changes the documentation of the Constraint struct to
put less emphasis on grouping fields by constraint type but rather
document for each field how it's used.
Discussion:
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org
---
src/backend/nodes/outfuncs.c | 126 -----------------------------
src/backend/nodes/readfuncs.c | 143 ---------------------------------
src/include/nodes/parsenodes.h | 38 +++------
3 files changed, 13 insertions(+), 294 deletions(-)
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 296ba845187..dee2b9e87b2 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -699,132 +699,6 @@ _outA_Const(StringInfo str, const A_Const *node)
WRITE_LOCATION_FIELD(location);
}
-static void
-_outConstraint(StringInfo str, const Constraint *node)
-{
- WRITE_NODE_TYPE("CONSTRAINT");
-
- WRITE_STRING_FIELD(conname);
- WRITE_BOOL_FIELD(deferrable);
- WRITE_BOOL_FIELD(initdeferred);
- WRITE_LOCATION_FIELD(location);
-
- appendStringInfoString(str, " :contype ");
- switch (node->contype)
- {
- case CONSTR_NULL:
- appendStringInfoString(str, "NULL");
- break;
-
- case CONSTR_NOTNULL:
- appendStringInfoString(str, "NOT_NULL");
- WRITE_NODE_FIELD(keys);
- WRITE_INT_FIELD(inhcount);
- WRITE_BOOL_FIELD(is_no_inherit);
- WRITE_BOOL_FIELD(skip_validation);
- WRITE_BOOL_FIELD(initially_valid);
- break;
-
- case CONSTR_DEFAULT:
- appendStringInfoString(str, "DEFAULT");
- WRITE_NODE_FIELD(raw_expr);
- WRITE_STRING_FIELD(cooked_expr);
- break;
-
- case CONSTR_IDENTITY:
- appendStringInfoString(str, "IDENTITY");
- WRITE_NODE_FIELD(options);
- WRITE_CHAR_FIELD(generated_when);
- break;
-
- case CONSTR_GENERATED:
- appendStringInfoString(str, "GENERATED");
- WRITE_NODE_FIELD(raw_expr);
- WRITE_STRING_FIELD(cooked_expr);
- WRITE_CHAR_FIELD(generated_when);
- break;
-
- case CONSTR_CHECK:
- appendStringInfoString(str, "CHECK");
- WRITE_BOOL_FIELD(is_no_inherit);
- WRITE_NODE_FIELD(raw_expr);
- WRITE_STRING_FIELD(cooked_expr);
- WRITE_BOOL_FIELD(skip_validation);
- WRITE_BOOL_FIELD(initially_valid);
- break;
-
- case CONSTR_PRIMARY:
- appendStringInfoString(str, "PRIMARY_KEY");
- WRITE_NODE_FIELD(keys);
- WRITE_NODE_FIELD(including);
- WRITE_NODE_FIELD(options);
- WRITE_STRING_FIELD(indexname);
- WRITE_STRING_FIELD(indexspace);
- WRITE_BOOL_FIELD(reset_default_tblspc);
- /* access_method and where_clause not currently used */
- break;
-
- case CONSTR_UNIQUE:
- appendStringInfoString(str, "UNIQUE");
- WRITE_BOOL_FIELD(nulls_not_distinct);
- WRITE_NODE_FIELD(keys);
- WRITE_NODE_FIELD(including);
- WRITE_NODE_FIELD(options);
- WRITE_STRING_FIELD(indexname);
- WRITE_STRING_FIELD(indexspace);
- WRITE_BOOL_FIELD(reset_default_tblspc);
- /* access_method and where_clause not currently used */
- break;
-
- case CONSTR_EXCLUSION:
- appendStringInfoString(str, "EXCLUSION");
- WRITE_NODE_FIELD(exclusions);
- WRITE_NODE_FIELD(including);
- WRITE_NODE_FIELD(options);
- WRITE_STRING_FIELD(indexname);
- WRITE_STRING_FIELD(indexspace);
- WRITE_BOOL_FIELD(reset_default_tblspc);
- WRITE_STRING_FIELD(access_method);
- WRITE_NODE_FIELD(where_clause);
- break;
-
- case CONSTR_FOREIGN:
- appendStringInfoString(str, "FOREIGN_KEY");
- WRITE_NODE_FIELD(pktable);
- WRITE_NODE_FIELD(fk_attrs);
- WRITE_NODE_FIELD(pk_attrs);
- WRITE_CHAR_FIELD(fk_matchtype);
- WRITE_CHAR_FIELD(fk_upd_action);
- WRITE_CHAR_FIELD(fk_del_action);
- WRITE_NODE_FIELD(fk_del_set_cols);
- WRITE_NODE_FIELD(old_conpfeqop);
- WRITE_OID_FIELD(old_pktable_oid);
- WRITE_BOOL_FIELD(skip_validation);
- WRITE_BOOL_FIELD(initially_valid);
- break;
-
- case CONSTR_ATTR_DEFERRABLE:
- appendStringInfoString(str, "ATTR_DEFERRABLE");
- break;
-
- case CONSTR_ATTR_NOT_DEFERRABLE:
- appendStringInfoString(str, "ATTR_NOT_DEFERRABLE");
- break;
-
- case CONSTR_ATTR_DEFERRED:
- appendStringInfoString(str, "ATTR_DEFERRED");
- break;
-
- case CONSTR_ATTR_IMMEDIATE:
- appendStringInfoString(str, "ATTR_IMMEDIATE");
- break;
-
- default:
- elog(ERROR, "unrecognized ConstrType: %d", (int)
node->contype);
- break;
- }
-}
-
/*
* outNode -
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 1624b345812..b1e2f2b440a 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -343,149 +343,6 @@ _readA_Const(void)
READ_DONE();
}
-/*
- * _readConstraint
- */
-static Constraint *
-_readConstraint(void)
-{
- READ_LOCALS(Constraint);
-
- READ_STRING_FIELD(conname);
- READ_BOOL_FIELD(deferrable);
- READ_BOOL_FIELD(initdeferred);
- READ_LOCATION_FIELD(location);
-
- token = pg_strtok(&length); /* skip :contype */
- token = pg_strtok(&length); /* get field value */
- if (length == 4 && strncmp(token, "NULL", 4) == 0)
- local_node->contype = CONSTR_NULL;
- else if (length == 8 && strncmp(token, "NOT_NULL", 8) == 0)
- local_node->contype = CONSTR_NOTNULL;
- else if (length == 7 && strncmp(token, "DEFAULT", 7) == 0)
- local_node->contype = CONSTR_DEFAULT;
- else if (length == 8 && strncmp(token, "IDENTITY", 8) == 0)
- local_node->contype = CONSTR_IDENTITY;
- else if (length == 9 && strncmp(token, "GENERATED", 9) == 0)
- local_node->contype = CONSTR_GENERATED;
- else if (length == 5 && strncmp(token, "CHECK", 5) == 0)
- local_node->contype = CONSTR_CHECK;
- else if (length == 11 && strncmp(token, "PRIMARY_KEY", 11) == 0)
- local_node->contype = CONSTR_PRIMARY;
- else if (length == 6 && strncmp(token, "UNIQUE", 6) == 0)
- local_node->contype = CONSTR_UNIQUE;
- else if (length == 9 && strncmp(token, "EXCLUSION", 9) == 0)
- local_node->contype = CONSTR_EXCLUSION;
- else if (length == 11 && strncmp(token, "FOREIGN_KEY", 11) == 0)
- local_node->contype = CONSTR_FOREIGN;
- else if (length == 15 && strncmp(token, "ATTR_DEFERRABLE", 15) == 0)
- local_node->contype = CONSTR_ATTR_DEFERRABLE;
- else if (length == 19 && strncmp(token, "ATTR_NOT_DEFERRABLE", 19) == 0)
- local_node->contype = CONSTR_ATTR_NOT_DEFERRABLE;
- else if (length == 13 && strncmp(token, "ATTR_DEFERRED", 13) == 0)
- local_node->contype = CONSTR_ATTR_DEFERRED;
- else if (length == 14 && strncmp(token, "ATTR_IMMEDIATE", 14) == 0)
- local_node->contype = CONSTR_ATTR_IMMEDIATE;
-
- switch (local_node->contype)
- {
- case CONSTR_NULL:
- /* no extra fields */
- break;
-
- case CONSTR_NOTNULL:
- READ_NODE_FIELD(keys);
- READ_INT_FIELD(inhcount);
- READ_BOOL_FIELD(is_no_inherit);
- READ_BOOL_FIELD(skip_validation);
- READ_BOOL_FIELD(initially_valid);
- break;
-
- case CONSTR_DEFAULT:
- READ_NODE_FIELD(raw_expr);
- READ_STRING_FIELD(cooked_expr);
- break;
-
- case CONSTR_IDENTITY:
- READ_NODE_FIELD(options);
- READ_CHAR_FIELD(generated_when);
- break;
-
- case CONSTR_GENERATED:
- READ_NODE_FIELD(raw_expr);
- READ_STRING_FIELD(cooked_expr);
- READ_CHAR_FIELD(generated_when);
- break;
-
- case CONSTR_CHECK:
- READ_BOOL_FIELD(is_no_inherit);
- READ_NODE_FIELD(raw_expr);
- READ_STRING_FIELD(cooked_expr);
- READ_BOOL_FIELD(skip_validation);
- READ_BOOL_FIELD(initially_valid);
- break;
-
- case CONSTR_PRIMARY:
- READ_NODE_FIELD(keys);
- READ_NODE_FIELD(including);
- READ_NODE_FIELD(options);
- READ_STRING_FIELD(indexname);
- READ_STRING_FIELD(indexspace);
- READ_BOOL_FIELD(reset_default_tblspc);
- /* access_method and where_clause not currently used */
- break;
-
- case CONSTR_UNIQUE:
- READ_BOOL_FIELD(nulls_not_distinct);
- READ_NODE_FIELD(keys);
- READ_NODE_FIELD(including);
- READ_NODE_FIELD(options);
- READ_STRING_FIELD(indexname);
- READ_STRING_FIELD(indexspace);
- READ_BOOL_FIELD(reset_default_tblspc);
- /* access_method and where_clause not currently used */
- break;
-
- case CONSTR_EXCLUSION:
- READ_NODE_FIELD(exclusions);
- READ_NODE_FIELD(including);
- READ_NODE_FIELD(options);
- READ_STRING_FIELD(indexname);
- READ_STRING_FIELD(indexspace);
- READ_BOOL_FIELD(reset_default_tblspc);
- READ_STRING_FIELD(access_method);
- READ_NODE_FIELD(where_clause);
- break;
-
- case CONSTR_FOREIGN:
- READ_NODE_FIELD(pktable);
- READ_NODE_FIELD(fk_attrs);
- READ_NODE_FIELD(pk_attrs);
- READ_CHAR_FIELD(fk_matchtype);
- READ_CHAR_FIELD(fk_upd_action);
- READ_CHAR_FIELD(fk_del_action);
- READ_NODE_FIELD(fk_del_set_cols);
- READ_NODE_FIELD(old_conpfeqop);
- READ_OID_FIELD(old_pktable_oid);
- READ_BOOL_FIELD(skip_validation);
- READ_BOOL_FIELD(initially_valid);
- break;
-
- case CONSTR_ATTR_DEFERRABLE:
- case CONSTR_ATTR_NOT_DEFERRABLE:
- case CONSTR_ATTR_DEFERRED:
- case CONSTR_ATTR_IMMEDIATE:
- /* no extra fields */
- break;
-
- default:
- elog(ERROR, "unrecognized ConstrType: %d", (int)
local_node->contype);
- break;
- }
-
- READ_DONE();
-}
-
static RangeTblEntry *
_readRangeTblEntry(void)
{
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b3181f34aee..648b6197502 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2566,43 +2566,33 @@ typedef enum ConstrType /* types of
constraints */
typedef struct Constraint
{
- pg_node_attr(custom_read_write)
-
NodeTag type;
ConstrType contype; /* see above */
-
- /* Fields used for most/all constraint types: */
char *conname; /* Constraint name, or NULL if unnamed
*/
bool deferrable; /* DEFERRABLE? */
bool initdeferred; /* INITIALLY DEFERRED? */
- int location; /* token location, or
-1 if unknown */
-
- /* Fields used for constraints with expressions (CHECK and DEFAULT): */
+ bool skip_validation; /* skip validation of existing
rows? */
+ bool initially_valid; /* mark the new constraint as
valid? */
bool is_no_inherit; /* is constraint non-inheritable? */
- Node *raw_expr; /* expr, as untransformed parse tree */
- char *cooked_expr; /* expr, as nodeToString representation
*/
+ Node *raw_expr; /* CHECK or DEFAULT expression, as
+ *
untransformed parse tree */
+ char *cooked_expr; /* CHECK or DEFAULT expression, as
+ * nodeToString
representation */
char generated_when; /* ALWAYS or BY DEFAULT */
-
- /* Fields used for "raw" NOT NULL constraints: */
- int inhcount; /* initial inheritance
count to apply */
-
- /* Fields used for unique constraints (UNIQUE and PRIMARY KEY): */
+ int inhcount; /* initial inheritance
count to apply, for
+ * "raw" NOT
NULL constraints */
bool nulls_not_distinct; /* null treatment for UNIQUE
constraints */
List *keys; /* String nodes naming
referenced key
- * column(s);
also used for NOT NULL */
+ * column(s);
for UNIQUE/PK/NOT NULL */
List *including; /* String nodes naming referenced nonkey
- * column(s) */
-
- /* Fields used for EXCLUSION constraints: */
- List *exclusions; /* list of (IndexElem, operator name)
pairs */
-
- /* Fields used for index constraints (UNIQUE, PRIMARY KEY, EXCLUSION):
*/
+ * column(s);
for UNIQUE/PK */
+ List *exclusions; /* list of (IndexElem, operator name)
pairs;
+ * for
exclusion constraints */
List *options; /* options from WITH clause */
char *indexname; /* existing index to use; otherwise
NULL */
char *indexspace; /* index tablespace; NULL for default */
bool reset_default_tblspc; /* reset default_tablespace
prior to
* creating the index */
- /* These could be, but currently are not, used for UNIQUE/PKEY: */
char *access_method; /* index access method; NULL for
default */
Node *where_clause; /* partial index predicate */
@@ -2618,9 +2608,7 @@ typedef struct Constraint
Oid old_pktable_oid; /*
pg_constraint.confrelid of my former
* self
*/
- /* Fields used for constraints that allow a NOT VALID specification */
- bool skip_validation; /* skip validation of existing
rows? */
- bool initially_valid; /* mark the new constraint as
valid? */
+ int location; /* token location, or
-1 if unknown */
} Constraint;
/* ----------------------
base-commit: 31acee4b66f9f88ad5c19c1276252688bdaa95c9
--
2.43.0
From 191aae34189594314042299f50309a1de3574be9 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 15 Jan 2024 11:23:39 +0100
Subject: [PATCH v2 2/4] Remove custom _jumbleRangeTblEntry()
This is part of an effort to reduce the number of special cases in the
automatically generated node support functions.
RangeTblEntry has a custom jumble function. This was probably just
carried over from the pg_stat_statements-specific code without any
detailed review. For example, the "inh" field is documented to be
valid in all RTEs, but it's only jumbled for RTE_RELATION. The
"lateral" field isn't looked at at all. I wouldn't be surprised if
there are more cases like this.
This patch removes _jumbleRangeTblEntry() and instead adds per-field
query_jumble_ignore annotations to approximately 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. So for example the "inh" field is now considered in each
case. But it leaves "lateral" alone. Probably, several of these new
query_jumble_ignore should actually be dropped because the code was
wrong before.
Discussion:
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org
---
src/backend/nodes/queryjumblefuncs.c | 48 ----------------------------
src/include/nodes/parsenodes.h | 42 ++++++++++++------------
2 files changed, 21 insertions(+), 69 deletions(-)
diff --git a/src/backend/nodes/queryjumblefuncs.c
b/src/backend/nodes/queryjumblefuncs.c
index e489bfceb56..7accd7b6242 100644
--- a/src/backend/nodes/queryjumblefuncs.c
+++ b/src/backend/nodes/queryjumblefuncs.c
@@ -347,51 +347,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_NODE(tablesample);
- JUMBLE_FIELD(inh);
- break;
- case RTE_SUBQUERY:
- JUMBLE_NODE(subquery);
- break;
- case RTE_JOIN:
- JUMBLE_FIELD(jointype);
- break;
- case RTE_FUNCTION:
- JUMBLE_NODE(functions);
- 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 648b6197502..d377f16a72b 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1018,7 +1018,7 @@ typedef enum RTEKind
typedef struct RangeTblEntry
{
- pg_node_attr(custom_read_write, custom_query_jumble)
+ pg_node_attr(custom_read_write)
NodeTag type;
@@ -1062,16 +1062,16 @@ typedef struct RangeTblEntry
* tables to be invalidated if the underlying table is altered.
*/
Oid relid; /* OID of the relation
*/
- char relkind; /* relation kind (see
pg_class.relkind) */
- int rellockmode; /* lock level that query
requires on the rel */
+ char relkind pg_node_attr(query_jumble_ignore);
/* relation kind (see pg_class.relkind) */
+ int rellockmode pg_node_attr(query_jumble_ignore);
/* lock level that query requires on the rel */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
- Index perminfoindex;
+ Index perminfoindex pg_node_attr(query_jumble_ignore);
/*
* Fields valid for a subquery RTE (else NULL):
*/
Query *subquery; /* the sub-query */
- bool security_barrier; /* is from security_barrier
view? */
+ bool security_barrier pg_node_attr(query_jumble_ignore);
/* is from security_barrier view? */
/*
* Fields valid for a join RTE (else NULL/zero):
@@ -1117,17 +1117,17 @@ typedef struct RangeTblEntry
* 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 */
+ int joinmergedcols
pg_node_attr(query_jumble_ignore); /* number of merged (JOIN USING) columns */
+ List *joinaliasvars pg_node_attr(query_jumble_ignore); /* list
of alias-var expansions */
+ List *joinleftcols pg_node_attr(query_jumble_ignore); /*
left-side input column numbers */
+ List *joinrightcols pg_node_attr(query_jumble_ignore); /*
right-side input column numbers */
/*
* 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):
@@ -1138,7 +1138,7 @@ typedef struct RangeTblEntry
* expandRTE().
*/
List *functions; /* list of RangeTblFunction nodes */
- bool funcordinality; /* is this called WITH ORDINALITY? */
+ bool funcordinality pg_node_attr(query_jumble_ignore); /* is
this called WITH ORDINALITY? */
/*
* Fields valid for a TableFunc RTE (else NULL):
@@ -1155,7 +1155,7 @@ typedef struct RangeTblEntry
*/
char *ctename; /* name of the WITH list item */
Index ctelevelsup; /* number of query levels up */
- bool self_reference; /* is this a recursive self-reference?
*/
+ bool self_reference pg_node_attr(query_jumble_ignore); /* is
this a recursive self-reference? */
/*
* Fields valid for CTE, VALUES, ENR, and TableFunc RTEs (else NIL):
@@ -1175,25 +1175,25 @@ 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 */
+ List *coltypes pg_node_attr(query_jumble_ignore); /* OID
list of column type OIDs */
+ List *coltypmods pg_node_attr(query_jumble_ignore);
/* integer list of column typmods */
+ List *colcollations pg_node_attr(query_jumble_ignore); /* OID
list of column collation OIDs */
/*
* Fields valid for ENR RTEs (else NULL/zero):
*/
char *enrname; /* name of ephemeral named relation */
- Cardinality enrtuples; /* estimated or actual from caller */
+ Cardinality enrtuples pg_node_attr(query_jumble_ignore);
/* estimated or actual from caller */
/*
* Fields valid in all RTEs:
*/
- Alias *alias; /* user-written alias clause,
if any */
- Alias *eref; /* expanded reference names */
- bool lateral; /* subquery, function, or
values is LATERAL? */
+ Alias *alias pg_node_attr(query_jumble_ignore);
/* user-written alias clause, if any */
+ Alias *eref pg_node_attr(query_jumble_ignore);
/* expanded reference names */
+ bool lateral pg_node_attr(query_jumble_ignore);
/* subquery, function, or values is LATERAL? */
bool inh; /* inheritance requested? */
- bool inFromCl; /* present in FROM clause? */
- List *securityQuals; /* security barrier quals to apply, if
any */
+ bool inFromCl pg_node_attr(query_jumble_ignore);
/* present in FROM clause? */
+ List *securityQuals pg_node_attr(query_jumble_ignore); /*
security barrier quals to apply, if any */
} RangeTblEntry;
/*
--
2.43.0
From df2898235350aafe82fb948b73e12a976e71237a Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 15 Jan 2024 11:23:39 +0100
Subject: [PATCH v2 3/4] Simplify range_table_mutator_impl()
This is part of an effort to reduce the number of special cases in the
node support functions.
Allegedly, only certain fields of RangeTblEntry are valid based on
rtekind. But exactly which ones seems to be documented and handled
inconsistently. It seems that over time, new RTE kinds have
"borrowed" fields that notionally belong to other RTE kinds, which is
technically not a problem but creates a bit of a mess when trying to
understand all this.
This patch removes the switch on rtekind from
range_table_mutator_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 | 61 +++++++++++++----------------------
1 file changed, 23 insertions(+), 38 deletions(-)
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index e1a5bc7e95d..fe87238f195 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -3694,47 +3694,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.43.0
From 3f8c3217e529e2b5a07e9ea226fc71eb33e485ad Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 15 Jan 2024 11:23:39 +0100
Subject: [PATCH v2 4/4] 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.
Allegedly, only certain fields of RangeTblEntry are valid based on
rtekind. But exactly which ones seems to be documented and handled
inconsistently. It seems that over time, new RTE kinds have
"borrowed" fields that notionally belong to other RTE kinds, which is
technically not a problem but creates a bit of a mess when trying to
understand all this.
This patch removes the custom read/write functions for RangeTblEntry.
Those functions wanted to have a few fields at the front to make the
dump more legible; this is done now by moving the fields up in the
actual struct.
Discussion:
https://www.postgresql.org/message-id/flat/4b27fc50-8cd6-46f5-ab20-88dbaadca...@eisentraut.org
TODO: clean up the documentation RangeTblEntry node
TODO: check how much this bloats stored rules
TODO: catversion
---
src/backend/nodes/outfuncs.c | 80 -----------------------------
src/backend/nodes/readfuncs.c | 92 ----------------------------------
src/include/nodes/parsenodes.h | 12 +++--
3 files changed, 8 insertions(+), 176 deletions(-)
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index dee2b9e87b2..26cfd60aed9 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -489,86 +489,6 @@ _outExtensibleNode(StringInfo str, const ExtensibleNode
*node)
methods->nodeOut(str, node);
}
-static void
-_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);
-
- switch (node->rtekind)
- {
- case RTE_RELATION:
- WRITE_OID_FIELD(relid);
- WRITE_CHAR_FIELD(relkind);
- WRITE_INT_FIELD(rellockmode);
- WRITE_NODE_FIELD(tablesample);
- WRITE_UINT_FIELD(perminfoindex);
- 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_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(inh);
- 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 b1e2f2b440a..54d3eecc1bc 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -343,98 +343,6 @@ _readA_Const(void)
READ_DONE();
}
-static RangeTblEntry *
-_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);
-
- switch (local_node->rtekind)
- {
- case RTE_RELATION:
- READ_OID_FIELD(relid);
- READ_CHAR_FIELD(relkind);
- READ_INT_FIELD(rellockmode);
- READ_NODE_FIELD(tablesample);
- READ_UINT_FIELD(perminfoindex);
- 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_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(inh);
- READ_BOOL_FIELD(inFromCl);
- READ_NODE_FIELD(securityQuals);
-
- READ_DONE();
-}
-
static A_Expr *
_readA_Expr(void)
{
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index d377f16a72b..8042c5d91ed 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1018,8 +1018,6 @@ typedef enum RTEKind
typedef struct RangeTblEntry
{
- pg_node_attr(custom_read_write)
-
NodeTag type;
RTEKind rtekind; /* see above */
@@ -1030,6 +1028,14 @@ typedef struct RangeTblEntry
* code that is being actively worked on. FIXME someday.
*/
+ /*
+ * Fields valid in all RTEs:
+ *
+ * put alias + eref first to make dump more legible
+ */
+ Alias *alias pg_node_attr(query_jumble_ignore);
/* user-written alias clause, if any */
+ Alias *eref pg_node_attr(query_jumble_ignore);
/* expanded reference names */
+
/*
* Fields valid for a plain relation RTE (else zero):
*
@@ -1188,8 +1194,6 @@ typedef struct RangeTblEntry
/*
* Fields valid in all RTEs:
*/
- Alias *alias pg_node_attr(query_jumble_ignore);
/* user-written alias clause, if any */
- Alias *eref pg_node_attr(query_jumble_ignore);
/* expanded reference names */
bool lateral pg_node_attr(query_jumble_ignore);
/* subquery, function, or values is LATERAL? */
bool inh; /* inheritance requested? */
bool inFromCl pg_node_attr(query_jumble_ignore);
/* present in FROM clause? */
--
2.43.0