aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/Makefile10
-rw-r--r--src/backend/nodes/.gitignore4
-rw-r--r--src/backend/nodes/Makefile59
-rw-r--r--src/backend/nodes/README80
-rw-r--r--src/backend/nodes/copyfuncs.c20
-rw-r--r--src/backend/nodes/equalfuncs.c22
-rw-r--r--src/backend/nodes/gen_node_support.pl920
-rw-r--r--src/backend/nodes/outfuncs.c34
-rw-r--r--src/backend/nodes/readfuncs.c23
9 files changed, 1117 insertions, 55 deletions
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 4a02006788a..953c80db5ab 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -144,10 +144,14 @@ 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` && \
@@ -185,6 +189,7 @@ distprep:
$(MAKE) -C parser gram.c gram.h scan.c
$(MAKE) -C bootstrap bootparse.c bootscanner.c
$(MAKE) -C catalog distprep
+ $(MAKE) -C nodes distprep
$(MAKE) -C replication repl_gram.c repl_scanner.c syncrep_gram.c syncrep_scanner.c
$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
$(MAKE) -C utils distprep
@@ -297,6 +302,7 @@ distclean: clean
maintainer-clean: distclean
$(MAKE) -C catalog $@
+ $(MAKE) -C nodes $@
$(MAKE) -C utils $@
rm -f bootstrap/bootparse.c \
bootstrap/bootscanner.c \
diff --git a/src/backend/nodes/.gitignore b/src/backend/nodes/.gitignore
new file mode 100644
index 00000000000..0c14b5697b4
--- /dev/null
+++ b/src/backend/nodes/.gitignore
@@ -0,0 +1,4 @@
+/node-support-stamp
+/nodetags.h
+/*funcs.funcs.c
+/*funcs.switch.c
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index 5d2b12a993c..1a0d5b93140 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -30,3 +30,62 @@ 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/extensible.h \
+ nodes/parsenodes.h \
+ nodes/replnodes.h \
+ nodes/value.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
+
+# see also catalog/Makefile for an explanation of these make rules
+
+all: distprep generated-header-symlinks
+
+distprep: node-support-stamp
+
+.PHONY: generated-header-symlinks
+
+generated-header-symlinks: $(top_builddir)/src/include/nodes/header-stamp
+
+# node-support-stamp records the last time we ran gen_node_support.pl.
+# We don't rely on the timestamps of the individual output files,
+# because the Perl script won't update them if they didn't change (to
+# avoid unnecessary recompiles).
+node-support-stamp: gen_node_support.pl $(addprefix $(top_srcdir)/src/include/,$(node_headers))
+ $(PERL) $^
+ touch $@
+
+# These generated headers must be symlinked into builddir/src/include/,
+# using absolute links for the reasons explained in src/backend/Makefile.
+# We use header-stamp to record that we've done this because the symlinks
+# themselves may appear older than node-support-stamp.
+$(top_builddir)/src/include/nodes/header-stamp: node-support-stamp
+ prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \
+ cd '$(dir $@)' && for file in nodetags.h; do \
+ rm -f $$file && $(LN_S) "$$prereqdir/$$file" . ; \
+ done
+ touch $@
+
+copyfuncs.o: copyfuncs.c copyfuncs.funcs.c copyfuncs.switch.c | node-support-stamp
+equalfuncs.o: equalfuncs.c equalfuncs.funcs.c equalfuncs.switch.c | node-support-stamp
+outfuncs.o: outfuncs.c outfuncs.funcs.c outfuncs.switch.c | node-support-stamp
+readfuncs.o: readfuncs.c readfuncs.funcs.c readfuncs.switch.c | node-support-stamp
+
+maintainer-clean: clean
+ rm -f node-support-stamp $(addsuffix funcs.funcs.c,copy equal out read) $(addsuffix funcs.switch.c,copy equal out read) nodetags.h
diff --git a/src/backend/nodes/README b/src/backend/nodes/README
index d066ac5c617..b3dc9afaf77 100644
--- a/src/backend/nodes/README
+++ b/src/backend/nodes/README
@@ -3,26 +3,34 @@ src/backend/nodes/README
Node Structures
===============
-Andrew Yu (11/94)
-
Introduction
------------
-The current node structures are plain old C structures. "Inheritance" is
-achieved by convention. No additional functions will be generated. Functions
-that manipulate node structures reside in this directory.
+The node structures are plain old C structures with the first field
+being of type NodeTag. "Inheritance" is achieved by convention:
+the first field can alternatively be of another node type.
+
+Utility functions for manipulating node structures reside in this
+directory. Some support functions are automatically generated by the
+gen_node_support.pl script, other functions are maintained manually.
+To control the automatic generation of support functions, node types
+and node fields can be annotated with pg_node_attr() specifications;
+see further documentation in src/include/nodes/nodes.h.
FILES IN THIS DIRECTORY (src/backend/nodes/)
General-purpose node manipulation functions:
- copyfuncs.c - copy a node tree
- equalfuncs.c - compare two node trees
- outfuncs.c - convert a node tree to text representation
- readfuncs.c - convert text representation back to a node tree
+ copyfuncs.c - copy a node tree (*)
+ equalfuncs.c - compare two node trees (*)
+ outfuncs.c - convert a node tree to text representation (*)
+ readfuncs.c - convert text representation back to a node tree (*)
makefuncs.c - creator functions for some common node types
nodeFuncs.c - some other general-purpose manipulation functions
+ (*) - Most functions in these files are generated by
+ gen_node_support.pl and #include'd there.
+
Specialized manipulation functions:
bitmapset.c - Bitmapset support
list.c - generic list support
@@ -33,7 +41,7 @@ FILES IN THIS DIRECTORY (src/backend/nodes/)
FILES IN src/include/nodes/
Node definitions:
- nodes.h - define node tags (NodeTag)
+ nodes.h - define node tags (NodeTag) (*)
primnodes.h - primitive nodes
parsenodes.h - parse tree nodes
pathnodes.h - path tree nodes and planner internal structures
@@ -42,39 +50,39 @@ FILES IN src/include/nodes/
memnodes.h - memory nodes
pg_list.h - generic list
+ (*) - Also #include's files generated by gen_node_support.pl.
+
Steps to Add a Node
-------------------
Suppose you want to define a node Foo:
-1. Add a tag (T_Foo) to the enum NodeTag in nodes.h. (If you insert the
- tag in a way that moves the numbers associated with existing tags,
- you'll need to recompile the whole tree after doing this. It doesn't
- force initdb though, because the numbers never go to disk.)
-2. Add the structure definition to the appropriate include/nodes/???.h file.
+1. Add the structure definition to the appropriate include/nodes/???.h file.
If you intend to inherit from, say a Plan node, put Plan as the first field
- of your struct definition.
-3. If you intend to use copyObject, equal, nodeToString or stringToNode,
- add an appropriate function to copyfuncs.c, equalfuncs.c, outfuncs.c
- and readfuncs.c accordingly. (Except for frequently used nodes, don't
- bother writing a creator function in makefuncs.c) The header comments
- in those files give general rules for whether you need to add support.
-4. Add cases to the functions in nodeFuncs.c as needed. There are many
+ of your struct definition. (The T_Foo tag is created automatically.)
+2. Check that the generated support functions in copyfuncs.funcs.c,
+ equalfuncs.funcs.c, outfuncs.funcs.c and readfuncs.funcs.c look
+ correct. Add attributes as necessary to control the outcome. (For
+ some classes of node types, you don't need all four support functions.
+ Use node attributes similar to those of related node types.)
+3. Add cases to the functions in nodeFuncs.c as needed. There are many
other places you'll probably also need to teach about your new node
type. Best bet is to grep for references to one or two similar existing
node types to find all the places to touch.
-
-
-Historical Note
----------------
-
-Prior to the current simple C structure definitions, the Node structures
-used a pseudo-inheritance system which automatically generated creator and
-accessor functions. Since every node inherited from LispValue, the whole thing
-was a mess. Here's a little anecdote:
-
- LispValue definition -- class used to support lisp structures
- in C. This is here because we did not want to totally rewrite
- planner and executor code which depended on lisp structures when
- we ported postgres V1 from lisp to C. -cim 4/23/90
+ (Except for frequently-created nodes, don't bother writing a creator
+ function in makefuncs.c.)
+4. Consider testing your new code with COPY_PARSE_PLAN_TREES,
+ WRITE_READ_PARSE_PLAN_TREES, and RAW_EXPRESSION_COVERAGE_TEST to ensure
+ support has been added everywhere that it's necessary; see
+ pg_config_manual.h about these.
+
+Adding a new node type moves the numbers associated with existing
+tags, so you'll need to recompile the whole tree after doing this.
+(--enable-depend usually helps.) It doesn't force initdb though,
+because the numbers never go to disk. But altering or removing a node
+type should usually be accompanied by an initdb-forcing catalog
+version change, since the interpretation of serialized node trees
+stored in system catalogs is affected by that. (If the node type
+never appears in stored parse trees, as for example Plan nodes do not,
+then a catversion change is not needed to change it.)
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 2c834e4d0d4..b72c79f2dfe 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -23,11 +23,7 @@
#include "postgres.h"
#include "miscadmin.h"
-#include "nodes/extensible.h"
-#include "nodes/pathnodes.h"
-#include "nodes/plannodes.h"
#include "utils/datum.h"
-#include "utils/rel.h"
/*
@@ -73,6 +69,9 @@
(newnode->fldname = from->fldname)
+#include "copyfuncs.funcs.c"
+
+#ifdef OBSOLETE
/* ****************************************************************
* plannodes.h copy functions
* ****************************************************************
@@ -1431,6 +1430,7 @@ _copyVar(const Var *from)
return newnode;
}
+#endif /* OBSOLETE */
/*
* _copyConst
@@ -1470,6 +1470,7 @@ _copyConst(const Const *from)
return newnode;
}
+#ifdef OBSOLETE
/*
* _copyParam
*/
@@ -3214,6 +3215,7 @@ _copyParamRef(const ParamRef *from)
return newnode;
}
+#endif /* OBSOLETE */
static A_Const *
_copyA_Const(const A_Const *from)
@@ -3254,6 +3256,7 @@ _copyA_Const(const A_Const *from)
return newnode;
}
+#ifdef OBSOLETE
static FuncCall *
_copyFuncCall(const FuncCall *from)
{
@@ -5419,6 +5422,7 @@ _copyDropSubscriptionStmt(const DropSubscriptionStmt *from)
return newnode;
}
+#endif /* OBSOLETE */
/* ****************************************************************
* extensible.h copy functions
@@ -5441,6 +5445,7 @@ _copyExtensibleNode(const ExtensibleNode *from)
return newnode;
}
+#ifdef OBSOLETE
/* ****************************************************************
* value.h copy functions
* ****************************************************************
@@ -5511,6 +5516,7 @@ _copyForeignKeyCacheInfo(const ForeignKeyCacheInfo *from)
return newnode;
}
+#endif /* OBSOLETE */
/*
* copyObjectImpl -- implementation of copyObject(); see nodes/nodes.h
@@ -5531,6 +5537,8 @@ copyObjectImpl(const void *from)
switch (nodeTag(from))
{
+#include "copyfuncs.switch.c"
+#ifdef OBSOLETE
/*
* PLAN NODES
*/
@@ -5969,6 +5977,7 @@ copyObjectImpl(const void *from)
case T_BitString:
retval = _copyBitString(from);
break;
+#endif /* OBSOLETE */
/*
* LIST NODES
@@ -5986,6 +5995,8 @@ copyObjectImpl(const void *from)
retval = list_copy(from);
break;
+#ifdef OBSOLETE
+
/*
* EXTENSIBLE NODES
*/
@@ -6537,6 +6548,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 449352639f6..8d18548adee 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.
@@ -30,8 +27,6 @@
#include "postgres.h"
#include "miscadmin.h"
-#include "nodes/extensible.h"
-#include "nodes/pathnodes.h"
#include "utils/datum.h"
@@ -97,6 +92,9 @@
((void) 0)
+#include "equalfuncs.funcs.c"
+
+#ifdef OBSOLETE
/*
* Stuff from primnodes.h
*/
@@ -258,6 +256,7 @@ _equalVar(const Var *a, const Var *b)
return true;
}
+#endif /* OBSOLETE */
static bool
_equalConst(const Const *a, const Const *b)
@@ -280,6 +279,7 @@ _equalConst(const Const *a, const Const *b)
a->constbyval, a->constlen);
}
+#ifdef OBSOLETE
static bool
_equalParam(const Param *a, const Param *b)
{
@@ -1304,6 +1304,7 @@ _equalPlaceHolderInfo(const PlaceHolderInfo *a, const PlaceHolderInfo *b)
return true;
}
+#endif /* OBSOLETE */
/*
* Stuff from extensible.h
@@ -1325,6 +1326,7 @@ _equalExtensibleNode(const ExtensibleNode *a, const ExtensibleNode *b)
return true;
}
+#ifdef OBSOLETE
/*
* Stuff from parsenodes.h
*/
@@ -2815,6 +2817,7 @@ _equalParamRef(const ParamRef *a, const ParamRef *b)
return true;
}
+#endif /* OBSOLETE */
static bool
_equalA_Const(const A_Const *a, const A_Const *b)
@@ -2831,6 +2834,7 @@ _equalA_Const(const A_Const *a, const A_Const *b)
return true;
}
+#ifdef OBSOLETE
static bool
_equalFuncCall(const FuncCall *a, const FuncCall *b)
{
@@ -3468,6 +3472,7 @@ _equalPartitionCmd(const PartitionCmd *a, const PartitionCmd *b)
return true;
}
+#endif /* OBSOLETE */
/*
* Stuff from pg_list.h
@@ -3528,6 +3533,7 @@ _equalList(const List *a, const List *b)
return true;
}
+#ifdef OBSOLETE
/*
* Stuff from value.h
*/
@@ -3571,6 +3577,7 @@ _equalBitString(const BitString *a, const BitString *b)
return true;
}
+#endif /* OBSOLETE */
/*
* equal
@@ -3601,6 +3608,8 @@ equal(const void *a, const void *b)
switch (nodeTag(a))
{
+#include "equalfuncs.switch.c"
+#ifdef OBSOLETE
/*
* PRIMITIVE NODES
*/
@@ -3821,6 +3830,7 @@ equal(const void *a, const void *b)
case T_PlaceHolderInfo:
retval = _equalPlaceHolderInfo(a, b);
break;
+#endif /* OBSOLETE */
case T_List:
case T_IntList:
@@ -3828,6 +3838,7 @@ equal(const void *a, const void *b)
retval = _equalList(a, b);
break;
+#ifdef OBSOLETE
case T_Integer:
retval = _equalInteger(a, b);
break;
@@ -4430,6 +4441,7 @@ equal(const void *a, const void *b)
case T_JsonTableColumn:
retval = _equalJsonTableColumn(a, b);
break;
+#endif /* OBSOLETE */
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl
new file mode 100644
index 00000000000..dca5819f951
--- /dev/null
+++ b/src/backend/nodes/gen_node_support.pl
@@ -0,0 +1,920 @@
+#!/usr/bin/perl
+#----------------------------------------------------------------------
+#
+# Generate node support files:
+# - nodetags.h
+# - copyfuncs
+# - equalfuncs
+# - readfuncs
+# - outfuncs
+#
+# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# src/backend/nodes/gen_node_support.pl
+#
+#----------------------------------------------------------------------
+
+use strict;
+use warnings;
+
+use File::Basename;
+
+use FindBin;
+use lib "$FindBin::RealBin/../catalog";
+
+use Catalog; # for RenameTempFile
+
+
+# Test whether first argument is element of the list in the second
+# argument
+sub elem
+{
+ my $x = shift;
+ return grep { $_ eq $x } @_;
+}
+
+
+# collect node names
+my @node_types = qw(Node);
+# collect info for each node type
+my %node_type_info;
+
+# node types we don't want copy support for
+my @no_copy;
+# node types we don't want equal support for
+my @no_equal;
+# node types we don't want read support for
+my @no_read;
+# node types we don't want read/write support for
+my @no_read_write;
+
+# types that are copied by straight assignment
+my @scalar_types = qw(
+ bits32 bool char double int int8 int16 int32 int64 long uint8 uint16 uint32 uint64
+ AclMode AttrNumber Cardinality Cost Index Oid RelFileNumber Selectivity Size StrategyNumber SubTransactionId TimeLineID XLogRecPtr
+);
+
+# collect enum types
+my @enum_types;
+
+# collect types that are abstract (hence no node tag, no support functions)
+my @abstract_types = qw(Node);
+
+# Special cases that either don't have their own struct or the struct
+# is not in a header file. We generate node tags for them, but
+# they otherwise don't participate in node support.
+my @extra_tags = qw(
+ IntList OidList XidList
+ AllocSetContext GenerationContext SlabContext
+ TIDBitmap
+ WindowObjectData
+);
+
+# This is a regular node, but we skip parsing it from its header file
+# since we won't use its internal structure here anyway.
+push @node_types, qw(List);
+# Lists are specially treated in all four support files, too.
+push @no_copy, qw(List);
+push @no_equal, qw(List);
+push @no_read_write, qw(List);
+
+# Nodes with custom copy/equal implementations are skipped from
+# .funcs.c but need case statements in .switch.c.
+my @custom_copy_equal;
+
+# Similarly for custom read/write implementations.
+my @custom_read_write;
+
+# EquivalenceClasses are never moved, so just shallow-copy the pointer
+push @scalar_types, qw(EquivalenceClass* EquivalenceMember*);
+
+# This is a struct, so we can copy it by assignment. Equal support is
+# currently not required.
+push @scalar_types, qw(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_equal, qw(CallContext InlineCodeBlock);
+push @no_read_write,
+ qw(AccessPriv AlterTableCmd CallContext CreateOpClassItem FunctionParameter InferClause InlineCodeBlock ObjectWithArgs OnConflictClause PartitionCmd RoleSpec VacuumRelation);
+push @no_read, qw(A_ArrayExpr A_Indices A_Indirection AlterStatsStmt
+ CollateClause ColumnDef ColumnRef CreateForeignTableStmt CreateStatsStmt
+ CreateStmt FuncCall ImportForeignSchemaStmt IndexElem IndexStmt
+ JsonAggConstructor JsonArgument JsonArrayAgg JsonArrayConstructor
+ JsonArrayQueryConstructor JsonCommon JsonFuncExpr JsonKeyValue
+ JsonObjectAgg JsonObjectConstructor JsonOutput JsonParseExpr JsonScalarExpr
+ JsonSerializeExpr JsonTable JsonTableColumn JsonTablePlan LockingClause
+ MultiAssignRef PLAssignStmt ParamRef PartitionElem PartitionSpec
+ PlaceHolderVar PublicationObjSpec PublicationTable RangeFunction
+ RangeSubselect RangeTableFunc RangeTableFuncCol RangeTableSample RawStmt
+ ResTarget ReturnStmt SelectStmt SortBy StatsElem TableLikeClause
+ TriggerTransition TypeCast TypeName WindowDef WithClause XmlSerialize);
+
+
+## read input
+
+foreach my $infile (@ARGV)
+{
+ my $in_struct;
+ my $subline;
+ my $is_node_struct;
+ my $supertype;
+ my $supertype_field;
+
+ my $node_attrs = '';
+ my @my_fields;
+ my %my_field_types;
+ my %my_field_attrs;
+
+ open my $ifh, '<', $infile or die "could not open \"$infile\": $!";
+
+ my $file_content = do { local $/; <$ifh> };
+
+ # strip C comments
+ $file_content =~ s{/\*.*?\*/}{}gs;
+
+ foreach my $line (split /\n/, $file_content)
+ {
+ chomp $line;
+ $line =~ s/\s*$//;
+ next if $line eq '';
+ next if $line =~ /^#(define|ifdef|endif)/;
+
+ # we are analyzing a struct definition
+ if ($in_struct)
+ {
+ $subline++;
+
+ # first line should have opening brace
+ if ($subline == 1)
+ {
+ $is_node_struct = 0;
+ $supertype = undef;
+ next if $line eq '{';
+ die "$infile:$.: expected opening brace\n";
+ }
+ # second line could be node attributes
+ elsif ($subline == 2
+ && $line =~ /^\s*pg_node_attr\(([\w(), ]*)\)$/)
+ {
+ $node_attrs = $1;
+ # hack: don't count the line
+ $subline--;
+ next;
+ }
+ # next 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+);/ and elem $1, @node_types)
+ {
+ $is_node_struct = 1;
+ $supertype = $1;
+ $supertype_field = $2;
+ next;
+ }
+ }
+
+ # end of struct
+ if ($line =~ /^\}\s*(?:\Q$in_struct\E\s*)?;$/)
+ {
+ if ($is_node_struct)
+ {
+ # This is the end of a node struct definition.
+ # Save everything we have collected.
+
+ foreach my $attr (split /,\s*/, $node_attrs)
+ {
+ if ($attr eq 'abstract')
+ {
+ push @abstract_types, $in_struct;
+ }
+ elsif ($attr eq 'custom_copy_equal')
+ {
+ push @custom_copy_equal, $in_struct;
+ }
+ elsif ($attr eq 'custom_read_write')
+ {
+ push @custom_read_write, $in_struct;
+ }
+ elsif ($attr eq 'no_copy')
+ {
+ push @no_copy, $in_struct;
+ }
+ elsif ($attr eq 'no_equal')
+ {
+ push @no_equal, $in_struct;
+ }
+ elsif ($attr eq 'no_copy_equal')
+ {
+ push @no_copy, $in_struct;
+ push @no_equal, $in_struct;
+ }
+ elsif ($attr eq 'no_read')
+ {
+ push @no_read, $in_struct;
+ }
+ elsif ($attr eq 'special_read_write')
+ {
+ # This attribute is called
+ # "special_read_write" because there is
+ # special treatment in outNode() and
+ # nodeRead() for these nodes. For this
+ # script, it's the same as
+ # "no_read_write", but calling the
+ # attribute that externally would probably
+ # be confusing, since read/write support
+ # does in fact exist.
+ push @no_read_write, $in_struct;
+ }
+ else
+ {
+ die
+ "$infile:$.: unrecognized attribute \"$attr\"\n";
+ }
+ }
+
+ # node name
+ push @node_types, $in_struct;
+
+ # field names, types, attributes
+ my @f = @my_fields;
+ my %ft = %my_field_types;
+ my %fa = %my_field_attrs;
+
+ # If there is a supertype, add those fields, too.
+ 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};
+ if ($node_type_info{$supertype}
+ ->{field_attrs}{$sf})
+ {
+ # Copy any attributes, adjusting array_size field references
+ my @newa = @{ $node_type_info{$supertype}
+ ->{field_attrs}{$sf} };
+ foreach my $a (@newa)
+ {
+ $a =~
+ s/array_size\((\w+)\)/array_size(${supertype_field}.$1)/;
+ }
+ $fa{$fn} = \@newa;
+ }
+ }
+ unshift @f, @superfields;
+ }
+ # save in global info structure
+ $node_type_info{$in_struct}->{fields} = \@f;
+ $node_type_info{$in_struct}->{field_types} = \%ft;
+ $node_type_info{$in_struct}->{field_attrs} = \%fa;
+
+ # Nodes from these files don't need support functions,
+ # just node tags.
+ if (elem basename($infile),
+ qw(execnodes.h trigger.h event_trigger.h amapi.h tableam.h
+ tsmapi.h fdwapi.h tuptable.h replnodes.h supportnodes.h)
+ )
+ {
+ push @no_copy, $in_struct;
+ push @no_equal, $in_struct;
+ push @no_read_write, $in_struct;
+ }
+
+ # Propagate some node attributes from supertypes
+ if ($supertype)
+ {
+ push @no_copy, $in_struct
+ if elem $supertype, @no_copy;
+ push @no_equal, $in_struct
+ if elem $supertype, @no_equal;
+ push @no_read, $in_struct
+ if elem $supertype, @no_read;
+ }
+ }
+
+ # start new cycle
+ $in_struct = undef;
+ $node_attrs = '';
+ @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 $attrs = $4;
+
+ # strip "const"
+ $type =~ s/^const\s*//;
+ # strip trailing space
+ $type =~ s/\s*$//;
+ # strip space between type and "*" (pointer) */
+ $type =~ s/\s+\*$/*/;
+
+ die if $type eq '';
+
+ my @attrs;
+ if ($attrs)
+ {
+ @attrs = split /,\s*/, $attrs;
+ foreach my $attr (@attrs)
+ {
+ if ( $attr !~ /^array_size\(\w+\)$/
+ && $attr !~ /^copy_as\(\w+\)$/
+ && $attr !~ /^read_as\(\w+\)$/
+ && !elem $attr,
+ qw(equal_ignore equal_ignore_if_zero read_write_ignore
+ write_only_relids write_only_nondefault_pathtarget write_only_req_outer)
+ )
+ {
+ die
+ "$infile:$.: unrecognized attribute \"$attr\"\n";
+ }
+ }
+ }
+
+ $type = $type . $array_size if $array_size;
+ push @my_fields, $name;
+ $my_field_types{$name} = $type;
+ $my_field_attrs{$name} = \@attrs;
+ }
+ }
+ 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+)$/ && $1 ne 'Node')
+ {
+ $in_struct = $1;
+ $subline = 0;
+ }
+ # one node type typedef'ed directly from another
+ elsif ($line =~ /^typedef (\w+) (\w+);$/ and elem $1, @node_types)
+ {
+ my $alias_of = $1;
+ my $n = $2;
+
+ # copy everything over
+ 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 elem $n, @abstract_types;
+ print $nt "\tT_${n} = $i,\n";
+ $i++;
+}
+
+close $nt;
+
+
+# make #include lines necessary to pull in all the struct definitions
+my $node_includes = '';
+foreach my $infile (sort @ARGV)
+{
+ $infile =~ s!.*src/include/!!;
+ $node_includes .= qq{#include "$infile"\n};
+}
+
+
+# copyfuncs.c, equalfuncs.c
+
+open my $cff, '>', 'copyfuncs.funcs.c' . $tmpext or die $!;
+open my $eff, '>', 'equalfuncs.funcs.c' . $tmpext or die $!;
+open my $cfs, '>', 'copyfuncs.switch.c' . $tmpext or die $!;
+open my $efs, '>', 'equalfuncs.switch.c' . $tmpext or die $!;
+
+# add required #include lines to each file set
+print $cff $node_includes;
+print $eff $node_includes;
+
+foreach my $n (@node_types)
+{
+ next if elem $n, @abstract_types;
+ my $struct_no_copy = (elem $n, @no_copy);
+ my $struct_no_equal = (elem $n, @no_equal);
+ next if $struct_no_copy && $struct_no_equal;
+
+ print $cfs "\t\tcase T_${n}:\n"
+ . "\t\t\tretval = _copy${n}(from);\n"
+ . "\t\t\tbreak;\n"
+ unless $struct_no_copy;
+
+ print $efs "\t\tcase T_${n}:\n"
+ . "\t\t\tretval = _equal${n}(a, b);\n"
+ . "\t\t\tbreak;\n"
+ unless $struct_no_equal;
+
+ next if elem $n, @custom_copy_equal;
+
+ print $cff "
+static $n *
+_copy${n}(const $n *from)
+{
+\t${n} *newnode = makeNode($n);
+
+" unless $struct_no_copy;
+
+ print $eff "
+static bool
+_equal${n}(const $n *a, const $n *b)
+{
+" unless $struct_no_equal;
+
+ # print instructions for each 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 = $struct_no_copy;
+ my $equal_ignore = $struct_no_equal;
+
+ # extract per-field attributes
+ my $array_size_field;
+ my $copy_as_field;
+ foreach my $a (@a)
+ {
+ if ($a =~ /^array_size\(([\w.]+)\)$/)
+ {
+ $array_size_field = $1;
+ }
+ elsif ($a =~ /^copy_as\(([\w.]+)\)$/)
+ {
+ $copy_as_field = $1;
+ }
+ elsif ($a eq 'equal_ignore')
+ {
+ $equal_ignore = 1;
+ }
+ }
+
+ # override type-specific copy method if copy_as is specified
+ if (defined $copy_as_field)
+ {
+ print $cff "\tnewnode->$f = $copy_as_field;\n"
+ unless $copy_ignore;
+ $copy_ignore = 1;
+ }
+
+ # select instructions by field type
+ if ($t eq 'char*')
+ {
+ print $cff "\tCOPY_STRING_FIELD($f);\n" unless $copy_ignore;
+ print $eff "\tCOMPARE_STRING_FIELD($f);\n" unless $equal_ignore;
+ }
+ elsif ($t eq 'Bitmapset*' || $t eq 'Relids')
+ {
+ print $cff "\tCOPY_BITMAPSET_FIELD($f);\n" unless $copy_ignore;
+ print $eff "\tCOMPARE_BITMAPSET_FIELD($f);\n"
+ unless $equal_ignore;
+ }
+ elsif ($t eq 'int' && $f =~ 'location$')
+ {
+ print $cff "\tCOPY_LOCATION_FIELD($f);\n" unless $copy_ignore;
+ print $eff "\tCOMPARE_LOCATION_FIELD($f);\n" unless $equal_ignore;
+ }
+ elsif (elem $t, @scalar_types or elem $t, @enum_types)
+ {
+ print $cff "\tCOPY_SCALAR_FIELD($f);\n" unless $copy_ignore;
+ if (elem 'equal_ignore_if_zero', @a)
+ {
+ print $eff
+ "\tif (a->$f != b->$f && a->$f != 0 && b->$f != 0)\n\t\treturn false;\n";
+ }
+ else
+ {
+ # All CoercionForm fields are treated as equal_ignore
+ print $eff "\tCOMPARE_SCALAR_FIELD($f);\n"
+ unless $equal_ignore || $t eq 'CoercionForm';
+ }
+ }
+ # scalar type pointer
+ elsif ($t =~ /(\w+)\*/ and elem $1, @scalar_types)
+ {
+ my $tt = $1;
+ if (!defined $array_size_field)
+ {
+ die "no array size defined for $n.$f of type $t";
+ }
+ if ($node_type_info{$n}->{field_types}{$array_size_field} eq
+ 'List*')
+ {
+ print $cff
+ "\tCOPY_POINTER_FIELD($f, list_length(from->$array_size_field) * sizeof($tt));\n"
+ unless $copy_ignore;
+ print $eff
+ "\tCOMPARE_POINTER_FIELD($f, list_length(a->$array_size_field) * sizeof($tt));\n"
+ unless $equal_ignore;
+ }
+ else
+ {
+ print $cff
+ "\tCOPY_POINTER_FIELD($f, from->$array_size_field * sizeof($tt));\n"
+ unless $copy_ignore;
+ print $eff
+ "\tCOMPARE_POINTER_FIELD($f, a->$array_size_field * sizeof($tt));\n"
+ unless $equal_ignore;
+ }
+ }
+ # node type
+ elsif ($t =~ /(\w+)\*/ and elem $1, @node_types)
+ {
+ print $cff "\tCOPY_NODE_FIELD($f);\n" unless $copy_ignore;
+ print $eff "\tCOMPARE_NODE_FIELD($f);\n" unless $equal_ignore;
+ }
+ # array (inline)
+ elsif ($t =~ /\w+\[/)
+ {
+ print $cff "\tCOPY_ARRAY_FIELD($f);\n" unless $copy_ignore;
+ print $eff "\tCOMPARE_ARRAY_FIELD($f);\n" unless $equal_ignore;
+ }
+ elsif ($t eq 'struct CustomPathMethods*'
+ || $t eq 'struct CustomScanMethods*')
+ {
+ # Fields of these types are required to be a pointer to a
+ # static table of callback functions. So we don't copy
+ # the table itself, just reference the original one.
+ print $cff "\tCOPY_SCALAR_FIELD($f);\n" unless $copy_ignore;
+ print $eff "\tCOMPARE_SCALAR_FIELD($f);\n" unless $equal_ignore;
+ }
+ else
+ {
+ die "could not handle type \"$t\" in struct \"$n\" field \"$f\"";
+ }
+ }
+
+ print $cff "
+\treturn newnode;
+}
+" unless $struct_no_copy;
+ print $eff "
+\treturn true;
+}
+" unless $struct_no_equal;
+}
+
+close $cff;
+close $eff;
+close $cfs;
+close $efs;
+
+
+# outfuncs.c, readfuncs.c
+
+open my $off, '>', 'outfuncs.funcs.c' . $tmpext or die $!;
+open my $rff, '>', 'readfuncs.funcs.c' . $tmpext or die $!;
+open my $ofs, '>', 'outfuncs.switch.c' . $tmpext or die $!;
+open my $rfs, '>', 'readfuncs.switch.c' . $tmpext or die $!;
+
+print $off $node_includes;
+print $rff $node_includes;
+
+foreach my $n (@node_types)
+{
+ next if elem $n, @abstract_types;
+ next if elem $n, @no_read_write;
+
+ # 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 elem $n, @keep;
+ }
+
+ my $no_read = (elem $n, @no_read);
+
+ # output format starts with upper case node type name
+ my $N = uc $n;
+
+ print $ofs "\t\t\tcase T_${n}:\n"
+ . "\t\t\t\t_out${n}(str, obj);\n"
+ . "\t\t\t\tbreak;\n";
+
+ print $rfs "\telse if (MATCH(\"$N\", "
+ . length($N) . "))\n"
+ . "\t\treturn_value = _read${n}();\n"
+ unless $no_read;
+
+ next if elem $n, @custom_read_write;
+
+ print $off "
+static void
+_out${n}(StringInfo str, const $n *node)
+{
+\tWRITE_NODE_TYPE(\"$N\");
+
+";
+
+ print $rff "
+static $n *
+_read${n}(void)
+{
+\tREAD_LOCALS($n);
+
+" unless $no_read;
+
+ # print instructions for each 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} };
+
+ # extract per-field attributes
+ my $read_write_ignore = 0;
+ my $read_as_field;
+ foreach my $a (@a)
+ {
+ if ($a =~ /^read_as\(([\w.]+)\)$/)
+ {
+ $read_as_field = $1;
+ }
+ elsif ($a eq 'read_write_ignore')
+ {
+ $read_write_ignore = 1;
+ }
+ }
+
+ if ($read_write_ignore)
+ {
+ # nothing to do if no_read
+ next if $no_read;
+ # for read_write_ignore with read_as(), emit the appropriate
+ # assignment on the read side and move on.
+ if (defined $read_as_field)
+ {
+ print $rff "\tlocal_node->$f = $read_as_field;\n";
+ next;
+ }
+ # else, bad specification
+ die "$n.$f must not be marked read_write_ignore\n";
+ }
+
+ # select instructions by field type
+ if ($t eq 'bool')
+ {
+ print $off "\tWRITE_BOOL_FIELD($f);\n";
+ print $rff "\tREAD_BOOL_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'int' && $f =~ 'location$')
+ {
+ print $off "\tWRITE_LOCATION_FIELD($f);\n";
+ print $rff "\tREAD_LOCATION_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'int'
+ || $t eq 'int32'
+ || $t eq 'AttrNumber'
+ || $t eq 'StrategyNumber')
+ {
+ print $off "\tWRITE_INT_FIELD($f);\n";
+ print $rff "\tREAD_INT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'uint32'
+ || $t eq 'bits32'
+ || $t eq 'AclMode'
+ || $t eq 'BlockNumber'
+ || $t eq 'Index'
+ || $t eq 'SubTransactionId')
+ {
+ print $off "\tWRITE_UINT_FIELD($f);\n";
+ print $rff "\tREAD_UINT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'uint64')
+ {
+ print $off "\tWRITE_UINT64_FIELD($f);\n";
+ print $rff "\tREAD_UINT64_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'Oid' || $t eq 'RelFileNumber')
+ {
+ print $off "\tWRITE_OID_FIELD($f);\n";
+ print $rff "\tREAD_OID_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'long')
+ {
+ print $off "\tWRITE_LONG_FIELD($f);\n";
+ print $rff "\tREAD_LONG_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'char')
+ {
+ print $off "\tWRITE_CHAR_FIELD($f);\n";
+ print $rff "\tREAD_CHAR_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'double')
+ {
+ print $off "\tWRITE_FLOAT_FIELD($f, \"%.6f\");\n";
+ print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'Cardinality')
+ {
+ print $off "\tWRITE_FLOAT_FIELD($f, \"%.0f\");\n";
+ print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'Cost')
+ {
+ print $off "\tWRITE_FLOAT_FIELD($f, \"%.2f\");\n";
+ print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'QualCost')
+ {
+ print $off "\tWRITE_FLOAT_FIELD($f.startup, \"%.2f\");\n";
+ print $off "\tWRITE_FLOAT_FIELD($f.per_tuple, \"%.2f\");\n";
+ print $rff "\tREAD_FLOAT_FIELD($f.startup);\n" unless $no_read;
+ print $rff "\tREAD_FLOAT_FIELD($f.per_tuple);\n" unless $no_read;
+ }
+ elsif ($t eq 'Selectivity')
+ {
+ print $off "\tWRITE_FLOAT_FIELD($f, \"%.4f\");\n";
+ print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'char*')
+ {
+ print $off "\tWRITE_STRING_FIELD($f);\n";
+ print $rff "\tREAD_STRING_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'Bitmapset*' || $t eq 'Relids')
+ {
+ print $off "\tWRITE_BITMAPSET_FIELD($f);\n";
+ print $rff "\tREAD_BITMAPSET_FIELD($f);\n" unless $no_read;
+ }
+ elsif (elem $t, @enum_types)
+ {
+ print $off "\tWRITE_ENUM_FIELD($f, $t);\n";
+ print $rff "\tREAD_ENUM_FIELD($f, $t);\n" unless $no_read;
+ }
+ # arrays
+ elsif ($t =~ /(\w+)(\*|\[)/ and elem $1, @scalar_types)
+ {
+ my $tt = uc $1;
+ my $array_size_field;
+ foreach my $a (@a)
+ {
+ if ($a =~ /^array_size\(([\w.]+)\)$/)
+ {
+ $array_size_field = $1;
+ last;
+ }
+ }
+ if (!defined $array_size_field)
+ {
+ die "no array size defined for $n.$f of type $t";
+ }
+ if ($node_type_info{$n}->{field_types}{$array_size_field} eq
+ 'List*')
+ {
+ print $off
+ "\tWRITE_${tt}_ARRAY($f, list_length(node->$array_size_field));\n";
+ print $rff
+ "\tREAD_${tt}_ARRAY($f, list_length(local_node->$array_size_field));\n"
+ unless $no_read;
+ }
+ else
+ {
+ print $off
+ "\tWRITE_${tt}_ARRAY($f, node->$array_size_field);\n";
+ print $rff
+ "\tREAD_${tt}_ARRAY($f, local_node->$array_size_field);\n"
+ unless $no_read;
+ }
+ }
+ # Special treatments of several Path node fields
+ elsif ($t eq 'RelOptInfo*' && elem 'write_only_relids', @a)
+ {
+ print $off
+ "\tappendStringInfoString(str, \" :parent_relids \");\n"
+ . "\toutBitmapset(str, node->$f->relids);\n";
+ }
+ elsif ($t eq 'PathTarget*' && elem 'write_only_nondefault_pathtarget',
+ @a)
+ {
+ (my $f2 = $f) =~ s/pathtarget/parent/;
+ print $off "\tif (node->$f != node->$f2->reltarget)\n"
+ . "\t\tWRITE_NODE_FIELD($f);\n";
+ }
+ elsif ($t eq 'ParamPathInfo*' && elem 'write_only_req_outer', @a)
+ {
+ print $off
+ "\tappendStringInfoString(str, \" :required_outer \");\n"
+ . "\tif (node->$f)\n"
+ . "\t\toutBitmapset(str, node->$f->ppi_req_outer);\n"
+ . "\telse\n"
+ . "\t\toutBitmapset(str, NULL);\n";
+ }
+ # node type
+ elsif ($t =~ /(\w+)\*/ and elem $1, @node_types)
+ {
+ print $off "\tWRITE_NODE_FIELD($f);\n";
+ print $rff "\tREAD_NODE_FIELD($f);\n" unless $no_read;
+ }
+ elsif ($t eq 'struct CustomPathMethods*'
+ || $t eq 'struct CustomScanMethods*')
+ {
+ print $off q{
+ /* CustomName is a key to lookup CustomScanMethods */
+ appendStringInfoString(str, " :methods ");
+ outToken(str, node->methods->CustomName);
+};
+ print $rff 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;
+ }
+ else
+ {
+ die "could not handle type \"$t\" in struct \"$n\" field \"$f\"";
+ }
+
+ # for read_as() without read_write_ignore, we have to read the value
+ # that outfuncs.c wrote and then overwrite it.
+ if (defined $read_as_field)
+ {
+ print $rff "\tlocal_node->$f = $read_as_field;\n" unless $no_read;
+ }
+ }
+
+ print $off "}
+";
+ print $rff "
+\tREAD_DONE();
+}
+" unless $no_read;
+}
+
+close $off;
+close $rff;
+close $ofs;
+close $rfs;
+
+
+# now rename the temporary files to their final name
+foreach my $file (
+ qw(nodetags.h copyfuncs.funcs.c copyfuncs.switch.c equalfuncs.funcs.c equalfuncs.switch.c outfuncs.funcs.c outfuncs.switch.c readfuncs.funcs.c readfuncs.switch.c)
+ )
+{
+ Catalog::RenameTempFile($file, $tmpext);
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 77a7a868ca3..f26c129d596 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -31,11 +31,10 @@
#include "lib/stringinfo.h"
#include "miscadmin.h"
-#include "nodes/extensible.h"
-#include "nodes/pathnodes.h"
-#include "nodes/plannodes.h"
+#include "nodes/bitmapset.h"
+#include "nodes/nodes.h"
+#include "nodes/pg_list.h"
#include "utils/datum.h"
-#include "utils/rel.h"
static void outChar(StringInfo str, char c);
@@ -306,6 +305,9 @@ outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
}
+#include "outfuncs.funcs.c"
+
+#ifdef OBSOLETE
/*
* Stuff from plannodes.h
*/
@@ -1138,6 +1140,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)
@@ -1159,6 +1162,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)
{
@@ -1329,6 +1333,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)
@@ -1357,6 +1362,7 @@ _outBoolExpr(StringInfo str, const BoolExpr *node)
WRITE_LOCATION_FIELD(location);
}
+#ifdef OBSOLETE
static void
_outSubLink(StringInfo str, const SubLink *node)
{
@@ -2569,6 +2575,7 @@ _outIndexOptInfo(StringInfo str, const IndexOptInfo *node)
WRITE_BOOL_FIELD(hypothetical);
/* we don't bother with fields copied from the index AM's API struct */
}
+#endif /* OBSOLETE */
static void
_outForeignKeyOptInfo(StringInfo str, const ForeignKeyOptInfo *node)
@@ -2596,6 +2603,7 @@ _outForeignKeyOptInfo(StringInfo str, const ForeignKeyOptInfo *node)
appendStringInfo(str, " %d", list_length(node->rinfos[i]));
}
+#ifdef OBSOLETE
static void
_outStatisticExtInfo(StringInfo str, const StatisticExtInfo *node)
{
@@ -2607,6 +2615,7 @@ _outStatisticExtInfo(StringInfo str, const StatisticExtInfo *node)
WRITE_CHAR_FIELD(kind);
WRITE_BITMAPSET_FIELD(keys);
}
+#endif /* OBSOLETE */
static void
_outEquivalenceClass(StringInfo str, const EquivalenceClass *node)
@@ -2635,6 +2644,7 @@ _outEquivalenceClass(StringInfo str, const EquivalenceClass *node)
WRITE_UINT_FIELD(ec_max_security);
}
+#ifdef OBSOLETE
static void
_outEquivalenceMember(StringInfo str, const EquivalenceMember *node)
{
@@ -2819,6 +2829,7 @@ _outPlannerParamItem(StringInfo str, const PlannerParamItem *node)
WRITE_NODE_FIELD(item);
WRITE_INT_FIELD(paramId);
}
+#endif /* OBSOLETE */
/*****************************************************************************
*
@@ -2841,6 +2852,7 @@ _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
methods->nodeOut(str, node);
}
+#ifdef OBSOLETE
/*****************************************************************************
*
* Stuff from parsenodes.h.
@@ -3174,6 +3186,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)
@@ -3248,6 +3261,7 @@ _outQuery(StringInfo str, const Query *node)
WRITE_INT_FIELD(stmt_len);
}
+#ifdef OBSOLETE
static void
_outWithCheckOption(StringInfo str, const WithCheckOption *node)
{
@@ -3413,6 +3427,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)
@@ -3493,6 +3508,7 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
WRITE_NODE_FIELD(securityQuals);
}
+#ifdef OBSOLETE
static void
_outRangeTblFunction(StringInfo str, const RangeTblFunction *node)
{
@@ -3516,6 +3532,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)
@@ -3634,6 +3651,7 @@ _outBitString(StringInfo str, const BitString *node)
appendStringInfoString(str, node->bsval);
}
+#ifdef OBSOLETE
static void
_outColumnRef(StringInfo str, const ColumnRef *node)
{
@@ -3665,6 +3683,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)
@@ -3681,6 +3700,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)
{
@@ -3825,6 +3845,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)
@@ -3947,6 +3968,7 @@ _outConstraint(StringInfo str, const Constraint *node)
}
}
+#ifdef OBSOLETE
static void
_outForeignKeyCacheInfo(StringInfo str, const ForeignKeyCacheInfo *node)
{
@@ -4007,6 +4029,7 @@ _outPartitionRangeDatum(StringInfo str, const PartitionRangeDatum *node)
WRITE_NODE_FIELD(value);
WRITE_LOCATION_FIELD(location);
}
+#endif /* OBSOLETE */
/*
* outNode -
@@ -4038,6 +4061,8 @@ outNode(StringInfo str, const void *obj)
appendStringInfoChar(str, '{');
switch (nodeTag(obj))
{
+#include "outfuncs.switch.c"
+#ifdef OBSOLETE
case T_PlannedStmt:
_outPlannedStmt(str, obj);
break;
@@ -4743,6 +4768,7 @@ outNode(StringInfo str, const void *obj)
case T_JsonTableSibling:
_outJsonTableSibling(str, obj);
break;
+#endif /* OBSOLETE */
default:
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 6b11f0481bf..21176cd4c04 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -33,9 +33,7 @@
#include <math.h>
#include "miscadmin.h"
-#include "nodes/extensible.h"
-#include "nodes/parsenodes.h"
-#include "nodes/plannodes.h"
+#include "nodes/bitmapset.h"
#include "nodes/readfuncs.h"
@@ -238,6 +236,8 @@ readBitmapset(void)
return _readBitmapset();
}
+#include "readfuncs.funcs.c"
+
/*
* _readQuery
*/
@@ -291,6 +291,7 @@ _readQuery(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readNotifyStmt
*/
@@ -629,6 +630,7 @@ _readVar(void)
READ_DONE();
}
+#endif /* OBSOLETE */
/*
* _readConst
@@ -655,6 +657,7 @@ _readConst(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readParam
*/
@@ -880,6 +883,7 @@ _readScalarArrayOpExpr(void)
READ_DONE();
}
+#endif /* OBSOLETE */
/*
* _readBoolExpr
@@ -907,6 +911,7 @@ _readBoolExpr(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readSubLink
*/
@@ -1649,6 +1654,7 @@ _readAppendRelInfo(void)
/*
* Stuff from parsenodes.h.
*/
+#endif /* OBSOLETE */
/*
* _readRangeTblEntry
@@ -1744,6 +1750,7 @@ _readRangeTblEntry(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readRangeTblFunction
*/
@@ -2846,6 +2853,7 @@ _readAlternativeSubPlan(void)
READ_DONE();
}
+#endif /* OBSOLETE */
/*
* _readExtensibleNode
@@ -2877,6 +2885,7 @@ _readExtensibleNode(void)
READ_DONE();
}
+#ifdef OBSOLETE
/*
* _readPartitionBoundSpec
*/
@@ -2911,6 +2920,7 @@ _readPartitionRangeDatum(void)
READ_DONE();
}
+#endif /* OBSOLETE */
/*
* parseNodeString
@@ -2935,7 +2945,11 @@ parseNodeString(void)
#define MATCH(tokname, namelen) \
(length == namelen && memcmp(token, tokname, namelen) == 0)
- if (MATCH("QUERY", 5))
+ if (false)
+ ;
+#include "readfuncs.switch.c"
+#ifdef OBSOLETE
+ else if (MATCH("QUERY", 5))
return_value = _readQuery();
else if (MATCH("WITHCHECKOPTION", 15))
return_value = _readWithCheckOption();
@@ -3205,6 +3219,7 @@ parseNodeString(void)
return_value = _readJsonTableParent();
else if (MATCH("JSONTABLESIBLING", 16))
return_value = _readJsonTableSibling();
+#endif /* OBSOLETE */
else
{
elog(ERROR, "badly formatted node string \"%.32s\"...", token);