PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
spgvalidate.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * spgvalidate.c
4  * Opclass validator for SP-GiST.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/access/spgist/spgvalidate.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "access/amvalidate.h"
17 #include "access/htup_details.h"
18 #include "access/spgist_private.h"
19 #include "catalog/pg_amop.h"
20 #include "catalog/pg_amproc.h"
21 #include "catalog/pg_opclass.h"
22 #include "catalog/pg_opfamily.h"
23 #include "catalog/pg_type.h"
24 #include "utils/builtins.h"
25 #include "utils/regproc.h"
26 #include "utils/syscache.h"
27 
28 
29 /*
30  * Validator for an SP-GiST opclass.
31  *
32  * Some of the checks done here cover the whole opfamily, and therefore are
33  * redundant when checking each opclass in a family. But they don't run long
34  * enough to be much of a problem, so we accept the duplication rather than
35  * complicate the amvalidate API.
36  */
37 bool
38 spgvalidate(Oid opclassoid)
39 {
40  bool result = true;
41  HeapTuple classtup;
42  Form_pg_opclass classform;
43  Oid opfamilyoid;
44  Oid opcintype;
45  char *opclassname;
46  HeapTuple familytup;
47  Form_pg_opfamily familyform;
48  char *opfamilyname;
49  CatCList *proclist,
50  *oprlist;
51  List *grouplist;
52  OpFamilyOpFuncGroup *opclassgroup;
53  int i;
54  ListCell *lc;
55 
56  /* Fetch opclass information */
57  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
58  if (!HeapTupleIsValid(classtup))
59  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
60  classform = (Form_pg_opclass) GETSTRUCT(classtup);
61 
62  opfamilyoid = classform->opcfamily;
63  opcintype = classform->opcintype;
64  opclassname = NameStr(classform->opcname);
65 
66  /* Fetch opfamily information */
67  familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
68  if (!HeapTupleIsValid(familytup))
69  elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
70  familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
71 
72  opfamilyname = NameStr(familyform->opfname);
73 
74  /* Fetch all operators and support functions of the opfamily */
75  oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
76  proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
77 
78  /* Check individual support functions */
79  for (i = 0; i < proclist->n_members; i++)
80  {
81  HeapTuple proctup = &proclist->members[i]->tuple;
82  Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
83  bool ok;
84 
85  /*
86  * All SP-GiST support functions should be registered with matching
87  * left/right types
88  */
89  if (procform->amproclefttype != procform->amprocrighttype)
90  {
91  ereport(INFO,
92  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
93  errmsg("operator family \"%s\" of access method %s contains support procedure %s with different left and right input types",
94  opfamilyname, "spgist",
95  format_procedure(procform->amproc))));
96  result = false;
97  }
98 
99  /* Check procedure numbers and function signatures */
100  switch (procform->amprocnum)
101  {
102  case SPGIST_CONFIG_PROC:
103  case SPGIST_CHOOSE_PROC:
106  ok = check_amproc_signature(procform->amproc, VOIDOID, true,
107  2, 2, INTERNALOID, INTERNALOID);
108  break;
110  ok = check_amproc_signature(procform->amproc, BOOLOID, true,
111  2, 2, INTERNALOID, INTERNALOID);
112  break;
113  default:
114  ereport(INFO,
115  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
116  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
117  opfamilyname, "spgist",
118  format_procedure(procform->amproc),
119  procform->amprocnum)));
120  result = false;
121  continue; /* don't want additional message */
122  }
123 
124  if (!ok)
125  {
126  ereport(INFO,
127  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
128  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
129  opfamilyname, "spgist",
130  format_procedure(procform->amproc),
131  procform->amprocnum)));
132  result = false;
133  }
134  }
135 
136  /* Check individual operators */
137  for (i = 0; i < oprlist->n_members; i++)
138  {
139  HeapTuple oprtup = &oprlist->members[i]->tuple;
140  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
141 
142  /* TODO: Check that only allowed strategy numbers exist */
143  if (oprform->amopstrategy < 1 || oprform->amopstrategy > 63)
144  {
145  ereport(INFO,
146  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
147  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
148  opfamilyname, "spgist",
149  format_operator(oprform->amopopr),
150  oprform->amopstrategy)));
151  result = false;
152  }
153 
154  /* spgist doesn't support ORDER BY operators */
155  if (oprform->amoppurpose != AMOP_SEARCH ||
156  OidIsValid(oprform->amopsortfamily))
157  {
158  ereport(INFO,
159  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
160  errmsg("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
161  opfamilyname, "spgist",
162  format_operator(oprform->amopopr))));
163  result = false;
164  }
165 
166  /* Check operator signature --- same for all spgist strategies */
167  if (!check_amop_signature(oprform->amopopr, BOOLOID,
168  oprform->amoplefttype,
169  oprform->amoprighttype))
170  {
171  ereport(INFO,
172  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
173  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
174  opfamilyname, "spgist",
175  format_operator(oprform->amopopr))));
176  result = false;
177  }
178  }
179 
180  /* Now check for inconsistent groups of operators/functions */
181  grouplist = identify_opfamily_groups(oprlist, proclist);
182  opclassgroup = NULL;
183  foreach(lc, grouplist)
184  {
185  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
186 
187  /* Remember the group exactly matching the test opclass */
188  if (thisgroup->lefttype == opcintype &&
189  thisgroup->righttype == opcintype)
190  opclassgroup = thisgroup;
191 
192  /*
193  * Complain if there are any datatype pairs with functions but no
194  * operators. This is about the best we can do for now to detect
195  * missing operators.
196  */
197  if (thisgroup->operatorset == 0)
198  {
199  ereport(INFO,
200  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
201  errmsg("operator family \"%s\" of access method %s is missing operator(s) for types %s and %s",
202  opfamilyname, "spgist",
203  format_type_be(thisgroup->lefttype),
204  format_type_be(thisgroup->righttype))));
205  result = false;
206  }
207 
208  /*
209  * Complain if we're missing functions for any datatype, remembering
210  * that SP-GiST doesn't use cross-type support functions.
211  */
212  if (thisgroup->lefttype != thisgroup->righttype)
213  continue;
214 
215  for (i = 1; i <= SPGISTNProc; i++)
216  {
217  if ((thisgroup->functionset & (((uint64) 1) << i)) != 0)
218  continue; /* got it */
219  ereport(INFO,
220  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
221  errmsg("operator family \"%s\" of access method %s is missing support function %d for type %s",
222  opfamilyname, "spgist", i,
223  format_type_be(thisgroup->lefttype))));
224  result = false;
225  }
226  }
227 
228  /* Check that the originally-named opclass is supported */
229  /* (if group is there, we already checked it adequately above) */
230  if (!opclassgroup)
231  {
232  ereport(INFO,
233  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
234  errmsg("operator class \"%s\" of access method %s is missing operator(s)",
235  opclassname, "spgist")));
236  result = false;
237  }
238 
239  ReleaseCatCacheList(proclist);
240  ReleaseCatCacheList(oprlist);
241  ReleaseSysCache(familytup);
242  ReleaseSysCache(classtup);
243 
244  return result;
245 }
int n_members
Definition: catcache.h:154
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:32
#define AMOP_SEARCH
Definition: pg_amop.h:69
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:59
int errcode(int sqlerrcode)
Definition: elog.c:575
#define INFO
Definition: elog.h:33
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
return result
Definition: formatting.c:1633
char * format_operator(Oid operator_oid)
Definition: regproc.c:820
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1601
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 VOIDOID
Definition: pg_type.h:690
#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
#define ereport(elevel, rest)
Definition: elog.h:122
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:44
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
#define INTERNALOID
Definition: pg_type.h:698
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:323
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
#define SPGIST_CONFIG_PROC
Definition: spgist.h:28
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:194
#define BOOLOID
Definition: pg_type.h:288
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define SPGISTNProc
Definition: spgist.h:33
bool spgvalidate(Oid opclassoid)
Definition: spgvalidate.c:38
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:77
int i
#define NameStr(name)
Definition: c.h:499
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:31
HeapTupleData tuple
Definition: catcache.h:116
#define elog
Definition: elog.h:219
#define SPGIST_CHOOSE_PROC
Definition: spgist.h:29
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
#define SPGIST_PICKSPLIT_PROC
Definition: spgist.h:30
Definition: pg_list.h:45