Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 964d01a

Browse files
committed
Automatically generate node support functions
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 <tgl@sss.pgh.pa.us> Discussion: https://www.postgresql.org/message-id/flat/c1097590-a6a4-486a-64b1-e1f9cc0533ce%40enterprisedb.com
1 parent 2373fe7 commit 964d01a

23 files changed

+1614
-223
lines changed

src/backend/Makefile

+8-2
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,15 @@ storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lw
143143
submake-catalog-headers:
144144
$(MAKE) -C catalog distprep generated-header-symlinks
145145

146+
# run this unconditionally to avoid needing to know its dependencies here:
147+
submake-nodes-headers:
148+
$(MAKE) -C nodes distprep generated-header-symlinks
149+
146150
# run this unconditionally to avoid needing to know its dependencies here:
147151
submake-utils-headers:
148152
$(MAKE) -C utils distprep generated-header-symlinks
149153

150-
.PHONY: submake-catalog-headers submake-utils-headers
154+
.PHONY: submake-catalog-headers submake-nodes-headers submake-utils-headers
151155

152156
# Make symlinks for these headers in the include directory. That way
153157
# we can cut down on the -I options. Also, a symlink is automatically
@@ -162,7 +166,7 @@ submake-utils-headers:
162166

163167
.PHONY: generated-headers
164168

165-
generated-headers: $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/storage/lwlocknames.h submake-catalog-headers submake-utils-headers
169+
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
166170

167171
$(top_builddir)/src/include/parser/gram.h: parser/gram.h
168172
prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \
@@ -185,6 +189,7 @@ distprep:
185189
$(MAKE) -C parser gram.c gram.h scan.c
186190
$(MAKE) -C bootstrap bootparse.c bootscanner.c
187191
$(MAKE) -C catalog distprep
192+
$(MAKE) -C nodes distprep
188193
$(MAKE) -C replication repl_gram.c repl_scanner.c syncrep_gram.c syncrep_scanner.c
189194
$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
190195
$(MAKE) -C utils distprep
@@ -297,6 +302,7 @@ distclean: clean
297302

298303
maintainer-clean: distclean
299304
$(MAKE) -C catalog $@
305+
$(MAKE) -C nodes $@
300306
$(MAKE) -C utils $@
301307
rm -f bootstrap/bootparse.c \
302308
bootstrap/bootscanner.c \

