Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * sortsupport.c
4 : * Support routines for accelerated sorting.
5 : *
6 : *
7 : * Portions Copyright (c) 1996-2023, 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 */
32 : } SortShimExtra;
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
4141 tgl 44 CBC 218941097 : comparison_shim(Datum x, Datum y, SortSupport ssup)
45 : {
46 218941097 : SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
47 : Datum result;
48 :
1534 andres 49 218941097 : extra->fcinfo.args[0].value = x;
50 218941097 : extra->fcinfo.args[1].value = y;
51 :
52 : /* just for paranoia's sake, we reset isnull each time */
4141 tgl 53 218941097 : extra->fcinfo.isnull = false;
54 :
55 218941097 : result = FunctionCallInvoke(&extra->fcinfo);
56 :
57 : /* Check for null result, since caller is clearly not expecting one */
58 218941097 : if (extra->fcinfo.isnull)
4141 tgl 59 UBC 0 : elog(ERROR, "function %u returned NULL", extra->flinfo.fn_oid);
60 :
4141 tgl 61 CBC 218941097 : 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
69 45317 : PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
70 : {
71 : SortShimExtra *extra;
72 :
73 45317 : extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
74 : SizeForSortShimExtra(2));
75 :
76 : /* Lookup the comparison function */
77 45317 : fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
78 :
79 : /* We can initialize the callinfo just once and re-use it */
80 45317 : InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
81 : ssup->ssup_collation, NULL, NULL);
1534 andres 82 45317 : extra->fcinfo.args[0].isnull = false;
83 45317 : extra->fcinfo.args[1].isnull = false;
84 :
4141 tgl 85 45317 : ssup->ssup_extra = extra;
86 45317 : ssup->comparator = comparison_shim;
87 45317 : }
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
3075 rhaas 95 423529 : FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
96 : {
97 : Oid sortSupportFunction;
98 :
99 : /* Look for a sort support function */
3168 100 423529 : sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
101 : BTSORTSUPPORT_PROC);
102 423529 : 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 378411 : OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
109 : }
110 :
111 423520 : if (ssup->comparator == NULL)
112 : {
113 : Oid sortFunction;
114 :
115 45118 : sortFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
116 : BTORDER_PROC);
117 :
118 45118 : if (!OidIsValid(sortFunction))
3168 rhaas 119 UBC 0 : 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 */
4141 tgl 123 CBC 45118 : PrepareSortSupportComparisonShim(sortFunction, ssup);
124 : }
125 423520 : }
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
3075 rhaas 135 216309 : PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
136 : {
137 : Oid opfamily;
138 : Oid opcintype;
139 : int16 strategy;
140 :
141 216309 : Assert(ssup->comparator == NULL);
142 :
143 : /* Find the operator in pg_amop */
144 216309 : if (!get_ordering_op_properties(orderingOp, &opfamily, &opcintype,
145 : &strategy))
3075 rhaas 146 UBC 0 : elog(ERROR, "operator %u is not a valid ordering operator",
147 : orderingOp);
3075 rhaas 148 CBC 216309 : ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
149 :
150 216309 : FinishSortSupportFunction(opfamily, opcintype, ssup);
151 216300 : }
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
162 207220 : PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy,
163 : SortSupport ssup)
164 : {
165 207220 : Oid opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
166 207220 : Oid opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
167 :
168 207220 : Assert(ssup->comparator == NULL);
169 :
170 207220 : if (indexRel->rd_rel->relam != BTREE_AM_OID)
3075 rhaas 171 UBC 0 : elog(ERROR, "unexpected non-btree AM: %u", indexRel->rd_rel->relam);
3075 rhaas 172 CBC 207220 : if (strategy != BTGreaterStrategyNumber &&
173 : strategy != BTLessStrategyNumber)
3075 rhaas 174 UBC 0 : elog(ERROR, "unexpected sort support strategy: %d", strategy);
3075 rhaas 175 CBC 207220 : ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
176 :
177 207220 : FinishSortSupportFunction(opfamily, opcintype, ssup);
178 207220 : }
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
934 heikki.linnakangas 189 69 : PrepareSortSupportFromGistIndexRel(Relation indexRel, SortSupport ssup)
190 : {
191 69 : Oid opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
192 69 : Oid opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
193 : Oid sortSupportFunction;
194 :
195 69 : Assert(ssup->comparator == NULL);
196 :
197 69 : if (indexRel->rd_rel->relam != GIST_AM_OID)
934 heikki.linnakangas 198 UBC 0 : elog(ERROR, "unexpected non-gist AM: %u", indexRel->rd_rel->relam);
934 heikki.linnakangas 199 CBC 69 : 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 69 : sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
206 : GIST_SORTSUPPORT_PROC);
207 69 : if (!OidIsValid(sortSupportFunction))
934 heikki.linnakangas 208 UBC 0 : elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
209 : GIST_SORTSUPPORT_PROC, opcintype, opcintype, opfamily);
934 heikki.linnakangas 210 CBC 69 : OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
211 69 : }
|