v1-0009-Add-script-to-generate-node-support-functions.patch
text/plain
Filename: v1-0009-Add-script-to-generate-node-support-functions.patch
Type: text/plain
Part: 8
Patch
Format: format-patch
Series: patch v1-0009
Subject: Add script to generate node support functions
| File | + | − |
|---|---|---|
| src/backend/Makefile | 6 | 2 |
| src/backend/nodes/copyfuncs.c | 15 | 0 |
| src/backend/nodes/equalfuncs.c | 16 | 3 |
| src/backend/nodes/gen_node_stuff.pl | 641 | 0 |
| src/backend/nodes/.gitignore | 3 | 0 |
| src/backend/nodes/Makefile | 55 | 0 |
| src/backend/nodes/outfuncs.c | 25 | 0 |
| src/backend/nodes/readfuncs.c | 18 | 1 |
| src/include/nodes/.gitignore | 2 | 0 |
| src/include/nodes/nodes.h | 8 | 0 |
| src/include/nodes/parsenodes.h | 1 | 1 |
| src/include/nodes/pathnodes.h | 58 | 58 |
| src/include/nodes/primnodes.h | 9 | 9 |
From 79da68dba05e3ea3b506c4ebf6ea1a1c1e2de6f3 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 7 Jun 2021 16:08:54 +0200
Subject: [PATCH v1 09/10] Add script to generate node support functions
---
src/backend/Makefile | 8 +-
src/backend/nodes/.gitignore | 3 +
src/backend/nodes/Makefile | 55 +++
src/backend/nodes/copyfuncs.c | 15 +
src/backend/nodes/equalfuncs.c | 19 +-
src/backend/nodes/gen_node_stuff.pl | 641 ++++++++++++++++++++++++++++
src/backend/nodes/outfuncs.c | 25 ++
src/backend/nodes/readfuncs.c | 19 +-
src/include/nodes/.gitignore | 2 +
src/include/nodes/nodes.h | 8 +
src/include/nodes/parsenodes.h | 2 +-
src/include/nodes/pathnodes.h | 116 ++---
src/include/nodes/primnodes.h | 18 +-
13 files changed, 857 insertions(+), 74 deletions(-)
create mode 100644 src/backend/nodes/.gitignore
create mode 100644 src/backend/nodes/gen_node_stuff.pl
create mode 100644 src/include/nodes/.gitignore
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 0da848b1fd..a33db1ae01 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -143,11 +143,15 @@ storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lw
submake-catalog-headers:
$(MAKE) -C catalog distprep generated-header-symlinks
+# run this unconditionally to avoid needing to know its dependencies here:
+submake-nodes-headers:
+ $(MAKE) -C nodes distprep generated-header-symlinks
+
# run this unconditionally to avoid needing to know its dependencies here:
submake-utils-headers:
$(MAKE) -C utils distprep generated-header-symlinks
-.PHONY: submake-catalog-headers submake-utils-headers
+.PHONY: submake-catalog-headers submake-nodes-headers submake-utils-headers
# Make symlinks for these headers in the include directory. That way
# we can cut down on the -I options. Also, a symlink is automatically
@@ -162,7 +166,7 @@ submake-utils-headers:
.PHONY: generated-headers
-generated-headers: $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/storage/lwlocknames.h submake-catalog-headers submake-utils-headers
+generated-headers: $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/storage/lwlocknames.h submake-catalog-headers submake-nodes-headers submake-utils-headers
$(top_builddir)/src/include/parser/gram.h: parser/gram.h
prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \
diff --git a/src/backend/nodes/.gitignore b/src/backend/nodes/.gitignore
new file mode 100644
index 0000000000..232c6e1817
--- /dev/null
+++ b/src/backend/nodes/.gitignore
@@ -0,0 +1,3 @@
+/node-stuff-stamp
+/nodetags.h
+/*funcs.inc?.c
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index 5d2b12a993..eb93166e9e 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -30,3 +30,58 @@ OBJS = \
value.o
include $(top_srcdir)/src/backend/common.mk
+
+node_headers = \
+ nodes/nodes.h \
+ nodes/execnodes.h \
+ nodes/plannodes.h \
+ nodes/primnodes.h \
+ nodes/pathnodes.h \
+ nodes/memnodes.h \
+ nodes/extensible.h \
+ nodes/parsenodes.h \
+ nodes/replnodes.h \
+ commands/trigger.h \
+ commands/event_trigger.h \
+ foreign/fdwapi.h \
+ access/amapi.h \
+ access/tableam.h \
+ access/tsmapi.h \
+ utils/rel.h \
+ nodes/supportnodes.h \
+ executor/tuptable.h \
+ nodes/lockoptions.h \
+ access/sdir.h
+
+node_sources = \
+ executor/nodeWindowAgg.c \
+ nodes/tidbitmap.c \
+ utils/mmgr/aset.c \
+ utils/mmgr/generation.c \
+ utils/mmgr/slab.c
+
+node_files = $(addprefix $(top_srcdir)/src/include/,$(node_headers)) $(addprefix $(top_srcdir)/src/backend/,$(node_sources))
+
+# see also catalog/Makefile for an explanation of these make rules
+
+all: distprep generated-header-symlinks
+
+distprep: node-stuff-stamp
+
+.PHONY: generated-header-symlinks
+
+generated-header-symlinks: $(top_builddir)/src/include/nodes/header-stamp
+
+node-stuff-stamp: gen_node_stuff.pl
+ $(PERL) $< $(node_files)
+ touch $@
+
+$(top_builddir)/src/include/nodes/header-stamp: node-stuff-stamp
+ prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \
+ cd '$(dir $@)' && for file in nodetags.h; do \
+ rm -f $$file && $(LN_S) "$$prereqdir/$$file" . ; \
+ done
+ touch $@
+
+maintainer-clean: clean
+ rm -f node-stuff-stamp *funcs.inc?.c nodetags.h
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index dde2d47338..4f57923e9e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -69,6 +69,9 @@
(newnode->fldname = from->fldname)
+#include "copyfuncs.inc1.c"
+
+#ifdef OBSOLETE
/* ****************************************************************
* plannodes.h copy functions
* ****************************************************************
@@ -1450,6 +1453,7 @@ _copyVar(const Var *from)
return newnode;
}
+#endif /*OBSOLETE*/
/*
* _copyConst
@@ -1489,6 +1493,7 @@ _copyConst(const Const *from)
return newnode;
}
+#ifdef OBSOLETE
/*
* _copyParam
*/
@@ -2722,6 +2727,7 @@ _copyParamRef(const ParamRef *from)
return newnode;
}
+#endif /*OBSOLETE*/
static A_Const *
_copyA_Const(const A_Const *from)
@@ -2754,6 +2760,7 @@ _copyA_Const(const A_Const *from)
return newnode;
}
+#ifdef OBSOLETE
static FuncCall *
_copyFuncCall(const FuncCall *from)
{
@@ -4863,6 +4870,7 @@ _copyDropSubscriptionStmt(const DropSubscriptionStmt *from)
return newnode;
}
+#endif /*OBSOLETE*/
/* ****************************************************************
* extensible.h copy functions
@@ -4919,6 +4927,7 @@ _copyValue(const Value *from)
}
+#ifdef OBSOLETE
static ForeignKeyCacheInfo *
_copyForeignKeyCacheInfo(const ForeignKeyCacheInfo *from)
{
@@ -4935,6 +4944,7 @@ _copyForeignKeyCacheInfo(const ForeignKeyCacheInfo *from)
return newnode;
}
+#endif /*OBSOLETE*/
/*
@@ -4956,6 +4966,8 @@ copyObjectImpl(const void *from)
switch (nodeTag(from))
{
+#include "copyfuncs.inc2.c"
+#ifdef OBSOLETE
/*
* PLAN NODES
*/
@@ -5297,6 +5309,7 @@ copyObjectImpl(const void *from)
case T_PlaceHolderInfo:
retval = _copyPlaceHolderInfo(from);
break;
+#endif /*OBSOLETE*/
/*
* VALUE NODES
@@ -5325,6 +5338,7 @@ copyObjectImpl(const void *from)
retval = list_copy(from);
break;
+#ifdef OBSOLETE
/*
* EXTENSIBLE NODES
*/
@@ -5858,6 +5872,7 @@ copyObjectImpl(const void *from)
case T_ForeignKeyCacheInfo:
retval = _copyForeignKeyCacheInfo(from);
break;
+#endif /*OBSOLETE*/
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index e04ec41904..6757337062 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -10,9 +10,6 @@
* because the circular linkages between RelOptInfo and Path nodes can't
* be handled easily in a simple depth-first traversal.
*
- * Currently, in fact, equal() doesn't know how to compare Plan trees
- * either. This might need to be fixed someday.
- *
* NOTE: it is intentional that parse location fields (in nodes that have
* one) are not compared. This is because we want, for example, a variable
* "x" to be considered equal() to another reference to "x" in the query.
@@ -33,6 +30,7 @@
#include "nodes/extensible.h"
#include "nodes/pathnodes.h"
#include "utils/datum.h"
+#include "utils/rel.h"
/*
@@ -90,6 +88,9 @@
((void) 0)
+#include "equalfuncs.inc1.c"
+
+#ifdef OBSOLETE
/*
* Stuff from primnodes.h
*/
@@ -178,6 +179,7 @@ _equalVar(const Var *a, const Var *b)
return true;
}
+#endif /*OBSOLETE*/
static bool
_equalConst(const Const *a, const Const *b)
@@ -200,6 +202,7 @@ _equalConst(const Const *a, const Const *b)
a->constbyval, a->constlen);
}
+#ifdef OBSOLETE
static bool
_equalParam(const Param *a, const Param *b)
{
@@ -933,6 +936,7 @@ _equalPlaceHolderInfo(const PlaceHolderInfo *a, const PlaceHolderInfo *b)
return true;
}
+#endif /*OBSOLETE*/
/*
* Stuff from extensible.h
@@ -954,6 +958,7 @@ _equalExtensibleNode(const ExtensibleNode *a, const ExtensibleNode *b)
return true;
}
+#ifdef OBSOLETE
/*
* Stuff from parsenodes.h
*/
@@ -2397,6 +2402,7 @@ _equalParamRef(const ParamRef *a, const ParamRef *b)
return true;
}
+#endif /*OBSOLETE*/
static bool
_equalA_Const(const A_Const *a, const A_Const *b)
@@ -2408,6 +2414,7 @@ _equalA_Const(const A_Const *a, const A_Const *b)
return true;
}
+#ifdef OBSOLETE
static bool
_equalFuncCall(const FuncCall *a, const FuncCall *b)
{
@@ -3016,6 +3023,7 @@ _equalPartitionCmd(const PartitionCmd *a, const PartitionCmd *b)
return true;
}
+#endif /*OBSOLETE*/
/*
* Stuff from pg_list.h
@@ -3135,6 +3143,8 @@ equal(const void *a, const void *b)
switch (nodeTag(a))
{
+#include "equalfuncs.inc2.c"
+#ifdef OBSOLETE
/*
* PRIMITIVE NODES
*/
@@ -3313,6 +3323,7 @@ equal(const void *a, const void *b)
case T_PlaceHolderInfo:
retval = _equalPlaceHolderInfo(a, b);
break;
+#endif /*OBSOLETE*/
case T_List:
case T_IntList:
@@ -3328,6 +3339,7 @@ equal(const void *a, const void *b)
retval = _equalValue(a, b);
break;
+#ifdef OBSOLETE
/*
* EXTENSIBLE NODES
*/
@@ -3854,6 +3866,7 @@ equal(const void *a, const void *b)
case T_PartitionCmd:
retval = _equalPartitionCmd(a, b);
break;
+#endif /*OBSOLETE*/
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/nodes/gen_node_stuff.pl b/src/backend/nodes/gen_node_stuff.pl
new file mode 100644
index 0000000000..aafe320e0a
--- /dev/null
+++ b/src/backend/nodes/gen_node_stuff.pl
@@ -0,0 +1,641 @@
+#!/usr/bin/perl
+#----------------------------------------------------------------------
+#
+# Generate node support files:
+# - nodetags.h
+# - copyfuncs
+# - equalfuncs
+# - readfuncs
+# - outfuncs
+#
+# src/backend/nodes/gen_node_stuff.pl
+#
+#----------------------------------------------------------------------
+
+use strict;
+use warnings;
+
+use experimental 'smartmatch';
+
+use File::Basename;
+
+use FindBin;
+use lib "$FindBin::RealBin/../catalog";
+
+use Catalog; # for RenameTempFile
+
+
+my @node_types = qw(Node);
+my %node_type_info;
+
+my @no_copy;
+my @no_read_write;
+
+my @scalar_types = qw(
+ bits32 bool char double int int8 int16 int32 int64 long uint8 uint16 uint32 uint64
+ AclMode AttrNumber Cost Index Oid Selectivity Size StrategyNumber SubTransactionId TimeLineID XLogRecPtr
+);
+
+my @enum_types;
+
+# For abstract types we track their fields, so that subtypes can use
+# them, but we don't emit a node tag, so you can't instantiate them.
+my @abstract_types = qw(
+ Node
+ BufferHeapTupleTableSlot HeapTupleTableSlot MinimalTupleTableSlot VirtualTupleTableSlot
+ JoinPath
+ MemoryContextData
+ PartitionPruneStep
+);
+
+# These are additional node tags that don't have their own struct.
+my @extra_tags = qw(IntList OidList Integer Float String BitString Null);
+
+# These are regular nodes, but we skip parsing them from their header
+# files since we won't use their internal structure here anyway.
+push @node_types, qw(List Value);
+
+# XXX maybe this should be abstract?
+push @no_copy, qw(Expr);
+push @no_read_write, qw(Expr);
+
+# pathnodes.h exceptions
+push @no_copy, qw(
+ RelOptInfo IndexOptInfo Path PlannerGlobal EquivalenceClass EquivalenceMember ForeignKeyOptInfo
+ GroupingSetData IncrementalSortPath IndexClause MinMaxAggInfo PathTarget PlannerInfo PlannerParamItem
+ ParamPathInfo RollupData RowIdentityVarInfo StatisticExtInfo
+);
+push @scalar_types, qw(EquivalenceClass* EquivalenceMember* QualCost);
+
+# XXX various things we are not publishing right now to stay level
+# with the manual system
+push @no_copy, qw(CallContext InlineCodeBlock);
+push @no_read_write, qw(AccessPriv AlterTableCmd CallContext CreateOpClassItem FunctionParameter InferClause InlineCodeBlock ObjectWithArgs OnConflictClause PartitionCmd RoleSpec VacuumRelation);
+
+
+## read input
+
+foreach my $infile (@ARGV)
+{
+ my $in_struct;
+ my $subline;
+ my $is_node_struct;
+ my $supertype;
+ my $supertype_field;
+
+ my @my_fields;
+ my %my_field_types;
+ my %my_field_attrs;
+
+ open my $ifh, '<', $infile or die "could not open \"$infile\": $!";
+
+ while (my $line = <$ifh>)
+ {
+ chomp $line;
+ $line =~ s!/\*.*$!!;
+ $line =~ s/\s*$//;
+ next if $line eq '';
+ next if $line =~ m!^\s*\*.*$!; # line starts with *, probably comment continuation
+ next if $line =~ /^#(define|ifdef|endif)/;
+
+ if ($in_struct)
+ {
+ $subline++;
+
+ # first line should have opening brace
+ if ($subline == 1)
+ {
+ $is_node_struct = 0;
+ $supertype = undef;
+ next if $line eq '{';
+ die;
+ }
+ # second line should have node tag or supertype
+ elsif ($subline == 2)
+ {
+ if ($line =~ /^\s*NodeTag\s+type;/)
+ {
+ $is_node_struct = 1;
+ next;
+ }
+ elsif ($line =~ /\s*(\w+)\s+(\w+);/ && $1 ~~ @node_types)
+ {
+ $is_node_struct = 1;
+ $supertype = $1;
+ $supertype_field = $2;
+ next;
+ }
+ }
+
+ # end of struct
+ if ($line =~ /^\}\s*$in_struct;$/ || $line =~ /^\};$/)
+ {
+ if ($is_node_struct)
+ {
+ push @node_types, $in_struct;
+ my @f = @my_fields;
+ my %ft = %my_field_types;
+ my %fa = %my_field_attrs;
+ if ($supertype)
+ {
+ my @superfields;
+ foreach my $sf (@{$node_type_info{$supertype}->{fields}})
+ {
+ my $fn = "${supertype_field}.$sf";
+ push @superfields, $fn;
+ $ft{$fn} = $node_type_info{$supertype}->{field_types}{$sf};
+ $fa{$fn} = $node_type_info{$supertype}->{field_attrs}{$sf};
+ }
+ unshift @f, @superfields;
+ }
+ $node_type_info{$in_struct}->{fields} = \@f;
+ $node_type_info{$in_struct}->{field_types} = \%ft;
+ $node_type_info{$in_struct}->{field_attrs} = \%fa;
+
+ if (basename($infile) eq 'execnodes.h' ||
+ basename($infile) eq 'trigger.h' ||
+ basename($infile) eq 'event_trigger.h' ||
+ basename($infile) eq 'amapi.h' ||
+ basename($infile) eq 'tableam.h' ||
+ basename($infile) eq 'tsmapi.h' ||
+ basename($infile) eq 'fdwapi.h' ||
+ basename($infile) eq 'tuptable.h' ||
+ basename($infile) eq 'replnodes.h' ||
+ basename($infile) eq 'supportnodes.h' ||
+ $infile =~ /\.c$/
+ )
+ {
+ push @no_copy, $in_struct;
+ push @no_read_write, $in_struct;
+ }
+
+ if ($supertype && ($supertype eq 'Path' || $supertype eq 'JoinPath'))
+ {
+ push @no_copy, $in_struct;
+ }
+ }
+
+ # start new cycle
+ $in_struct = undef;
+ @my_fields = ();
+ %my_field_types = ();
+ %my_field_attrs = ();
+ }
+ # normal struct field
+ elsif ($line =~ /^\s*(.+)\s*\b(\w+)(\[\w+\])?\s*(?:pg_node_attr\(([\w ]*)\))?;/)
+ {
+ if ($is_node_struct)
+ {
+ my $type = $1;
+ my $name = $2;
+ my $array_size = $3;
+ my $attr = $4;
+
+ $type =~ s/^const\s*//;
+ $type =~ s/\s*$//;
+ $type =~ s/\s+\*$/*/;
+ die if $type eq '';
+ $type = $type . $array_size if $array_size;
+ push @my_fields, $name;
+ $my_field_types{$name} = $type;
+ $my_field_attrs{$name} = $attr;
+ }
+ }
+ else
+ {
+ if ($is_node_struct)
+ {
+ #warn "$infile:$.: could not parse \"$line\"\n";
+ }
+ }
+ }
+ # not in a struct
+ else
+ {
+ # start of a struct?
+ if ($line =~ /^(?:typedef )?struct (\w+)(\s*\/\*.*)?$/ && $1 ne 'Node')
+ {
+ $in_struct = $1;
+ $subline = 0;
+ }
+ # one node type typedef'ed directly from another
+ elsif ($line =~ /^typedef (\w+) (\w+);$/ && $1 ~~ @node_types)
+ {
+ my $alias_of = $1;
+ my $n = $2;
+
+ push @node_types, $n;
+ my @f = @{$node_type_info{$alias_of}->{fields}};
+ my %ft = %{$node_type_info{$alias_of}->{field_types}};
+ my %fa = %{$node_type_info{$alias_of}->{field_attrs}};
+ $node_type_info{$n}->{fields} = \@f;
+ $node_type_info{$n}->{field_types} = \%ft;
+ $node_type_info{$n}->{field_attrs} = \%fa;
+ }
+ # collect enum names
+ elsif ($line =~ /^typedef enum (\w+)(\s*\/\*.*)?$/)
+ {
+ push @enum_types, $1;
+ }
+ }
+ }
+
+ if ($in_struct)
+ {
+ die "runaway \"$in_struct\" in file \"$infile\"\n";
+ }
+
+ close $ifh;
+} # for each file
+
+
+## write output
+
+my $tmpext = ".tmp$$";
+
+# nodetags.h
+
+open my $nt, '>', 'nodetags.h' . $tmpext or die $!;
+
+my $i = 1;
+foreach my $n (@node_types,@extra_tags)
+{
+ next if $n ~~ @abstract_types;
+ print $nt "\tT_${n} = $i,\n";
+ $i++;
+}
+
+close $nt;
+
+
+# copyfuncs.c, equalfuncs.c
+
+open my $cf, '>', 'copyfuncs.inc1.c' . $tmpext or die $!;
+open my $ef, '>', 'equalfuncs.inc1.c' . $tmpext or die $!;
+open my $cf2, '>', 'copyfuncs.inc2.c' . $tmpext or die $!;
+open my $ef2, '>', 'equalfuncs.inc2.c' . $tmpext or die $!;
+
+my @custom_copy = qw(A_Const Const ExtensibleNode);
+
+foreach my $n (@node_types)
+{
+ next if $n ~~ @abstract_types;
+ next if $n ~~ @no_copy;
+ next if $n eq 'List';
+ next if $n eq 'Value';
+
+ print $cf2 "
+\t\tcase T_${n}:
+\t\t\tretval = _copy${n}(from);
+\t\t\tbreak;";
+
+ print $ef2 "
+\t\tcase T_${n}:
+\t\t\tretval = _equal${n}(a, b);
+\t\t\tbreak;";
+
+ next if $n ~~ @custom_copy;
+
+ print $cf "
+static $n *
+_copy${n}(const $n *from)
+{
+\t${n} *newnode = makeNode($n);
+
+";
+
+ print $ef "
+static bool
+_equal${n}(const $n *a, const $n *b)
+{
+";
+
+ my $last_array_size_field;
+
+ foreach my $f (@{$node_type_info{$n}->{fields}})
+ {
+ my $t = $node_type_info{$n}->{field_types}{$f};
+ my $a = $node_type_info{$n}->{field_attrs}{$f} || '';
+ my $copy_ignore = ($a =~ /\bcopy_ignore\b/);
+ my $equal_ignore = ($a =~ /\bequal_ignore\b/);
+ if ($t eq 'char*')
+ {
+ print $cf "\tCOPY_STRING_FIELD($f);\n" unless $copy_ignore;
+ print $ef "\tCOMPARE_STRING_FIELD($f);\n" unless $equal_ignore;
+ }
+ elsif ($t eq 'Bitmapset*' || $t eq 'Relids')
+ {
+ print $cf "\tCOPY_BITMAPSET_FIELD($f);\n" unless $copy_ignore;
+ print $ef "\tCOMPARE_BITMAPSET_FIELD($f);\n" unless $equal_ignore;
+ }
+ elsif ($t eq 'int' && $f =~ 'location$')
+ {
+ print $cf "\tCOPY_LOCATION_FIELD($f);\n" unless $copy_ignore;
+ print $ef "\tCOMPARE_LOCATION_FIELD($f);\n" unless $equal_ignore;
+ }
+ elsif ($t ~~ @scalar_types || $t ~~ @enum_types)
+ {
+ print $cf "\tCOPY_SCALAR_FIELD($f);\n" unless $copy_ignore;
+ if ($a =~ /\bequal_ignore_if_zero\b/)
+ {
+ print $ef "\tif (a->$f != b->$f && a->$f != 0 && b->$f != 0)\n\t\treturn false;\n";
+ }
+ else
+ {
+ print $ef "\tCOMPARE_SCALAR_FIELD($f);\n" unless $equal_ignore || $t eq 'CoercionForm';
+ }
+ $last_array_size_field = "from->$f";
+ }
+ elsif ($t =~ /(\w+)\*/ && $1 ~~ @scalar_types)
+ {
+ my $tt = $1;
+ print $cf "\tCOPY_POINTER_FIELD($f, $last_array_size_field * sizeof($tt));\n" unless $copy_ignore;
+ (my $l2 = $last_array_size_field) =~ s/from/a/;
+ print $ef "\tCOMPARE_POINTER_FIELD($f, $l2 * sizeof($tt));\n" unless $equal_ignore;
+ }
+ elsif ($t =~ /(\w+)\*/ && $1 ~~ @node_types)
+ {
+ print $cf "\tCOPY_NODE_FIELD($f);\n" unless $copy_ignore;
+ print $ef "\tCOMPARE_NODE_FIELD($f);\n" unless $equal_ignore;
+ $last_array_size_field = "list_length(from->$f)" if $t eq 'List*';
+ }
+ elsif ($t =~ /\w+\[/)
+ {
+ # COPY_SCALAR_FIELD might work for these, but let's not assume that
+ print $cf "\tmemcpy(newnode->$f, from->$f, sizeof(newnode->$f));\n" unless $copy_ignore;
+ print $ef "\tCOMPARE_POINTER_FIELD($f, sizeof(a->$f));\n" unless $equal_ignore;
+ }
+ elsif ($t eq 'struct CustomPathMethods*' || $t eq 'struct CustomScanMethods*')
+ {
+ print $cf "\tCOPY_SCALAR_FIELD($f);\n" unless $copy_ignore;
+ print $ef "\tCOMPARE_SCALAR_FIELD($f);\n" unless $equal_ignore;
+ }
+ else
+ {
+ die "could not handle type \"$t\" in struct \"$n\" field \"$f\"";
+ }
+ }
+
+ print $cf "
+\treturn newnode;
+}
+";
+ print $ef "
+\treturn true;
+}
+";
+}
+
+close $cf;
+close $ef;
+close $cf2;
+close $ef2;
+
+
+# outfuncs.c, readfuncs.c
+
+open my $of, '>', 'outfuncs.inc1.c' . $tmpext or die $!;
+open my $rf, '>', 'readfuncs.inc1.c' . $tmpext or die $!;
+open my $of2, '>', 'outfuncs.inc2.c' . $tmpext or die $!;
+open my $rf2, '>', 'readfuncs.inc2.c' . $tmpext or die $!;
+
+my %name_map = (
+ 'ARRAYEXPR' => 'ARRAY',
+ 'CASEEXPR' => 'CASE',
+ 'CASEWHEN' => 'WHEN',
+ 'COALESCEEXPR' => 'COALESCE',
+ 'COLLATEEXPR' => 'COLLATE',
+ 'DECLARECURSORSTMT' => 'DECLARECURSOR',
+ 'MINMAXEXPR' => 'MINMAX',
+ 'NOTIFYSTMT' => 'NOTIFY',
+ 'RANGETBLENTRY' => 'RTE',
+ 'ROWCOMPAREEXPR' => 'ROWCOMPARE',
+ 'ROWEXPR' => 'ROW',
+);
+
+my @custom_readwrite = qw(A_Const A_Expr BoolExpr Const Constraint ExtensibleNode Query RangeTblEntry);
+
+foreach my $n (@node_types)
+{
+ next if $n ~~ @abstract_types;
+ next if $n ~~ @no_read_write;
+ next if $n eq 'List';
+ next if $n eq 'Value';
+
+ # XXX For now, skip all "Stmt"s except that ones that were there before.
+ if ($n =~ /Stmt$/)
+ {
+ my @keep = qw(AlterStatsStmt CreateForeignTableStmt CreateStatsStmt CreateStmt DeclareCursorStmt ImportForeignSchemaStmt IndexStmt NotifyStmt PlannedStmt PLAssignStmt RawStmt ReturnStmt SelectStmt SetOperationStmt);
+ next unless $n ~~ @keep;
+ }
+
+ # XXX Also skip read support for those that didn't have it before.
+ my $no_read = ($n eq 'A_Star' || $n eq 'A_Const' || $n eq 'A_Expr' || $n eq 'Constraint' || $n =~ /Path$/ || $n eq 'ForeignKeyCacheInfo' || $n eq 'ForeignKeyOptInfo' || $n eq 'PathTarget');
+
+ my $N = uc $n;
+ $N =~ s/_//g;
+ $N = $name_map{$N} if $name_map{$N};
+
+ print $of2 "\t\t\tcase T_${n}:\n".
+ "\t\t\t\t_out${n}(str, obj);\n".
+ "\t\t\t\tbreak;\n";
+
+ print $rf2 "\telse if (MATCH(\"$N\", " . length($N) . "))\n".
+ "\t\treturn_value = _read${n}();\n" unless $no_read;
+
+ next if $n ~~ @custom_readwrite;
+
+ print $of "
+static void
+_out${n}(StringInfo str, const $n *node)
+{
+\tWRITE_NODE_TYPE(\"$N\");
+
+";
+
+ print $rf "
+static $n *
+_read${n}(void)
+{
+\tREAD_LOCALS($n);
+
+" unless $no_read;
+
+ my $last_array_size_field;
+
+ foreach my $f (@{$node_type_info{$n}->{fields}})
+ {
+ my $t = $node_type_info{$n}->{field_types}{$f};
+ my $a = $node_type_info{$n}->{field_attrs}{$f} || '';
+ my $readwrite_ignore = ($a =~ /\breadwrite_ignore\b/);
+ next if $readwrite_ignore;
+
+ # XXX Previously, for subtyping, only the leaf field name is
+ # used. Ponder whether we want to keep it that way.
+
+ if ($t eq 'bool')
+ {
+ print $of "\tWRITE_BOOL_FIELD($f);\n";
+ print $rf "\tREAD_BOOL_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'int' && $f =~ 'location$')
+ {
+ print $of "\tWRITE_LOCATION_FIELD($f);\n";
+ print $rf "\tREAD_LOCATION_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'int' || $t eq 'int32' || $t eq 'AttrNumber' || $t eq 'StrategyNumber')
+ {
+ print $of "\tWRITE_INT_FIELD($f);\n";
+ print $rf "\tREAD_INT_FIELD($f);\n" unless $no_read;
+ $last_array_size_field = "node->$f" if $t eq 'int';
+ }
+ elsif ($t eq 'uint32' || $t eq 'bits32' || $t eq 'AclMode' || $t eq 'BlockNumber' || $t eq 'Index' || $t eq 'SubTransactionId')
+ {
+ print $of "\tWRITE_UINT_FIELD($f);\n";
+ print $rf "\tREAD_UINT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'uint64')
+ {
+ print $of "\tWRITE_UINT64_FIELD($f);\n";
+ print $rf "\tREAD_UINT64_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'Oid')
+ {
+ print $of "\tWRITE_OID_FIELD($f);\n";
+ print $rf "\tREAD_OID_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'long')
+ {
+ print $of "\tWRITE_LONG_FIELD($f);\n";
+ print $rf "\tREAD_LONG_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'char')
+ {
+ print $of "\tWRITE_CHAR_FIELD($f);\n";
+ print $rf "\tREAD_CHAR_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'double')
+ {
+ # XXX We out to split these into separate types, like Cost
+ # etc.
+ if ($f eq 'allvisfrac')
+ {
+ print $of "\tWRITE_FLOAT_FIELD($f, \"%.6f\");\n";
+ }
+ else
+ {
+ print $of "\tWRITE_FLOAT_FIELD($f, \"%.0f\");\n";
+ }
+ print $rf "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'Cost')
+ {
+ print $of "\tWRITE_FLOAT_FIELD($f, \"%.2f\");\n";
+ print $rf "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'QualCost')
+ {
+ print $of "\tWRITE_FLOAT_FIELD($f.startup, \"%.2f\");\n";
+ print $of "\tWRITE_FLOAT_FIELD($f.per_tuple, \"%.2f\");\n";
+ print $rf "\tREAD_FLOAT_FIELD($f.startup);\n" unless $no_read;
+ print $rf "\tREAD_FLOAT_FIELD($f.per_tuple);\n" unless $no_read;
+ }
+ elsif ($t eq 'Selectivity')
+ {
+ print $of "\tWRITE_FLOAT_FIELD($f, \"%.4f\");\n";
+ print $rf "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'char*')
+ {
+ print $of "\tWRITE_STRING_FIELD($f);\n";
+ print $rf "\tREAD_STRING_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'Bitmapset*' || $t eq 'Relids')
+ {
+ print $of "\tWRITE_BITMAPSET_FIELD($f);\n";
+ print $rf "\tREAD_BITMAPSET_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t ~~ @enum_types)
+ {
+ print $of "\tWRITE_ENUM_FIELD($f, $t);\n";
+ print $rf "\tREAD_ENUM_FIELD($f, $t);\n" unless $no_read;
+ }
+ elsif ($t =~ /(\w+)(\*|\[)/ && $1 ~~ @scalar_types)
+ {
+ warn "$t $n.$f" unless $last_array_size_field;
+ my $tt = uc $1;
+ print $of "\tWRITE_${tt}_ARRAY($f, $last_array_size_field);\n";
+ (my $l2 = $last_array_size_field) =~ s/node/local_node/;
+ print $rf "\tREAD_${tt}_ARRAY($f, $l2);\n" unless $no_read;
+ }
+ elsif ($t eq 'RelOptInfo*' && $a eq 'path_hack1')
+ {
+ print $of "\tappendStringInfoString(str, \" :parent_relids \");\n".
+ "\toutBitmapset(str, node->$f->relids);\n";
+ }
+ elsif ($t eq 'PathTarget*' && $a eq 'path_hack2')
+ {
+ (my $f2 = $f) =~ s/pathtarget/parent/;
+ print $of "\tif (node->$f != node->$f2->reltarget)\n".
+ "\t\tWRITE_NODE_FIELD($f);\n";
+ }
+ elsif ($t eq 'ParamPathInfo*' && $a eq 'path_hack3')
+ {
+ print $of "\tif (node->$f)\n".
+ "\t\toutBitmapset(str, node->$f->ppi_req_outer);\n".
+ "\telse\n".
+ "\t\toutBitmapset(str, NULL);\n";
+ }
+ elsif ($t =~ /(\w+)\*/ && $1 ~~ @node_types)
+ {
+ print $of "\tWRITE_NODE_FIELD($f);\n";
+ print $rf "\tREAD_NODE_FIELD($f);\n" unless $no_read;
+ $last_array_size_field = "list_length(node->$f)" if $t eq 'List*';
+ }
+ elsif ($t eq 'struct CustomPathMethods*' || $t eq 'struct CustomScanMethods*')
+ {
+ print $of q{
+ appendStringInfoString(str, " :methods ");
+ outToken(str, node->methods->CustomName);
+};
+ print $rf q!
+ {
+ /* Lookup CustomScanMethods by CustomName */
+ char *custom_name;
+ const CustomScanMethods *methods;
+ token = pg_strtok(&length); /* skip methods: */
+ token = pg_strtok(&length); /* CustomName */
+ custom_name = nullable_string(token, length);
+ methods = GetCustomScanMethods(custom_name, false);
+ local_node->methods = methods;
+ }
+! unless $no_read;
+ }
+ elsif ($t eq 'ParamListInfo' || $t =~ /PartitionBoundInfoData/ || $t eq 'PartitionDirectory' || $t eq 'PartitionScheme' || $t eq 'void*' || $t =~ /\*\*$/)
+ {
+ # ignore
+ }
+ else
+ {
+ die "could not handle type \"$t\" in struct \"$n\" field \"$f\"";
+ }
+ }
+
+ print $of "}
+";
+ print $rf "
+\tREAD_DONE();
+}
+" unless $no_read;
+}
+
+close $of;
+close $rf;
+close $of2;
+close $rf2;
+
+
+foreach my $file (qw(nodetags.h copyfuncs.inc1.c copyfuncs.inc2.c equalfuncs.inc1.c equalfuncs.inc2.c outfuncs.inc1.c outfuncs.inc2.c readfuncs.inc1.c readfuncs.inc2.c))
+{
+ Catalog::RenameTempFile($file, $tmpext);
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index ed08f5acf4..0978bc4e81 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -124,6 +124,8 @@ static void outChar(StringInfo str, char c);
appendStringInfo(str, " %u", node->fldname[i]); \
} while(0)
+#define WRITE_INDEX_ARRAY(fldname, len) WRITE_OID_ARRAY(fldname, len)
+
#define WRITE_INT_ARRAY(fldname, len) \
do { \
appendStringInfoString(str, " :" CppAsString(fldname) " "); \
@@ -288,6 +290,9 @@ outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
}
+#include "outfuncs.inc1.c"
+
+#ifdef OBSOLETE
/*
* Stuff from plannodes.h
*/
@@ -1126,6 +1131,7 @@ _outVar(StringInfo str, const Var *node)
WRITE_INT_FIELD(varattnosyn);
WRITE_LOCATION_FIELD(location);
}
+#endif /*OBSOLETE*/
static void
_outConst(StringInfo str, const Const *node)
@@ -1147,6 +1153,7 @@ _outConst(StringInfo str, const Const *node)
outDatum(str, node->constvalue, node->constlen, node->constbyval);
}
+#ifdef OBSOLETE
static void
_outParam(StringInfo str, const Param *node)
{
@@ -1316,6 +1323,7 @@ _outScalarArrayOpExpr(StringInfo str, const ScalarArrayOpExpr *node)
WRITE_NODE_FIELD(args);
WRITE_LOCATION_FIELD(location);
}
+#endif /*OBSOLETE*/
static void
_outBoolExpr(StringInfo str, const BoolExpr *node)
@@ -1344,6 +1352,7 @@ _outBoolExpr(StringInfo str, const BoolExpr *node)
WRITE_LOCATION_FIELD(location);
}
+#ifdef OBSOLETE
static void
_outSubLink(StringInfo str, const SubLink *node)
{
@@ -2658,6 +2667,7 @@ _outPlannerParamItem(StringInfo str, const PlannerParamItem *node)
WRITE_NODE_FIELD(item);
WRITE_INT_FIELD(paramId);
}
+#endif /*OBSOLETE*/
/*****************************************************************************
*
@@ -2680,6 +2690,7 @@ _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
methods->nodeOut(str, node);
}
+#ifdef OBSOLETE
/*****************************************************************************
*
* Stuff from parsenodes.h.
@@ -3012,6 +3023,7 @@ _outStatsElem(StringInfo str, const StatsElem *node)
WRITE_STRING_FIELD(name);
WRITE_NODE_FIELD(expr);
}
+#endif /*OBSOLETE*/
static void
_outQuery(StringInfo str, const Query *node)
@@ -3084,6 +3096,7 @@ _outQuery(StringInfo str, const Query *node)
WRITE_INT_FIELD(stmt_len);
}
+#ifdef OBSOLETE
static void
_outWithCheckOption(StringInfo str, const WithCheckOption *node)
{
@@ -3222,6 +3235,7 @@ _outSetOperationStmt(StringInfo str, const SetOperationStmt *node)
WRITE_NODE_FIELD(colCollations);
WRITE_NODE_FIELD(groupClauses);
}
+#endif /*OBSOLETE*/
static void
_outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
@@ -3302,6 +3316,7 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
WRITE_NODE_FIELD(securityQuals);
}
+#ifdef OBSOLETE
static void
_outRangeTblFunction(StringInfo str, const RangeTblFunction *node)
{
@@ -3325,6 +3340,7 @@ _outTableSampleClause(StringInfo str, const TableSampleClause *node)
WRITE_NODE_FIELD(args);
WRITE_NODE_FIELD(repeatable);
}
+#endif /*OBSOLETE*/
static void
_outA_Expr(StringInfo str, const A_Expr *node)
@@ -3442,6 +3458,7 @@ _outValue(StringInfo str, const Value *node)
}
}
+#ifdef OBSOLETE
static void
_outColumnRef(StringInfo str, const ColumnRef *node)
{
@@ -3473,6 +3490,7 @@ _outRawStmt(StringInfo str, const RawStmt *node)
WRITE_LOCATION_FIELD(stmt_location);
WRITE_INT_FIELD(stmt_len);
}
+#endif /*OBSOLETE*/
static void
_outA_Const(StringInfo str, const A_Const *node)
@@ -3484,6 +3502,7 @@ _outA_Const(StringInfo str, const A_Const *node)
WRITE_LOCATION_FIELD(location);
}
+#ifdef OBSOLETE
static void
_outA_Star(StringInfo str, const A_Star *node)
{
@@ -3628,6 +3647,7 @@ _outRangeTableFuncCol(StringInfo str, const RangeTableFuncCol *node)
WRITE_NODE_FIELD(coldefexpr);
WRITE_LOCATION_FIELD(location);
}
+#endif /*OBSOLETE*/
static void
_outConstraint(StringInfo str, const Constraint *node)
@@ -3748,6 +3768,7 @@ _outConstraint(StringInfo str, const Constraint *node)
}
}
+#ifdef OBSOLETE
static void
_outForeignKeyCacheInfo(StringInfo str, const ForeignKeyCacheInfo *node)
{
@@ -3808,6 +3829,7 @@ _outPartitionRangeDatum(StringInfo str, const PartitionRangeDatum *node)
WRITE_NODE_FIELD(value);
WRITE_LOCATION_FIELD(location);
}
+#endif /*OBSOLETE*/
/*
* outNode -
@@ -3836,6 +3858,8 @@ outNode(StringInfo str, const void *obj)
appendStringInfoChar(str, '{');
switch (nodeTag(obj))
{
+#include "outfuncs.inc2.c"
+#ifdef OBSOLETE
case T_PlannedStmt:
_outPlannedStmt(str, obj);
break;
@@ -4505,6 +4529,7 @@ outNode(StringInfo str, const void *obj)
case T_PartitionRangeDatum:
_outPartitionRangeDatum(str, obj);
break;
+#endif /*OBSOLETE*/
default:
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index fef4de94e6..b4b9379d9d 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -240,6 +240,8 @@ readBitmapset(void)
return _readBitmapset();
}
+#include "readfuncs.inc1.c"
+
/*
* _readQuery
*/
@@ -291,6 +293,7 @@ _readQuery(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readNotifyStmt
*/
@@ -589,6 +592,7 @@ _readVar(void)
READ_DONE();
}
+#endif /*OBSOLETE*/
/*
* _readConst
@@ -615,6 +619,7 @@ _readConst(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readParam
*/
@@ -839,6 +844,7 @@ _readScalarArrayOpExpr(void)
READ_DONE();
}
+#endif /*OBSOLETE*/
/*
* _readBoolExpr
@@ -866,6 +872,7 @@ _readBoolExpr(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readSubLink
*/
@@ -1420,6 +1427,7 @@ _readAppendRelInfo(void)
/*
* Stuff from parsenodes.h.
*/
+#endif /*OBSOLETE*/
/*
* _readRangeTblEntry
@@ -1515,6 +1523,7 @@ _readRangeTblEntry(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readRangeTblFunction
*/
@@ -2635,6 +2644,7 @@ _readAlternativeSubPlan(void)
READ_DONE();
}
+#endif /*OBSOLETE*/
/*
* _readExtensibleNode
@@ -2666,6 +2676,7 @@ _readExtensibleNode(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readPartitionBoundSpec
*/
@@ -2700,6 +2711,7 @@ _readPartitionRangeDatum(void)
READ_DONE();
}
+#endif /*OBSOLETE*/
/*
* parseNodeString
@@ -2724,7 +2736,11 @@ parseNodeString(void)
#define MATCH(tokname, namelen) \
(length == namelen && memcmp(token, tokname, namelen) == 0)
- if (MATCH("QUERY", 5))
+ if (false)
+ ;
+#include "readfuncs.inc2.c"
+#ifdef OBSOLETE
+ else if (MATCH("QUERY", 5))
return_value = _readQuery();
else if (MATCH("WITHCHECKOPTION", 15))
return_value = _readWithCheckOption();
@@ -2972,6 +2988,7 @@ parseNodeString(void)
return_value = _readPartitionBoundSpec();
else if (MATCH("PARTITIONRANGEDATUM", 19))
return_value = _readPartitionRangeDatum();
+#endif /*OBSOLETE*/
else
{
elog(ERROR, "badly formatted node string \"%.32s\"...", token);
diff --git a/src/include/nodes/.gitignore b/src/include/nodes/.gitignore
new file mode 100644
index 0000000000..99fb1d3787
--- /dev/null
+++ b/src/include/nodes/.gitignore
@@ -0,0 +1,2 @@
+/nodetags.h
+/header-stamp
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 5e049a67e1..cb140a3b93 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -27,6 +27,8 @@ typedef enum NodeTag
{
T_Invalid = 0,
+#include "nodes/nodetags.h"
+#ifdef OBSOLETE
/*
* TAGS FOR EXECUTOR NODES (execnodes.h)
*/
@@ -527,8 +529,14 @@ typedef enum NodeTag
T_SupportRequestCost, /* in nodes/supportnodes.h */
T_SupportRequestRows, /* in nodes/supportnodes.h */
T_SupportRequestIndexCondition /* in nodes/supportnodes.h */
+#endif /*OBSOLETE*/
} NodeTag;
+/*
+ * used in node definitions to set extra information for gen_node_stuff.pl
+ */
+#define pg_node_attr(x)
+
/*
* The first field of a node of any type is guaranteed to be the NodeTag.
* Hence the type of any node can be gotten by casting it to Node. Declaring
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index cd9115dbb5..b35d1414de 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -121,7 +121,7 @@ typedef struct Query
QuerySource querySource; /* where did I come from? */
- uint64 queryId; /* query identifier (can be set by plugins) */
+ uint64 queryId pg_node_attr(equal_ignore); /* query identifier (can be set by plugins) */
bool canSetTag; /* do I set the command result tag? */
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 03c80c1620..b98d1958fc 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -226,7 +226,7 @@ struct PlannerInfo
* GEQO.
*/
List *join_rel_list; /* list of join-relation RelOptInfos */
- struct HTAB *join_rel_hash; /* optional hashtable for join relations */
+ struct HTAB *join_rel_hash pg_node_attr(readwrite_ignore); /* optional hashtable for join relations */
/*
* When doing a dynamic-programming-style join search, join_rel_level[k]
@@ -331,7 +331,7 @@ struct PlannerInfo
AttrNumber *grouping_map; /* for GroupingFunc fixup */
List *minmax_aggs; /* List of MinMaxAggInfos */
- MemoryContext planner_cxt; /* context holding PlannerInfo */
+ MemoryContext planner_cxt pg_node_attr(readwrite_ignore); /* context holding PlannerInfo */
double total_table_pages; /* # of pages in all non-dummy tables of
* query */
@@ -706,8 +706,8 @@ typedef struct RelOptInfo
RTEKind rtekind; /* RELATION, SUBQUERY, FUNCTION, etc */
AttrNumber min_attr; /* smallest attrno of rel (often <0) */
AttrNumber max_attr; /* largest attrno of rel */
- Relids *attr_needed; /* array indexed [min_attr .. max_attr] */
- int32 *attr_widths; /* array indexed [min_attr .. max_attr] */
+ Relids *attr_needed pg_node_attr(readwrite_ignore); /* array indexed [min_attr .. max_attr] */
+ int32 *attr_widths pg_node_attr(readwrite_ignore); /* array indexed [min_attr .. max_attr] */
List *lateral_vars; /* LATERAL Vars and PHVs referenced by rel */
Relids lateral_referencers; /* rels that reference me laterally */
List *indexlist; /* list of IndexOptInfo */
@@ -728,13 +728,13 @@ typedef struct RelOptInfo
Oid userid; /* identifies user to check access as */
bool useridiscurrent; /* join is only valid for current user */
/* use "struct FdwRoutine" to avoid including fdwapi.h here */
- struct FdwRoutine *fdwroutine;
+ struct FdwRoutine *fdwroutine pg_node_attr(readwrite_ignore);
void *fdw_private;
/* cache space for remembering if we have proven this relation unique */
- List *unique_for_rels; /* known unique for these other relid
+ List *unique_for_rels pg_node_attr(readwrite_ignore); /* known unique for these other relid
* set(s) */
- List *non_unique_for_rels; /* known not unique for these set(s) */
+ List *non_unique_for_rels pg_node_attr(readwrite_ignore); /* known not unique for these set(s) */
/* used by various scans and joins: */
List *baserestrictinfo; /* RestrictInfo structures (if base rel) */
@@ -829,7 +829,7 @@ struct IndexOptInfo
Oid indexoid; /* OID of the index relation */
Oid reltablespace; /* tablespace of index (not table) */
- RelOptInfo *rel; /* back-link to index's table */
+ RelOptInfo *rel pg_node_attr(readwrite_ignore); /* back-link to index's table */
/* index-size statistics (from pg_class and elsewhere) */
BlockNumber pages; /* number of disk pages in index */
@@ -839,20 +839,20 @@ struct IndexOptInfo
/* index descriptor information */
int ncolumns; /* number of columns in index */
int nkeycolumns; /* number of key columns in index */
- int *indexkeys; /* column numbers of index's attributes both
+ int *indexkeys pg_node_attr(readwrite_ignore); /* column numbers of index's attributes both
* key and included columns, or 0 */
- Oid *indexcollations; /* OIDs of collations of index columns */
- Oid *opfamily; /* OIDs of operator families for columns */
- Oid *opcintype; /* OIDs of opclass declared input data types */
- Oid *sortopfamily; /* OIDs of btree opfamilies, if orderable */
- bool *reverse_sort; /* is sort order descending? */
- bool *nulls_first; /* do NULLs come first in the sort order? */
- bytea **opclassoptions; /* opclass-specific options for columns */
- bool *canreturn; /* which index cols can be returned in an
+ Oid *indexcollations pg_node_attr(readwrite_ignore); /* OIDs of collations of index columns */
+ Oid *opfamily pg_node_attr(readwrite_ignore); /* OIDs of operator families for columns */
+ Oid *opcintype pg_node_attr(readwrite_ignore); /* OIDs of opclass declared input data types */
+ Oid *sortopfamily pg_node_attr(readwrite_ignore); /* OIDs of btree opfamilies, if orderable */
+ bool *reverse_sort pg_node_attr(readwrite_ignore); /* is sort order descending? */
+ bool *nulls_first pg_node_attr(readwrite_ignore); /* do NULLs come first in the sort order? */
+ bytea **opclassoptions pg_node_attr(readwrite_ignore); /* opclass-specific options for columns */
+ bool *canreturn pg_node_attr(readwrite_ignore); /* which index cols can be returned in an
* index-only scan? */
Oid relam; /* OID of the access method (in pg_am) */
- List *indexprs; /* expressions for non-simple index columns */
+ List *indexprs pg_node_attr(readwrite_ignore); /* expressions for non-simple index columns */
List *indpred; /* predicate if a partial index, else NIL */
List *indextlist; /* targetlist representing index columns */
@@ -869,14 +869,14 @@ struct IndexOptInfo
bool hypothetical; /* true if index doesn't really exist */
/* Remaining fields are copied from the index AM's API struct: */
- bool amcanorderbyop; /* does AM support order by operator result? */
- bool amoptionalkey; /* can query omit key for the first column? */
- bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */
- bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */
- bool amhasgettuple; /* does AM have amgettuple interface? */
- bool amhasgetbitmap; /* does AM have amgetbitmap interface? */
- bool amcanparallel; /* does AM support parallel scan? */
- bool amcanmarkpos; /* does AM support mark/restore? */
+ bool amcanorderbyop pg_node_attr(readwrite_ignore); /* does AM support order by operator result? */
+ bool amoptionalkey pg_node_attr(readwrite_ignore); /* can query omit key for the first column? */
+ bool amsearcharray pg_node_attr(readwrite_ignore); /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearchnulls pg_node_attr(readwrite_ignore); /* can AM search for NULL/NOT NULL entries? */
+ bool amhasgettuple pg_node_attr(readwrite_ignore); /* does AM have amgettuple interface? */
+ bool amhasgetbitmap pg_node_attr(readwrite_ignore); /* does AM have amgetbitmap interface? */
+ bool amcanparallel pg_node_attr(readwrite_ignore); /* does AM support parallel scan? */
+ bool amcanmarkpos pg_node_attr(readwrite_ignore); /* does AM support mark/restore? */
/* Rather than include amapi.h here, we declare amcostestimate like this */
void (*amcostestimate) (); /* AM's cost estimator */
};
@@ -926,7 +926,7 @@ typedef struct StatisticExtInfo
NodeTag type;
Oid statOid; /* OID of the statistics row */
- RelOptInfo *rel; /* back-link to statistic's table */
+ RelOptInfo *rel pg_node_attr(readwrite_ignore); /* back-link to statistic's table */
char kind; /* statistics kind of this entry */
Bitmapset *keys; /* attnums of the columns covered */
List *exprs; /* expressions */
@@ -1171,10 +1171,10 @@ typedef struct Path
NodeTag pathtype; /* tag identifying scan/join method */
- RelOptInfo *parent; /* the relation this path can build */
- PathTarget *pathtarget; /* list of Vars/Exprs, cost, width */
+ RelOptInfo *parent pg_node_attr(path_hack1); /* the relation this path can build */
+ PathTarget *pathtarget pg_node_attr(path_hack2); /* list of Vars/Exprs, cost, width */
- ParamPathInfo *param_info; /* parameterization info, or NULL if none */
+ ParamPathInfo *param_info pg_node_attr(path_hack3); /* parameterization info, or NULL if none */
bool parallel_aware; /* engage parallel-aware logic? */
bool parallel_safe; /* OK to use as part of parallel plan? */
@@ -2051,19 +2051,19 @@ typedef struct RestrictInfo
bool outerjoin_delayed; /* true if delayed by lower outer join */
- bool can_join; /* see comment above */
+ bool can_join pg_node_attr(equal_ignore); /* see comment above */
- bool pseudoconstant; /* see comment above */
+ bool pseudoconstant pg_node_attr(equal_ignore); /* see comment above */
- bool leakproof; /* true if known to contain no leaked Vars */
+ bool leakproof pg_node_attr(equal_ignore); /* true if known to contain no leaked Vars */
- VolatileFunctionStatus has_volatile; /* to indicate if clause contains
+ VolatileFunctionStatus has_volatile pg_node_attr(equal_ignore); /* to indicate if clause contains
* any volatile functions. */
Index security_level; /* see comment above */
/* The set of relids (varnos) actually referenced in the clause: */
- Relids clause_relids;
+ Relids clause_relids pg_node_attr(equal_ignore);
/* The set of relids required to evaluate the clause: */
Relids required_relids;
@@ -2075,47 +2075,47 @@ typedef struct RestrictInfo
Relids nullable_relids;
/* These fields are set for any binary opclause: */
- Relids left_relids; /* relids in left side of clause */
- Relids right_relids; /* relids in right side of clause */
+ Relids left_relids pg_node_attr(equal_ignore); /* relids in left side of clause */
+ Relids right_relids pg_node_attr(equal_ignore); /* relids in right side of clause */
/* This field is NULL unless clause is an OR clause: */
- Expr *orclause; /* modified clause with RestrictInfos */
+ Expr *orclause pg_node_attr(equal_ignore); /* modified clause with RestrictInfos */
/* This field is NULL unless clause is potentially redundant: */
- EquivalenceClass *parent_ec; /* generating EquivalenceClass */
+ EquivalenceClass *parent_ec pg_node_attr(equal_ignore readwrite_ignore); /* generating EquivalenceClass */
/* cache space for cost and selectivity */
- QualCost eval_cost; /* eval cost of clause; -1 if not yet set */
- Selectivity norm_selec; /* selectivity for "normal" (JOIN_INNER)
+ QualCost eval_cost pg_node_attr(equal_ignore); /* eval cost of clause; -1 if not yet set */
+ Selectivity norm_selec pg_node_attr(equal_ignore); /* selectivity for "normal" (JOIN_INNER)
* semantics; -1 if not yet set; >1 means a
* redundant clause */
- Selectivity outer_selec; /* selectivity for outer join semantics; -1 if
+ Selectivity outer_selec pg_node_attr(equal_ignore); /* selectivity for outer join semantics; -1 if
* not yet set */
/* valid if clause is mergejoinable, else NIL */
- List *mergeopfamilies; /* opfamilies containing clause operator */
+ List *mergeopfamilies pg_node_attr(equal_ignore); /* opfamilies containing clause operator */
/* cache space for mergeclause processing; NULL if not yet set */
- EquivalenceClass *left_ec; /* EquivalenceClass containing lefthand */
- EquivalenceClass *right_ec; /* EquivalenceClass containing righthand */
- EquivalenceMember *left_em; /* EquivalenceMember for lefthand */
- EquivalenceMember *right_em; /* EquivalenceMember for righthand */
- List *scansel_cache; /* list of MergeScanSelCache structs */
+ EquivalenceClass *left_ec pg_node_attr(equal_ignore readwrite_ignore); /* EquivalenceClass containing lefthand */
+ EquivalenceClass *right_ec pg_node_attr(equal_ignore readwrite_ignore); /* EquivalenceClass containing righthand */
+ EquivalenceMember *left_em pg_node_attr(equal_ignore); /* EquivalenceMember for lefthand */
+ EquivalenceMember *right_em pg_node_attr(equal_ignore); /* EquivalenceMember for righthand */
+ List *scansel_cache pg_node_attr(copy_ignore equal_ignore); /* list of MergeScanSelCache structs */
/* transient workspace for use while considering a specific join path */
- bool outer_is_left; /* T = outer var on left, F = on right */
+ bool outer_is_left pg_node_attr(equal_ignore); /* T = outer var on left, F = on right */
/* valid if clause is hashjoinable, else InvalidOid: */
- Oid hashjoinoperator; /* copy of clause operator */
+ Oid hashjoinoperator pg_node_attr(equal_ignore); /* copy of clause operator */
/* cache space for hashclause processing; -1 if not yet set */
- Selectivity left_bucketsize; /* avg bucketsize of left side */
- Selectivity right_bucketsize; /* avg bucketsize of right side */
- Selectivity left_mcvfreq; /* left side's most common val's freq */
- Selectivity right_mcvfreq; /* right side's most common val's freq */
+ Selectivity left_bucketsize pg_node_attr(equal_ignore); /* avg bucketsize of left side */
+ Selectivity right_bucketsize pg_node_attr(equal_ignore); /* avg bucketsize of right side */
+ Selectivity left_mcvfreq pg_node_attr(equal_ignore); /* left side's most common val's freq */
+ Selectivity right_mcvfreq pg_node_attr(equal_ignore); /* right side's most common val's freq */
/* hash equality operator used for result cache, else InvalidOid */
- Oid hasheqoperator;
+ Oid hasheqoperator pg_node_attr(equal_ignore);
} RestrictInfo;
/*
@@ -2170,8 +2170,8 @@ typedef struct MergeScanSelCache
typedef struct PlaceHolderVar
{
Expr xpr;
- Expr *phexpr; /* the represented expression */
- Relids phrels; /* base relids syntactically within expr src */
+ Expr *phexpr pg_node_attr(equal_ignore); /* the represented expression */
+ Relids phrels pg_node_attr(equal_ignore); /* base relids syntactically within expr src */
Index phid; /* ID for PHV (unique within planner run) */
Index phlevelsup; /* > 0 if PHV belongs to outer query */
} PlaceHolderVar;
@@ -2420,7 +2420,7 @@ typedef struct MinMaxAggInfo
Oid aggfnoid; /* pg_proc Oid of the aggregate */
Oid aggsortop; /* Oid of its sort operator */
Expr *target; /* expression we are aggregating on */
- PlannerInfo *subroot; /* modified "root" for planning the subquery */
+ PlannerInfo *subroot pg_node_attr(readwrite_ignore); /* modified "root" for planning the subquery */
Path *path; /* access path for subquery */
Cost pathcost; /* estimated cost to fetch first row */
Param *param; /* param for subplan's output */
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 3418e23873..62f6413684 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -63,7 +63,7 @@ typedef enum OnCommitAction
typedef struct RangeVar
{
NodeTag type;
- char *catalogname; /* the catalog (database) name, or NULL */
+ char *catalogname pg_node_attr(readwrite_ignore); /* the catalog (database) name, or NULL */
char *schemaname; /* the schema name, or NULL */
char *relname; /* the relation/sequence name */
bool inh; /* expand rel by inheritance? recursively act
@@ -196,8 +196,8 @@ typedef struct Var
Index varlevelsup; /* for subquery variables referencing outer
* relations; 0 in a normal var, >0 means N
* levels up */
- Index varnosyn; /* syntactic relation index (0 if unknown) */
- AttrNumber varattnosyn; /* syntactic attribute number */
+ Index varnosyn pg_node_attr(equal_ignore); /* syntactic relation index (0 if unknown) */
+ AttrNumber varattnosyn pg_node_attr(equal_ignore); /* syntactic attribute number */
int location; /* token location, or -1 if unknown */
} Var;
@@ -324,7 +324,7 @@ typedef struct Aggref
Oid aggtype; /* type Oid of result of the aggregate */
Oid aggcollid; /* OID of collation of result */
Oid inputcollid; /* OID of collation that function should use */
- Oid aggtranstype; /* type Oid of aggregate's transition value */
+ Oid aggtranstype pg_node_attr(equal_ignore); /* type Oid of aggregate's transition value */
List *aggargtypes; /* type Oids of direct and aggregated args */
List *aggdirectargs; /* direct arguments, if an ordered-set agg */
List *args; /* aggregated arguments and sort expressions */
@@ -371,8 +371,8 @@ typedef struct GroupingFunc
Expr xpr;
List *args; /* arguments, not evaluated but kept for
* benefit of EXPLAIN etc. */
- List *refs; /* ressortgrouprefs of arguments */
- List *cols; /* actual column positions set by planner */
+ List *refs pg_node_attr(equal_ignore); /* ressortgrouprefs of arguments */
+ List *cols pg_node_attr(equal_ignore); /* actual column positions set by planner */
Index agglevelsup; /* same as Aggref.agglevelsup */
int location; /* token location */
} GroupingFunc;
@@ -540,7 +540,7 @@ typedef struct OpExpr
{
Expr xpr;
Oid opno; /* PG_OPERATOR OID of the operator */
- Oid opfuncid; /* PG_PROC OID of underlying function */
+ Oid opfuncid pg_node_attr(equal_ignore_if_zero); /* PG_PROC OID of underlying function */
Oid opresulttype; /* PG_TYPE OID of result value */
bool opretset; /* true if operator returns set */
Oid opcollid; /* OID of collation of result */
@@ -589,8 +589,8 @@ typedef struct ScalarArrayOpExpr
{
Expr xpr;
Oid opno; /* PG_OPERATOR OID of the operator */
- Oid opfuncid; /* PG_PROC OID of comparison function */
- Oid hashfuncid; /* PG_PROC OID of hash func or InvalidOid */
+ Oid opfuncid pg_node_attr(equal_ignore_if_zero); /* PG_PROC OID of comparison function */
+ Oid hashfuncid pg_node_attr(equal_ignore_if_zero); /* PG_PROC OID of hash func or InvalidOid */
bool useOr; /* true for ANY, false for ALL */
Oid inputcollid; /* OID of collation that operator should use */
List *args; /* the scalar and array operands */
--
2.31.1