primnodes.h 21.4 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * primnodes.h
4 5 6 7
 *	  Definitions for "primitive" node types, those that are used in more
 *	  than one of the parse/plan/execute stages of the query pipeline.
 *	  Currently, these are mostly nodes for executable expressions
 *	  and join trees.
8 9
 *
 *
10
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
11
 * Portions Copyright (c) 1994, Regents of the University of California
12
 *
13
 * $Id: primnodes.h,v 1.63 2002/05/12 23:43:04 tgl Exp $
14 15 16 17
 *
 *-------------------------------------------------------------------------
 */
#ifndef PRIMNODES_H
18
#define PRIMNODES_H
19

20 21
#include "access/attnum.h"
#include "nodes/pg_list.h"
22 23 24 25

/* FunctionCache is declared in utils/fcache.h */
typedef struct FunctionCache *FunctionCachePtr;

26 27

/* ----------------------------------------------------------------
28
 *						node definitions
29 30 31
 * ----------------------------------------------------------------
 */

32
/*--------------------
33 34
 * Resdom (Result Domain)
 *
35 36
 * Notes:
 * ressortgroupref is the parse/plan-time representation of ORDER BY and
37
 * GROUP BY items.	Targetlist entries with ressortgroupref=0 are not
38
 * sort/group items.  If ressortgroupref>0, then this item is an ORDER BY or
39
 * GROUP BY value.	No two entries in a targetlist may have the same nonzero
40
 * ressortgroupref --- but there is no particular meaning to the nonzero
41 42
 * values, except as tags.	(For example, one must not assume that lower
 * ressortgroupref means a more significant sort key.)	The order of the
43 44 45 46 47
 * associated SortClause or GroupClause lists determine the semantics.
 *
 * reskey and reskeyop are the execution-time representation of sorting.
 * reskey must be zero in any non-sort-key item.  The reskey of sort key
 * targetlist items for a sort plan node is 1,2,...,n for the n sort keys.
48 49
 * The reskeyop of each such targetlist item is the sort operator's OID.
 * reskeyop will be zero in non-sort-key items.
50 51 52
 *
 * Both reskey and reskeyop are typically zero during parse/plan stages.
 * The executor does not pay any attention to ressortgroupref.
53
 *--------------------
54
 */
55 56
typedef struct Resdom
{
B
Bruce Momjian 已提交
57 58 59 60 61
	NodeTag		type;
	AttrNumber	resno;			/* attribute number */
	Oid			restype;		/* type of the value */
	int32		restypmod;		/* type-specific modifier of the value */
	char	   *resname;		/* name of the resdom (could be NULL) */
62
	Index		ressortgroupref;
B
Bruce Momjian 已提交
63 64
	/* nonzero if referenced by a sort/group clause */
	Index		reskey;			/* order of key in a sort (for those > 0) */
65
	Oid			reskeyop;		/* sort operator's Oid */
B
Bruce Momjian 已提交
66 67
	bool		resjunk;		/* set to true to eliminate the attribute
								 * from final target list */
68
} Resdom;
69

70
/*
71 72
 * Fjoin
 */
73 74
typedef struct Fjoin
{
75
	NodeTag		type;
B
Bruce Momjian 已提交
76 77 78 79 80
	bool		fj_initialized; /* true if the Fjoin has already been
								 * initialized for the current target list
								 * evaluation */
	int			fj_nNodes;		/* The number of Iter nodes returning sets
								 * that the node will flatten */
81 82 83 84
	List	   *fj_innerNode;	/* exactly one Iter node.  We eval every
								 * node in the outerList once then eval
								 * the inner node to completion pair the
								 * outerList result vector with each inner
B
Bruce Momjian 已提交
85
								 * result to form the full result.	When
86 87
								 * the inner has been exhausted, we get
								 * the next outer result vector and reset
B
Bruce Momjian 已提交
88
								 * the inner. */
89 90 91
	DatumPtr	fj_results;		/* The complete (flattened) result vector */
	BoolPtr		fj_alwaysDone;	/* a null vector to indicate sets with a
								 * cardinality of 0, we treat them as the
B
Bruce Momjian 已提交
92
								 * set {NULL}. */
93
} Fjoin;
94

