.\"----------------------------------------------------------------------
.\" FILE
.\"	query-tree.t
.\"
.\" DESCRIPTION
.\"	Specification for the query (parser => planner) and plan 
.\"	(planner => executor) trees
.\"
.\" RCS ID
.\"	$Header: /private/postgres/doc/implementation/RCS/query-tree.me,v 1.1 1990/07/30 13:50:41 kemnitz Exp $
.\"----------------------------------------------------------------------
.ds ar <\\(em\\(em
.nr pp 11
.nr sp 12
.nr tp 12
.nr fp 10
.ll 6.5i
.(l C
.sz \n(sp
.ft B
QUERY TREE / QUERY PLAN SPECIFICATION
(Printed: \*(td)
.ft R
.)l
.sp
.sz \n(pp
.sp
For notational purposes, anything appearing in italics is defined
elsewhere in this document.
Anything in bold face surrounded by quotes appears explicitly within a
runtime query tree/plan as a LISP string.
Anything appearing as a list is represented literally as a LISP list.
[] indicates something that is optional; {} indicates 0 or more.
.sp
.he 'Query Tree / Query Plan Specification''%'
.sh 1 "Query Tree Representation"
.sp
The parser will produce the following query tree for each query that
requires optimization:
.(l
(\fIRoot TargetList Qualification\fR)
.)l
Each of the above three components is a list containing further information.
.sh 2 "Root"
.sp
\fBRoot\fR looks like:
.(l
(\fINumLevels CommandType ResultRelation RangeTable Priority RuleInfo\fR)
.)l
This list contains information required by the planner as well as the
executor.
The planner itself does not modify any of these elements,
although some of its preprocessing routines may change portions of 
root before it is seen by the executor.
.sh 3 "NumLevels"
.sp
\fBNumLevels\fR indicates the maximum attribute nesting in a query.
That is, it indicates the maximum number of \*(lqnested dot\*(rq
fields found in any variable in that query.
For example, a query without range variables such as
.(l
retrieve (x = 1 + 2)
.)l
will have \fBNumLevels\fR = 0,
a query such as 
.(l
retrieve (pinhead.name) where pinhead.saying = "Yow!!!"
.)l
that contains normal range variables will have \fBNumLevels\fR = 1,
a query such as 
.(l
retrieve (sorority.all) where sorority.members.name = "Marti"
.)l
will have \fBNumLevels\fR = 2,
and so on.
.sh 3 "CommandType"
.sp
\fBCommandType\fR indicates what kind of query is being executed.
\fBCommandType\fR will be a single symbol from:
.(l
retrieve append replace delete
.)l
(other POSTQUEL commands are not optimized, so the planner should
never see them).
.sh 3 "ResultRelation"
.sp
\fBResultRelation\fR specifies the target relation of a 
\*(lqretrieve\*(rq
or the update relation for
\*(lqappend\*(rq, \*(lqreplace\*(rq, and \*(lqdelete\*(rq.
It may take one of three forms:
.np
If the query is a \*(lqretrieve\*(rq and no result relation is
specified, then \fBResultRelation\fR is nil.
.np
If the query is a \*(lqretrieve into\*(rq, then \fBResultRelation\fR
is a list containing a string representing the result relation's name
and a string from:
.(l
\fB\*(lqHEAVY\*(rq \*(lqLIGHT\*(rq \*(lqNONE\*(rq\fR
.)l
which represents the level of archiving which has been specified for the
result relation.
.np
If the query is an update, \fBResultRelation\fR will always be the
index into the \fIrangetable\fR corresponding to the relation to be
updated.
.sh 3 "RangeTable"
.sp
\fBRangeTable\fR is a list containing a \fIrangetable entry\fR for
each instance of a relation (i.e., range variable) in a query.  Every
\fIrelid\fR and \fIvarno\fR within the query tree, and almost every one
within the resulting query plan, is an integer index within the
query's rangetable.  This index is 1-based (e.g., var nodes that refer
to the first relation in the rangetable are given varno ``1'').
.sp
A rangetable entry looks like:
.(l
( \fIRelationName RelationOID TimeRange Flags RuleLocks\fR )
.)l
\fBRelationName\fR is a string corresponding to the relation's catalog
name, \fBRelationOID\fR is an integer corresponding to the OID of the
RELATION relation tuple that describes the given relation,
\fBTimeRange\fR is an internal structure that describes the historical
time span over which this rangetable entry is valid,
\fBFlags\fR is a list of zero or more symbols from:
.(l
archive inheritance union version
.)l
that specifies special treatment from the planner, and 
\fBRuleLocks\fR holds the rule lock information for that relation
(since this is generated by a planner preprocessor, the parser simply
puts nil here).
In the case of archival, inheritance, union and version queries,
the planner generates an \fBAPPEND\fR query plan node (see below) that
contains a set of rangetable entries which must be substituted in turn
for this rangetable entry, as well as separate query plans to be
executed.
.sh 3 "Priority"
.sp
\fBPriority\fR is simply an integer from 0..7 that indicates the
query priority.  Only rule plans can have priorities greater than 0.
.sh 3 "RuleInfo"
.sp
If the query is part of a \*(lqdefine rule\*(rq query, \fBRuleInfo\fR
is a containing a \fIrule identifier\fR and exactly one symbol from:
.(l
always once never
.)l
The rule identifier is an object identifier from the RULE relation;
the symbol is the tag associated with the rule definition.
For example, \fBRuleInfo\fR might look like:
.(l
( 387457893 always )
.)l
The rule identifier will be filled in by a traffic cop or planner
preprocessor routine.
For all other queries, \fBRuleInfo\fR is nil.
.sh 2 "TargetList"
.sp
A targetlist describes the structure of a tuple
and consists of a list of (\fIresdom expr\fR) pairs, one for
each attribute in the tuple to be constructed.
A \fBresdom\fR (result domain) node contains information about the
attribute, and
an \fBexpr\fR (expression) describes how to set the value of the
attribute.
.sp
The initial targetlist from the query tree describes what the final
result tuples should look like (targetlists are also used in
query plans to describe intermediate results such as scan projections,
join results, and temporaries).
In the case of the delete command, the initial targetlist is always nil.
For the other update queries, the planner's preprocessor fills in any
missing attributes that the user has not specified, either with
constants corresponding to the default values of the missing
attributes\**
.(f
\** If no default value exists for an attribute type, the attribute
will have a null value.
.)f
(for \*(lqappend\*(rq) or with variables corresponding to
the unchanged attributes of a tuple (for \*(lqreplace\*(rq).
.sp
The structure of the \fBresdom\fR node is described below;
an \fBexpr\fR can consist of a combination of nodes:
.(l
\fIexpr\fR = \fIvar\fR | \fIconst\fR | \fIparam\fR | (\fIoper expr\fR [\fIexpr\fR]) | (\fIfunc\fR {\fIexpr\fR})
.)l
.sp
The structures of the different nodes in an expr are described
below, but the function of the nodes may be briefly summarized as:
.nr zz \n(ii
.nr ii 6m
.sp
.ip \fIvar\fR
Refer to some relation attribute entry which corresponds to the target
list entry (i.e., the contents of a relation's tuple).
.ip \fIconst\fR
Constant values.
.ip \fIparam\fR
Used as parameters \(em placeholders for constants \(em within a
query.  The planner treats them as if they are constants of unknown
value (i.e., null constants) for optimization purposes.
.ip \fIoper\fR
Describes the system- or user-defined unary or binary operator that
will be applied to the argument exprs to produce a new value.
.ip \fIfunc\fR
Correspond to calls to system- or user-defined functions, which
may have zero or more arguments.
.nr ii \n(zz
.lp
Example:  ((\fIresdom var\fR) (\fIresdom\fR (\fIoper var var\fR)))
.br
is a targetlist with two attributes, where the second element involves
a computation between two tuple attributes.
.sh 2 "Qualification"
.sp
A qualification consists of restriction and join clauses which are
evaluated before the final result is returned.
.sp
The qualifications produced by the parser are not normalized in any
way.
That is, the parsed qualification will be an arbitrary boolean
expression:
.(l
\fIqualification\fR = ({\fIqual\fR})
\fIqual\fR = \fIexpr\fR | (\*(lq\fBNOT\fR\*(rq \fIqual\fR) | (\*(lq\fBOR\fR\*(rq \fIqual \fR{\fIqual\fR}) | (\*(lq\fBAND\fR\*(rq \fIqual \fR{\fIqual\fR})
.)l
.sp
The qualification supplied to the planner must be normalized in
certain ways.\**
.(f
\** This normalization occurs in yet another preprocessing module.
.)f
A qualification must be specified in conjunctive normal form.
Furthermore, if it is at all possible, all \*(lqnot\*(rqs are removed
and all variables are placed on the left hand side of the clause
operator.
If it is not possible to remove a \*(lqnot\*(rq (perhaps because a
negator is unavailable),
then the \*(lqnot\*(rq must be pushed to the innermost comparison,
e.g.,
\*(lq(not ((a = b) and (c = d)))\*(rq
might become
\*(lq(not (a = b) or not (c = d))\*(rq
if the operator \*(lq!=\*(rq does not exist for the appropriate types.
.sp
A qualification as seen by the planner is:
.(l
\fIqualification\fR = ({\fIqual\fR | \fIorqual\fR})
\fIqual\fR = \fIexpr\fR | (\*(lq\fBNOT\fR\*(rq \fIexpr\fR)
\fIorqual\fR = (\*(lq\fBOR\fR\*(rq \fIqual qual \fR{\fIqual\fR})
.)l
.sp
Example: If a user specifies the following clause:
.(l
not (r.f = 1) or (r.f2 > 1 and 2 > r.f2),
.)l
then in conjunctive normal form with \*(lqnot\*(rqs removed
and variables on the left hand side, we have the following equivalent clause:
.(l
(r.f != 1 or r.f2 > 1) and (r.f != 1 or r.f2 < 2)
.)l
In LISP form, it would look like:
.(l
((or (!= r.f 1) (> r.f2 1)) (or (!= r.f 1) (< r.f2 2)))
.)l
.sp
A set of macros for manipulating clause entries is contained in:
.(l
~postgres/src/planner/clauses.l
.)l
Additional parse tree manipulation routines are in:
.(l
~postgres/src/planner/nodeDefs.l
.)l
.bp
.sh 1 "Query Plan Representation"
.sp
A query plan is represented as a node.
Every plan node contains the following slots:
.(l
.ft B
state
qptargetlist
lefttree
righttree
.ft R
.)l
Thus, while a query plan is externally a single object, it may in fact
constitute a tree of plan nodes because of the child tree fields.
.sp
A \fIplan\fP consists of \fIsubplans\fP interconnected together with
\fBRESULT\fR,
\fBEXISTENTIAL\fP,
and
\fBAPPEND\fR
nodes.  These nodes may also have each other as children.
.sp
\fBRESULT\fR nodes interconnect plan levels.
The planner generates subqueries for all variables which operate at a
given level of nesting (that is, all non-nested variables are handled
in one plan level, all variables of the form \*(lqfoo.bar.baz\*(rq are
handled in another, and so on).
Thus, \fBRESULT\fR nodes indicate which attributes should be selected
from lower levels in the plan tree.
If a \fBRESULT\fR node has subtrees,
then the left tree always is a \fIsubplan\fR,
and the right tree is a \fIplan\fR for processing the
(more deeply nested) remainder of the query.
It is also possible for a \fBRESULT\fR node to have only a single left
subtree.
This occurs when the \fBRESULT\fR node is needed solely for storing
relation-level clauses.
A query plan can be a single \fBRESULT\fR node with no subtrees if the
query contains no variables.
.sp
\fBEXISTENTIAL\fP nodes also connect subplans.
The left subtree of an \fBEXISTENTIAL\fP node is a special
subplan which determines whether the existential members
of the subplan qualification are all true or not.
The right subtree is the actual query plan for the
subquery (minus the existential qualification clauses).
\fBEXISTENTIAL\fP nodes may also have one (left) or zero subtrees.
.sp
\fBAPPEND\fR nodes indicate that the executor should use the subplans it
contains sequentially, returning the appropriate tuples in a seamless
manner (at least as far as the external interface is concerned).
\fBAPPEND\fR nodes may be thought of as taking the place of N
scan nodes, each of which are substituted for the \fBAPPEND\fR node in turn.
.sp
A \fIsubplan\fR is an access plan for processing the (current)
topmost level of attributes in a query and consists of join and scan
nodes.
.sp
Joins are represented such that the left tree is the outer join relation
and the right tree is the inner join relation.
The three types of join nodes are:
.(l
.ft B
NESTLOOP
MERGESORT
HASHJOIN
.ft R
.)l
The two types of scan nodes are:
.(l
.ft B
SEQSCAN
INDEXSCAN
.ft R
.)l
.sp
Lastly, there are two types of nodes which involve the creation of
temporary relations:
.(l
.ft B
SORT
HASH
.ft R
.)l
If a stream of tuples must be sorted into a temporary prior
to join processing, its parent is a \fBSORT\fR node and the parent of
the \fBSORT\fR node is a \fBSEQSCAN\fR node:
.(l
<some-join> \fB\*(ar SEQSCAN \*(ar SORT \*(ar\fR <some-scan>
.)l
Similarly, if the relation is to be hashed, its corresponding scan
node's parent is a \fBHASH\fR node.
.(l
<some-join> \fB\*(ar SEQSCAN \*(ar HASH \*(ar\fR <some-scan>
.)l
Example: A \*(lqretrieve\*(rq involving a single mergesort join that
uses an index as an ordered inner path and a sorted outer path might
look like:
.(l
.ft B
MERGE	\*(ar SEQSCAN \*(ar SORT \*(ar SEQSCAN
SORT		\*(ar INDEXSCAN
.ft R
.)l
.sp
The same idea applies to sorts in general.  The node is simply
preceded by a \fBSORT\fR and then a \fBSEQSCAN\fR node in the plan
tree.  However, if a retrieve result is to be sorted into a relation,
the \fBSEQSCAN\fR node is omitted.
.sp
Example: The top level nodes for a plan that returns a set of tuples
that must be sorted into a particular order might look like:
.(l
\fBRESULT	\*(ar SORT \*(ar\fR ...rest of plan...
.)l
.bp
.sh 1 "Primitive Nodes"
.sp
The following is a description of the primitive nodes, which are used
in both the input query tree and the final query plan.
.sp
Each type of node is implemented as a defstruct vector.  To access
slots within a node, use:
.(l
(get_\fIslotname node\fR)
.)l
where \fIslotname\fR is the desired slot name as described in this
section and \fInode\fR is an appropriate defstruct node.
.sp
To set a slot field, use:
.(l
(set_\fIslotname node new-slot-value\fR)
.)l
For details see
.(l
~postgres/src/planner/nodeDefs.l
.)l
.sp
.sh 2 "RESDOM"
.ip "1)"
\fBresno\fR - result domain number.  This is equivalent to the
attribute number for a (temporary or result) tuple.  Just as attribute
numbers being at 1, a \fBresno\fR of 1 denotes the first attribute in
a targetlist.
.ip "2)"
\fBrestype\fR - either:
.br
(1) the OID corresponding to the type of the result, or
.br
(2) *UNION-TYPE-ID*, an identifier for a type internal to the planner
that describes multi-dot attributes (since it cannot determine the
final attribute type until the nesting is eliminated by the executor).
.ip "3)"
\fBreslen\fR - length of a domain element in bytes (-1 if it is
variable length).
.ip "4)"
\fBresname\fR - result domain name, either user-specified or the
corresponding name of an attribute (if applicable).
.ip "5)"
\fBreskey\fR - ordinality of the result domain as a sort or hash key,
e.g.,
0 if the domain won't be included as a sort or hash key;
1 if the domain is the first key,
2 if it is the second,
and so on.
.ip "6)"
\fBreskeyop\fR - OID of the operator on which \fBreskey\fR will be
sorted or hashed.
.sp
.lp
To create a \fBRESDOM\fR node:
.sp
(make_resdom \fIresno restype reslen resname reskey reskeyop\fR)
.sp
.sh 2 "VAR"
.ip "1)"
\fBvarno\fR - From the parser's standpoint, \fBvarno\fR is simply the
index into the rangetable corresponding to the relation an attribute
belongs to.
.sp
For the query processor, \fBvarno\fR may take on one of three values
depending on the attribute entry under consideration.
.br
(1) If \fBVAR\fR belongs to the relation currently being scanned
(either a cataloged or temporary relation, but not a materialized
one), \fBvarno\fR is still the \fIindex into the rangetable\fP
corresponding to the relation being scanned.
.br
(2) If \fBVAR\fR is associated with some join node, varno is the
\fIname of the temporary join relation\fP accessed.  If \fBVAR\fR
originates from the outer join relation, \fBvarno\fR =
\fB\*(lqOUTER\*(rq\fR.  If it originated from the inner join relation,
\fBvarno\fR = \fB\*(lqINNER\*(rq\fR.
.br
(3) For \fBVAR\fRs corresponding to entries within relations that are
materialized from a POSTQUEL field or attributes from some previous
nesting level, \fBvarno\fR is a \fIreference pair\fP, i.e., a list
(\fIlevelnum resno\fR), that corresponds to the attribute entry where
either the query field or desired value can be found.  \fIlevelnum\fR
refers to the processing level number (where \fI0\fR is the topmost),
and \fIresno\fR refers to the result domain number within the tuple
where the entry is stored.
.sp
Therefore, whether a relation should be materialized is implicit in
the \fBvarno\fR value and information in the attribute entry
corresponding to the query field.
.ip "2)"
\fBvarattno\fR - as with \fBvarno\fR, the meaning of this field
depends on the node's position in the plan tree.
.br
(1) For attributes at the topmost nesting level, \fBvarattno\fR
corresponds to the \fIattribute number\fR within a relation (or domain
number within a tuple if this is a join tuple \(em that is, if
\fBvarno\fR = \fB\*(lqOUTER\*(rq\fR or \fB\*(lqINNER\*(rq\fR).
.br
(2) If the attribute corresponds to some attribute from a previous
nesting level, \fBvarattno\fR = \fInil\fR.
.br
(3) For nested attributes, the value of \fBvarattno\fR is a
\fIstring\fR identical to the attribute name since the attribute
number will not be known until the POSTQUEL field is materialized.
Note that at the lowest nesting level, \fBvarattno\fR may be
\*(lq\fBALL\fR\*(rq (again, since neither the parser nor the planner
know what the attributes of the field's parent are \(em it must be
determined at run-time by the query processor when the appropriate
POSTQUEL field is retrieved).
.ip "3)"
\fBvartype\fR - either:
.br
(1) the OID of the type of the attribute referred to by \fBvarattno\fR,
or
.br
(2) *UNION-TYPE-ID*
.ip "4)"
\fBvardotfields\fR - list of attribute names beyond the first nesting
level.
.br
(\fIThis field is internal to the parser and planner\fR)
.ip "5)"
\fBvararrayindex\fR - array index of a variable, nil if this is not an
array attribute.
.br
Since arrays can only contain primitive types, only the bottommost
attribute in a nesting will be array indexed.  The parser will set
the \fBvararrayindex\fR field if a variable contains an array index.
The planner will only set this field if the query processor is to
retrieve an array element within some attribute entry.
.ip "6)"
\fBvarid\fR - a list containing \fBvarno\fR and \fBvarattno\fR, as
well as \fBvardotfields\fR and \fBvararrayindex\fR (if the latter two
exist).
.br
(\fIThis field is internal to the planner\fR)
.sp
.nf
Example: w.x.y.z[a]
.sp
.nf
The parser will set the following fields:
.sp
\fBvarno\fR = identifier of w, \fBvarattno\fR = attribute number of x, 
.br
\fBvardotfields\fR = (y z), \fBvararrayindex\fR = a,
.br
\fBvarid\fR = (\fBvarno varattno\fR y z (a)),
\fBvartype\fR = type of attribute x
.fi
.sp
.lp
To create a \fBVAR\fR node:
.sp
(make_var \fIvarno varattno vartype vardotfields vararrayindex varid\fR)
.sp
.sh 2 "OPER"
.ip "1)"
\fBopno\fR - for the parser, \fBopno\fR is the OID of the operator to
which this node corresponds.  For the executor, \fBopno\fR is the OID
of the operator \fIprocedure\fR.  The conversion occurs in the planner
(which needs the operator OID to determine selectivities).
.ip "2)"
\fBoprelationlevel\fR - t if an operator is a relation level operator.
.ip "3)"
\fBopresulttype\fR - OID of the result type of this particular
operator.
.sp
.lp
To create a \fBOPER\fR node:
.sp
(make_oper \fIopno oprelationlevel opresulttype\fR)
.sp
.sh 2 "CONST"
.ip "1)"
\fBconsttype\fR - OID of the constant's type.
.ip "2)"
\fBconstlen\fR - length in bytes (-1 if it is a variable-length type).
.ip "3)"
\fBconstvalue\fR - actual value of the constant (i.e., the internal
representation).
.br
\fBconstvalue\fR is nil if the constant is null.  Objects represented
by pointers must appear as palloc'ed LISP vectori-bytes.
.ip "4)"
\fBconstisnull\fR - t if the constant has the null value.
.br
This is set by the planner when filling in \*(lqreplace\*(rq and
\*(lqappend\*(rq targetlist entries which are unspecified by the user.
If the typdefault field of the \fBTYPE\fR relation is not specified,
\fBconstisnull\fR is set to t and \fBconstvalue\fR is set to nil.
.sp
.lp
To create a \fBCONST\fR node:
.sp
(make_const \fIconsttype constlen constvalue constisnull\fR)
.sp
.sh 2 "PARAM"
.ip "1)"
\fBparamid\fR - either:
.br
(1) a fixnum corresponding to the parameter name for constant value
substitution, e.g., \*(lq1\*(rq in the case of \*(lq$1\*(rq
.br
(2) a string corresponding to the attribute name for relation name
substitution, e.g, \*(lqattname\*(rq in the case of
\*(lq$.attname\*(rq
.sp
.lp
To create a \fBPARAM\fR node:
.sp
(make_param \fIparamid\fR)
.sp
.sh 2 "FUNC"
.ip "1)"
\fBfuncid\fR - OID of the function to which this node corresponds.
.ip "2)"
\fBfunctype\fR - OID of the type of the function's return value.
.sp
.lp
To create a \fBFUNC\fR node:
.sp
(make_func \fIfuncid functype\fR)
.bp
.sh 1 "Plan Nodes"
.sp
The following is a description of each type of plan node.  Each type
of node is implemented as a defstruct vector.  To access slots within
a node, use:
.(l
(get_\fIslotname node\fR)
.)l
where \fIslotname\fR is the desired slot name as described in this
section and \fInode\fR is an appropriate defstruct node.
.sp
To set a slot field, use:
.(l
(set_\fIslotname node new-slot-value\fR)
.)l
For details see
.(l
~postgres/src/planner/nodeDefs.l
.)l
.sp
.sh 2 "RESULT"
.ip "1)"
\fBstate\fR - used by the query executor to store runtime-specific
information.
.ip "2)"
\fBqptargetlist\fR - the target list for a sublevel of the query; the
attributes in node \fBRESULT\fI(i)\fR are derived from values returned
by \fIsubplan(i)\fR, and either \fBRESULT\fI(i+1)\fR or
\fIsubplan(i+1)\fR, depending on whether or not there is an i+1'th
nesting level.
.ip "3)"
\fBlefttree\fR - \fIsubplan(i)\fR.
.ip "4)"
\fBrighttree\fR - either \fBRESULT\fI(i+1)\fR or \fIsubplan(i+1)\fR,
depending on whether or not there are deeper nesting levels.
.ip "5)"
\fBresrellevelqual\fR - list of any relation level clauses that must
be satisfied (e.g., \*(lqR1.f1 = R2.f2\*(rq or \*(lqfoo.bar = 2\*(rq)
.ip "6)"
\fBresconstantqual\fR - a list containing all qualifications which
contain no var nodes.
.br
This field will only be set at the topmost \fBRESULT\fR node.  These
qualifications should always be tested first at runtime; if they are
false, then the rest of the query plan need not be processed because
no tuples will be returned.
.sp
To create a \fBRESULT\fR node:
.sp
(make_result \fIqptargetlist resrellevelqual lefttree righttree\fR)
.sp
.sh 2 "EXISTENTIAL"
.ip "1)"
\fBstate\fR
.ip "2)"
\fBqptargetlist\fR - always nil.
.ip "3)"
\fBlefttree\fR - subplan for the existential query.
.br
This is planned as a \*(lqretrieve\*(rq with a null target list.
.ip "4)"
\fBrighttree\fR - subplan for the non-existential query.
.sp
.lp
To create a \fBEXISTENTIAL\fR node:
.sp
(make_existential \fIlefttree righttree\fR)
.sp
.sh 2 "APPEND"
.ip "1)"
\fBstate\fR
.ip "2) - 4) \fBqptargetlist\fR, \fBlefttree\fR, \fBrighttree\fR - always nil"
.ip "5)"
\fBplans\fR - a list of plans which are to be executed sequentially.
.ip "6)"
\fBrelid\fR - the rangetable index of the variable which caused this
node to be formed.  For example, if this is a query that uses the
\fBfrom\fR clause \*(lqfrom p in person*\*(rq, then this would contain
the rangetable index of the entry for \*(lqperson\*(rq.
.ip "7)"
\fBrtentries\fR - a list of rangetable entries which must be
substituted into the executor's rangetable in conjunction with
execution of the plans stored in the \fBplans\fR field.
.ip "8)"
\fBflags\fR - a symbol from 
\fBarchive\fR, \fBinheritance\fR, \fBunion\fR, or \fBversion\fR
that specifies how the executor should execute each entry in the
\fBplans\fR.
.sp
.lp
To create a \fBAPPEND\fR node:
.sp
(make_append \fIplans relid rtentries flags\fR)
.sp
.sh 2 "NESTLOOP"
.ip "1)"
\fBstate\fR
.ip "2)"
\fBqptargetlist\fR - attributes to be retrieved into the join result
from attributes in the inner and outer join relations.
.ip "3)"
\fBlefttree\fR - outer join path.
.ip "4)"
\fBrighttree\fR - inner join path.
.ip "5)"
\fBqpqual\fR - a list of join clauses to be satisfied.
.sp
.lp
To create a \fBNESTLOOP\fR node:
.sp
(make_nestloop \fIqptargetlist qpqual lefttree righttree\fR)
.sp
.sh 2 "HASHJOIN"
.ip "1) - 5) from above"
.ip "6)"
\fBmergehashclauses\fR - join clauses to be used in performing the
hash join; if there are multiple clauses, the clauses are arranged in
the order of the hash keys, from primary downward.
.br
Note: These clauses are not contained in \fBqpqual\fR above to avoid
redundant checking.
.sp
.lp
To create a \fBHASHJOIN\fR node:
.sp
(make_hashjoin \fIqptargetlist qpqual mergehashclauses lefttree righttree\fR)
.sp
.sh 2 "MERGESORT"
.ip "1) - 5) from above"
.ip "6)"
\fBmergehashclauses\fR - join clauses to be used in performing the
merge join; if there are multiple clauses, the clauses are arranged in
the order of the merge keys, from the primary ordering key downward.
.br
(Again, these clauses are not contained in \fBqpqual\fR)
.ip "7)"
\fBmergesortop\fR - OID of the operator procedure used to merge the
tuples.
.sp
.lp
To create a \fBMERGESORT\fR node:
.sp
(make_mergesort \fIqptargetlist qpqual mergehashclauses mergesortop lefttree righttree\fR)
.sp
.sh 2 "SEQSCAN"
.ip "1)"
\fBstate\fR
.ip "2)"
\fBqptargetlist\fR - attributes to be retrieved into scan result.
.ip "3)"
\fBlefttree\fR - either nil, a \fBSORT\fR node, or a \fBHASH\fR node.
.ip "4)"
\fBrighttree\fR - always nil.
.ip "5)"
\fBqpqual\fR - list of restriction clauses on the relation.
.ip "6)"
\fBscanrelid\fR - either:
.br
(1) an index into the rangetable corresponding to the relation to be
scanned, or
.br
(2) a reference to an attribute from a previous level that corresponds
to a relation to be materialized from some POSTQUEL field.
.sp
.lp
To create a \fBSEQSCAN\fR node:
.sp
(make_seqscan \fIqptargetlist qpqual scanrelid lefttree\fR)
.sp
.sh 2 "INDEXSCAN"
.ip "1) - 2) from above"
.ip "3) - 4) \fBlefttree\fR, \fBrighttree\fR - always nil.
.ip "5) - 6) from above"
.ip "7)"
\fBindxid\fR - list of the OIDs of all indices to be used to scan a
relation: (OID1 OID2 ... ).  The idea here is that more than one index
may be used to scan a relation.  For example, if we have the clause
\*(lqR.foo = foo or R.foo = foobar\*(rq, the first index might use
\*(lqfoo\*(rq as a key and the second could use \*(lqfoobar\*(rq.
Currently, this tactic is only used as just described (in conjunction
with \*(lqor\*(rq clauses).
.ip "8)"
\fBindxqual\fR - list of qualifications to be used in conjunction with
each index (e.g., ((qual1) (qual2)), where qual1 corresponds to ID1
and qual2 corresponds to ID2).  For multi-key indices, subclauses are
arranged in the order of the index keys.
.br
Note, again, that the clauses here are not contained in the
\fBqpqual\fR field above to avoid redundant checking.
.sp
If \fBindxqual\fR is nil, but \fBindxid\fR isn't, then the entire
relation is to be scanned starting at the first key of the index.
This is used when the ordering of an indexscan is needed for a
mergesort.
.sp
If an index is defined on an inner join relation, \fBindxqual\fR may
be a join clause.  If this is the case, the query processor must
substitute values for the outer relation at runtime.  The outer join
attribute is identified by its relative position of within the
resulting tuple of the outer join relation.  This type of
qualification is also omitted from \fBqpqual\fR above to avoid
redundant checking.
.sp
.lp
To create a \fBINDEXSCAN\fR node:
.sp
(make_indexscan \fIqptargetlist qpqual scanrelid indxid indxqual\fR)
.sp
.sh 2 "SORT"
.ip "1)"
\fBstate\fR
.ip "2)"
\fBqptargetlist\fR - targetlist for the tuples which are to be placed
into the temporary relation.
.ip "3)"
\fBlefttree\fR - plan node whose result is to be sorted.
.ip "4)"
\fBrighttree\fR - always nil.
.ip "5)"
\fBtempid\fR - either:
.br
(1) a string corresponding to a user-specified result relation, or 
.br
(2) *TEMP-RELATION-ID* (a special identifier indicating a temporary
relation).
.ip "6)"
\fBkeycount\fR - the number of sort keys.
.sp
.lp
To create a \fBSORT\fR node:
.sp
(make_sort \fIqptargetlist tempid lefttree\fR)
.sp
.sh 2 "HASH"
.ip "1) - 6) from above"
.sp 2
.lp
To create a \fBHASH\fR node:
.sp
(make_hash \fIqptargetlist tempid lefttree\fR)
