]> granicus.if.org Git - postgresql/blob - src/include/nodes/relation.h
Move WAL params higher in file, next to fsync option.
[postgresql] / src / include / nodes / relation.h
1 /*-------------------------------------------------------------------------
2  *
3  * relation.h
4  *        Definitions for internal planner nodes.
5  *
6  *
7  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * $Id: relation.h,v 1.57 2001/06/05 05:26:05 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #ifndef RELATION_H
15 #define RELATION_H
16
17 #include "access/sdir.h"
18 #include "nodes/parsenodes.h"
19
20 /*
21  * Relids
22  *              List of relation identifiers (indexes into the rangetable).
23  *
24  *              Note: these are lists of integers, not Nodes.
25  */
26
27 typedef List *Relids;
28
29 /*
30  * When looking for a "cheapest path", this enum specifies whether we want
31  * cheapest startup cost or cheapest total cost.
32  */
33 typedef enum CostSelector
34 {
35         STARTUP_COST, TOTAL_COST
36 } CostSelector;
37
38 /*----------
39  * RelOptInfo
40  *              Per-relation information for planning/optimization
41  *
42  *              For planning purposes, a "base rel" is either a plain relation (a
43  *              table) or the output of a sub-SELECT that appears in the range table.
44  *              In either case it is uniquely identified by an RT index.  A "joinrel"
45  *              is the joining of two or more base rels.  A joinrel is identified by
46  *              the set of RT indexes for its component baserels.
47  *
48  *              Note that there is only one joinrel for any given set of component
49  *              baserels, no matter what order we assemble them in; so an unordered
50  *              set is the right datatype to identify it with.
51  *
52  *              Parts of this data structure are specific to various scan and join
53  *              mechanisms.  It didn't seem worth creating new node types for them.
54  *
55  *              relids - List of base-relation identifiers; it is a base relation
56  *                              if there is just one, a join relation if more than one
57  *              rows - estimated number of tuples in the relation after restriction
58  *                         clauses have been applied (ie, output rows of a plan for it)
59  *              width - avg. number of bytes per tuple in the relation after the
60  *                              appropriate projections have been done (ie, output width)
61  *              targetlist - List of TargetEntry nodes for the attributes we need
62  *                                       to output from this relation
63  *              pathlist - List of Path nodes, one for each potentially useful
64  *                                 method of generating the relation
65  *              cheapest_startup_path - the pathlist member with lowest startup cost
66  *                                                              (regardless of its ordering)
67  *              cheapest_total_path - the pathlist member with lowest total cost
68  *                                                        (regardless of its ordering)
69  *              pruneable - flag to let the planner know whether it can prune the
70  *                                      pathlist of this RelOptInfo or not.
71  *
72  *       * If the relation is a base relation it will have these fields set:
73  *
74  *              issubquery - true if baserel is a subquery RTE rather than a table
75  *              indexlist - list of IndexOptInfo nodes for relation's indexes
76  *                                      (always NIL if it's a subquery)
77  *              pages - number of disk pages in relation (zero if a subquery)
78  *              tuples - number of tuples in relation (not considering restrictions)
79  *              subplan - plan for subquery (NULL if it's a plain table)
80  *
81  *              Note: for a subquery, tuples and subplan are not set immediately
82  *              upon creation of the RelOptInfo object; they are filled in when
83  *              set_base_rel_pathlist processes the object.
84  *
85  *              Note: if a base relation is the root of an inheritance tree
86  *              (SELECT FROM foo*) it is still considered a base rel.  We will
87  *              generate a list of candidate Paths for accessing that table itself,
88  *              and also generate baserel RelOptInfo nodes for each child table,
89  *              with their own candidate Path lists.  Then, an AppendPath is built
90  *              from the cheapest Path for each of these tables, and set to be the
91  *              only available Path for the inheritance baserel.
92  *
93  *       * The presence of the remaining fields depends on the restrictions
94  *              and joins that the relation participates in:
95  *
96  *              baserestrictinfo - List of RestrictInfo nodes, containing info about
97  *                                      each qualification clause in which this relation
98  *                                      participates (only used for base rels)
99  *              baserestrictcost - Estimated cost of evaluating the baserestrictinfo
100  *                                      clauses at a single tuple (only used for base rels)
101  *              outerjoinset - If the rel appears within the nullable side of an outer
102  *                                      join, the list of all relids participating in the highest
103  *                                      such outer join; else NIL (only used for base rels)
104  *              joininfo  - List of JoinInfo nodes, containing info about each join
105  *                                      clause in which this relation participates
106  *              innerjoin - List of Path nodes that represent indices that may be used
107  *                                      as inner paths of nestloop joins. This field is non-null
108  *                                      only for base rels, since join rels have no indices.
109  *
110  * Note: Keeping a restrictinfo list in the RelOptInfo is useful only for
111  * base rels, because for a join rel the set of clauses that are treated as
112  * restrict clauses varies depending on which sub-relations we choose to join.
113  * (For example, in a 3-base-rel join, a clause relating rels 1 and 2 must be
114  * treated as a restrictclause if we join {1} and {2 3} to make {1 2 3}; but
115  * if we join {1 2} and {3} then that clause will be a restrictclause in {1 2}
116  * and should not be processed again at the level of {1 2 3}.)  Therefore,
117  * the restrictinfo list in the join case appears in individual JoinPaths
118  * (field joinrestrictinfo), not in the parent relation.  But it's OK for
119  * the RelOptInfo to store the joininfo lists, because those are the same
120  * for a given rel no matter how we form it.
121  *
122  * We store baserestrictcost in the RelOptInfo (for base relations) because
123  * we know we will need it at least once (to price the sequential scan)
124  * and may need it multiple times to price index scans.
125  *
126  * outerjoinset is used to ensure correct placement of WHERE clauses that
127  * apply to outer-joined relations; we must not apply such WHERE clauses
128  * until after the outer join is performed.
129  *----------
130  */
131
132 typedef struct RelOptInfo
133 {
134         NodeTag         type;
135
136         /* all relations included in this RelOptInfo */
137         Relids          relids;                 /* integer list of base relids (RT
138                                                                  * indexes) */
139
140         /* size estimates generated by planner */
141         double          rows;                   /* estimated number of result tuples */
142         int                     width;                  /* estimated avg width of result tuples */
143
144         /* materialization information */
145         List       *targetlist;
146         List       *pathlist;           /* Path structures */
147         struct Path *cheapest_startup_path;
148         struct Path *cheapest_total_path;
149         bool            pruneable;
150
151         /* information about a base rel (not set for join rels!) */
152         bool            issubquery;
153         List       *indexlist;
154         long            pages;
155         double          tuples;
156         struct Plan *subplan;
157
158         /* used by various scans and joins: */
159         List       *baserestrictinfo;           /* RestrictInfo structures (if
160                                                                                  * base rel) */
161         Cost            baserestrictcost;               /* cost of evaluating the above */
162         Relids          outerjoinset;   /* integer list of base relids */
163         List       *joininfo;           /* JoinInfo structures */
164         List       *innerjoin;          /* potential indexscans for nestloop joins */
165
166         /*
167          * innerjoin indexscans are not in the main pathlist because they are
168          * not usable except in specific join contexts; we have to test before
169          * seeing whether they can be used.
170          */
171 } RelOptInfo;
172
173 /*
174  * IndexOptInfo
175  *              Per-index information for planning/optimization
176  *
177  *              Prior to Postgres 7.0, RelOptInfo was used to describe both relations
178  *              and indexes, but that created confusion without actually doing anything
179  *              useful.  So now we have a separate IndexOptInfo struct for indexes.
180  *
181  *              indexoid  - OID of the index relation itself
182  *              pages     - number of disk pages in index
183  *              tuples    - number of index tuples in index
184  *              ncolumns  - number of columns in index
185  *              nkeys     - number of keys used by index (input columns)
186  *              classlist - List of PG_AMOPCLASS OIDs for the index
187  *              indexkeys - List of base-relation attribute numbers that are index keys
188  *              ordering  - List of PG_OPERATOR OIDs which order the indexscan result
189  *              relam     - the OID of the pg_am of the index
190  *              amcostestimate - OID of the relam's cost estimator
191  *              indproc   - OID of the function if a functional index, else 0
192  *              indpred   - index predicate if a partial index, else NULL
193  *              unique    - true if index is unique
194  *              lossy     - true if index is lossy (may return non-matching tuples)
195  *
196  *              ncolumns and nkeys are the same except for a functional index,
197  *              wherein ncolumns is 1 (the single function output) while nkeys
198  *              is the number of table columns passed to the function. classlist[]
199  *              and ordering[] have ncolumns entries, while indexkeys[] has nkeys
200  *              entries.
201  * 
202  *              Note: for historical reasons, the arrays classlist, indexkeys and
203  *              ordering have an extra entry that is always zero.  Some code scans
204  *              until it sees a zero rather than looking at ncolumns or nkeys.
205  */
206
207 typedef struct IndexOptInfo
208 {
209         NodeTag         type;
210
211         Oid                     indexoid;               /* OID of the index relation */
212
213         /* statistics from pg_class */
214         long            pages;
215         double          tuples;
216
217         /* index descriptor information */
218         int                     ncolumns;               /* number of columns in index */
219         int                     nkeys;                  /* number of keys used by index */
220         Oid                *classlist;          /* AM operator classes for columns */
221         int                *indexkeys;          /* column numbers of index's keys */
222         Oid                *ordering;           /* OIDs of sort operators for each column */
223         Oid                     relam;                  /* OID of the access method (in pg_am) */
224
225         RegProcedure amcostestimate;/* OID of the access method's cost fcn */
226
227         Oid                     indproc;                /* if a functional index */
228         List       *indpred;            /* if a partial index */
229         bool            unique;                 /* if a unique index */
230         bool            lossy;                  /* if a lossy index */
231 } IndexOptInfo;
232
233 /*
234  * PathKeys
235  *
236  *      The sort ordering of a path is represented by a list of sublists of
237  *      PathKeyItem nodes.      An empty list implies no known ordering.  Otherwise
238  *      the first sublist represents the primary sort key, the second the
239  *      first secondary sort key, etc.  Each sublist contains one or more
240  *      PathKeyItem nodes, each of which can be taken as the attribute that
241  *      appears at that sort position.  (See the top of optimizer/path/pathkeys.c
242  *      for more information.)
243  */
244
245 typedef struct PathKeyItem
246 {
247         NodeTag         type;
248
249         Node       *key;                        /* the item that is ordered */
250         Oid                     sortop;                 /* the ordering operator ('<' op) */
251
252         /*
253          * key typically points to a Var node, ie a relation attribute, but it
254          * can also point to a Func clause representing the value indexed by a
255          * functional index.  Someday we might allow arbitrary expressions as
256          * path keys, so don't assume more than you must.
257          */
258 } PathKeyItem;
259
260 /*
261  * Type "Path" is used as-is for sequential-scan paths.  For other
262  * path types it is the first component of a larger struct.
263  */
264
265 typedef struct Path
266 {
267         NodeTag         type;
268
269         RelOptInfo *parent;                     /* the relation this path can build */
270
271         /* estimated execution costs for path (see costsize.c for more info) */
272         Cost            startup_cost;   /* cost expended before fetching any
273                                                                  * tuples */
274         Cost            total_cost;             /* total cost (assuming all tuples
275                                                                  * fetched) */
276
277         NodeTag         pathtype;               /* tag identifying scan/join method */
278         /* XXX why is pathtype separate from the NodeTag? */
279
280         List       *pathkeys;           /* sort ordering of path's output */
281         /* pathkeys is a List of Lists of PathKeyItem nodes; see above */
282 } Path;
283
284 /*----------
285  * IndexPath represents an index scan.  Although an indexscan can only read
286  * a single relation, it can scan it more than once, potentially using a
287  * different index during each scan.  The result is the union (OR) of all the
288  * tuples matched during any scan.      (The executor is smart enough not to return
289  * the same tuple more than once, even if it is matched in multiple scans.)
290  *
291  * 'indexinfo' is a list of IndexOptInfo nodes, one per scan to be performed.
292  *
293  * 'indexqual' is a list of index qualifications, also one per scan.
294  * Each entry in 'indexqual' is a sublist of qualification expressions with
295  * implicit AND semantics across the sublist items.  Only expressions that
296  * are usable as indexquals (as determined by indxpath.c) may appear here.
297  * NOTE that the semantics of the top-level list in 'indexqual' is OR
298  * combination, while the sublists are implicitly AND combinations!
299  * Also note that indexquals lists do not contain RestrictInfo nodes,
300  * just bare clause expressions.
301  *
302  * 'indexscandir' is one of:
303  *              ForwardScanDirection: forward scan of an ordered index
304  *              BackwardScanDirection: backward scan of an ordered index
305  *              NoMovementScanDirection: scan of an unordered index, or don't care
306  * (The executor doesn't care whether it gets ForwardScanDirection or
307  * NoMovementScanDirection for an indexscan, but the planner wants to
308  * distinguish ordered from unordered indexes for building pathkeys.)
309  *
310  * 'joinrelids' is only used in IndexPaths that are constructed for use
311  * as the inner path of a nestloop join.  These paths have indexquals
312  * that refer to values of other rels, so those other rels must be
313  * included in the outer joinrel in order to make a usable join.
314  *
315  * 'alljoinquals' is also used only for inner paths of nestloop joins.
316  * This flag is TRUE iff all the indexquals came from non-pushed-down
317  * JOIN/ON conditions, which means the path is safe to use for an outer join.
318  *
319  * 'rows' is the estimated result tuple count for the indexscan.  This
320  * is the same as path.parent->rows for a simple indexscan, but it is
321  * different for a nestloop inner path, because the additional indexquals
322  * coming from join clauses make the scan more selective than the parent
323  * rel's restrict clauses alone would do.
324  *----------
325  */
326 typedef struct IndexPath
327 {
328         Path            path;
329         List       *indexinfo;
330         List       *indexqual;
331         ScanDirection indexscandir;
332         Relids          joinrelids;             /* other rels mentioned in indexqual */
333         bool            alljoinquals;   /* all indexquals derived from JOIN conds? */
334         double          rows;                   /* estimated number of result tuples */
335 } IndexPath;
336
337 /*
338  * TidPath represents a scan by TID
339  */
340 typedef struct TidPath
341 {
342         Path            path;
343         List       *tideval;
344         Relids          unjoined_relids;/* some rels not yet part of my Path */
345 } TidPath;
346
347 /*
348  * AppendPath represents an Append plan, ie, successive execution of
349  * several member plans.  Currently it is only used to handle expansion
350  * of inheritance trees.
351  */
352 typedef struct AppendPath
353 {
354         Path            path;
355         List       *subpaths;           /* list of component Paths */
356 } AppendPath;
357
358 /*
359  * All join-type paths share these fields.
360  */
361
362 typedef struct JoinPath
363 {
364         Path            path;
365
366         JoinType        jointype;
367
368         Path       *outerjoinpath;      /* path for the outer side of the join */
369         Path       *innerjoinpath;      /* path for the inner side of the join */
370
371         List       *joinrestrictinfo;           /* RestrictInfos to apply to join */
372
373         /*
374          * See the notes for RelOptInfo to understand why joinrestrictinfo is
375          * needed in JoinPath, and can't be merged into the parent RelOptInfo.
376          */
377 } JoinPath;
378
379 /*
380  * A nested-loop path needs no special fields.
381  */
382
383 typedef JoinPath NestPath;
384
385 /*
386  * A mergejoin path has these fields.
387  *
388  * path_mergeclauses lists the clauses (in the form of RestrictInfos)
389  * that will be used in the merge.      (Before 7.0, this was a list of bare
390  * clause expressions, but we can save on list memory and cost_qual_eval
391  * work by leaving it in the form of a RestrictInfo list.)
392  *
393  * Note that the mergeclauses are a subset of the parent relation's
394  * restriction-clause list.  Any join clauses that are not mergejoinable
395  * appear only in the parent's restrict list, and must be checked by a
396  * qpqual at execution time.
397  *
398  * outersortkeys (resp. innersortkeys) is NIL if the outer path
399  * (resp. inner path) is already ordered appropriately for the
400  * mergejoin.  If it is not NIL then it is a PathKeys list describing
401  * the ordering that must be created by an explicit sort step.
402  */
403
404 typedef struct MergePath
405 {
406         JoinPath        jpath;
407         List       *path_mergeclauses;          /* join clauses to be used for
408                                                                                  * merge */
409         List       *outersortkeys;      /* keys for explicit sort, if any */
410         List       *innersortkeys;      /* keys for explicit sort, if any */
411 } MergePath;
412
413 /*
414  * A hashjoin path has these fields.
415  *
416  * The remarks above for mergeclauses apply for hashclauses as well.
417  * (But note that path_hashclauses will always be a one-element list,
418  * since we only hash on one hashable clause.)
419  *
420  * Hashjoin does not care what order its inputs appear in, so we have
421  * no need for sortkeys.
422  */
423
424 typedef struct HashPath
425 {
426         JoinPath        jpath;
427         List       *path_hashclauses;           /* join clauses used for hashing */
428 } HashPath;
429
430 /*
431  * Restriction clause info.
432  *
433  * We create one of these for each AND sub-clause of a restriction condition
434  * (WHERE or JOIN/ON clause).  Since the restriction clauses are logically
435  * ANDed, we can use any one of them or any subset of them to filter out
436  * tuples, without having to evaluate the rest.  The RestrictInfo node itself
437  * stores data used by the optimizer while choosing the best query plan.
438  *
439  * If a restriction clause references a single base relation, it will appear
440  * in the baserestrictinfo list of the RelOptInfo for that base rel.
441  *
442  * If a restriction clause references more than one base rel, it will
443  * appear in the JoinInfo lists of every RelOptInfo that describes a strict
444  * subset of the base rels mentioned in the clause.  The JoinInfo lists are
445  * used to drive join tree building by selecting plausible join candidates.
446  * The clause cannot actually be applied until we have built a join rel
447  * containing all the base rels it references, however.
448  *
449  * When we construct a join rel that includes all the base rels referenced
450  * in a multi-relation restriction clause, we place that clause into the
451  * joinrestrictinfo lists of paths for the join rel, if neither left nor
452  * right sub-path includes all base rels referenced in the clause.      The clause
453  * will be applied at that join level, and will not propagate any further up
454  * the join tree.  (Note: the "predicate migration" code was once intended to
455  * push restriction clauses up and down the plan tree based on evaluation
456  * costs, but it's dead code and is unlikely to be resurrected in the
457  * foreseeable future.)
458  *
459  * Note that in the presence of more than two rels, a multi-rel restriction
460  * might reach different heights in the join tree depending on the join
461  * sequence we use.  So, these clauses cannot be associated directly with
462  * the join RelOptInfo, but must be kept track of on a per-join-path basis.
463  *
464  * When dealing with outer joins we have to be very careful about pushing qual
465  * clauses up and down the tree.  An outer join's own JOIN/ON conditions must
466  * be evaluated exactly at that join node, and any quals appearing in WHERE or
467  * in a JOIN above the outer join cannot be pushed down below the outer join.
468  * Otherwise the outer join will produce wrong results because it will see the
469  * wrong sets of input rows.  All quals are stored as RestrictInfo nodes
470  * during planning, but there's a flag to indicate whether a qual has been
471  * pushed down to a lower level than its original syntactic placement in the
472  * join tree would suggest.  If an outer join prevents us from pushing a qual
473  * down to its "natural" semantic level (the level associated with just the
474  * base rels used in the qual) then the qual will appear in JoinInfo lists
475  * that reference more than just the base rels it actually uses.  By
476  * pretending that the qual references all the rels appearing in the outer
477  * join, we prevent it from being evaluated below the outer join's joinrel.
478  * When we do form the outer join's joinrel, we still need to distinguish
479  * those quals that are actually in that join's JOIN/ON condition from those
480  * that appeared higher in the tree and were pushed down to the join rel
481  * because they used no other rels.  That's what the ispusheddown flag is for;
482  * it tells us that a qual came from a point above the join of the specific
483  * set of base rels that it uses (or that the JoinInfo structures claim it
484  * uses).  A clause that originally came from WHERE will *always* have its
485  * ispusheddown flag set; a clause that came from an INNER JOIN condition,
486  * but doesn't use all the rels being joined, will also have ispusheddown set
487  * because it will get attached to some lower joinrel.
488  *
489  * In general, the referenced clause might be arbitrarily complex.      The
490  * kinds of clauses we can handle as indexscan quals, mergejoin clauses,
491  * or hashjoin clauses are fairly limited --- the code for each kind of
492  * path is responsible for identifying the restrict clauses it can use
493  * and ignoring the rest.  Clauses not implemented by an indexscan,
494  * mergejoin, or hashjoin will be placed in the plan qual or joinqual field
495  * of the finished Plan node, where they will be enforced by general-purpose
496  * qual-expression-evaluation code.  (But we are still entitled to count
497  * their selectivity when estimating the result tuple count, if we
498  * can guess what it is...)
499  */
500
501 typedef struct RestrictInfo
502 {
503         NodeTag         type;
504
505         Expr       *clause;                     /* the represented clause of WHERE or JOIN */
506
507         bool            ispusheddown;   /* TRUE if clause was pushed down in level */
508
509         /* only used if clause is an OR clause: */
510         List       *subclauseindices;           /* indexes matching subclauses */
511         /* subclauseindices is a List of Lists of IndexOptInfos */
512
513         /* cache space for costs (currently only used for join clauses) */
514         Cost            eval_cost;              /* eval cost of clause; -1 if not yet set */
515         Selectivity     this_selec;             /* selectivity; -1 if not yet set */
516
517         /* valid if clause is mergejoinable, else InvalidOid: */
518         Oid                     mergejoinoperator;              /* copy of clause operator */
519         Oid                     left_sortop;    /* leftside sortop needed for mergejoin */
520         Oid                     right_sortop;   /* rightside sortop needed for mergejoin */
521
522         /* cache space for mergeclause processing; NIL if not yet set */
523         List       *left_pathkey;       /* canonical pathkey for left side */
524         List       *right_pathkey;      /* canonical pathkey for right side */
525
526         /* valid if clause is hashjoinable, else InvalidOid: */
527         Oid                     hashjoinoperator;               /* copy of clause operator */
528
529         /* cache space for hashclause processing; -1 if not yet set */
530         Selectivity left_bucketsize;            /* avg bucketsize of left side */
531         Selectivity right_bucketsize;           /* avg bucketsize of right side */
532 } RestrictInfo;
533
534 /*
535  * Join clause info.
536  *
537  * We make a list of these for each RelOptInfo, containing info about
538  * all the join clauses this RelOptInfo participates in.  (For this
539  * purpose, a "join clause" is a WHERE clause that mentions both vars
540  * belonging to this relation and vars belonging to relations not yet
541  * joined to it.)  We group these clauses according to the set of
542  * other base relations (unjoined relations) mentioned in them.
543  * There is one JoinInfo for each distinct set of unjoined_relids,
544  * and its jinfo_restrictinfo lists the clause(s) that use that set
545  * of other relations.
546  */
547
548 typedef struct JoinInfo
549 {
550         NodeTag         type;
551         Relids          unjoined_relids; /* some rels not yet part of my RelOptInfo */
552         List       *jinfo_restrictinfo;         /* relevant RestrictInfos */
553 } JoinInfo;
554
555 /*
556  *      Stream:
557  *      A stream represents a root-to-leaf path in a plan tree (i.e. a tree of
558  *      JoinPaths and Paths).  The stream includes pointers to all Path nodes,
559  *      as well as to any clauses that reside above Path nodes. This structure
560  *      is used to make Path nodes and clauses look similar, so that Predicate
561  *      Migration can run.
562  *
563  *      XXX currently, Predicate Migration is dead code, and so is this node type.
564  *      Probably should remove support for it.
565  *
566  *      pathptr -- pointer to the current path node
567  *      cinfo -- if NULL, this stream node referes to the path node.
568  *                        Otherwise this is a pointer to the current clause.
569  *      clausetype -- whether cinfo is in loc_restrictinfo or pathinfo in the
570  *                        path node (XXX this is now used only by dead code, which is
571  *                        good because the distinction no longer exists...)
572  *      upstream -- linked list pointer upwards
573  *      downstream -- ditto, downwards
574  *      groupup -- whether or not this node is in a group with the node upstream
575  *      groupcost -- total cost of the group that node is in
576  *      groupsel -- total selectivity of the group that node is in
577  */
578 typedef struct Stream *StreamPtr;
579
580 typedef struct Stream
581 {
582         NodeTag         type;
583         Path       *pathptr;
584         RestrictInfo *cinfo;
585         int                *clausetype;
586         StreamPtr       upstream;
587         StreamPtr       downstream;
588         bool            groupup;
589         Cost            groupcost;
590         Selectivity groupsel;
591 } Stream;
592
593 #endif   /* RELATION_H */