]> granicus.if.org Git - postgresql/blob - src/backend/utils/sort/sortsupport.c
Update copyright via script for 2017
[postgresql] / src / backend / utils / sort / sortsupport.c
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 comparison_shim(Datum x, Datum y, SortSupport ssup)
43 {
44         SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
45         Datum           result;
46
47         extra->fcinfo.arg[0] = x;
48         extra->fcinfo.arg[1] = y;
49
50         /* just for paranoia's sake, we reset isnull each time */
51         extra->fcinfo.isnull = false;
52
53         result = FunctionCallInvoke(&extra->fcinfo);
54
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);
58
59         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 PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
68 {
69         SortShimExtra *extra;
70
71         extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
72                                                                                                  sizeof(SortShimExtra));
73
74         /* Lookup the comparison function */
75         fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
76
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;
82
83         ssup->ssup_extra = extra;
84         ssup->comparator = comparison_shim;
85 }
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 FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
94 {
95         Oid                     sortSupportFunction;
96
97         /* Look for a sort support function */
98         sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
99                                                                                         BTSORTSUPPORT_PROC);
100         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                 OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
107         }
108
109         if (ssup->comparator == NULL)
110         {
111                 Oid                     sortFunction;
112
113                 sortFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
114                                                                                  BTORDER_PROC);
115
116                 if (!OidIsValid(sortFunction))
117                         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                 PrepareSortSupportComparisonShim(sortFunction, ssup);
122         }
123 }
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 PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
134 {
135         Oid                     opfamily;
136         Oid                     opcintype;
137         int16           strategy;
138
139         Assert(ssup->comparator == NULL);
140
141         /* Find the operator in pg_amop */
142         if (!get_ordering_op_properties(orderingOp, &opfamily, &opcintype,
143                                                                         &strategy))
144                 elog(ERROR, "operator %u is not a valid ordering operator",
145                          orderingOp);
146         ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
147
148         FinishSortSupportFunction(opfamily, opcintype, ssup);
149 }
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 PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy,
161                                                            SortSupport ssup)
162 {
163         Oid                     opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
164         Oid                     opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
165
166         Assert(ssup->comparator == NULL);
167
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);
174
175         FinishSortSupportFunction(opfamily, opcintype, ssup);
176 }