From 79da68dba05e3ea3b506c4ebf6ea1a1c1e2de6f3 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut 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