95

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
/*
 * Alias -
 *	  specifies an alias for a range variable; the alias might also
 *	  specify renaming of columns within the table.
 */
typedef struct Alias
{
	NodeTag		type;
	char	   *aliasname;		/* aliased rel name (never qualified) */
	List	   *colnames;		/* optional list of column aliases */
	/* Note: colnames is a list of Value nodes (always strings) */
} Alias;

typedef enum InhOption
{
	INH_NO,						/* Do NOT scan child tables */
	INH_YES,					/* DO scan child tables */
	INH_DEFAULT					/* Use current SQL_inheritance option */
} InhOption;

/*
 * RangeVar - range variable, used in FROM clauses
 *
 * Also used to represent table names in utility statements; there, the alias
 * field is not used, and inhOpt shows whether to apply the operation
 * recursively to child tables.  In some contexts it is also useful to carry
 * a TEMP table indication here.
 */
typedef struct RangeVar
{
	NodeTag		type;
	char	   *catalogname;	/* the catalog (database) name, or NULL */
	char	   *schemaname;		/* the schema name, or NULL */
	char	   *relname;		/* the relation/sequence name */
	InhOption	inhOpt;			/* expand rel by inheritance? 
								 * recursively act on children? */
	bool		istemp;			/* is this a temp relation/sequence? */
	Alias	   *alias;			/* table alias & optional column aliases */
} RangeVar;


137 138 139 140 141
/* ----------------------------------------------------------------
 *					node types for executable expressions
 * ----------------------------------------------------------------
 */

142
/*
143 144
 * Expr
 */
145 146
typedef enum OpType
{
147
	OP_EXPR, FUNC_EXPR, OR_EXPR, AND_EXPR, NOT_EXPR, SUBPLAN_EXPR
148
} OpType;
149

150 151
typedef struct Expr
{
152
	NodeTag		type;
B
Bruce Momjian 已提交
153
	Oid			typeOid;		/* oid of the type of this expression */
154
	OpType		opType;			/* kind of expression */
B
Bruce Momjian 已提交
155 156 157
	Node	   *oper;			/* operator node if needed (Oper, Func, or
								 * SubPlan) */
	List	   *args;			/* arguments to this expression */
158
} Expr;
159

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
/*
 * Oper - Expr subnode for an OP_EXPR
 *
 * NOTE: in the good old days 'opno' used to be both (or either, or
 * neither) the pg_operator oid, and/or the pg_proc oid depending
 * on the postgres module in question (parser->pg_operator,
 * executor->pg_proc, planner->both), the mood of the programmer,
 * and the phase of the moon (rumors that it was also depending on the day
 * of the week are probably false). To make things even more postgres-like
 * (i.e. a mess) some comments were referring to 'opno' using the name
 * 'opid'. Anyway, now we have two separate fields, and of course that
 * immediately removes all bugs from the code...		[ sp :-) ].
 *
 * Note also that opid is not necessarily filled in immediately on creation
 * of the node.  The planner makes sure it is valid before passing the node
 * tree to the executor, but during parsing/planning opid is typically 0.
 */
typedef struct Oper
{
	NodeTag		type;
	Oid			opno;			/* PG_OPERATOR OID of the operator */
	Oid			opid;			/* PG_PROC OID of underlying function */
	Oid			opresulttype;	/* PG_TYPE OID of result value */
	bool		opretset;		/* true if operator returns set */
	FunctionCachePtr op_fcache;	/* runtime state, else NULL */
} Oper;

/*
 * Func - Expr subnode for a FUNC_EXPR
 */
typedef struct Func
{
	NodeTag		type;
	Oid			funcid;			/* PG_PROC OID of the function */
	Oid			funcresulttype;	/* PG_TYPE OID of result value */
	bool		funcretset;		/* true if function returns set */
	FunctionCachePtr func_fcache; /* runtime state, or NULL */
} Func;