src/backend/nodes/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/node-support-stamp
2+
/nodetags.h
3+
/*funcs.funcs.c
4+
/*funcs.switch.c

src/backend/nodes/Makefile

+59
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,62 @@ OBJS = \
3030
value.o
3131

3232
include $(top_srcdir)/src/backend/common.mk
33+
34+
node_headers = \
35+
nodes/nodes.h \
36+
nodes/execnodes.h \
37+
nodes/plannodes.h \
38+
nodes/primnodes.h \
39+
nodes/pathnodes.h \
40+
nodes/extensible.h \
41+
nodes/parsenodes.h \
42+
nodes/replnodes.h \
43+
nodes/value.h \
44+
commands/trigger.h \
45+
commands/event_trigger.h \
46+
foreign/fdwapi.h \
47+
access/amapi.h \
48+
access/tableam.h \
49+
access/tsmapi.h \
50+
utils/rel.h \
51+
nodes/supportnodes.h \
52+
executor/tuptable.h \
53+
nodes/lockoptions.h \
54+
access/sdir.h
55+
56+
# see also catalog/Makefile for an explanation of these make rules
57+
58+
all: distprep generated-header-symlinks
59+
60+
distprep: node-support-stamp
61+
62+
.PHONY: generated-header-symlinks
63+
64+
generated-header-symlinks: $(top_builddir)/src/include/nodes/header-stamp
65+
66+
# node-support-stamp records the last time we ran gen_node_support.pl.
67+
# We don't rely on the timestamps of the individual output files,
68+
# because the Perl script won't update them if they didn't change (to
69+
# avoid unnecessary recompiles).
70+
node-support-stamp: gen_node_support.pl $(addprefix $(top_srcdir)/src/include/,$(node_headers))
71+
$(PERL) $^
72+
touch $@
73+
74+
# These generated headers must be symlinked into builddir/src/include/,
75+
# using absolute links for the reasons explained in src/backend/Makefile.
76+
# We use header-stamp to record that we've done this because the symlinks
77+
# themselves may appear older than node-support-stamp.
78+
$(top_builddir)/src/include/nodes/header-stamp: node-support-stamp
79+
prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \
80+
cd '$(dir $@)' && for file in nodetags.h; do \
81+
rm -f $$file && $(LN_S) "$$prereqdir/$$file" . ; \
82+
done
83+
touch $@
84+
85+
copyfuncs.o: copyfuncs.c copyfuncs.funcs.c copyfuncs.switch.c | node-support-stamp
86+
equalfuncs.o: equalfuncs.c equalfuncs.funcs.c equalfuncs.switch.c | node-support-stamp
87+
outfuncs.o: outfuncs.c outfuncs.funcs.c outfuncs.switch.c | node-support-stamp
88+
readfuncs.o: readfuncs.c readfuncs.funcs.c readfuncs.switch.c | node-support-stamp
89+
90+
maintainer-clean: clean
91+
rm -f node-support-stamp $(addsuffix funcs.funcs.c,copy equal out read) $(addsuffix funcs.switch.c,copy equal out read) nodetags.h

src/backend/nodes/README

+44-36
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,34 @@ src/backend/nodes/README
33
Node Structures
44
===============
55

6-
Andrew Yu (11/94)
7-
86
Introduction
97
------------
108

11-
The current node structures are plain old C structures. "Inheritance" is
12-
achieved by convention. No additional functions will be generated. Functions
13-
that manipulate node structures reside in this directory.
9+
The node structures are plain old C structures with the first field
10+
being of type NodeTag. "Inheritance" is achieved by convention:
11+
the first field can alternatively be of another node type.
12+
13+
Utility functions for manipulating node structures reside in this
14+
directory. Some support functions are automatically generated by the
15+
gen_node_support.pl script, other functions are maintained manually.
16+
To control the automatic generation of support functions, node types
17+
and node fields can be annotated with pg_node_attr() specifications;
18+
see further documentation in src/include/nodes/nodes.h.
1419

1520

1621
FILES IN THIS DIRECTORY (src/backend/nodes/)
1722

1823
General-purpose node manipulation functions:
19-
copyfuncs.c - copy a node tree
20-
equalfuncs.c - compare two node trees
21-
outfuncs.c - convert a node tree to text representation
22-
readfuncs.c - convert text representation back to a node tree
24+
copyfuncs.c - copy a node tree (*)
25+
equalfuncs.c - compare two node trees (*)
26+
outfuncs.c - convert a node tree to text representation (*)
27+
readfuncs.c - convert text representation back to a node tree (*)
2328
makefuncs.c - creator functions for some common node types
2429
nodeFuncs.c - some other general-purpose manipulation functions
2530

31+
(*) - Most functions in these files are generated by
32+
gen_node_support.pl and #include'd there.
33+
2634
Specialized manipulation functions:
2735
bitmapset.c - Bitmapset support
2836
list.c - generic list support
@@ -33,7 +41,7 @@ FILES IN THIS DIRECTORY (src/backend/nodes/)
3341
FILES IN src/include/nodes/
3442

3543
Node definitions:
36-
nodes.h - define node tags (NodeTag)
44+
nodes.h - define node tags (NodeTag) (*)
3745
primnodes.h - primitive nodes
3846
parsenodes.h - parse tree nodes
3947
pathnodes.h - path tree nodes and planner internal structures
@@ -42,39 +50,39 @@ FILES IN src/include/nodes/
4250
memnodes.h - memory nodes
4351
pg_list.h - generic list
4452

53+
(*) - Also #include's files generated by gen_node_support.pl.
54+
4555

4656
Steps to Add a Node
4757
-------------------
4858

4959
Suppose you want to define a node Foo:
5060

51-
1. Add a tag (T_Foo) to the enum NodeTag in nodes.h. (If you insert the
52-
tag in a way that moves the numbers associated with existing tags,
53-
you'll need to recompile the whole tree after doing this. It doesn't
54-
force initdb though, because the numbers never go to disk.)
55-
2. Add the structure definition to the appropriate include/nodes/???.h file.
61+
1. Add the structure definition to the appropriate include/nodes/???.h file.
5662
If you intend to inherit from, say a Plan node, put Plan as the first field
57-
of your struct definition.
58-
3. If you intend to use copyObject, equal, nodeToString or stringToNode,
59-
add an appropriate function to copyfuncs.c, equalfuncs.c, outfuncs.c
60-
and readfuncs.c accordingly. (Except for frequently used nodes, don't
61-
bother writing a creator function in makefuncs.c) The header comments
62-
in those files give general rules for whether you need to add support.
63-
4. Add cases to the functions in nodeFuncs.c as needed. There are many
63+
of your struct definition. (The T_Foo tag is created automatically.)
64+
2. Check that the generated support functions in copyfuncs.funcs.c,
65+
equalfuncs.funcs.c, outfuncs.funcs.c and readfuncs.funcs.c look
66+
correct. Add attributes as necessary to control the outcome. (For
67+
some classes of node types, you don't need all four support functions.
68+
Use node attributes similar to those of related node types.)
69+
3. Add cases to the functions in nodeFuncs.c as needed. There are many
6470
other places you'll probably also need to teach about your new node
6571
type. Best bet is to grep for references to one or two similar existing
6672
node types to find all the places to touch.
67-
68-
69-
Historical Note
70-
---------------
71-
72-
Prior to the current simple C structure definitions, the Node structures
73-
used a pseudo-inheritance system which automatically generated creator and
74-
accessor functions. Since every node inherited from LispValue, the whole thing
75-
was a mess. Here's a little anecdote:
76-
77-
LispValue definition -- class used to support lisp structures
78-
in C. This is here because we did not want to totally rewrite
79-
planner and executor code which depended on lisp structures when
80-
we ported postgres V1 from lisp to C. -cim 4/23/90
73+
(Except for frequently-created nodes, don't bother writing a creator
74+
function in makefuncs.c.)
75+
4. Consider testing your new code with COPY_PARSE_PLAN_TREES,
76+
WRITE_READ_PARSE_PLAN_TREES, and RAW_EXPRESSION_COVERAGE_TEST to ensure
77+
support has been added everywhere that it's necessary; see
78+
pg_config_manual.h about these.
79+
80+
Adding a new node type moves the numbers associated with existing
81+
tags, so you'll need to recompile the whole tree after doing this.
82+
(--enable-depend usually helps.) It doesn't force initdb though,
83+
because the numbers never go to disk. But altering or removing a node
84+
type should usually be accompanied by an initdb-forcing catalog
85+
version change, since the interpretation of serialized node trees
86+
stored in system catalogs is affected by that. (If the node type
87+
never appears in stored parse trees, as for example Plan nodes do not,
88+
then a catversion change is not needed to change it.)

src/backend/nodes/copyfuncs.c

+16-4
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,7 @@
2323
#include "postgres.h"
2424

2525
#include "miscadmin.h"
26-
#include "nodes/extensible.h"
27-
#include "nodes/pathnodes.h"
28-
#include "nodes/plannodes.h"
2926
#include "utils/datum.h"
30-
#include "utils/rel.h"
3127

3228

3329
/*
@@ -73,6 +69,9 @@
7369
(newnode->fldname = from->fldname)
7470

7571

72+
#include "copyfuncs.funcs.c"
73+
74+
#ifdef OBSOLETE
7675
/* ****************************************************************
7776
* plannodes.h copy functions
7877
* ****************************************************************
@@ -1431,6 +1430,7 @@ _copyVar(const Var *from)
14311430

14321431
return newnode;
14331432
}
1433+
#endif /* OBSOLETE */
14341434

