1515#include "access/brin_tuple.h"
1616#include "access/skey.h"
1717#include "catalog/pg_type.h"
18+ #include "catalog/pg_amop.h"
1819#include "utils/datum.h"
1920#include "utils/lsyscache.h"
21+ #include "utils/rel.h"
2022#include "utils/syscache.h"
2123
2224
23- /*
24- * Procedure numbers must not collide with BRIN_PROCNUM defines in
25- * brin_internal.h. Note we only need inequality functions.
26- */
27- #define MINMAX_NUM_PROCNUMS 4 /* # support procs we need */
28- #define PROCNUM_LESS 11
29- #define PROCNUM_LESSEQUAL 12
30- #define PROCNUM_GREATEREQUAL 13
31- #define PROCNUM_GREATER 14
32-
33- /*
34- * Subtract this from procnum to obtain index in MinmaxOpaque arrays
35- * (Must be equal to minimum of private procnums)
36- */
37- #define PROCNUM_BASE 11
38-
3925typedef struct MinmaxOpaque
4026{
41- FmgrInfo operators [ MINMAX_NUM_PROCNUMS ] ;
42- bool inited [ MINMAX_NUM_PROCNUMS ];
27+ Oid cached_subtype ;
28+ FmgrInfo strategy_procinfos [ BTMaxStrategyNumber ];
4329} MinmaxOpaque ;
4430
45- static FmgrInfo * minmax_get_procinfo (BrinDesc * bdesc , uint16 attno ,
46- uint16 procnum );
31+ static FmgrInfo * minmax_get_strategy_procinfo (BrinDesc * bdesc , uint16 attno ,
32+ Oid subtype , uint16 strategynum );
4733
4834
4935Datum
@@ -53,17 +39,17 @@ brin_minmax_opcinfo(PG_FUNCTION_ARGS)
5339 BrinOpcInfo * result ;
5440
5541 /*
56- * opaque->operators is initialized lazily, as indicated by 'inited' which
57- * is initialized to all false by palloc0 .
42+ * opaque->strategy_procinfos is initialized lazily; here it is set to
43+ * all-uninitialized by palloc0 which sets fn_oid to InvalidOid .
5844 */
5945
6046 result = palloc0 (MAXALIGN (SizeofBrinOpcInfo (2 )) +
6147 sizeof (MinmaxOpaque ));
6248 result -> oi_nstored = 2 ;
6349 result -> oi_opaque = (MinmaxOpaque * )
6450 MAXALIGN ((char * ) result + SizeofBrinOpcInfo (2 ));
65- result -> oi_typids [0 ] = typoid ;
66- result -> oi_typids [ 1 ] = typoid ;
51+ result -> oi_typcache [0 ] = result -> oi_typcache [ 1 ] =
52+ lookup_type_cache ( typoid , 0 ) ;
6753
6854 PG_RETURN_POINTER (result );
6955}
@@ -122,7 +108,8 @@ brin_minmax_add_value(PG_FUNCTION_ARGS)
122108 * and update them accordingly. First check if it's less than the
123109 * existing minimum.
124110 */
125- cmpFn = minmax_get_procinfo (bdesc , attno , PROCNUM_LESS );
111+ cmpFn = minmax_get_strategy_procinfo (bdesc , attno , attr -> atttypid ,
112+ BTLessStrategyNumber );
126113 compar = FunctionCall2Coll (cmpFn , colloid , newval , column -> bv_values [0 ]);
127114 if (DatumGetBool (compar ))
128115 {
@@ -135,7 +122,8 @@ brin_minmax_add_value(PG_FUNCTION_ARGS)
135122 /*
136123 * And now compare it to the existing maximum.
137124 */
138- cmpFn = minmax_get_procinfo (bdesc , attno , PROCNUM_GREATER );
125+ cmpFn = minmax_get_strategy_procinfo (bdesc , attno , attr -> atttypid ,
126+ BTGreaterStrategyNumber );
139127 compar = FunctionCall2Coll (cmpFn , colloid , newval , column -> bv_values [1 ]);
140128 if (DatumGetBool (compar ))
141129 {
@@ -159,10 +147,12 @@ brin_minmax_consistent(PG_FUNCTION_ARGS)
159147 BrinDesc * bdesc = (BrinDesc * ) PG_GETARG_POINTER (0 );
160148 BrinValues * column = (BrinValues * ) PG_GETARG_POINTER (1 );
161149 ScanKey key = (ScanKey ) PG_GETARG_POINTER (2 );
162- Oid colloid = PG_GET_COLLATION ();
150+ Oid colloid = PG_GET_COLLATION (),
151+ subtype ;
163152 AttrNumber attno ;
164153 Datum value ;
165154 Datum matches ;
155+ FmgrInfo * finfo ;
166156
167157 Assert (key -> sk_attno == column -> bv_attno );
168158
@@ -189,18 +179,16 @@ brin_minmax_consistent(PG_FUNCTION_ARGS)
189179 PG_RETURN_BOOL (false);
190180
191181 attno = key -> sk_attno ;
182+ subtype = key -> sk_subtype ;
192183 value = key -> sk_argument ;
193184 switch (key -> sk_strategy )
194185 {
195186 case BTLessStrategyNumber :
196- matches = FunctionCall2Coll (minmax_get_procinfo (bdesc , attno ,
197- PROCNUM_LESS ),
198- colloid , column -> bv_values [0 ], value );
199- break ;
200187 case BTLessEqualStrategyNumber :
201- matches = FunctionCall2Coll (minmax_get_procinfo (bdesc , attno ,
202- PROCNUM_LESSEQUAL ),
203- colloid , column -> bv_values [0 ], value );
188+ finfo = minmax_get_strategy_procinfo (bdesc , attno , subtype ,
189+ key -> sk_strategy );
190+ matches = FunctionCall2Coll (finfo , colloid , column -> bv_values [0 ],
191+ value );
204192 break ;
205193 case BTEqualStrategyNumber :
206194
@@ -209,25 +197,24 @@ brin_minmax_consistent(PG_FUNCTION_ARGS)
209197 * the current page range if the minimum value in the range <=
210198 * scan key, and the maximum value >= scan key.
211199 */
212- matches = FunctionCall2Coll (minmax_get_procinfo (bdesc , attno ,
213- PROCNUM_LESSEQUAL ),
214- colloid , column -> bv_values [0 ], value );
200+ finfo = minmax_get_strategy_procinfo (bdesc , attno , subtype ,
201+ BTLessEqualStrategyNumber );
202+ matches = FunctionCall2Coll (finfo , colloid , column -> bv_values [0 ],
203+ value );
215204 if (!DatumGetBool (matches ))
216205 break ;
217206 /* max() >= scankey */
218- matches = FunctionCall2Coll (minmax_get_procinfo (bdesc , attno ,
219- PROCNUM_GREATEREQUAL ),
220- colloid , column -> bv_values [1 ], value );
207+ finfo = minmax_get_strategy_procinfo (bdesc , attno , subtype ,
208+ BTGreaterEqualStrategyNumber );
209+ matches = FunctionCall2Coll (finfo , colloid , column -> bv_values [1 ],
210+ value );
221211 break ;
222212 case BTGreaterEqualStrategyNumber :
223- matches = FunctionCall2Coll (minmax_get_procinfo (bdesc , attno ,
224- PROCNUM_GREATEREQUAL ),
225- colloid , column -> bv_values [1 ], value );
226- break ;
227213 case BTGreaterStrategyNumber :
228- matches = FunctionCall2Coll (minmax_get_procinfo (bdesc , attno ,
229- PROCNUM_GREATER ),
230- colloid , column -> bv_values [1 ], value );
214+ finfo = minmax_get_strategy_procinfo (bdesc , attno , subtype ,
215+ key -> sk_strategy );
216+ matches = FunctionCall2Coll (finfo , colloid , column -> bv_values [1 ],
217+ value );
231218 break ;
232219 default :
233220 /* shouldn't happen */
@@ -252,6 +239,7 @@ brin_minmax_union(PG_FUNCTION_ARGS)
252239 Oid colloid = PG_GET_COLLATION ();
253240 AttrNumber attno ;
254241 Form_pg_attribute attr ;
242+ FmgrInfo * finfo ;
255243 bool needsadj ;
256244
257245 Assert (col_a -> bv_attno == col_b -> bv_attno );
@@ -284,9 +272,10 @@ brin_minmax_union(PG_FUNCTION_ARGS)
284272 }
285273
286274 /* Adjust minimum, if B's min is less than A's min */
287- needsadj = FunctionCall2Coll (minmax_get_procinfo (bdesc , attno ,
288- PROCNUM_LESS ),
289- colloid , col_b -> bv_values [0 ], col_a -> bv_values [0 ]);
275+ finfo = minmax_get_strategy_procinfo (bdesc , attno , attr -> atttypid ,
276+ BTLessStrategyNumber );
277+ needsadj = FunctionCall2Coll (finfo , colloid , col_b -> bv_values [0 ],
278+ col_a -> bv_values [0 ]);
290279 if (needsadj )
291280 {
292281 if (!attr -> attbyval )
@@ -296,9 +285,10 @@ brin_minmax_union(PG_FUNCTION_ARGS)
296285 }
297286
298287 /* Adjust maximum, if B's max is greater than A's max */
299- needsadj = FunctionCall2Coll (minmax_get_procinfo (bdesc , attno ,
300- PROCNUM_GREATER ),
301- colloid , col_b -> bv_values [1 ], col_a -> bv_values [1 ]);
288+ finfo = minmax_get_strategy_procinfo (bdesc , attno , attr -> atttypid ,
289+ BTGreaterStrategyNumber );
290+ needsadj = FunctionCall2Coll (finfo , colloid , col_b -> bv_values [1 ],
291+ col_a -> bv_values [1 ]);
302292 if (needsadj )
303293 {
304294 if (!attr -> attbyval )
@@ -311,27 +301,61 @@ brin_minmax_union(PG_FUNCTION_ARGS)
311301}
312302
313303/*
314- * Return the procedure corresponding to the given function support number .
304+ * Cache and return the procedure for the given strategy .
315305 */
316- static FmgrInfo *
317- minmax_get_procinfo (BrinDesc * bdesc , uint16 attno , uint16 procnum )
306+ FmgrInfo *
307+ minmax_get_strategy_procinfo (BrinDesc * bdesc , uint16 attno , Oid subtype ,
308+ uint16 strategynum )
318309{
319310 MinmaxOpaque * opaque ;
320- uint16 basenum = procnum - PROCNUM_BASE ;
311+
312+ Assert (strategynum >= 1 &&
313+ strategynum <= BTMaxStrategyNumber );
321314
322315 opaque = (MinmaxOpaque * ) bdesc -> bd_info [attno - 1 ]-> oi_opaque ;
323316
324317 /*
325- * We cache these in the opaque struct, to avoid repetitive syscache
326- * lookups.
318+ * We cache the procedures for the previous subtype in the opaque struct,
319+ * to avoid repetitive syscache lookups. If the subtype changed,
320+ * invalidate all the cached entries.
327321 */
328- if (!opaque -> inited [basenum ])
322+ if (opaque -> cached_subtype != subtype )
323+ {
324+ uint16 i ;
325+
326+ for (i = 1 ; i <= BTMaxStrategyNumber ; i ++ )
327+ opaque -> strategy_procinfos [i - 1 ].fn_oid = InvalidOid ;
328+ opaque -> cached_subtype = subtype ;
329+ }
330+
331+ if (opaque -> strategy_procinfos [strategynum - 1 ].fn_oid == InvalidOid )
329332 {
330- fmgr_info_copy (& opaque -> operators [basenum ],
331- index_getprocinfo (bdesc -> bd_index , attno , procnum ),
332- bdesc -> bd_context );
333- opaque -> inited [basenum ] = true;
333+ Form_pg_attribute attr ;
334+ HeapTuple tuple ;
335+ Oid opfamily ,
336+ oprid ;
337+ bool isNull ;
338+
339+ opfamily = bdesc -> bd_index -> rd_opfamily [attno - 1 ];
340+ attr = bdesc -> bd_tupdesc -> attrs [attno - 1 ];
341+ tuple = SearchSysCache4 (AMOPSTRATEGY , ObjectIdGetDatum (opfamily ),
342+ ObjectIdGetDatum (attr -> atttypid ),
343+ ObjectIdGetDatum (subtype ),
344+ Int16GetDatum (strategynum ));
345+
346+ if (!HeapTupleIsValid (tuple ))
347+ elog (ERROR , "missing operator %d(%u,%u) in opfamily %u" ,
348+ strategynum , attr -> atttypid , subtype , opfamily );
349+
350+ oprid = DatumGetObjectId (SysCacheGetAttr (AMOPSTRATEGY , tuple ,
351+ Anum_pg_amop_amopopr , & isNull ));
352+ ReleaseSysCache (tuple );
353+ Assert (!isNull && RegProcedureIsValid (oprid ));
354+
355+ fmgr_info_cxt (get_opcode (oprid ),
356+ & opaque -> strategy_procinfos [strategynum - 1 ],
357+ bdesc -> bd_context );
334358 }
335359
336- return & opaque -> operators [ basenum ];
360+ return & opaque -> strategy_procinfos [ strategynum - 1 ];
337361}
0 commit comments