199
/*
200
 * Var
201 202 203 204 205 206 207 208 209
 *
 * Note: during parsing/planning, varnoold/varoattno are always just copies
 * of varno/varattno.  At the tail end of planning, Var nodes appearing in
 * upper-level plan nodes are reassigned to point to the outputs of their
 * subplans; for example, in a join node varno becomes INNER or OUTER and
 * varattno becomes the index of the proper element of that subplan's target
 * list.  But varnoold/varoattno continue to hold the original values.
 * The code doesn't really need varnoold/varoattno, but they are very useful
 * for debugging and interpreting completed plans, so we keep them around.
210
 */
211 212
#define    INNER		65000
#define    OUTER		65001
213

214 215
#define    PRS2_OLD_VARNO			1
#define    PRS2_NEW_VARNO			2
216

217 218
typedef struct Var
{
219
	NodeTag		type;
B
Bruce Momjian 已提交
220 221 222 223 224 225 226 227
	Index		varno;			/* index of this var's relation in the
								 * range table (could also be INNER or
								 * OUTER) */
	AttrNumber	varattno;		/* attribute number of this var, or zero
								 * for all */
	Oid			vartype;		/* pg_type tuple OID for the type of this
								 * var */
	int32		vartypmod;		/* pg_attribute typmod value */
228
	Index		varlevelsup;
B
Bruce Momjian 已提交
229 230 231 232 233 234 235

	/*
	 * for subquery variables referencing outer relations; 0 in a normal
	 * var, >0 means N levels up
	 */
	Index		varnoold;		/* original value of varno, for debugging */
	AttrNumber	varoattno;		/* original value of varattno */
236
} Var;
237

238
/*
239 240
 * Const
 */
241 242
typedef struct Const
{
243
	NodeTag		type;
244 245 246 247 248 249
	Oid			consttype;		/* PG_TYPE OID of the constant's value */
	int			constlen;		/* length in bytes of the constant's value */
	Datum		constvalue;		/* the constant's value */
	bool		constisnull;	/* whether the constant is null (if true,
								 * the other fields are undefined) */
	bool		constbyval;		/* whether the information in constvalue
B
Bruce Momjian 已提交
250
								 * if passed by value.	If true, then all
251
								 * the information is stored in the datum.
B
Bruce Momjian 已提交
252 253 254 255
								 * If false, then the datum contains a
								 * pointer to the information. */
	bool		constisset;		/* whether the const represents a set. The
								 * const value corresponding will be the
256
								 * query that defines the set. */
257
	bool		constiscast;
258
} Const;
259 260 261

/* ----------------
 * Param
262 263
 *		paramkind - specifies the kind of parameter. The possible values
 *		for this field are specified in "params.h", and they are:
264
 *
265 266 267
 *		PARAM_NAMED: The parameter has a name, i.e. something
 *				like `$.salary' or `$.foobar'.
 *				In this case field `paramname' must be a valid Name.
268
 *
269 270 271
 *		PARAM_NUM:	 The parameter has only a numeric identifier,
 *				i.e. something like `$1', `$2' etc.
 *				The number is contained in the `paramid' field.
272
 *
273 274 275 276
 *		PARAM_NEW:	 Used in PRS2 rule, similar to PARAM_NAMED.
 *					 The `paramname' and `paramid' refer to the "NEW" tuple
 *					 The `pramname' is the attribute name and `paramid'
 *					 is the attribute number.
277
 *
278 279
 *		PARAM_OLD:	 Same as PARAM_NEW, but in this case we refer to
 *				the "OLD" tuple.
280 281
 * ----------------
 */
282 283
typedef struct Param
{
284
	NodeTag		type;
B
Bruce Momjian 已提交
285 286 287 288 289 290 291
	int			paramkind;		/* specifies the kind of parameter.  See
								 * above */
	AttrNumber	paramid;		/* numeric identifier for literal-constant
								 * parameters ("$1") */
	char	   *paramname;		/* attribute name for tuple-substitution
								 * parameters ("$.foo") */
	Oid			paramtype;		/* PG_TYPE OID of the parameter's value */
292
} Param;
293

294
/*
B
Bruce Momjian 已提交
295
 * Aggref
296
 */
