28
28
#include "utils/lsyscache.h"
29
29
30
30
31
- static PathKey * makePathKey (EquivalenceClass * eclass , Oid opfamily ,
32
- int strategy , bool nulls_first );
33
31
static PathKey * make_canonical_pathkey (PlannerInfo * root ,
34
32
EquivalenceClass * eclass , Oid opfamily ,
35
33
int strategy , bool nulls_first );
@@ -41,35 +39,16 @@ static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey);
41
39
* PATHKEY CONSTRUCTION AND REDUNDANCY TESTING
42
40
****************************************************************************/
43
41
44
- /*
45
- * makePathKey
46
- * create a PathKey node
47
- *
48
- * This does not promise to create a canonical PathKey, it's merely a
49
- * convenience routine to build the specified node.
50
- */
51
- static PathKey *
52
- makePathKey (EquivalenceClass * eclass , Oid opfamily ,
53
- int strategy , bool nulls_first )
54
- {
55
- PathKey * pk = makeNode (PathKey );
56
-
57
- pk -> pk_eclass = eclass ;
58
- pk -> pk_opfamily = opfamily ;
59
- pk -> pk_strategy = strategy ;
60
- pk -> pk_nulls_first = nulls_first ;
61
-
62
- return pk ;
63
- }
64
-
65
42
/*
66
43
* make_canonical_pathkey
67
44
* Given the parameters for a PathKey, find any pre-existing matching
68
45
* pathkey in the query's list of "canonical" pathkeys. Make a new
69
46
* entry if there's not one already.
70
47
*
71
48
* Note that this function must not be used until after we have completed
72
- * merging EquivalenceClasses.
49
+ * merging EquivalenceClasses. (We don't try to enforce that here; instead,
50
+ * equivclass.c will complain if a merge occurs after root->canon_pathkeys
51
+ * has become nonempty.)
73
52
*/
74
53
static PathKey *
75
54
make_canonical_pathkey (PlannerInfo * root ,
@@ -100,7 +79,12 @@ make_canonical_pathkey(PlannerInfo *root,
100
79
*/
101
80
oldcontext = MemoryContextSwitchTo (root -> planner_cxt );
102
81
103
- pk = makePathKey (eclass , opfamily , strategy , nulls_first );
82
+ pk = makeNode (PathKey );
83
+ pk -> pk_eclass = eclass ;
84
+ pk -> pk_opfamily = opfamily ;
85
+ pk -> pk_strategy = strategy ;
86
+ pk -> pk_nulls_first = nulls_first ;
87
+
104
88
root -> canon_pathkeys = lappend (root -> canon_pathkeys , pk );
105
89
106
90
MemoryContextSwitchTo (oldcontext );
@@ -112,8 +96,7 @@ make_canonical_pathkey(PlannerInfo *root,
112
96
* pathkey_is_redundant
113
97
* Is a pathkey redundant with one already in the given list?
114
98
*
115
- * Both the given pathkey and the list members must be canonical for this
116
- * to work properly. We detect two cases:
99
+ * We detect two cases:
117
100
*
118
101
* 1. If the new pathkey's equivalence class contains a constant, and isn't
119
102
* below an outer join, then we can disregard it as a sort key. An example:
@@ -135,6 +118,12 @@ make_canonical_pathkey(PlannerInfo *root,
135
118
* Note in particular that we need not compare opfamily (all the opfamilies
136
119
* of the EC have the same notion of equality) nor sort direction.
137
120
*
121
+ * Both the given pathkey and the list members must be canonical for this
122
+ * to work properly, but that's okay since we no longer ever construct any
123
+ * non-canonical pathkeys. (Note: the notion of a pathkey *list* being
124
+ * canonical includes the additional requirement of no redundant entries,
125
+ * which is exactly what we are checking for here.)
126
+ *
138
127
* Because the equivclass.c machinery forms only one copy of any EC per query,
139
128
* pointer comparison is enough to decide whether canonical ECs are the same.
140
129
*/
@@ -144,9 +133,6 @@ pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys)
144
133
EquivalenceClass * new_ec = new_pathkey -> pk_eclass ;
145
134
ListCell * lc ;
146
135
147
- /* Assert we've been given canonical pathkeys */
148
- Assert (!new_ec -> ec_merged );
149
-
150
136
/* Check for EC containing a constant --- unconditionally redundant */
151
137
if (EC_MUST_BE_REDUNDANT (new_ec ))
152
138
return true;
@@ -156,9 +142,6 @@ pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys)
156
142
{
157
143
PathKey * old_pathkey = (PathKey * ) lfirst (lc );
158
144
159
- /* Assert we've been given canonical pathkeys */
160
- Assert (!old_pathkey -> pk_eclass -> ec_merged );
161
-
162
145
if (new_ec == old_pathkey -> pk_eclass )
163
146
return true;
164
147
}
@@ -170,53 +153,22 @@ pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys)
170
153
* canonicalize_pathkeys
171
154
* Convert a not-necessarily-canonical pathkeys list to canonical form.
172
155
*
173
- * Note that this function must not be used until after we have completed
174
- * merging EquivalenceClasses.
156
+ * This is a no-op now that all pathkeys are canonical, but we keep it
157
+ * to avoid possibly breaking plug-ins in the 9.2 release cycle.
158
+ *
159
+ * Since the previous implementation made a fresh List, we use list_copy
160
+ * (NOT list_copy_deep) to preserve that behavior.
175
161
*/
176
162
List *
177
163
canonicalize_pathkeys (PlannerInfo * root , List * pathkeys )
178
164
{
179
- List * new_pathkeys = NIL ;
180
- ListCell * l ;
181
-
182
- foreach (l , pathkeys )
183
- {
184
- PathKey * pathkey = (PathKey * ) lfirst (l );
185
- EquivalenceClass * eclass ;
186
- PathKey * cpathkey ;
187
-
188
- /* Find the canonical (merged) EquivalenceClass */
189
- eclass = pathkey -> pk_eclass ;
190
- while (eclass -> ec_merged )
191
- eclass = eclass -> ec_merged ;
192
-
193
- /*
194
- * If we can tell it's redundant just from the EC, skip.
195
- * pathkey_is_redundant would notice that, but we needn't even bother
196
- * constructing the node...
197
- */
198
- if (EC_MUST_BE_REDUNDANT (eclass ))
199
- continue ;
200
-
201
- /* OK, build a canonicalized PathKey struct */
202
- cpathkey = make_canonical_pathkey (root ,
203
- eclass ,
204
- pathkey -> pk_opfamily ,
205
- pathkey -> pk_strategy ,
206
- pathkey -> pk_nulls_first );
207
-
208
- /* Add to list unless redundant */
209
- if (!pathkey_is_redundant (cpathkey , new_pathkeys ))
210
- new_pathkeys = lappend (new_pathkeys , cpathkey );
211
- }
212
- return new_pathkeys ;
165
+ return list_copy (pathkeys );
213
166
}
214
167
215
168
/*
216
169
* make_pathkey_from_sortinfo
217
170
* Given an expression and sort-order information, create a PathKey.
218
- * If canonicalize = true, the result is a "canonical" PathKey,
219
- * otherwise not. (But note it might be redundant anyway.)
171
+ * The result is always a "canonical" PathKey, but it might be redundant.
220
172
*
221
173
* If the PathKey is being generated from a SortGroupClause, sortref should be
222
174
* the SortGroupClause's SortGroupRef; otherwise zero.
@@ -229,9 +181,6 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys)
229
181
* create_it is TRUE if we should create any missing EquivalenceClass
230
182
* needed to represent the sort key. If it's FALSE, we return NULL if the
231
183
* sort key isn't already present in any EquivalenceClass.
232
- *
233
- * canonicalize should always be TRUE after EquivalenceClass merging has
234
- * been performed, but FALSE if we haven't done EquivalenceClass merging yet.
235
184
*/
236
185
static PathKey *
237
186
make_pathkey_from_sortinfo (PlannerInfo * root ,
@@ -251,6 +200,8 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
251
200
List * opfamilies ;
252
201
EquivalenceClass * eclass ;
253
202
203
+ Assert (canonicalize );
204
+
254
205
strategy = reverse_sort ? BTGreaterStrategyNumber : BTLessStrategyNumber ;
255
206
256
207
/*
@@ -281,11 +232,8 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
281
232
return NULL ;
282
233
283
234
/* And finally we can find or create a PathKey node */
284
- if (canonicalize )
285
- return make_canonical_pathkey (root , eclass , opfamily ,
286
- strategy , nulls_first );
287
- else
288
- return makePathKey (eclass , opfamily , strategy , nulls_first );
235
+ return make_canonical_pathkey (root , eclass , opfamily ,
236
+ strategy , nulls_first );
289
237
}
290
238
291
239
/*
@@ -341,9 +289,8 @@ make_pathkey_from_sortop(PlannerInfo *root,
341
289
* Compare two pathkeys to see if they are equivalent, and if not whether
342
290
* one is "better" than the other.
343
291
*
344
- * This function may only be applied to canonicalized pathkey lists.
345
- * In the canonical representation, pathkeys can be checked for equality
346
- * by simple pointer comparison.
292
+ * We assume the pathkeys are canonical, and so they can be checked for
293
+ * equality by simple pointer comparison.
347
294
*/
348
295
PathKeysComparison
349
296
compare_pathkeys (List * keys1 , List * keys2 )
@@ -364,15 +311,6 @@ compare_pathkeys(List *keys1, List *keys2)
364
311
PathKey * pathkey1 = (PathKey * ) lfirst (key1 );
365
312
PathKey * pathkey2 = (PathKey * ) lfirst (key2 );
366
313
367
- /*
368
- * XXX would like to check that we've been given canonicalized input,
369
- * but PlannerInfo not accessible here...
370
- */
371
- #ifdef NOT_USED
372
- Assert (list_member_ptr (root -> canon_pathkeys , pathkey1 ));
373
- Assert (list_member_ptr (root -> canon_pathkeys , pathkey2 ));
374
- #endif
375
-
376
314
if (pathkey1 != pathkey2 )
377
315
return PATHKEYS_DIFFERENT ; /* no need to keep looking */
378
316
}
@@ -414,7 +352,7 @@ pathkeys_contained_in(List *keys1, List *keys2)
414
352
* Return NULL if no such path.
415
353
*
416
354
* 'paths' is a list of possible paths that all generate the same relation
417
- * 'pathkeys' represents a required ordering (already canonicalized !)
355
+ * 'pathkeys' represents a required ordering (in canonical form !)
418
356
* 'required_outer' denotes allowable outer relations for parameterized paths
419
357
* 'cost_criterion' is STARTUP_COST or TOTAL_COST
420
358
*/
@@ -455,7 +393,7 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
455
393
* parameter.
456
394
*
457
395
* 'paths' is a list of possible paths that all generate the same relation
458
- * 'pathkeys' represents a required ordering (already canonicalized !)
396
+ * 'pathkeys' represents a required ordering (in canonical form !)
459
397
* 'required_outer' denotes allowable outer relations for parameterized paths
460
398
* 'fraction' is the fraction of the total tuples expected to be retrieved
461
399
*/
@@ -829,12 +767,8 @@ build_join_pathkeys(PlannerInfo *root,
829
767
* Generate a pathkeys list that represents the sort order specified
830
768
* by a list of SortGroupClauses
831
769
*
832
- * If canonicalize is TRUE, the resulting PathKeys are all in canonical form;
833
- * otherwise not. canonicalize should always be TRUE after EquivalenceClass
834
- * merging has been performed, but FALSE if we haven't done EquivalenceClass
835
- * merging yet. (We provide this option because grouping_planner() needs to
836
- * be able to represent requested pathkeys before the equivalence classes have
837
- * been created for the query.)
770
+ * The resulting PathKeys are always in canonical form. (Actually, there
771
+ * is no longer any code anywhere that creates non-canonical PathKeys.)
838
772
*
839
773
* 'sortclauses' is a list of SortGroupClause nodes
840
774
* 'tlist' is the targetlist to find the referenced tlist entries in
@@ -848,6 +782,8 @@ make_pathkeys_for_sortclauses(PlannerInfo *root,
848
782
List * pathkeys = NIL ;
849
783
ListCell * l ;
850
784
785
+ Assert (canonicalize );
786
+
851
787
foreach (l , sortclauses )
852
788
{
853
789
SortGroupClause * sortcl = (SortGroupClause * ) lfirst (l );
@@ -862,15 +798,10 @@ make_pathkeys_for_sortclauses(PlannerInfo *root,
862
798
sortcl -> nulls_first ,
863
799
sortcl -> tleSortGroupRef ,
864
800
true,
865
- canonicalize );
801
+ true );
866
802
867
803
/* Canonical form eliminates redundant ordering keys */
868
- if (canonicalize )
869
- {
870
- if (!pathkey_is_redundant (pathkey , pathkeys ))
871
- pathkeys = lappend (pathkeys , pathkey );
872
- }
873
- else
804
+ if (!pathkey_is_redundant (pathkey , pathkeys ))
874
805
pathkeys = lappend (pathkeys , pathkey );
875
806
}
876
807
return pathkeys ;
0 commit comments