]> granicus.if.org Git - postgresql/blob - src/include/nodes/relation.h
Restructure pg_opclass, pg_amop, and pg_amproc per previous discussions in
[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.58 2001/08/21 16:36:06 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_OPCLASS 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  *
195  *              ncolumns and nkeys are the same except for a functional index,
196  *              wherein ncolumns is 1 (the single function output) while nkeys
197  *              is the number of table columns passed to the function. classlist[]
198  *              and ordering[] have ncolumns entries, while indexkeys[] has nkeys
199  *              entries.
200  * 
201  *              Note: for historical reasons, the arrays classlist, indexkeys and
202  *              ordering have an extra entry that is always zero.  Some code scans
203  *              until it sees a zero rather than looking at ncolumns or nkeys.
204  */
205
206 typedef struct IndexOptInfo
207 {
208         NodeTag         type;
209
210         Oid                     indexoid;               /* OID of the index relation */
211
212         /* statistics from pg_class */
213         long            pages;
214         double          tuples;
215
216         /* index descriptor information */
217         int                     ncolumns;               /* number of columns in index */
218         int                     nkeys;                  /* number of keys used by index */
219         Oid                *classlist;          /* AM operator classes for columns */
220         int                *indexkeys;          /* column numbers of index's keys */
221         Oid                *ordering;           /* OIDs of sort operators for each column */
222         Oid                     relam;                  /* OID of the access method (in pg_am) */
223
224         RegProcedure amcostestimate;/* OID of the access method's cost fcn */
225
226         Oid                     indproc;                /* if a functional index */
227         List       *indpred;            /* if a partial index */
228         bool            unique;                 /* if a unique index */
229 } IndexOptInfo;
230
231 /*
232  * PathKeys
233  *
234  *      The sort ordering of a path is represented by a list of sublists of
235  *      PathKeyItem nodes.      An empty list implies no known ordering.  Otherwise
236  *      the first sublist represents the primary sort key, the second the
237  *      first secondary sort key, etc.  Each sublist contains one or more
238  *      PathKeyItem nodes, each of which can be taken as the attribute that
239  *      appears at that sort position.  (See the top of optimizer/path/pathkeys.c
240  *      for more information.)
241  */
242
243 typedef struct PathKeyItem
244 {
245         NodeTag         type;
246
247         Node       *key;                        /* the item that is ordered */
248         Oid                     sortop;                 /* the ordering operator ('<' op) */
249
250         /*
251          * key typically points to a Var node, ie a relation attribute, but it
252          * can also point to a Func clause representing the value indexed by a
253          * functional index.  Someday we might allow arbitrary expressions as
254          * path keys, so don't assume more than you must.
255          */
256 } PathKeyItem;
257
258 /*
259  * Type "Path" is used as-is for sequential-scan paths.  For other
260  * path types it is the first component of a larger struct.
261  */
262
263 typedef struct Path
264 {
265         NodeTag         type;
266
267         RelOptInfo *parent;                     /* the relation this path can build */
268
269         /* estimated execution costs for path (see costsize.c for more info) */
270         Cost            startup_cost;   /* cost expended before fetching any
271                                                                  * tuples */
272         Cost            total_cost;             /* total cost (assuming all tuples
273                                                                  * fetched) */
274
275         NodeTag         pathtype;               /* tag identifying scan/join method */
276         /* XXX why is pathtype separate from the NodeTag? */
277
278         List       *pathkeys;           /* sort ordering of path's output */
279         /* pathkeys is a List of Lists of PathKeyItem nodes; see above */
280 } Path;
281
282 /*----------
283  * IndexPath represents an index scan.  Although an indexscan can only read
284  * a single relation, it can scan it more than once, potentially using a
285  * different index during each scan.  The result is the union (OR) of all the
286  * tuples matched during any scan.      (The executor is smart enough not to return
287  * the same tuple more than once, even if it is matched in multiple scans.)
288  *
289  * 'indexinfo' is a list of IndexOptInfo nodes, one per scan to be performed.
290  *
291  * 'indexqual' is a list of index qualifications, also one per scan.
292  * Each entry in 'indexqual' is a sublist of qualification expressions with
293  * implicit AND semantics across the sublist items.  Only expressions that
294  * are usable as indexquals (as determined by indxpath.c) may appear here.
295  * NOTE that the semantics of the top-level list in 'indexqual' is OR
296  * combination, while the sublists are implicitly AND combinations!
297  * Also note that indexquals lists do not contain RestrictInfo nodes,
298  * just bare clause expressions.
299  *
300  * 'indexscandir' is one of:
301  *              ForwardScanDirection: forward scan of an ordered index
302  *              BackwardScanDirection: backward scan of an ordered index
303  *              NoMovementScanDirection: scan of an unordered index, or don't care
304  * (The executor doesn't care whether it gets ForwardScanDirection or
305  * NoMovementScanDirection for an indexscan, but the planner wants to
306  * distinguish ordered from unordered indexes for building pathkeys.)
307  *
308  * 'joinrelids' is only used in IndexPaths that are constructed for use
309  * as the inner path of a nestloop join.  These paths have indexquals
310  * that refer to values of other rels, so those other rels must be
311  * included in the outer joinrel in order to make a usable join.
312  *
313  * 'alljoinquals' is also used only for inner paths of nestloop joins.
314  * This flag is TRUE iff all the indexquals came from non-pushed-down
315  * JOIN/ON conditions, which means the path is safe to use for an outer join.
316  *
317  * 'rows' is the estimated result tuple count for the indexscan.  This
318  * is the same as path.parent->rows for a simple indexscan, but it is
319  * different for a nestloop inner path, because the additional indexquals
320  * coming from join clauses make the scan more selective than the parent
321  * rel's restrict clauses alone would do.
322  *----------
323  */
324 typedef struct IndexPath
325 {
326         Path            path;
327         List       *indexinfo;
328         List       *indexqual;
329         ScanDirection indexscandir;
330         Relids          joinrelids;             /* other rels mentioned in indexqual */
331         bool            alljoinquals;   /* all indexquals derived from JOIN conds? */
332         double          rows;                   /* estimated number of result tuples */
333 } IndexPath;
334
335 /*
336  * TidPath represents a scan by TID
337  */
338 typedef struct TidPath
339 {
340         Path            path;
341         List       *tideval;
342         Relids          unjoined_relids;/* some rels not yet part of my Path */
343 } TidPath;
344
345 /*
346  * AppendPath represents an Append plan, ie, successive execution of
347  * several member plans.  Currently it is only used to handle expansion
348  * of inheritance trees.
349  */
350 typedef struct AppendPath
351 {
352         Path            path;
353         List       *subpaths;           /* list of component Paths */
354 } AppendPath;
355
356 /*
357  * All join-type paths share these fields.
358  */
359
360 typedef struct JoinPath
361 {
362         Path            path;
363
364         JoinType        jointype;
365
366         Path       *outerjoinpath;      /* path for the outer side of the join */
367         Path       *innerjoinpath;      /* path for the inner side of the join */
368
369         List       *joinrestrictinfo;           /* RestrictInfos to apply to join */
370
371         /*
372          * See the notes for RelOptInfo to understand why joinrestrictinfo is
373          * needed in JoinPath, and can't be merged into the parent RelOptInfo.
374          */
375 } JoinPath;
376
377 /*
378  * A nested-loop path needs no special fields.
379  */
380
381 typedef JoinPath NestPath;
382
383 /*
384  * A mergejoin path has these fields.
385  *
386  * path_mergeclauses lists the clauses (in the form of RestrictInfos)
387  * that will be used in the merge.      (Before 7.0, this was a list of bare
388  * clause expressions, but we can save on list memory and cost_qual_eval
389  * work by leaving it in the form of a RestrictInfo list.)
390  *
391  * Note that the mergeclauses are a subset of the parent relation's
392  * restriction-clause list.  Any join clauses that are not mergejoinable
393  * appear only in the parent's restrict list, and must be checked by a
394  * qpqual at execution time.
395  *
396  * outersortkeys (resp. innersortkeys) is NIL if the outer path
397  * (resp. inner path) is already ordered appropriately for the
398  * mergejoin.  If it is not NIL then it is a PathKeys list describing
399  * the ordering that must be created by an explicit sort step.
400  */
401
402 typedef struct MergePath
403 {
404         JoinPath        jpath;
405         List       *path_mergeclauses;          /* join clauses to be used for
406                                                                                  * merge */
407         List       *outersortkeys;      /* keys for explicit sort, if any */
408         List       *innersortkeys;      /* keys for explicit sort, if any */
409 } MergePath;
410
411 /*
412  * A hashjoin path has these fields.
413  *
414  * The remarks above for mergeclauses apply for hashclauses as well.
415  * (But note that path_hashclauses will always be a one-element list,
416  * since we only hash on one hashable clause.)
417  *
418  * Hashjoin does not care what order its inputs appear in, so we have
419  * no need for sortkeys.
420  */
421
422 typedef struct HashPath
423 {
424         JoinPath        jpath;
425         List       *path_hashclauses;           /* join clauses used for hashing */
426 } HashPath;
427
428 /*
429  * Restriction clause info.
430  *
431  * We create one of these for each AND sub-clause of a restriction condition
432  * (WHERE or JOIN/ON clause).  Since the restriction clauses are logically
433  * ANDed, we can use any one of them or any subset of them to filter out
434  * tuples, without having to evaluate the rest.  The RestrictInfo node itself
435  * stores data used by the optimizer while choosing the best query plan.
436  *
437  * If a restriction clause references a single base relation, it will appear
438  * in the baserestrictinfo list of the RelOptInfo for that base rel.
439  *
440  * If a restriction clause references more than one base rel, it will
441  * appear in the JoinInfo lists of every RelOptInfo that describes a strict
442  * subset of the base rels mentioned in the clause.  The JoinInfo lists are
443  * used to drive join tree building by selecting plausible join candidates.
444  * The clause cannot actually be applied until we have built a join rel
445  * containing all the base rels it references, however.
446  *
447  * When we construct a join rel that includes all the base rels referenced
448  * in a multi-relation restriction clause, we place that clause into the
449  * joinrestrictinfo lists of paths for the join rel, if neither left nor
450  * right sub-path includes all base rels referenced in the clause.      The clause
451  * will be applied at that join level, and will not propagate any further up
452  * the join tree.  (Note: the "predicate migration" code was once intended to
453  * push restriction clauses up and down the plan tree based on evaluation
454  * costs, but it's dead code and is unlikely to be resurrected in the
455  * foreseeable future.)
456  *
457  * Note that in the presence of more than two rels, a multi-rel restriction
458  * might reach different heights in the join tree depending on the join
459  * sequence we use.  So, these clauses cannot be associated directly with
460  * the join RelOptInfo, but must be kept track of on a per-join-path basis.
461  *
462  * When dealing with outer joins we have to be very careful about pushing qual
463  * clauses up and down the tree.  An outer join's own JOIN/ON conditions must
464  * be evaluated exactly at that join node, and any quals appearing in WHERE or
465  * in a JOIN above the outer join cannot be pushed down below the outer join.
466  * Otherwise the outer join will produce wrong results because it will see the
467  * wrong sets of input rows.  All quals are stored as RestrictInfo nodes
468  * during planning, but there's a flag to indicate whether a qual has been
469  * pushed down to a lower level than its original syntactic placement in the
470  * join tree would suggest.  If an outer join prevents us from pushing a qual
471  * down to its "natural" semantic level (the level associated with just the
472  * base rels used in the qual) then the qual will appear in JoinInfo lists
473  * that reference more than just the base rels it actually uses.  By
474  * pretending that the qual references all the rels appearing in the outer
475  * join, we prevent it from being evaluated below the outer join's joinrel.
476  * When we do form the outer join's joinrel, we still need to distinguish
477  * those quals that are actually in that join's JOIN/ON condition from those
478  * that appeared higher in the tree and were pushed down to the join rel
479  * because they used no other rels.  That's what the ispusheddown flag is for;
480  * it tells us that a qual came from a point above the join of the specific
481  * set of base rels that it uses (or that the JoinInfo structures claim it
482  * uses).  A clause that originally came from WHERE will *always* have its
483  * ispusheddown flag set; a clause that came from an INNER JOIN condition,
484  * but doesn't use all the rels being joined, will also have ispusheddown set
485  * because it will get attached to some lower joinrel.
486  *
487  * In general, the referenced clause might be arbitrarily complex.      The
488  * kinds of clauses we can handle as indexscan quals, mergejoin clauses,
489  * or hashjoin clauses are fairly limited --- the code for each kind of
490  * path is responsible for identifying the restrict clauses it can use
491  * and ignoring the rest.  Clauses not implemented by an indexscan,
492  * mergejoin, or hashjoin will be placed in the plan qual or joinqual field
493  * of the finished Plan node, where they will be enforced by general-purpose
494  * qual-expression-evaluation code.  (But we are still entitled to count
495  * their selectivity when estimating the result tuple count, if we
496  * can guess what it is...)
497  */
498
499 typedef struct RestrictInfo
500 {
501         NodeTag         type;
502
503         Expr       *clause;                     /* the represented clause of WHERE or JOIN */
504
505         bool            ispusheddown;   /* TRUE if clause was pushed down in level */
506
507         /* only used if clause is an OR clause: */
508         List       *subclauseindices;           /* indexes matching subclauses */
509         /* subclauseindices is a List of Lists of IndexOptInfos */
510
511         /* cache space for costs (currently only used for join clauses) */
512         Cost            eval_cost;              /* eval cost of clause; -1 if not yet set */
513         Selectivity     this_selec;             /* selectivity; -1 if not yet set */
514
515         /* valid if clause is mergejoinable, else InvalidOid: */
516         Oid                     mergejoinoperator;              /* copy of clause operator */
517         Oid                     left_sortop;    /* leftside sortop needed for mergejoin */
518         Oid                     right_sortop;   /* rightside sortop needed for mergejoin */
519
520         /* cache space for mergeclause processing; NIL if not yet set */
521         List       *left_pathkey;       /* canonical pathkey for left side */
522         List       *right_pathkey;      /* canonical pathkey for right side */
523
524         /* valid if clause is hashjoinable, else InvalidOid: */
525         Oid                     hashjoinoperator;               /* copy of clause operator */
526
527         /* cache space for hashclause processing; -1 if not yet set */
528         Selectivity left_bucketsize;            /* avg bucketsize of left side */
529         Selectivity right_bucketsize;           /* avg bucketsize of right side */
530 } RestrictInfo;
531
532 /*
533  * Join clause info.
534  *
535  * We make a list of these for each RelOptInfo, containing info about
536  * all the join clauses this RelOptInfo participates in.  (For this
537  * purpose, a "join clause" is a WHERE clause that mentions both vars
538  * belonging to this relation and vars belonging to relations not yet
539  * joined to it.)  We group these clauses according to the set of
540  * other base relations (unjoined relations) mentioned in them.
541  * There is one JoinInfo for each distinct set of unjoined_relids,
542  * and its jinfo_restrictinfo lists the clause(s) that use that set
543  * of other relations.
544  */
545
546 typedef struct JoinInfo
547 {
548         NodeTag         type;
549         Relids          unjoined_relids; /* some rels not yet part of my RelOptInfo */
550         List       *jinfo_restrictinfo;         /* relevant RestrictInfos */
551 } JoinInfo;
552
553 /*
554  *      Stream:
555  *      A stream represents a root-to-leaf path in a plan tree (i.e. a tree of
556  *      JoinPaths and Paths).  The stream includes pointers to all Path nodes,
557  *      as well as to any clauses that reside above Path nodes. This structure
558  *      is used to make Path nodes and clauses look similar, so that Predicate
559  *      Migration can run.
560  *
561  *      XXX currently, Predicate Migration is dead code, and so is this node type.
562  *      Probably should remove support for it.
563  *
564  *      pathptr -- pointer to the current path node
565  *      cinfo -- if NULL, this stream node referes to the path node.
566  *                        Otherwise this is a pointer to the current clause.
567  *      clausetype -- whether cinfo is in loc_restrictinfo or pathinfo in the
568  *                        path node (XXX this is now used only by dead code, which is
569  *                        good because the distinction no longer exists...)
570  *      upstream -- linked list pointer upwards
571  *      downstream -- ditto, downwards
572  *      groupup -- whether or not this node is in a group with the node upstream
573  *      groupcost -- total cost of the group that node is in
574  *      groupsel -- total selectivity of the group that node is in
575  */
576 typedef struct Stream *StreamPtr;
577
578 typedef struct Stream
579 {
580         NodeTag         type;
581         Path       *pathptr;
582         RestrictInfo *cinfo;
583         int                *clausetype;
584         StreamPtr       upstream;
585         StreamPtr       downstream;
586         bool            groupup;
587         Cost            groupcost;
588         Selectivity groupsel;
589 } Stream;
590
591 #endif   /* RELATION_H */