]> granicus.if.org Git - postgresql/blob - src/backend/utils/sort/sortsupport.c
Update copyright notices for year 2012.
[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-2012, 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 "fmgr.h"
19 #include "utils/lsyscache.h"
20 #include "utils/sortsupport.h"
21
22
23 /* Info needed to use an old-style comparison function as a sort comparator */
24 typedef struct
25 {
26         FunctionCallInfoData fcinfo;    /* reusable callinfo structure */
27         FmgrInfo        flinfo;                         /* lookup data for comparison function */
28 } SortShimExtra;
29
30
31 /*
32  * sortsupport.h defines inline versions of these functions if allowed by the
33  * compiler; in which case the definitions below are skipped.
34  */
35 #ifndef USE_INLINE
36
37 /*
38  * Apply a sort comparator function and return a 3-way comparison result.
39  * This takes care of handling reverse-sort and NULLs-ordering properly.
40  */
41 int
42 ApplySortComparator(Datum datum1, bool isNull1,
43                                         Datum datum2, bool isNull2,
44                                         SortSupport ssup)
45 {
46         int                     compare;
47
48         if (isNull1)
49         {
50                 if (isNull2)
51                         compare = 0;            /* NULL "=" NULL */
52                 else if (ssup->ssup_nulls_first)
53                         compare = -1;           /* NULL "<" NOT_NULL */
54                 else
55                         compare = 1;            /* NULL ">" NOT_NULL */
56         }
57         else if (isNull2)
58         {
59                 if (ssup->ssup_nulls_first)
60                         compare = 1;            /* NOT_NULL ">" NULL */
61                 else
62                         compare = -1;           /* NOT_NULL "<" NULL */
63         }
64         else
65         {
66                 compare = (*ssup->comparator) (datum1, datum2, ssup);
67                 if (ssup->ssup_reverse)
68                         compare = -compare;
69         }
70
71         return compare;
72 }
73
74 #endif   /* ! USE_INLINE */
75
76 /*
77  * Shim function for calling an old-style comparator
78  *
79  * This is essentially an inlined version of FunctionCall2Coll(), except
80  * we assume that the FunctionCallInfoData was already mostly set up by
81  * PrepareSortSupportComparisonShim.
82  */
83 static int
84 comparison_shim(Datum x, Datum y, SortSupport ssup)
85 {
86         SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
87         Datum           result;
88
89         extra->fcinfo.arg[0] = x;
90         extra->fcinfo.arg[1] = y;
91
92         /* just for paranoia's sake, we reset isnull each time */
93         extra->fcinfo.isnull = false;
94
95         result = FunctionCallInvoke(&extra->fcinfo);
96
97         /* Check for null result, since caller is clearly not expecting one */
98         if (extra->fcinfo.isnull)
99                 elog(ERROR, "function %u returned NULL", extra->flinfo.fn_oid);
100
101         return result;
102 }
103
104 /*
105  * Set up a shim function to allow use of an old-style btree comparison
106  * function as if it were a sort support comparator.
107  */
108 void
109 PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
110 {
111         SortShimExtra   *extra;
112
113         extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
114                                                                                                  sizeof(SortShimExtra));
115
116         /* Lookup the comparison function */
117         fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
118
119         /* We can initialize the callinfo just once and re-use it */
120         InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
121                                                          ssup->ssup_collation, NULL, NULL);
122         extra->fcinfo.argnull[0] = false;
123         extra->fcinfo.argnull[1] = false;
124
125         ssup->ssup_extra = extra;
126         ssup->comparator = comparison_shim;
127 }
128
129 /*
130  * Fill in SortSupport given an ordering operator (btree "<" or ">" operator).
131  *
132  * Caller must previously have zeroed the SortSupportData structure and then
133  * filled in ssup_cxt, ssup_collation, and ssup_nulls_first.  This will fill
134  * in ssup_reverse as well as the comparator function pointer.
135  */
136 void
137 PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
138 {
139         Oid                     sortFunction;
140         bool            issupport;
141
142         if (!get_sort_function_for_ordering_op(orderingOp,
143                                                                                    &sortFunction,
144                                                                                    &issupport,
145                                                                                    &ssup->ssup_reverse))
146                 elog(ERROR, "operator %u is not a valid ordering operator",
147                          orderingOp);
148
149         if (issupport)
150         {
151                 /* The sort support function should provide a comparator */
152                 OidFunctionCall1(sortFunction, PointerGetDatum(ssup));
153                 Assert(ssup->comparator != NULL);
154         }
155         else
156         {
157                 /* We'll use a shim to call the old-style btree comparator */
158                 PrepareSortSupportComparisonShim(sortFunction, ssup);
159         }
160 }