Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * sortsupport.c
4 : * Support routines for accelerated sorting.
5 : *
6 : *
7 : * Portions Copyright (c) 1996-2017, 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/nbtree.h"
19 : #include "catalog/pg_am.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 : FunctionCallInfoData fcinfo; /* reusable callinfo structure */
30 : FmgrInfo flinfo; /* lookup data for comparison function */
31 : } SortShimExtra;
32 :
33 :
34 : /*
35 : * Shim function for calling an old-style comparator
36 : *
37 : * This is essentially an inlined version of FunctionCall2Coll(), except
38 : * we assume that the FunctionCallInfoData was already mostly set up by
39 : * PrepareSortSupportComparisonShim.
40 : */
41 : static int
42 1410086 : comparison_shim(Datum x, Datum y, SortSupport ssup)
43 : {
44 1410086 : SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
45 : Datum result;
46 :
47 1410086 : extra->fcinfo.arg[0] = x;
48 1410086 : extra->fcinfo.arg[1] = y;
49 :
50 : /* just for paranoia's sake, we reset isnull each time */
51 1410086 : extra->fcinfo.isnull = false;
52 :
53 1410086 : result = FunctionCallInvoke(&extra->fcinfo);
54 :
55 : /* Check for null result, since caller is clearly not expecting one */
56 1410086 : if (extra->fcinfo.isnull)
57 0 : elog(ERROR, "function %u returned NULL", extra->flinfo.fn_oid);
58 :
59 1410086 : return result;
60 : }
61 :
62 : /*
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.
65 : */
66 : void
67 543 : PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
68 : {
69 : SortShimExtra *extra;
70 :
71 543 : extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
72 : sizeof(SortShimExtra));
73 :
74 : /* Lookup the comparison function */
75 543 : fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
76 :
77 : /* We can initialize the callinfo just once and re-use it */
78 543 : InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
79 : ssup->ssup_collation, NULL, NULL);
80 543 : extra->fcinfo.argnull[0] = false;
81 543 : extra->fcinfo.argnull[1] = false;
82 :
83 543 : ssup->ssup_extra = extra;
84 543 : ssup->comparator = comparison_shim;
85 543 : }
86 :
87 : /*
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.
91 : */
92 : static void
93 9628 : FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
94 : {
95 : Oid sortSupportFunction;
96 :
97 : /* Look for a sort support function */
98 9628 : sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
99 : BTSORTSUPPORT_PROC);
100 9628 : if (OidIsValid(sortSupportFunction))
101 : {
102 : /*
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).
105 : */
106 9095 : OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
107 : }
108 :
109 9627 : if (ssup->comparator == NULL)
110 : {
111 : Oid sortFunction;
112 :
113 533 : sortFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
114 : BTORDER_PROC);
115 :
116 533 : if (!OidIsValid(sortFunction))
117 0 : elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
118 : BTORDER_PROC, opcintype, opcintype, opfamily);
119 :
120 : /* We'll use a shim to call the old-style btree comparator */
121 533 : PrepareSortSupportComparisonShim(sortFunction, ssup);
122 : }
123 9627 : }
124 :
125 : /*
126 : * Fill in SortSupport given an ordering operator (btree "<" or ">" operator).
127 : *
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.
131 : */
132 : void
133 5210 : PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
134 : {
135 : Oid opfamily;
136 : Oid opcintype;
137 : int16 strategy;
138 :
139 5210 : Assert(ssup->comparator == NULL);
140 :
141 : /* Find the operator in pg_amop */
142 5210 : if (!get_ordering_op_properties(orderingOp, &opfamily, &opcintype,
143 : &strategy))
144 0 : elog(ERROR, "operator %u is not a valid ordering operator",
145 : orderingOp);
146 5210 : ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
147 :
148 5210 : FinishSortSupportFunction(opfamily, opcintype, ssup);
149 5209 : }
150 :
151 : /*
152 : * Fill in SortSupport given an index relation, attribute, and strategy.
153 : *
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.
158 : */
159 : void
160 4418 : PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy,
161 : SortSupport ssup)
162 : {
163 4418 : Oid opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
164 4418 : Oid opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
165 :
166 4418 : Assert(ssup->comparator == NULL);
167 :
168 4418 : if (indexRel->rd_rel->relam != BTREE_AM_OID)
169 0 : elog(ERROR, "unexpected non-btree AM: %u", indexRel->rd_rel->relam);
170 4418 : if (strategy != BTGreaterStrategyNumber &&
171 : strategy != BTLessStrategyNumber)
172 0 : elog(ERROR, "unexpected sort support strategy: %d", strategy);
173 4418 : ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
174 :
175 4418 : FinishSortSupportFunction(opfamily, opcintype, ssup);
176 4418 : }
|