]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/plan/initsplan.c
Revise handling of index-type-specific indexscan cost estimation, per
[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.42 2000/01/22 23:50:16 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 static void set_restrictinfo_joininfo(RestrictInfo *restrictinfo);
34 static void check_mergejoinable(RestrictInfo *restrictinfo);
35 static void check_hashjoinable(RestrictInfo *restrictinfo);
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, false);
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_rels_to_query
82  *
83  *        If we have a range variable in the FROM clause that does not appear
84  *        in the target list nor qualifications, we must add it to the base
85  *        relation list so that it will be joined.  For instance, "select f.x
86  *        from foo f, foo f2" is a join of f and f2.  Note that if we have
87  *        "select foo.x from foo f", it also gets turned into a join (between
88  *        foo as foo and foo as f).
89  *
90  *        To avoid putting useless entries into the per-relation targetlists,
91  *        this should only be called after all the variables in the targetlist
92  *        and quals have been processed by the routines above.
93  */
94 void
95 add_missing_rels_to_query(Query *root)
96 {
97         int                     varno = 1;
98         List       *l;
99
100         foreach(l, root->rtable)
101         {
102                 RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
103
104                 if (rte->inJoinSet)
105                 {
106                         RelOptInfo *rel = get_base_rel(root, varno);
107
108                         /* If the rel isn't otherwise referenced, give it a dummy
109                          * targetlist consisting of its own OID.
110                          */
111                         if (rel->targetlist == NIL)
112                         {
113                                 Var                *var = makeVar(varno, ObjectIdAttributeNumber,
114                                                                                   OIDOID, -1, 0);
115                                 add_var_to_tlist(rel, var);
116                         }
117                 }
118                 varno++;
119         }
120 }
121
122 /*****************************************************************************
123  *
124  *        QUALIFICATIONS
125  *
126  *****************************************************************************/
127
128
129
130 /*
131  * add_restrict_and_join_to_rels
132  *        Fill RestrictInfo and JoinInfo lists of relation entries for all
133  *        relations appearing within clauses.  Creates new relation entries if
134  *        necessary, adding them to *query_relation_list*.
135  *
136  * 'clauses': the list of clauses in the cnfify'd query qualification.
137  */
138 void
139 add_restrict_and_join_to_rels(Query *root, List *clauses)
140 {
141         List       *clause;
142
143         foreach(clause, clauses)
144                 add_restrict_and_join_to_rel(root, (Node*) lfirst(clause));
145 }
146
147 /*
148  * add_restrict_and_join_to_rel
149  *        Add clause information to either the 'RestrictInfo' or 'JoinInfo' field
150  *        (depending on whether the clause is a join) of each base relation
151  *        mentioned in the clause.  A RestrictInfo node is created and added to
152  *        the appropriate list for each rel.
153  */
154 static void
155 add_restrict_and_join_to_rel(Query *root, Node *clause)
156 {
157         RestrictInfo *restrictinfo = makeNode(RestrictInfo);
158         Relids          relids;
159         List       *vars;
160
161         restrictinfo->clause = (Expr *) clause;
162         restrictinfo->subclauseindices = NIL;
163         restrictinfo->mergejoinoperator = InvalidOid;
164         restrictinfo->left_sortop = InvalidOid;
165         restrictinfo->right_sortop = InvalidOid;
166         restrictinfo->hashjoinoperator = InvalidOid;
167
168         /*
169          * Retrieve all relids and vars contained within the clause.
170          */
171         clause_get_relids_vars(clause, &relids, &vars);
172
173         if (length(relids) == 1)
174         {
175                 /*
176                  * There is only one relation participating in 'clause', so
177                  * 'clause' must be a restriction clause for that relation.
178                  */
179                 RelOptInfo *rel = get_base_rel(root, lfirsti(relids));
180
181                 rel->restrictinfo = lcons(restrictinfo, rel->restrictinfo);
182         }
183         else
184         {
185                 /*
186                  * 'clause' is a join clause, since there is more than one atom in
187                  * the relid list.  Set additional RestrictInfo fields for joining.
188                  */
189                 set_restrictinfo_joininfo(restrictinfo);
190                 /*
191                  * Add clause to the join lists of all the relevant
192                  * relations.  (If, perchance, 'clause' contains NO vars, then
193                  * nothing will happen...)
194                  */
195                 add_join_info_to_rels(root, restrictinfo, relids);
196                 /*
197                  * Add vars used in the join clause to targetlists of member relations,
198                  * so that they will be emitted by the plan nodes that scan those
199                  * relations (else they won't be available at the join node!).
200                  */
201                 add_vars_to_targetlist(root, vars);
202         }
203 }
204
205 /*
206  * add_join_info_to_rels
207  *        For every relation participating in a join clause, add 'restrictinfo' to
208  *        the appropriate joininfo list (creating a new list and adding it to the
209  *        appropriate rel node if necessary).
210  *
211  * 'restrictinfo' describes the join clause
212  * 'join_relids' is the list of relations participating in the join clause
213  */
214 static void
215 add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
216                                           Relids join_relids)
217 {
218         List       *join_relid;
219
220         /* For every relid, find the joininfo, and add the proper join entries */
221         foreach(join_relid, join_relids)
222         {
223                 int                     cur_relid = lfirsti(join_relid);
224                 Relids          unjoined_relids = NIL;
225                 JoinInfo   *joininfo;
226                 List       *otherrel;
227
228                 /* Get the relids not equal to the current relid */
229                 foreach(otherrel, join_relids)
230                 {
231                         if (lfirsti(otherrel) != cur_relid)
232                                 unjoined_relids = lappendi(unjoined_relids, lfirsti(otherrel));
233                 }
234
235                 /*
236                  * Find or make the joininfo node for this combination of rels,
237                  * and add the restrictinfo node to it.
238                  */
239                 joininfo = find_joininfo_node(get_base_rel(root, cur_relid),
240                                                                           unjoined_relids);
241                 joininfo->jinfo_restrictinfo = lcons(restrictinfo,
242                                                                                          joininfo->jinfo_restrictinfo);
243         }
244 }
245
246 /*****************************************************************************
247  *
248  *       JOININFO
249  *
250  *****************************************************************************/
251
252 /*
253  * set_restrictinfo_joininfo
254  *        Examine a RestrictInfo that has been determined to be a join clause,
255  *        and set the merge and hash info fields if it can be merge/hash joined.
256  */
257 static void
258 set_restrictinfo_joininfo(RestrictInfo *restrictinfo)
259 {
260         if (enable_mergejoin)
261                 check_mergejoinable(restrictinfo);
262         if (enable_hashjoin)
263                 check_hashjoinable(restrictinfo);
264 }
265
266 /*
267  * check_mergejoinable
268  *        If the restrictinfo's clause is mergejoinable, set the mergejoin
269  *        info fields in the restrictinfo.
270  *
271  *        Currently, we support mergejoin for binary opclauses where
272  *        both operands are simple Vars and the operator is a mergejoinable
273  *        operator.  (Note: since we are only examining clauses that were
274  *        classified as joins, it is certain that the two Vars belong to
275  *        different relations... if we accepted more general clause structures
276  *        we might need to check that the two sides refer to different rels...)
277  */
278 static void
279 check_mergejoinable(RestrictInfo *restrictinfo)
280 {
281         Expr       *clause = restrictinfo->clause;
282         Var                *left,
283                            *right;
284         Oid                     opno,
285                                 leftOp,
286                                 rightOp;
287
288         if (! is_opclause((Node *) clause))
289                 return;
290
291         left = get_leftop(clause);
292         right = get_rightop(clause);
293
294         /* caution: is_opclause accepts more than I do, so check it */
295         if (! right)
296                 return;                                 /* unary opclauses need not apply */
297         if (!IsA(left, Var) || !IsA(right, Var))
298                 return;
299
300         opno = ((Oper *) clause->oper)->opno;
301
302         if (op_mergejoinable(opno,
303                                                  left->vartype,
304                                                  right->vartype,
305                                                  &leftOp,
306                                                  &rightOp))
307         {
308                 restrictinfo->mergejoinoperator = opno;
309                 restrictinfo->left_sortop = leftOp;
310                 restrictinfo->right_sortop = rightOp;
311         }
312 }
313
314 /*
315  * check_hashjoinable
316  *        If the restrictinfo's clause is hashjoinable, set the hashjoin
317  *        info fields in the restrictinfo.
318  *
319  *        Currently, we support hashjoin for binary opclauses where
320  *        both operands are simple Vars and the operator is a hashjoinable
321  *        operator.  (Note: since we are only examining clauses that were
322  *        classified as joins, it is certain that the two Vars belong to
323  *        different relations... if we accepted more general clause structures
324  *        we might need to check that the two sides refer to different rels...)
325  */
326 static void
327 check_hashjoinable(RestrictInfo *restrictinfo)
328 {
329         Expr       *clause = restrictinfo->clause;
330         Var                *left,
331                            *right;
332         Oid                     opno;
333
334         if (! is_opclause((Node *) clause))
335                 return;
336
337         left = get_leftop(clause);
338         right = get_rightop(clause);
339
340         /* caution: is_opclause accepts more than I do, so check it */
341         if (! right)
342                 return;                                 /* unary opclauses need not apply */
343         if (!IsA(left, Var) || !IsA(right, Var))
344                 return;
345
346         opno = ((Oper *) clause->oper)->opno;
347
348         if (op_hashjoinable(opno,
349                                                 left->vartype,
350                                                 right->vartype))
351         {
352                 restrictinfo->hashjoinoperator = opno;
353         }
354 }