B
Bruce Momjian 已提交
297
typedef struct Aggref
298
{
299
	NodeTag		type;
300 301 302
	Oid			aggfnoid;		/* pg_proc Oid of the aggregate */
	Oid			aggtype;		/* type Oid of result of the aggregate */
	Node	   *target;			/* expression we are aggregating on */
B
Bruce Momjian 已提交
303 304 305
	bool		aggstar;		/* TRUE if argument was really '*' */
	bool		aggdistinct;	/* TRUE if it's agg(DISTINCT ...) */
	int			aggno;			/* workspace for executor (see nodeAgg.c) */
306
} Aggref;
307

308 309
/* ----------------
 * SubLink
310
 *
311
 * A SubLink represents a subselect appearing in an expression, and in some
312
 * cases also the combining operator(s) just above it.	The subLinkType
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
 * indicates the form of the expression represented:
 *	EXISTS_SUBLINK		EXISTS(SELECT ...)
 *	ALL_SUBLINK			(lefthand) op ALL (SELECT ...)
 *	ANY_SUBLINK			(lefthand) op ANY (SELECT ...)
 *	MULTIEXPR_SUBLINK	(lefthand) op (SELECT ...)
 *	EXPR_SUBLINK		(SELECT with single targetlist item ...)
 * For ALL, ANY, and MULTIEXPR, the lefthand is a list of expressions of the
 * same length as the subselect's targetlist.  MULTIEXPR will *always* have
 * a list with more than one entry; if the subselect has just one target
 * then the parser will create an EXPR_SUBLINK instead (and any operator
 * above the subselect will be represented separately).  Note that both
 * MULTIEXPR and EXPR require the subselect to deliver only one row.
 * ALL, ANY, and MULTIEXPR require the combining operators to deliver boolean
 * results.  These are reduced to one result per row using OR or AND semantics
 * depending on the "useor" flag.  ALL and ANY combine the per-row results
 * using AND and OR semantics respectively.
 *
330 331 332
 * NOTE: lefthand and oper have varying meanings depending on where you look
 * in the parse/plan pipeline:
 * 1. gram.y delivers a list of the (untransformed) lefthand expressions in
333 334
 *	  lefthand, and sets oper to a single A_Expr (not a list!) containing
 *	  the string name of the operator, but no arguments.
335
 * 2. The parser's expression transformation transforms lefthand normally,
336 337 338 339 340 341
 *	  and replaces oper with a list of Oper nodes, one per lefthand
 *	  expression.  These nodes represent the parser's resolution of exactly
 *	  which operator to apply to each pair of lefthand and targetlist
 *	  expressions.	However, we have not constructed actual Expr trees for
 *	  these operators yet.	This is the representation seen in saved rules
 *	  and in the rewriter.
342
 * 3. Finally, the planner converts the oper list to a list of normal Expr
343 344 345 346 347
 *	  nodes representing the application of the operator(s) to the lefthand
 *	  expressions and values from the inner targetlist.  The inner
 *	  targetlist items are represented by placeholder Param or Const nodes.
 *	  The lefthand field is set to NIL, since its expressions are now in
 *	  the Expr list.  This representation is passed to the executor.
348 349 350 351 352 353
 *
 * Planner routines that might see either representation 2 or 3 can tell
 * the difference by checking whether lefthand is NIL or not.  Also,
 * representation 2 appears in a "bare" SubLink, while representation 3 is
 * found in SubLinks that are children of SubPlan nodes.
 *
354
 * In EXISTS and EXPR SubLinks, both lefthand and oper are unused and are
355
 * always NIL.	useor is not significant either for these sublink types.
356 357 358 359
 * ----------------
 */
typedef enum SubLinkType
{
360
	EXISTS_SUBLINK, ALL_SUBLINK, ANY_SUBLINK, MULTIEXPR_SUBLINK, EXPR_SUBLINK
361 362 363 364 365 366
} SubLinkType;


typedef struct SubLink
{
	NodeTag		type;
B
Bruce Momjian 已提交
367 368 369 370 371 372 373 374
	SubLinkType subLinkType;	/* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
	bool		useor;			/* TRUE to combine column results with
								 * "OR" not "AND" */
	List	   *lefthand;		/* list of outer-query expressions on the
								 * left */
	List	   *oper;			/* list of Oper nodes for combining
								 * operators */
	Node	   *subselect;		/* subselect as Query* or parsetree */
375 376
} SubLink;

