PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
sortsupport.c
Go to the documentation of this file.
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 */
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
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
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;
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,
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
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
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 }
signed short int16
Definition: c.h:255
int(* comparator)(Datum x, Datum y, SortSupport ssup)
Definition: sortsupport.h:107
Definition: fmgr.h:56
#define BTORDER_PROC
Definition: nbtree.h:229
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:230
void PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
Definition: sortsupport.c:67
#define PointerGetDatum(X)
Definition: postgres.h:562
#define BTREE_AM_OID
Definition: pg_am.h:70
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:133
return result
Definition: formatting.c:1633
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
#define ERROR
Definition: elog.h:43
MemoryContext ssup_cxt
Definition: sortsupport.h:66
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:622
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
void * ssup_extra
Definition: sortsupport.h:87
Oid * rd_opfamily
Definition: rel.h:182
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
void PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy, SortSupport ssup)
Definition: sortsupport.c:160
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
static int comparison_shim(Datum x, Datum y, SortSupport ssup)
Definition: sortsupport.c:42
static void FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
Definition: sortsupport.c:93
uintptr_t Datum
Definition: postgres.h:372
AttrNumber ssup_attno
Definition: sortsupport.h:81
FunctionCallInfoData fcinfo
Definition: sortsupport.c:29
Oid fn_oid
Definition: fmgr.h:59
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:744
bool get_ordering_op_properties(Oid opno, Oid *opfamily, Oid *opcintype, int16 *strategy)
Definition: lsyscache.c:204
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:120
FmgrInfo flinfo
Definition: sortsupport.c:30
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:707
#define elog
Definition: elog.h:219
Oid * rd_opcintype
Definition: rel.h:183
#define BTLessStrategyNumber
Definition: stratnum.h:29