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