PostgreSQL Source Code  git master
sortsupport.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * sortsupport.c
4  * Support routines for accelerated sorting.
5  *
6  *
7  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/utils/sort/sortsupport.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include "access/gist.h"
19 #include "access/nbtree.h"
20 #include "catalog/pg_am.h"
21 #include "fmgr.h"
22 #include "utils/lsyscache.h"
23 #include "utils/rel.h"
24 #include "utils/sortsupport.h"
25 
26 
27 /* Info needed to use an old-style comparison function as a sort comparator */
28 typedef struct
29 {
30  FmgrInfo flinfo; /* lookup data for comparison function */
31  FunctionCallInfoBaseData fcinfo; /* reusable callinfo structure */
33 
34 #define SizeForSortShimExtra(nargs) (offsetof(SortShimExtra, fcinfo) + SizeForFunctionCallInfo(nargs))
35 
36 /*
37  * Shim function for calling an old-style comparator
38  *
39  * This is essentially an inlined version of FunctionCall2Coll(), except
40  * we assume that the FunctionCallInfoBaseData was already mostly set up by
41  * PrepareSortSupportComparisonShim.
42  */
43 static int
45 {
46  SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
47  Datum result;
48 
49  extra->fcinfo.args[0].value = x;
50  extra->fcinfo.args[1].value = y;
51 
52  /* just for paranoia's sake, we reset isnull each time */
53  extra->fcinfo.isnull = false;
54 
55  result = FunctionCallInvoke(&extra->fcinfo);
56 
57  /* Check for null result, since caller is clearly not expecting one */
58  if (extra->fcinfo.isnull)
59  elog(ERROR, "function %u returned NULL", extra->flinfo.fn_oid);
60 
61  return result;
62 }
63 
64 /*
65  * Set up a shim function to allow use of an old-style btree comparison
66  * function as if it were a sort support comparator.
67  */
68 void
70 {
71  SortShimExtra *extra;
72 
73  extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
75 
76  /* Lookup the comparison function */
77  fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
78 
79  /* We can initialize the callinfo just once and re-use it */
80  InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
81  ssup->ssup_collation, NULL, NULL);
82  extra->fcinfo.args[0].isnull = false;
83  extra->fcinfo.args[1].isnull = false;
84 
85  ssup->ssup_extra = extra;
87 }
88 
89 /*
90  * Look up and call sortsupport function to setup SortSupport comparator;
91  * or if no such function exists or it declines to set up the appropriate
92  * state, prepare a suitable shim.
93  */
94 static void
95 FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
96 {
97  Oid sortSupportFunction;
98 
99  /* Look for a sort support function */
100  sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
102  if (OidIsValid(sortSupportFunction))
103  {
104  /*
105  * The sort support function can provide a comparator, but it can also
106  * choose not to so (e.g. based on the selected collation).
107  */
108  OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
109  }
110 
111  if (ssup->comparator == NULL)
112  {
113  Oid sortFunction;
114 
115  sortFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
116  BTORDER_PROC);
117 
118  if (!OidIsValid(sortFunction))
119  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
120  BTORDER_PROC, opcintype, opcintype, opfamily);
121 
122  /* We'll use a shim to call the old-style btree comparator */
123  PrepareSortSupportComparisonShim(sortFunction, ssup);
124  }
125 }
126 
127 /*
128  * Fill in SortSupport given an ordering operator (btree "<" or ">" operator).
129  *
130  * Caller must previously have zeroed the SortSupportData structure and then
131  * filled in ssup_cxt, ssup_collation, and ssup_nulls_first. This will fill
132  * in ssup_reverse as well as the comparator function pointer.
133  */
134 void
136 {
137  Oid opfamily;
138  Oid opcintype;
139  int16 strategy;
140 
141  Assert(ssup->comparator == NULL);
142 
143  /* Find the operator in pg_amop */
144  if (!get_ordering_op_properties(orderingOp, &opfamily, &opcintype,
145  &strategy))
146  elog(ERROR, "operator %u is not a valid ordering operator",
147  orderingOp);
148  ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
149 
150  FinishSortSupportFunction(opfamily, opcintype, ssup);
151 }
152 
153 /*
154  * Fill in SortSupport given an index relation, attribute, and strategy.
155  *
156  * Caller must previously have zeroed the SortSupportData structure and then
157  * filled in ssup_cxt, ssup_attno, ssup_collation, and ssup_nulls_first. This
158  * will fill in ssup_reverse (based on the supplied strategy), as well as the
159  * comparator function pointer.
160  */
161 void
163  SortSupport ssup)
164 {
165  Oid opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
166  Oid opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
167 
168  Assert(ssup->comparator == NULL);
169 
170  if (indexRel->rd_rel->relam != BTREE_AM_OID)
171  elog(ERROR, "unexpected non-btree AM: %u", indexRel->rd_rel->relam);
172  if (strategy != BTGreaterStrategyNumber &&
173  strategy != BTLessStrategyNumber)
174  elog(ERROR, "unexpected sort support strategy: %d", strategy);
175  ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
176 
177  FinishSortSupportFunction(opfamily, opcintype, ssup);
178 }
179 
180 /*
181  * Fill in SortSupport given a GiST index relation
182  *
183  * Caller must previously have zeroed the SortSupportData structure and then
184  * filled in ssup_cxt, ssup_attno, ssup_collation, and ssup_nulls_first. This
185  * will fill in ssup_reverse (always false for GiST index build), as well as
186  * the comparator function pointer.
187  */
188 void
190 {
191  Oid opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
192  Oid opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
193  Oid sortSupportFunction;
194 
195  Assert(ssup->comparator == NULL);
196 
197  if (indexRel->rd_rel->relam != GIST_AM_OID)
198  elog(ERROR, "unexpected non-gist AM: %u", indexRel->rd_rel->relam);
199  ssup->ssup_reverse = false;
200 
201  /*
202  * Look up the sort support function. This is simpler than for B-tree
203  * indexes because we don't support the old-style btree comparators.
204  */
205  sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
207  if (!OidIsValid(sortSupportFunction))
208  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
209  GIST_SORTSUPPORT_PROC, opcintype, opcintype, opfamily);
210  OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
211 }
signed short int16
Definition: c.h:361
Definition: fmgr.h:56
#define BTORDER_PROC
Definition: nbtree.h:575
FunctionCallInfoBaseData fcinfo
Definition: sortsupport.c:31
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:576
void PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
Definition: sortsupport.c:69
#define PointerGetDatum(X)
Definition: postgres.h:556
#define GIST_SORTSUPPORT_PROC
Definition: gist.h:40
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:135
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
#define SizeForSortShimExtra(nargs)
Definition: sortsupport.c:34
#define ERROR
Definition: elog.h:43
void PrepareSortSupportFromGistIndexRel(Relation indexRel, SortSupport ssup)
Definition: sortsupport.c:189
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
MemoryContext ssup_cxt
Definition: sortsupport.h:66
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:662
int(* comparator)(Datum x, Datum y, SortSupport ssup)
Definition: sortsupport.h:106
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
void * ssup_extra
Definition: sortsupport.h:87
Oid * rd_opfamily
Definition: rel.h:189
void PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy, SortSupport ssup)
Definition: sortsupport.c:162
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:136
static int comparison_shim(Datum x, Datum y, SortSupport ssup)
Definition: sortsupport.c:44
Datum value
Definition: postgres.h:378
static void FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
Definition: sortsupport.c:95
uintptr_t Datum
Definition: postgres.h:367
AttrNumber ssup_attno
Definition: sortsupport.h:81
Oid fn_oid
Definition: fmgr.h:59
#define Assert(condition)
Definition: c.h:745
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:794
bool get_ordering_op_properties(Oid opno, Oid *opfamily, Oid *opcintype, int16 *strategy)
Definition: lsyscache.c:205
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
FmgrInfo flinfo
Definition: sortsupport.c:30
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797
#define elog(elevel,...)
Definition: elog.h:214
Oid * rd_opcintype
Definition: rel.h:190
#define BTLessStrategyNumber
Definition: stratnum.h:29