]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/plan/initsplan.c
Minor cleanups and code beautification; eliminate some
[postgresql] / src / backend / optimizer / plan / initsplan.c
1 /*-------------------------------------------------------------------------
2  *
3  * initsplan.c
4  *        Target list, qualification, joininfo initialization routines
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.36 1999/08/10 03:00:14 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <sys/types.h>
15
16 #include "postgres.h"
17 #include "catalog/pg_type.h"
18 #include "nodes/makefuncs.h"
19 #include "optimizer/clauses.h"
20 #include "optimizer/cost.h"
21 #include "optimizer/joininfo.h"
22 #include "optimizer/pathnode.h"
23 #include "optimizer/planmain.h"
24 #include "optimizer/tlist.h"
25 #include "optimizer/var.h"
26 #include "utils/lsyscache.h"
27
28
29 static void add_restrict_and_join_to_rel(Query *root, Node *clause);
30 static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
31                                           Relids join_relids);
32 static void add_vars_to_targetlist(Query *root, List *vars);
33
34 static MergeOrder *mergejoinop(Expr *clause);
35 static Oid      hashjoinop(Expr *clause);
36
37
38 /*****************************************************************************
39  *
40  *       TARGET LISTS
41  *
42  *****************************************************************************/
43
44 /*
45  * make_var_only_tlist
46  *        Creates rel nodes for every relation mentioned in the target list
47  *        'tlist' (if a node hasn't already been created) and adds them to
48  *        *query_relation_list*.  Creates targetlist entries for each member of
49  *        'tlist' and adds them to the tlist field of the appropriate rel node.
50  */
51 void
52 make_var_only_tlist(Query *root, List *tlist)
53 {
54         List       *tlist_vars = pull_var_clause((Node *) tlist);
55
56         add_vars_to_targetlist(root, tlist_vars);
57         freeList(tlist_vars);
58 }
59
60 /*
61  * add_vars_to_targetlist
62  *        For each variable appearing in the list, add it to the relation's
63  *        targetlist if not already present.  Rel nodes will also be created
64  *        if not already present.
65  */
66 static void
67 add_vars_to_targetlist(Query *root, List *vars)
68 {
69         List       *temp;
70
71         foreach(temp, vars)
72         {
73                 Var                *var = (Var *) lfirst(temp);
74                 RelOptInfo *rel = get_base_rel(root, var->varno);
75
76                 add_var_to_tlist(rel, var);
77         }
78 }
79
80 /*
81  * add_missing_vars_to_tlist
82  *        If we have range variable(s) in the FROM clause that does not appear
83  *        in the target list nor qualifications, we add it to the base relation
84  *        list. For instance, "select f.x from foo f, foo f2" is a join of f and
85  *        f2. Note that if we have "select foo.x from foo f", it also gets turned
86  *        into a join.
87  */
88 void
89 add_missing_vars_to_tlist(Query *root, List *tlist)
90 {
91         int                     varno = 1;
92         List       *l;
93
94         foreach(l, root->rtable)
95         {
96                 RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
97                 Relids          relids;
98
99                 relids = lconsi(varno, NIL);
100                 if (rte->inFromCl && !rel_member(relids, root->base_rel_list))
101                 {
102                         RelOptInfo *rel;
103                         Var                *var;
104
105                         /* add it to base_rel_list */
106                         rel = get_base_rel(root, varno);
107                         /* give it a dummy tlist entry for its OID */
108                         var = makeVar(varno, ObjectIdAttributeNumber,
109                                                   OIDOID, -1, 0, varno, ObjectIdAttributeNumber);
110                         add_var_to_tlist(rel, var);
111                 }
112                 pfree(relids);
113                 varno++;
114         }
115 }
116
117 /*****************************************************************************
118  *
119  *        QUALIFICATIONS
120  *
121  *****************************************************************************/
122
123
124
125 /*
126  * add_restrict_and_join_to_rels-
127  *        Initializes RestrictInfo and JoinInfo fields of relation entries for all
128  *        relations appearing within clauses.  Creates new relation entries if
129  *        necessary, adding them to *query_relation_list*.
130  *
131  * 'clauses': the list of clauses in the cnfify'd query qualification.
132  */
133 void
134 add_restrict_and_join_to_rels(Query *root, List *clauses)
135 {
136         List       *clause;
137
138         foreach(clause, clauses)
139                 add_restrict_and_join_to_rel(root, (Node*) lfirst(clause));
140 }
141
142 /*
143  * add_restrict_and_join_to_rel-
144  *        Add clause information to either the 'RestrictInfo' or 'JoinInfo' field
145  *        of a relation entry (depending on whether or not the clause is a join)
146  *        by creating a new RestrictInfo node and setting appropriate fields
147  *        within the nodes.
148  */
149 static void
150 add_restrict_and_join_to_rel(Query *root, Node *clause)
151 {
152         RestrictInfo *restrictinfo = makeNode(RestrictInfo);
153         Relids          relids;
154         List       *vars;
155
156         restrictinfo->clause = (Expr *) clause;
157         restrictinfo->indexids = NIL;
158         restrictinfo->mergejoinorder = (MergeOrder *) NULL;
159         restrictinfo->hashjoinoperator = (Oid) 0;
160
161         /*
162          * The selectivity of the clause must be computed regardless of
163          * whether it's a restriction or a join clause
164          */
165         restrictinfo->selectivity = compute_clause_selec(root, clause);
166
167         /*
168          * Retrieve all relids and vars contained within the clause.
169          */
170         clause_get_relids_vars(clause, &relids, &vars);
171
172         if (length(relids) == 1)
173         {
174                 /*
175                  * There is only one relation participating in 'clause', so
176                  * 'clause' must be a restriction clause for that relation.
177                  */
178                 RelOptInfo *rel = get_base_rel(root, lfirsti(relids));
179
180                 rel->restrictinfo = lcons(restrictinfo, rel->restrictinfo);
181         }
182         else
183         {
184                 /*
185                  * 'clause' is a join clause, since there is more than one atom in
186                  * the relid list.  Add it to the join lists of all the relevant
187                  * relations.  (If, perchance, 'clause' contains NO vars, then
188                  * nothing will happen...)
189                  */
190                 add_join_info_to_rels(root, restrictinfo, relids);
191                 /* we are going to be doing a join, so add vars to targetlists */
192                 add_vars_to_targetlist(root, vars);
193         }
194 }
195
196 /*
197  * add_join_info_to_rels
198  *        For every relation participating in a join clause, add 'restrictinfo' to
199  *        the appropriate joininfo node (creating a new one and adding it to the
200  *        appropriate rel node if necessary).
201  *
202  * 'restrictinfo' describes the join clause
203  * 'join_relids' is the list of relations participating in the join clause
204  */
205 static void
206 add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
207                                           Relids join_relids)
208 {
209         List       *join_relid;
210
211         /* For every relid, find the joininfo, and add the proper join entries */
212         foreach(join_relid, join_relids)
213         {
214                 JoinInfo   *joininfo;
215                 Relids          unjoined_relids = NIL;
216                 List       *rel;
217
218                 /* Get the relids not equal to the current relid */
219                 foreach(rel, join_relids)
220                 {
221                         if (lfirsti(rel) != lfirsti(join_relid))
222                                 unjoined_relids = lappendi(unjoined_relids, lfirsti(rel));
223                 }
224
225                 /*
226                  * Find or make the joininfo node for this combination of rels
227                  */
228                 joininfo = find_joininfo_node(get_base_rel(root, lfirsti(join_relid)),
229                                                                           unjoined_relids);
230
231                 /*
232                  * And add the restrictinfo node to it.  NOTE that each joininfo
233                  * gets its own copy of the restrictinfo node!  (Is this really
234                  * necessary?  Possibly ... later parts of the optimizer destructively
235                  * modify restrict/join clauses...)
236                  */
237                 joininfo->jinfo_restrictinfo = lcons(copyObject((void *) restrictinfo),
238                                                                                          joininfo->jinfo_restrictinfo);
239         }
240 }
241
242 /*****************************************************************************
243  *
244  *       JOININFO
245  *
246  *****************************************************************************/
247
248 /*
249  * set_joininfo_mergeable_hashable
250  *        Set the MergeJoinable or HashJoinable field for every joininfo node
251  *        (within a rel node) and the mergejoinorder or hashjoinop field for
252  *        each restrictinfo node (within a joininfo node) for all relations in a
253  *        query.
254  *
255  *        Returns nothing.
256  */
257 void
258 set_joininfo_mergeable_hashable(List *rel_list)
259 {
260         List       *x;
261
262         foreach(x, rel_list)
263         {
264                 RelOptInfo *rel = (RelOptInfo *) lfirst(x);
265                 List       *y;
266
267                 foreach(y, rel->joininfo)
268                 {
269                         JoinInfo   *joininfo = (JoinInfo *) lfirst(y);
270                         List       *z;
271
272                         foreach(z, joininfo->jinfo_restrictinfo)
273                         {
274                                 RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(z);
275                                 Expr       *clause = restrictinfo->clause;
276
277                                 if (is_joinable((Node *) clause))
278                                 {
279                                         if (_enable_mergejoin_)
280                                         {
281                                                 MergeOrder *sortop = mergejoinop(clause);
282                                                 if (sortop)
283                                                 {
284                                                         restrictinfo->mergejoinorder = sortop;
285                                                         joininfo->mergejoinable = true;
286                                                 }
287                                         }
288
289                                         if (_enable_hashjoin_)
290                                         {
291                                                 Oid                     hashop = hashjoinop(clause);
292                                                 if (hashop)
293                                                 {
294                                                         restrictinfo->hashjoinoperator = hashop;
295                                                         joininfo->hashjoinable = true;
296                                                 }
297                                         }
298                                 }
299                         }
300                 }
301         }
302 }
303
304 /*
305  * mergejoinop
306  *        Returns a MergeOrder node for 'clause' iff 'clause' is mergejoinable,
307  *        i.e., both operands are single vars and the operator is
308  *        a mergejoinable operator.
309  */
310 static MergeOrder *
311 mergejoinop(Expr *clause)
312 {
313         Var                *left,
314                            *right;
315         Oid                     opno,
316                                 leftOp,
317                                 rightOp;
318         bool            sortable;
319
320         if (!is_opclause((Node *) clause))
321                 return NULL;
322
323         left = get_leftop(clause);
324         right = get_rightop(clause);
325
326         /* caution: is_opclause accepts more than I do, so check it */
327         if (!right)
328                 return NULL;                    /* unary opclauses need not apply */
329         if (!IsA(left, Var) || !IsA(right, Var))
330                 return NULL;
331
332         opno = ((Oper *) clause->oper)->opno;
333
334         sortable = op_mergejoinable(opno,
335                                                                 left->vartype,
336                                                                 right->vartype,
337                                                                 &leftOp,
338                                                                 &rightOp);
339
340         if (sortable)
341         {
342                 MergeOrder *morder = makeNode(MergeOrder);
343
344                 morder->join_operator = opno;
345                 morder->left_operator = leftOp;
346                 morder->right_operator = rightOp;
347                 morder->left_type = left->vartype;
348                 morder->right_type = right->vartype;
349                 return morder;
350         }
351         else
352                 return NULL;
353 }
354
355 /*
356  * hashjoinop
357  *        Returns the hashjoin operator iff 'clause' is hashjoinable,
358  *        i.e., both operands are single vars and the operator is
359  *        a hashjoinable operator.
360  */
361 static Oid
362 hashjoinop(Expr *clause)
363 {
364         Var                *left,
365                            *right;
366
367         if (!is_opclause((Node *) clause))
368                 return InvalidOid;
369
370         left = get_leftop(clause);
371         right = get_rightop(clause);
372
373         /* caution: is_opclause accepts more than I do, so check it */
374         if (!right)
375                 return InvalidOid;              /* unary opclauses need not apply */
376         if (!IsA(left, Var) || !IsA(right, Var))
377                 return InvalidOid;
378
379         return op_hashjoinable(((Oper *) clause->oper)->opno,
380                                                    left->vartype,
381                                                    right->vartype);
382 }