377
/* ----------------
378 379 380 381 382 383
 *	ArrayRef: describes an array subscripting operation
 *
 * An ArrayRef can describe fetching a single element from an array,
 * fetching a subarray (array slice), storing a single element into
 * an array, or storing a slice.  The "store" cases work with an
 * initial array value and a source value that is inserted into the
384 385
 * appropriate part of the array; the result of the operation is an
 * entire new modified array value.
386 387
 *
 * If reflowerindexpr = NIL, then we are fetching or storing a single array
388
 * element at the subscripts given by refupperindexpr.	Otherwise we are
389 390 391 392 393 394 395
 * fetching or storing an array slice, that is a rectangular subarray
 * with lower and upper bounds given by the index expressions.
 * reflowerindexpr must be the same length as refupperindexpr when it
 * is not NIL.
 *
 * Note: array types can be fixed-length (refattrlength > 0), but only
 * when the element type is itself fixed-length.  Otherwise they are
396
 * varlena structures and have refattrlength = -1.	In any case,
397 398 399 400 401
 * an array type is never pass-by-value.
 *
 * Note: currently, refelemtype is NOT the element type, but the array type,
 * when doing subarray fetch or either type of store.  It would be cleaner
 * to add more fields so we can distinguish the array element type from the
402
 * result type of the ArrayRef operator...
403 404
 * ----------------
 */
405 406
typedef struct ArrayRef
{
407
	NodeTag		type;
B
Bruce Momjian 已提交
408 409 410 411 412 413 414 415 416 417 418 419 420
	int			refattrlength;	/* typlen of array type */
	int			refelemlength;	/* typlen of the array element type */
	Oid			refelemtype;	/* type of the result of the ArrayRef
								 * operation */
	bool		refelembyval;	/* is the element type pass-by-value? */
	List	   *refupperindexpr;/* expressions that evaluate to upper
								 * array indexes */
	List	   *reflowerindexpr;/* expressions that evaluate to lower
								 * array indexes */
	Node	   *refexpr;		/* the expression that evaluates to an
								 * array value */
	Node	   *refassgnexpr;	/* expression for the source value, or
								 * NULL if fetch */
B
Bruce Momjian 已提交
421
} ArrayRef;
422

423 424 425 426 427 428 429 430 431 432 433 434 435
/* ----------------
 * FieldSelect
 *
 * FieldSelect represents the operation of extracting one field from a tuple
 * value.  At runtime, the input expression is expected to yield a Datum
 * that contains a pointer-to-TupleTableSlot.  The specified field number
 * is extracted and returned as a Datum.
 * ----------------
 */

typedef struct FieldSelect
{
	NodeTag		type;
436 437 438 439 440
	Node	   *arg;			/* input expression */
	AttrNumber	fieldnum;		/* attribute number of field to extract */
	Oid			resulttype;		/* type of the field (result type of this
								 * node) */
	int32		resulttypmod;	/* output typmod (usually -1) */
441 442
} FieldSelect;

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
/* ----------------
 * RelabelType
 *
 * RelabelType represents a "dummy" type coercion between two binary-
 * compatible datatypes, such as reinterpreting the result of an OID
 * expression as an int4.  It is a no-op at runtime; we only need it
 * to provide a place to store the correct type to be attributed to
 * the expression result during type resolution.  (We can't get away
 * with just overwriting the type field of the input expression node,
 * so we need a separate node to show the coercion's result type.)
 * ----------------
 */

typedef struct RelabelType
{
	NodeTag		type;
459 460 461
	Node	   *arg;			/* input expression */
	Oid			resulttype;		/* output type of coercion expression */
	int32		resulttypmod;	/* output typmod (usually -1) */
462 463
} RelabelType;

464 465 466 467 468 469

