Skip to content

Commit

Permalink
Automatically generate node support functions
Browse files Browse the repository at this point in the history
BABELFISH-CONFLICT: see Postgres community repo for original commit

Add a script to automatically generate the node support functions
(copy, equal, out, and read, as well as the node tags enum) from the
struct definitions.

For each of the four node support files, it creates two include files,
e.g., copyfuncs.funcs.c and copyfuncs.switch.c, to include in the main
file.  All the scaffolding of the main file stays in place.

I have tried to mostly make the coverage of the output match what is
currently there.  For example, one could now do out/read coverage of
utility statement nodes, but I have manually excluded those for now.
The reason is mainly that it's easier to diff the before and after,
and adding a bunch of stuff like this might require a separate
analysis and review.

Subtyping (TidScan -> Scan) is supported.

For the hard cases, you can just write a manual function and exclude
generating one.  For the not so hard cases, there is a way of
annotating struct fields to get special behaviors.  For example,
pg_node_attr(equal_ignore) has the field ignored in equal functions.

(In this patch, I have only ifdef'ed out the code to could be removed,
mainly so that it won't constantly have merge conflicts.  It will be
deleted in a separate patch.  All the code comments that are worth
keeping from those sections have already been moved to the header
files where the structs are defined.)

Reviewed-by: Tom Lane <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/c1097590-a6a4-486a-64b1-e1f9cc0533ce%40enterprisedb.com
(cherry picked from commit 964d01ae90c314eb31132c2e7712d5d9fc237331)
  • Loading branch information
petere authored and priyansx committed Nov 29, 2023
1 parent 339758a commit 47188d3
Show file tree
Hide file tree
Showing 23 changed files with 1,628 additions and 254 deletions.
10 changes: 8 additions & 2 deletions src/backend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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` && \
Expand All @@ -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
Expand Down Expand Up @@ -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 \
Expand Down
4 changes: 4 additions & 0 deletions src/backend/nodes/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/node-support-stamp
/nodetags.h
/*funcs.funcs.c
/*funcs.switch.c
59 changes: 59 additions & 0 deletions src/backend/nodes/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
80 changes: 44 additions & 36 deletions src/backend/nodes/README
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.)
33 changes: 16 additions & 17 deletions src/backend/nodes/copyfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"


/*
Expand Down Expand Up @@ -73,6 +69,9 @@
(newnode->fldname = from->fldname)


#include "copyfuncs.funcs.c"

#ifdef OBSOLETE
/* ****************************************************************
* plannodes.h copy functions
* ****************************************************************
Expand Down Expand Up @@ -1432,6 +1431,7 @@ _copyVar(const Var *from)

return newnode;
}
#endif /* OBSOLETE */

/*
* _copyConst
Expand Down Expand Up @@ -1471,6 +1471,7 @@ _copyConst(const Const *from)
return newnode;
}

#ifdef OBSOLETE
/*
* _copyParam
*/
Expand Down Expand Up @@ -3216,6 +3217,7 @@ _copyParamRef(const ParamRef *from)

return newnode;
}
#endif /* OBSOLETE */

static A_Const *
_copyA_Const(const A_Const *from)
Expand Down Expand Up @@ -3259,6 +3261,7 @@ _copyA_Const(const A_Const *from)
return newnode;
}

#ifdef OBSOLETE
static FuncCall *
_copyFuncCall(const FuncCall *from)
{
Expand Down Expand Up @@ -5437,6 +5440,7 @@ _copyDropSubscriptionStmt(const DropSubscriptionStmt *from)

return newnode;
}
#endif /* OBSOLETE */

/* ****************************************************************
* extensible.h copy functions
Expand All @@ -5459,6 +5463,7 @@ _copyExtensibleNode(const ExtensibleNode *from)
return newnode;
}

#ifdef OBSOLETE
/* ****************************************************************
* value.h copy functions
* ****************************************************************
Expand Down Expand Up @@ -5513,16 +5518,6 @@ _copyBitString(const BitString *from)
return newnode;
}

static TSQL_HexString *
_copyTSQL_HexString(const TSQL_HexString *from)
{
TSQL_HexString *newnode = makeNode(TSQL_HexString);

COPY_STRING_FIELD(hsval);

return newnode;
}


static ForeignKeyCacheInfo *
_copyForeignKeyCacheInfo(const ForeignKeyCacheInfo *from)
Expand All @@ -5539,6 +5534,7 @@ _copyForeignKeyCacheInfo(const ForeignKeyCacheInfo *from)

return newnode;
}
#endif /* OBSOLETE */

/*
* copyObjectImpl -- implementation of copyObject(); see nodes/nodes.h
Expand All @@ -5559,6 +5555,8 @@ copyObjectImpl(const void *from)

switch (nodeTag(from))
{
#include "copyfuncs.switch.c"
#ifdef OBSOLETE
/*
* PLAN NODES
*/
Expand Down Expand Up @@ -5997,9 +5995,7 @@ copyObjectImpl(const void *from)
case T_BitString:
retval = _copyBitString(from);
break;
case T_TSQL_HexString:
retval = _copyTSQL_HexString(from);
break;
#endif /* OBSOLETE */

/*
* LIST NODES
Expand All @@ -6017,6 +6013,8 @@ copyObjectImpl(const void *from)
retval = list_copy(from);
break;

#ifdef OBSOLETE

/*
* EXTENSIBLE NODES
*/
Expand Down Expand Up @@ -6568,6 +6566,7 @@ copyObjectImpl(const void *from)
case T_ForeignKeyCacheInfo:
retval = _copyForeignKeyCacheInfo(from);
break;
#endif /* OBSOLETE */

default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
Expand Down
Loading

0 comments on commit 47188d3

Please sign in to comment.