14351435
/*
14361436
* _copyConst
@@ -1470,6 +1470,7 @@ _copyConst(const Const *from)
14701470
return newnode;
14711471
}
14721472

1473+
#ifdef OBSOLETE
14731474
/*
14741475
* _copyParam
14751476
*/
@@ -3214,6 +3215,7 @@ _copyParamRef(const ParamRef *from)
32143215

32153216
return newnode;
32163217
}
3218+
#endif /* OBSOLETE */
32173219

32183220
static A_Const *
32193221
_copyA_Const(const A_Const *from)
@@ -3254,6 +3256,7 @@ _copyA_Const(const A_Const *from)
32543256
return newnode;
32553257
}
32563258

3259+
#ifdef OBSOLETE
32573260
static FuncCall *
32583261
_copyFuncCall(const FuncCall *from)
32593262
{
@@ -5419,6 +5422,7 @@ _copyDropSubscriptionStmt(const DropSubscriptionStmt *from)
54195422

54205423
return newnode;
54215424
}
5425+
#endif /* OBSOLETE */
54225426

54235427
/* ****************************************************************
54245428
* extensible.h copy functions
@@ -5441,6 +5445,7 @@ _copyExtensibleNode(const ExtensibleNode *from)
54415445
return newnode;
54425446
}
54435447

5448+
#ifdef OBSOLETE
54445449
/* ****************************************************************
54455450
* value.h copy functions
54465451
* ****************************************************************
@@ -5511,6 +5516,7 @@ _copyForeignKeyCacheInfo(const ForeignKeyCacheInfo *from)
55115516

55125517
return newnode;
55135518
}
5519+
#endif /* OBSOLETE */
55145520

55155521
/*
55165522
* copyObjectImpl -- implementation of copyObject(); see nodes/nodes.h
@@ -5531,6 +5537,8 @@ copyObjectImpl(const void *from)
55315537

55325538
switch (nodeTag(from))
55335539
{
5540+
#include "copyfuncs.switch.c"
5541+
#ifdef OBSOLETE
55345542
/*
55355543
* PLAN NODES
55365544
*/
@@ -5969,6 +5977,7 @@ copyObjectImpl(const void *from)
59695977
case T_BitString:
59705978
retval = _copyBitString(from);
59715979
break;
5980+
#endif /* OBSOLETE */
59725981

59735982
/*
59745983
* LIST NODES
@@ -5986,6 +5995,8 @@ copyObjectImpl(const void *from)
59865995
retval = list_copy(from);
59875996
break;
59885997

5998+
#ifdef OBSOLETE
5999+
59896000
/*
59906001
* EXTENSIBLE NODES
59916002
*/
@@ -6537,6 +6548,7 @@ copyObjectImpl(const void *from)
65376548
case T_ForeignKeyCacheInfo:
65386549
retval = _copyForeignKeyCacheInfo(from);
65396550
break;
6551+
#endif /* OBSOLETE */
65406552

65416553
default:
65426554
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));

0 commit comments

Comments
 (0)