Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * sortsupport.c
4 : : * Support routines for accelerated sorting.
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2025, 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 */
31 : : } SortShimExtra;
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
5022 tgl@sss.pgh.pa.us 43 :CBC 71889786 : comparison_shim(Datum x, Datum y, SortSupport ssup)
44 : : {
45 : 71889786 : SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
46 : : Datum result;
47 : :
2415 andres@anarazel.de 48 : 71889786 : extra->fcinfo.args[0].value = x;
49 : 71889786 : extra->fcinfo.args[1].value = y;
50 : :
51 : : /* just for paranoia's sake, we reset isnull each time */
5022 tgl@sss.pgh.pa.us 52 : 71889786 : extra->fcinfo.isnull = false;
53 : :
54 : 71889786 : result = FunctionCallInvoke(&extra->fcinfo);
55 : :
56 : : /* Check for null result, since caller is clearly not expecting one */
57 [ - + ]: 71889783 : if (extra->fcinfo.isnull)
5022 tgl@sss.pgh.pa.us 58 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", extra->flinfo.fn_oid);
59 : :
29 peter@eisentraut.org 60 :GNC 71889783 : return DatumGetInt32(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
5022 tgl@sss.pgh.pa.us 68 :CBC 16361 : PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
69 : : {
70 : : SortShimExtra *extra;
71 : :
72 : 16361 : extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
73 : : SizeForSortShimExtra(2));
74 : :
75 : : /* Lookup the comparison function */
76 : 16361 : fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
77 : :
78 : : /* We can initialize the callinfo just once and re-use it */
79 : 16361 : InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
80 : : ssup->ssup_collation, NULL, NULL);
2415 andres@anarazel.de 81 : 16361 : extra->fcinfo.args[0].isnull = false;
82 : 16361 : extra->fcinfo.args[1].isnull = false;
83 : :
5022 tgl@sss.pgh.pa.us 84 : 16361 : ssup->ssup_extra = extra;
85 : 16361 : ssup->comparator = comparison_shim;
86 : 16361 : }
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
3956 rhaas@postgresql.org 94 : 238915 : FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
95 : : {
96 : : Oid sortSupportFunction;
97 : :
98 : : /* Look for a sort support function */
4049 99 : 238915 : sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
100 : : BTSORTSUPPORT_PROC);
101 [ + + ]: 238915 : 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 : 222816 : OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
108 : : }
109 : :
110 [ + + ]: 238909 : if (ssup->comparator == NULL)
111 : : {
112 : : Oid sortFunction;
113 : :
114 : 16099 : sortFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
115 : : BTORDER_PROC);
116 : :
117 [ - + ]: 16099 : if (!OidIsValid(sortFunction))
4049 rhaas@postgresql.org 118 [ # # ]:UBC 0 : 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 */
5022 tgl@sss.pgh.pa.us 122 :CBC 16099 : PrepareSortSupportComparisonShim(sortFunction, ssup);
123 : : }
124 : 238909 : }
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
3956 rhaas@postgresql.org 134 : 162284 : PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
135 : : {
136 : : Oid opfamily;
137 : : Oid opcintype;
138 : : CompareType cmptype;
139 : :
140 [ - + ]: 162284 : Assert(ssup->comparator == NULL);
141 : :
142 : : /* Find the operator in pg_amop */
143 [ - + ]: 162284 : if (!get_ordering_op_properties(orderingOp, &opfamily, &opcintype,
144 : : &cmptype))
3956 rhaas@postgresql.org 145 [ # # ]:UBC 0 : elog(ERROR, "operator %u is not a valid ordering operator",
146 : : orderingOp);
153 peter@eisentraut.org 147 :CBC 162284 : ssup->ssup_reverse = (cmptype == COMPARE_GT);
148 : :
3956 rhaas@postgresql.org 149 : 162284 : FinishSortSupportFunction(opfamily, opcintype, ssup);
150 : 162278 : }
151 : :
152 : : /*
153 : : * Fill in SortSupport given an index relation and attribute.
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 argument), as well as the
158 : : * comparator function pointer.
159 : : */
160 : : void
176 peter@eisentraut.org 161 : 76631 : PrepareSortSupportFromIndexRel(Relation indexRel, bool reverse,
162 : : SortSupport ssup)
163 : : {
3956 rhaas@postgresql.org 164 : 76631 : Oid opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
165 : 76631 : Oid opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
166 : :
167 [ - + ]: 76631 : Assert(ssup->comparator == NULL);
168 : :
176 peter@eisentraut.org 169 [ - + ]: 76631 : if (!indexRel->rd_indam->amcanorder)
176 peter@eisentraut.org 170 [ # # ]:UBC 0 : elog(ERROR, "unexpected non-amcanorder AM: %u", indexRel->rd_rel->relam);
176 peter@eisentraut.org 171 :CBC 76631 : ssup->ssup_reverse = reverse;
172 : :
3956 rhaas@postgresql.org 173 : 76631 : FinishSortSupportFunction(opfamily, opcintype, ssup);
174 : 76631 : }
175 : :
176 : : /*
177 : : * Fill in SortSupport given a GiST index relation
178 : : *
179 : : * Caller must previously have zeroed the SortSupportData structure and then
180 : : * filled in ssup_cxt, ssup_attno, ssup_collation, and ssup_nulls_first. This
181 : : * will fill in ssup_reverse (always false for GiST index build), as well as
182 : : * the comparator function pointer.
183 : : */
184 : : void
1815 heikki.linnakangas@i 185 : 683 : PrepareSortSupportFromGistIndexRel(Relation indexRel, SortSupport ssup)
186 : : {
187 : 683 : Oid opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
188 : 683 : Oid opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
189 : : Oid sortSupportFunction;
190 : :
191 [ - + ]: 683 : Assert(ssup->comparator == NULL);
192 : :
193 [ - + ]: 683 : if (indexRel->rd_rel->relam != GIST_AM_OID)
1815 heikki.linnakangas@i 194 [ # # ]:UBC 0 : elog(ERROR, "unexpected non-gist AM: %u", indexRel->rd_rel->relam);
1815 heikki.linnakangas@i 195 :CBC 683 : ssup->ssup_reverse = false;
196 : :
197 : : /*
198 : : * Look up the sort support function. This is simpler than for B-tree
199 : : * indexes because we don't support the old-style btree comparators.
200 : : */
201 : 683 : sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
202 : : GIST_SORTSUPPORT_PROC);
203 [ - + ]: 683 : if (!OidIsValid(sortSupportFunction))
1815 heikki.linnakangas@i 204 [ # # ]:UBC 0 : elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
205 : : GIST_SORTSUPPORT_PROC, opcintype, opcintype, opfamily);
1815 heikki.linnakangas@i 206 :CBC 683 : OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
207 : 683 : }
|