]> granicus.if.org Git - postgresql/blob - src/backend/access/index/amvalidate.c
Extend index AM API for parallel index scans.
[postgresql] / src / backend / access / index / amvalidate.c
1 /*-------------------------------------------------------------------------
2  *
3  * amvalidate.c
4  *        Support routines for index access methods' amvalidate functions.
5  *
6  * Copyright (c) 2016-2017, PostgreSQL Global Development Group
7  *
8  *
9  * IDENTIFICATION
10  *        src/backend/access/index/amvalidate.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
16 #include "access/amvalidate.h"
17 #include "access/htup_details.h"
18 #include "catalog/pg_am.h"
19 #include "catalog/pg_amop.h"
20 #include "catalog/pg_amproc.h"
21 #include "catalog/pg_opclass.h"
22 #include "catalog/pg_operator.h"
23 #include "catalog/pg_proc.h"
24 #include "parser/parse_coerce.h"
25 #include "utils/syscache.h"
26
27
28 /*
29  * identify_opfamily_groups() returns a List of OpFamilyOpFuncGroup structs,
30  * one for each combination of lefttype/righttype present in the family's
31  * operator and support function lists.  If amopstrategy K is present for
32  * this datatype combination, we set bit 1 << K in operatorset, and similarly
33  * for the support functions.  With uint64 fields we can handle operator and
34  * function numbers up to 63, which is plenty for the foreseeable future.
35  *
36  * The given CatCLists are expected to represent a single opfamily fetched
37  * from the AMOPSTRATEGY and AMPROCNUM caches, so that they will be in
38  * order by those caches' second and third cache keys, namely the datatypes.
39  */
40 List *
41 identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
42 {
43         List       *result = NIL;
44         OpFamilyOpFuncGroup *thisgroup;
45         Form_pg_amop oprform;
46         Form_pg_amproc procform;
47         int                     io,
48                                 ip;
49
50         /* We need the lists to be ordered; should be true in normal operation */
51         if (!oprlist->ordered || !proclist->ordered)
52                 elog(ERROR, "cannot validate operator family without ordered data");
53
54         /*
55          * Advance through the lists concurrently.  Thanks to the ordering, we
56          * should see all operators and functions of a given datatype pair
57          * consecutively.
58          */
59         thisgroup = NULL;
60         io = ip = 0;
61         if (io < oprlist->n_members)
62         {
63                 oprform = (Form_pg_amop) GETSTRUCT(&oprlist->members[io]->tuple);
64                 io++;
65         }
66         else
67                 oprform = NULL;
68         if (ip < proclist->n_members)
69         {
70                 procform = (Form_pg_amproc) GETSTRUCT(&proclist->members[ip]->tuple);
71                 ip++;
72         }
73         else
74                 procform = NULL;
75
76         while (oprform || procform)
77         {
78                 if (oprform && thisgroup &&
79                         oprform->amoplefttype == thisgroup->lefttype &&
80                         oprform->amoprighttype == thisgroup->righttype)
81                 {
82                         /* Operator belongs to current group; include it and advance */
83
84                         /* Ignore strategy numbers outside supported range */
85                         if (oprform->amopstrategy > 0 && oprform->amopstrategy < 64)
86                                 thisgroup->operatorset |= ((uint64) 1) << oprform->amopstrategy;
87
88                         if (io < oprlist->n_members)
89                         {
90                                 oprform = (Form_pg_amop) GETSTRUCT(&oprlist->members[io]->tuple);
91                                 io++;
92                         }
93                         else
94                                 oprform = NULL;
95                         continue;
96                 }
97
98                 if (procform && thisgroup &&
99                         procform->amproclefttype == thisgroup->lefttype &&
100                         procform->amprocrighttype == thisgroup->righttype)
101                 {
102                         /* Procedure belongs to current group; include it and advance */
103
104                         /* Ignore function numbers outside supported range */
105                         if (procform->amprocnum > 0 && procform->amprocnum < 64)
106                                 thisgroup->functionset |= ((uint64) 1) << procform->amprocnum;
107
108                         if (ip < proclist->n_members)
109                         {
110                                 procform = (Form_pg_amproc) GETSTRUCT(&proclist->members[ip]->tuple);
111                                 ip++;
112                         }
113                         else
114                                 procform = NULL;
115                         continue;
116                 }
117
118                 /* Time for a new group */
119                 thisgroup = (OpFamilyOpFuncGroup *) palloc(sizeof(OpFamilyOpFuncGroup));
120                 if (oprform &&
121                         (!procform ||
122                          (oprform->amoplefttype < procform->amproclefttype ||
123                           (oprform->amoplefttype == procform->amproclefttype &&
124                            oprform->amoprighttype < procform->amprocrighttype))))
125                 {
126                         thisgroup->lefttype = oprform->amoplefttype;
127                         thisgroup->righttype = oprform->amoprighttype;
128                 }
129                 else
130                 {
131                         thisgroup->lefttype = procform->amproclefttype;
132                         thisgroup->righttype = procform->amprocrighttype;
133                 }
134                 thisgroup->operatorset = thisgroup->functionset = 0;
135                 result = lappend(result, thisgroup);
136         }
137
138         return result;
139 }
140
141 /*
142  * Validate the signature (argument and result types) of an opclass support
143  * function.  Return TRUE if OK, FALSE if not.
144  *
145  * The "..." represents maxargs argument-type OIDs.  If "exact" is TRUE, they
146  * must match the function arg types exactly, else only binary-coercibly.
147  * In any case the function result type must match restype exactly.
148  */
149 bool
150 check_amproc_signature(Oid funcid, Oid restype, bool exact,
151                                            int minargs, int maxargs,...)
152 {
153         bool            result = true;
154         HeapTuple       tp;
155         Form_pg_proc procform;
156         va_list         ap;
157         int                     i;
158
159         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
160         if (!HeapTupleIsValid(tp))
161                 elog(ERROR, "cache lookup failed for function %u", funcid);
162         procform = (Form_pg_proc) GETSTRUCT(tp);
163
164         if (procform->prorettype != restype || procform->proretset ||
165                 procform->pronargs < minargs || procform->pronargs > maxargs)
166                 result = false;
167
168         va_start(ap, maxargs);
169         for (i = 0; i < maxargs; i++)
170         {
171                 Oid                     argtype = va_arg(ap, Oid);
172
173                 if (i >= procform->pronargs)
174                         continue;
175                 if (exact ? (argtype != procform->proargtypes.values[i]) :
176                         !IsBinaryCoercible(argtype, procform->proargtypes.values[i]))
177                         result = false;
178         }
179         va_end(ap);
180
181         ReleaseSysCache(tp);
182         return result;
183 }
184
185 /*
186  * Validate the signature (argument and result types) of an opclass operator.
187  * Return TRUE if OK, FALSE if not.
188  *
189  * Currently, we can hard-wire this as accepting only binary operators.  Also,
190  * we can insist on exact type matches, since the given lefttype/righttype
191  * come from pg_amop and should always match the operator exactly.
192  */
193 bool
194 check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
195 {
196         bool            result = true;
197         HeapTuple       tp;
198         Form_pg_operator opform;
199
200         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
201         if (!HeapTupleIsValid(tp))      /* shouldn't happen */
202                 elog(ERROR, "cache lookup failed for operator %u", opno);
203         opform = (Form_pg_operator) GETSTRUCT(tp);
204
205         if (opform->oprresult != restype || opform->oprkind != 'b' ||
206                 opform->oprleft != lefttype || opform->oprright != righttype)
207                 result = false;
208
209         ReleaseSysCache(tp);
210         return result;
211 }
212
213 /*
214  * Is the datatype a legitimate input type for the btree opfamily?
215  */
216 bool
217 opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
218 {
219         bool            result = false;
220         CatCList   *opclist;
221         int                     i;
222
223         /*
224          * We search through all btree opclasses to see if one matches.  This is a
225          * bit inefficient but there is no better index available.  It also saves
226          * making an explicit check that the opfamily belongs to btree.
227          */
228         opclist = SearchSysCacheList1(CLAAMNAMENSP, ObjectIdGetDatum(BTREE_AM_OID));
229
230         for (i = 0; i < opclist->n_members; i++)
231         {
232                 HeapTuple       classtup = &opclist->members[i]->tuple;
233                 Form_pg_opclass classform = (Form_pg_opclass) GETSTRUCT(classtup);
234
235                 if (classform->opcfamily == opfamilyoid &&
236                         classform->opcintype == datatypeoid)
237                 {
238                         result = true;
239                         break;
240                 }
241         }
242
243         ReleaseCatCacheList(opclist);
244
245         return result;
246 }