1 /*-------------------------------------------------------------------------
4 * Support routines for accelerated sorting.
7 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/sort/sortsupport.c
13 *-------------------------------------------------------------------------
18 #include "access/nbtree.h"
19 #include "catalog/pg_am.h"
21 #include "utils/lsyscache.h"
22 #include "utils/rel.h"
23 #include "utils/sortsupport.h"
26 /* Info needed to use an old-style comparison function as a sort comparator */
29 FunctionCallInfoData fcinfo; /* reusable callinfo structure */
30 FmgrInfo flinfo; /* lookup data for comparison function */
35 * Shim function for calling an old-style comparator
37 * This is essentially an inlined version of FunctionCall2Coll(), except
38 * we assume that the FunctionCallInfoData was already mostly set up by
39 * PrepareSortSupportComparisonShim.
42 comparison_shim(Datum x, Datum y, SortSupport ssup)
44 SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
47 extra->fcinfo.arg[0] = x;
48 extra->fcinfo.arg[1] = y;
50 /* just for paranoia's sake, we reset isnull each time */
51 extra->fcinfo.isnull = false;
53 result = FunctionCallInvoke(&extra->fcinfo);
55 /* Check for null result, since caller is clearly not expecting one */
56 if (extra->fcinfo.isnull)
57 elog(ERROR, "function %u returned NULL", extra->flinfo.fn_oid);
63 * Set up a shim function to allow use of an old-style btree comparison
64 * function as if it were a sort support comparator.
67 PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
71 extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
72 sizeof(SortShimExtra));
74 /* Lookup the comparison function */
75 fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
77 /* We can initialize the callinfo just once and re-use it */
78 InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
79 ssup->ssup_collation, NULL, NULL);
80 extra->fcinfo.argnull[0] = false;
81 extra->fcinfo.argnull[1] = false;
83 ssup->ssup_extra = extra;
84 ssup->comparator = comparison_shim;
88 * Look up and call sortsupport function to setup SortSupport comparator;
89 * or if no such function exists or it declines to set up the appropriate
90 * state, prepare a suitable shim.
93 FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
95 Oid sortSupportFunction;
97 /* Look for a sort support function */
98 sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
100 if (OidIsValid(sortSupportFunction))
103 * The sort support function can provide a comparator, but it can also
104 * choose not to so (e.g. based on the selected collation).
106 OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
109 if (ssup->comparator == NULL)
113 sortFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
116 if (!OidIsValid(sortFunction))
117 elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
118 BTORDER_PROC, opcintype, opcintype, opfamily);
120 /* We'll use a shim to call the old-style btree comparator */
121 PrepareSortSupportComparisonShim(sortFunction, ssup);
126 * Fill in SortSupport given an ordering operator (btree "<" or ">" operator).
128 * Caller must previously have zeroed the SortSupportData structure and then
129 * filled in ssup_cxt, ssup_collation, and ssup_nulls_first. This will fill
130 * in ssup_reverse as well as the comparator function pointer.
133 PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
139 Assert(ssup->comparator == NULL);
141 /* Find the operator in pg_amop */
142 if (!get_ordering_op_properties(orderingOp, &opfamily, &opcintype,
144 elog(ERROR, "operator %u is not a valid ordering operator",
146 ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
148 FinishSortSupportFunction(opfamily, opcintype, ssup);
152 * Fill in SortSupport given an index relation, attribute, and strategy.
154 * Caller must previously have zeroed the SortSupportData structure and then
155 * filled in ssup_cxt, ssup_attno, ssup_collation, and ssup_nulls_first. This
156 * will fill in ssup_reverse (based on the supplied strategy), as well as the
157 * comparator function pointer.
160 PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy,
163 Oid opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
164 Oid opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
166 Assert(ssup->comparator == NULL);
168 if (indexRel->rd_rel->relam != BTREE_AM_OID)
169 elog(ERROR, "unexpected non-btree AM: %u", indexRel->rd_rel->relam);
170 if (strategy != BTGreaterStrategyNumber &&
171 strategy != BTLessStrategyNumber)
172 elog(ERROR, "unexpected sort support strategy: %d", strategy);
173 ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
175 FinishSortSupportFunction(opfamily, opcintype, ssup);