77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.144 2007/01/20 20:45:40 tgl Exp $
10+ * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.145 2007/01/21 00:57:15 tgl Exp $
1111 *
1212 * NOTES
1313 * Eventually, the index information should go through here, too.
@@ -139,40 +139,41 @@ get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
139139}
140140
141141/*
142- * get_compare_function_for_ordering_op
143- *Get the OID of the datatype-specific btree comparison function
144- *associated with an ordering operator (a "<" or ">" operator).
142+ * get_ordering_op_properties
143+ *Given the OID of an ordering operator (a btree "<" or ">" operator),
144+ *determine its opfamily, its declared input datatype, and its
145+ *strategy number (BTLessStrategyNumber or BTGreaterStrategyNumber).
145146 *
146- * *cmpfunc receives the comparison function OID.
147- * *reverse is set FALSE if the operator is "<", TRUE if it's ">"
148- * (indicating the comparison result must be negated before use).
149- *
150- * Returns TRUE if successful, FALSE if no btree function can be found.
147+ * Returns TRUE if successful, FALSE if no matching pg_amop entry exists.
151148 * (This indicates that the operator is not a valid ordering operator.)
149+ *
150+ * Note: the operator could be registered in multiple families, for example
151+ * if someone were to build a "reverse sort" opfamily. This would result in
152+ * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST
153+ * or NULLS LAST, as well as inefficient planning due to failure to match up
154+ * pathkeys that should be the same. So we want a determinate result here.
155+ * Because of the way the syscache search works, we'll use the interpretation
156+ * associated with the opfamily with smallest OID, which is probably
157+ * determinate enough. Since there is no longer any particularly good reason
158+ * to build reverse-sort opfamilies, it doesn't seem worth expending any
159+ * additional effort on ensuring consistency.
152160 */
153161bool
154- get_compare_function_for_ordering_op (Oid opno ,Oid * cmpfunc ,bool * reverse )
162+ get_ordering_op_properties (Oid opno ,
163+ Oid * opfamily ,Oid * opcintype ,int16 * strategy )
155164{
156165bool result = false;
157166CatCList * catlist ;
158167int i ;
159168
160- /* ensure outputs are set on failure */
161- * cmpfunc = InvalidOid ;
162- * reverse = false;
169+ /* ensure outputs are initialized on failure */
170+ * opfamily = InvalidOid ;
171+ * opcintype = InvalidOid ;
172+ * strategy = 0 ;
163173
164174/*
165175 * Search pg_amop to see if the target operator is registered as the "<"
166- * or ">" operator of any btree opfamily. It's possible that it might be
167- * registered both ways (if someone were to build a "reverse sort"
168- * opfamily); assume we can use either interpretation. (Note: the
169- * existence of a reverse-sort opfamily would result in uncertainty as
170- * to whether "ORDER BY USING op" would default to NULLS FIRST or NULLS
171- * LAST. Since there is no longer any particularly good reason to build
172- * reverse-sort opfamilies, we don't bother expending any extra work to
173- * make this more determinate. In practice, because of the way the
174- * syscache search works, we'll use the interpretation associated with
175- * the opfamily with smallest OID, which is probably determinate enough.)
176+ * or ">" operator of any btree opfamily.
176177 */
177178catlist = SearchSysCacheList (AMOPOPID ,1 ,
178179ObjectIdGetDatum (opno ),
@@ -190,18 +191,16 @@ get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse)
190191if (aform -> amopstrategy == BTLessStrategyNumber ||
191192aform -> amopstrategy == BTGreaterStrategyNumber )
192193{
193- /* Found a suitable opfamily, get matching support function */
194- * reverse = (aform -> amopstrategy == BTGreaterStrategyNumber );
195- * cmpfunc = get_opfamily_proc (aform -> amopfamily ,
196- aform -> amoplefttype ,
197- aform -> amoprighttype ,
198- BTORDER_PROC );
199- if (!OidIsValid (* cmpfunc ))/* should not happen */
200- elog (ERROR ,"missing support function %d(%u,%u) in opfamily %u" ,
201- BTORDER_PROC ,aform -> amoplefttype ,aform -> amoprighttype ,
202- aform -> amopfamily );
203- result = true;
204- break ;
194+ /* Found it ... should have consistent input types */
195+ if (aform -> amoplefttype == aform -> amoprighttype )
196+ {
197+ /* Found a suitable opfamily, return info */
198+ * opfamily = aform -> amopfamily ;
199+ * opcintype = aform -> amoplefttype ;
200+ * strategy = aform -> amopstrategy ;
201+ result = true;
202+ break ;
203+ }
205204}
206205}
207206
@@ -210,6 +209,47 @@ get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse)
210209return result ;
211210}
212211
212+ /*
213+ * get_compare_function_for_ordering_op
214+ *Get the OID of the datatype-specific btree comparison function
215+ *associated with an ordering operator (a "<" or ">" operator).
216+ *
217+ * *cmpfunc receives the comparison function OID.
218+ * *reverse is set FALSE if the operator is "<", TRUE if it's ">"
219+ * (indicating the comparison result must be negated before use).
220+ *
221+ * Returns TRUE if successful, FALSE if no btree function can be found.
222+ * (This indicates that the operator is not a valid ordering operator.)
223+ */
224+ bool
225+ get_compare_function_for_ordering_op (Oid opno ,Oid * cmpfunc ,bool * reverse )
226+ {
227+ Oid opfamily ;
228+ Oid opcintype ;
229+ int16 strategy ;
230+
231+ /* Find the operator in pg_amop */
232+ if (get_ordering_op_properties (opno ,
233+ & opfamily ,& opcintype ,& strategy ))
234+ {
235+ /* Found a suitable opfamily, get matching support function */
236+ * cmpfunc = get_opfamily_proc (opfamily ,
237+ opcintype ,
238+ opcintype ,
239+ BTORDER_PROC );
240+ if (!OidIsValid (* cmpfunc ))/* should not happen */
241+ elog (ERROR ,"missing support function %d(%u,%u) in opfamily %u" ,
242+ BTORDER_PROC ,opcintype ,opcintype ,opfamily );
243+ * reverse = (strategy == BTGreaterStrategyNumber );
244+ return true;
245+ }
246+
247+ /* ensure outputs are set on failure */
248+ * cmpfunc = InvalidOid ;
249+ * reverse = false;
250+ return false;
251+ }
252+
213253/*
214254 * get_equality_op_for_ordering_op
215255 *Get the OID of the datatype-specific btree equality operator
@@ -222,45 +262,21 @@ Oid
222262get_equality_op_for_ordering_op (Oid opno )
223263{
224264Oid result = InvalidOid ;
225- CatCList * catlist ;
226- int i ;
265+ Oid opfamily ;
266+ Oid opcintype ;
267+ int16 strategy ;
227268
228- /*
229- * Search pg_amop to see if the target operator is registered as the "<"
230- * or ">" operator of any btree opfamily. This is exactly like
231- * get_compare_function_for_ordering_op except we don't care whether the
232- * ordering op is "<" or ">" ... the equality operator will be the same
233- * either way.
234- */
235- catlist = SearchSysCacheList (AMOPOPID ,1 ,
236- ObjectIdGetDatum (opno ),
237- 0 ,0 ,0 );
238-
239- for (i = 0 ;i < catlist -> n_members ;i ++ )
269+ /* Find the operator in pg_amop */
270+ if (get_ordering_op_properties (opno ,
271+ & opfamily ,& opcintype ,& strategy ))
240272{
241- HeapTuple tuple = & catlist -> members [i ]-> tuple ;
242- Form_pg_amop aform = (Form_pg_amop )GETSTRUCT (tuple );
243-
244- /* must be btree */
245- if (aform -> amopmethod != BTREE_AM_OID )
246- continue ;
247-
248- if (aform -> amopstrategy == BTLessStrategyNumber ||
249- aform -> amopstrategy == BTGreaterStrategyNumber )
250- {
251- /* Found a suitable opfamily, get matching equality operator */
252- result = get_opfamily_member (aform -> amopfamily ,
253- aform -> amoplefttype ,
254- aform -> amoprighttype ,
255- BTEqualStrategyNumber );
256- if (OidIsValid (result ))
257- break ;
258- /* failure probably shouldn't happen, but keep looking if so */
259- }
273+ /* Found a suitable opfamily, get matching equality operator */
274+ result = get_opfamily_member (opfamily ,
275+ opcintype ,
276+ opcintype ,
277+ BTEqualStrategyNumber );
260278}
261279
262- ReleaseSysCacheList (catlist );
263-
264280return result ;
265281}
266282