/* ----------------------------------------------------------------
 *					node types for join trees
 *
 * The leaves of a join tree structure are RangeTblRef nodes.  Above
 * these, JoinExpr nodes can appear to denote a specific kind of join
470 471 472 473 474 475 476 477 478 479 480 481
 * or qualified join.  Also, FromExpr nodes can appear to denote an
 * ordinary cross-product join ("FROM foo, bar, baz WHERE ...").
 * FromExpr is like a JoinExpr of jointype JOIN_INNER, except that it
 * may have any number of child nodes, not just two.  Also, there is an
 * implementation-defined difference: the planner is allowed to join the
 * children of a FromExpr using whatever join order seems good to it.
 * At present, JoinExpr nodes are always joined in exactly the order
 * implied by the jointree structure (except the planner may choose to
 * swap inner and outer members of a join pair).
 *
 * NOTE: the top level of a Query's jointree is always a FromExpr.
 * Even if the jointree contains no rels, there will be a FromExpr.
482 483
 *
 * NOTE: the qualification expressions present in JoinExpr nodes are
484
 * *in addition to* the query's main WHERE clause, which appears as the
B
Bruce Momjian 已提交
485
 * qual of the top-level FromExpr.	The reason for associating quals with
486 487 488 489 490
 * specific nodes in the jointree is that the position of a qual is critical
 * when outer joins are present.  (If we enforce a qual too soon or too late,
 * that may cause the outer join to produce the wrong set of NULL-extended
 * rows.)  If all joins are inner joins then all the qual positions are
 * semantically interchangeable.
491
 *
492 493 494 495 496
 * NOTE: in the raw output of gram.y, a join tree contains RangeVar,
 * RangeSubselect, and RangeFunction nodes, which are all replaced by
 * RangeTblRef nodes during the parse analysis phase.  Also, the top-level
 * FromExpr is added during parse analysis; the grammar regards FROM and
 * WHERE as separate.
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
 * ----------------------------------------------------------------
 */

/*
 * RangeTblRef - reference to an entry in the query's rangetable
 *
 * We could use direct pointers to the RT entries and skip having these
 * nodes, but multiple pointers to the same node in a querytree cause
 * lots of headaches, so it seems better to store an index into the RT.
 */
typedef struct RangeTblRef
{
	NodeTag		type;
	int			rtindex;
} RangeTblRef;

/*----------
 * JoinExpr - for SQL JOIN expressions
 *
B
Bruce Momjian 已提交
516
 * isNatural, using, and quals are interdependent.	The user can write only
517 518 519 520
 * one of NATURAL, USING(), or ON() (this is enforced by the grammar).
 * If he writes NATURAL then parse analysis generates the equivalent USING()
 * list, and from that fills in "quals" with the right equality comparisons.
 * If he writes USING() then "quals" is filled with equality comparisons.
B
Bruce Momjian 已提交
521
 * If he writes ON() then only "quals" is set.	Note that NATURAL/USING
522 523
 * are not equivalent to ON() since they also affect the output column list.
 *
524
 * alias is an Alias node representing the AS alias-clause attached to the
525 526 527 528
 * join expression, or NULL if no clause.  NB: presence or absence of the
 * alias has a critical impact on semantics, because a join with an alias
 * restricts visibility of the tables/columns inside it.
 *
529 530 531
 * During parse analysis, an RTE is created for the Join, and its index
 * is filled into rtindex.  This RTE is present mainly so that Vars can
 * be created that refer to the outputs of the join.
532 533 534 535 536 537 538 539 540 541 542
 *----------
 */
typedef struct JoinExpr
{
	NodeTag		type;
	JoinType	jointype;		/* type of join */
	bool		isNatural;		/* Natural join? Will need to shape table */
	Node	   *larg;			/* left subtree */
	Node	   *rarg;			/* right subtree */
	List	   *using;			/* USING clause, if any (list of String) */
	Node	   *quals;			/* qualifiers on join, if any */
543
	Alias	   *alias;			/* user-written alias clause, if any */
544
	int			rtindex;		/* RT index assigned for join */
545 546
} JoinExpr;

547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
/*----------
 * FromExpr - represents a FROM ... WHERE ... construct
 *
 * This is both more flexible than a JoinExpr (it can have any number of
 * children, including zero) and less so --- we don't need to deal with
 * aliases and so on.  The output column set is implicitly just the union
 * of the outputs of the children.
 *----------
 */
typedef struct FromExpr
{
	NodeTag		type;
	List	   *fromlist;		/* List of join subtrees */
	Node	   *quals;			/* qualifiers on join, if any */
} FromExpr;
562

563
#endif   /* PRIMNODES_H */