]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/util/keys.c
Major optimizer improvement for joining a large number of tables.
[postgresql] / src / backend / optimizer / util / keys.c
1 /*-------------------------------------------------------------------------
2  *
3  * keys.c--
4  *        Key manipulation routines
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/keys.c,v 1.11 1999/02/09 03:51:26 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 #include "nodes/pg_list.h"
16 #include "nodes/nodes.h"
17 #include "nodes/relation.h"
18 #include "utils/elog.h"
19
20 #include "optimizer/internal.h"
21 #include "optimizer/keys.h"
22 #include "optimizer/tlist.h"
23
24
25 static Expr *matching2_tlvar(int var, List *tlist, bool (*test) ());
26 static bool equal_indexkey_var(int index_key, Var *var);
27
28 /*
29  * 1. index key
30  *              one of:
31  *                              attnum
32  *                              (attnum arrayindex)
33  * 2. path key
34  *              (subkey1 ... subkeyN)
35  *              where subkeyI is a var node
36  *              note that the 'Keys field is a list of these
37  * 3. join key
38  *              (outer-subkey inner-subkey)
39  *                              where each subkey is a var node
40  * 4. sort key
41  *              one of:
42  *                              SortKey node
43  *                              number
44  *                              nil
45  *              (may also refer to the 'SortKey field of a SortKey node,
46  *               which looks exactly like an index key)
47  *
48  */
49
50 /*
51  * match-indexkey-operand--
52  *        Returns t iff an index key 'index-key' matches the given clause
53  *        operand.
54  *
55  */
56 bool
57 match_indexkey_operand(int indexkey, Var *operand, RelOptInfo * rel)
58 {
59         if (IsA(operand, Var) &&
60                 (lfirsti(rel->relids) == operand->varno) &&
61                 equal_indexkey_var(indexkey, operand))
62                 return true;
63         else
64                 return false;
65 }
66
67 /*
68  * equal_indexkey_var--
69  *        Returns t iff an index key 'index-key' matches the corresponding
70  *        fields of var node 'var'.
71  *
72  */
73 static bool
74 equal_indexkey_var(int index_key, Var *var)
75 {
76         if (index_key == var->varattno)
77                 return true;
78         else
79                 return false;
80 }
81
82 /*
83  * extract-subkey--
84  *       Returns the subkey in a join key corresponding to the outer or inner
85  *       lelation.
86  *
87  */
88 Var *
89 extract_subkey(JoinKey *jk, int which_subkey)
90 {
91         Var                *retval;
92
93         switch (which_subkey)
94         {
95                 case OUTER:
96                         retval = jk->outer;
97                         break;
98                 case INNER:
99                         retval = jk->inner;
100                         break;
101                 default:                                /* do nothing */
102                         elog(DEBUG, "extract_subkey with neither INNER or OUTER");
103                         retval = NULL;
104         }
105         return retval;
106 }
107
108 /*
109  * samekeys--
110  *        Returns t iff two sets of path keys are equivalent.  They are
111  *        equivalent if the first subkey (var node) within each sublist of
112  *        list 'keys1' is contained within the corresponding sublist of 'keys2'.
113  *
114  *        XXX           It isn't necessary to check that each sublist exactly contain
115  *                              the same elements because if the routine that built these
116  *                              sublists together is correct, having one element in common
117  *                              implies having all elements in common.
118  *
119  */
120 bool
121 samekeys(List *keys1, List *keys2)
122 {
123         List       *key1,
124                            *key2;
125
126         for (key1 = keys1, key2 = keys2; key1 != NIL && key2 != NIL;
127                  key1 = lnext(key1), key2 = lnext(key2))
128                 if (!member(lfirst((List *)lfirst(key1)), lfirst(key2)))
129                         return false;
130
131         /* Now the result should be true if list keys2 has at least as many
132          * entries as keys1, ie, we did not fall off the end of keys2 first.
133          * If key1 is now NIL then we hit the end of keys1 before or at the
134          * same time as the end of keys2.
135          */
136         if (key1 == NIL)
137                 return true;
138         else
139                 return false;
140 }
141
142 /*
143  * collect-index-pathkeys--
144  *        Creates a list of subkeys by retrieving var nodes corresponding to
145  *        each index key in 'index-keys' from the relation's target list
146  *        'tlist'.      If the key is not in the target list, the key is irrelevant
147  *        and is thrown away.  The returned subkey list is of the form:
148  *                              ((var1) (var2) ... (varn))
149  *
150  * 'index-keys' is a list of index keys
151  * 'tlist' is a relation target list
152  *
153  * Returns the list of cons'd subkeys.
154  *
155  */
156 /* This function is identical to matching_tlvar and tlistentry_member.
157  * They should be merged.
158  */
159 static Expr *
160 matching2_tlvar(int var, List *tlist, bool (*test) ())
161 {
162         TargetEntry *tlentry = NULL;
163
164         if (var)
165         {
166                 List       *temp;
167
168                 foreach(temp, tlist)
169                 {
170                         if ((*test) (var, get_expr(lfirst(temp))))
171                         {
172                                 tlentry = lfirst(temp);
173                                 break;
174                         }
175                 }
176         }
177
178         if (tlentry)
179                 return (Expr *) get_expr(tlentry);
180         else
181                 return (Expr *) NULL;
182 }
183
184
185 List *
186 collect_index_pathkeys(int *index_keys, List *tlist)
187 {
188         List       *retval = NIL;
189
190         Assert(index_keys != NULL);
191
192         while (index_keys[0] != 0)
193         {
194                 Expr       *mvar;
195
196                 mvar = matching2_tlvar(index_keys[0],
197                                                            tlist,
198                                                            equal_indexkey_var);
199                 if (mvar)
200                         retval = nconc(retval, lcons(lcons(mvar, NIL),
201                                                                                  NIL));
202                 index_keys++;
203         }
204         return retval;
205 }