PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
amvalidate.c
Go to the documentation of this file.
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 *
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 
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 
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  */
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 }
#define NIL
Definition: pg_list.h:69
int n_members
Definition: catcache.h:154
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:217
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:59
#define BTREE_AM_OID
Definition: pg_am.h:70
return result
Definition: formatting.c:1633
unsigned int Oid
Definition: postgres_ext.h:31
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1651
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:155
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
Definition: amvalidate.c:150
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:41
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:201
bool IsBinaryCoercible(Oid srctype, Oid targettype)
List * lappend(List *list, void *datum)
Definition: list.c:128
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:194
FormData_pg_operator* Form_pg_operator
Definition: pg_operator.h:57
bool ordered
Definition: catcache.h:150
void * palloc(Size size)
Definition: mcxt.c:849
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:77
int i
HeapTupleData tuple
Definition: catcache.h:116
#define elog
Definition: elog.h:219
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
Definition: pg_list.h:45