PostgreSQL Source Code  git master
spgvalidate.c File Reference
#include "postgres.h"
#include "access/amvalidate.h"
#include "access/htup_details.h"
#include "access/spgist_private.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/regproc.h"
#include "utils/syscache.h"
Include dependency graph for spgvalidate.c:

Go to the source code of this file.

Functions

bool spgvalidate (Oid opclassoid)
 

Function Documentation

◆ spgvalidate()

bool spgvalidate ( Oid  opclassoid)

Definition at line 39 of file spgvalidate.c.

References AMOPSTRATEGY, AMPROCNUM, spgConfigIn::attType, check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), CLAOID, elog, ereport, errcode(), errmsg(), ERROR, format_operator(), format_procedure(), format_type_be(), OpFamilyOpFuncGroup::functionset, get_op_rettype(), GETSTRUCT, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, InvalidOid, spgConfigOut::leafType, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, ObjectIdGetDatum, OidFunctionCall2, OidIsValid, OpFamilyOpFuncGroup::operatorset, opfamily_can_sort_type(), OPFAMILYOID, PointerGetDatum, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, SPGIST_CHOOSE_PROC, SPGIST_COMPRESS_PROC, SPGIST_CONFIG_PROC, SPGIST_INNER_CONSISTENT_PROC, SPGIST_LEAF_CONSISTENT_PROC, SPGIST_OPTIONS_PROC, SPGIST_PICKSPLIT_PROC, SPGISTNProc, and catctup::tuple.

Referenced by spghandler().

40 {
41  bool result = true;
42  HeapTuple classtup;
43  Form_pg_opclass classform;
44  Oid opfamilyoid;
45  Oid opcintype;
46  char *opclassname;
47  HeapTuple familytup;
48  Form_pg_opfamily familyform;
49  char *opfamilyname;
50  CatCList *proclist,
51  *oprlist;
52  List *grouplist;
53  OpFamilyOpFuncGroup *opclassgroup;
54  int i;
55  ListCell *lc;
56  spgConfigIn configIn;
57  spgConfigOut configOut;
58  Oid configOutLefttype = InvalidOid;
59  Oid configOutRighttype = InvalidOid;
60 
61  /* Fetch opclass information */
62  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
63  if (!HeapTupleIsValid(classtup))
64  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
65  classform = (Form_pg_opclass) GETSTRUCT(classtup);
66 
67  opfamilyoid = classform->opcfamily;
68  opcintype = classform->opcintype;
69  opclassname = NameStr(classform->opcname);
70 
71  /* Fetch opfamily information */
72  familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
73  if (!HeapTupleIsValid(familytup))
74  elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
75  familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
76 
77  opfamilyname = NameStr(familyform->opfname);
78 
79  /* Fetch all operators and support functions of the opfamily */
80  oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
81  proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
82  grouplist = identify_opfamily_groups(oprlist, proclist);
83 
84  /* Check individual support functions */
85  for (i = 0; i < proclist->n_members; i++)
86  {
87  HeapTuple proctup = &proclist->members[i]->tuple;
88  Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
89  bool ok;
90 
91  /*
92  * All SP-GiST support functions should be registered with matching
93  * left/right types
94  */
95  if (procform->amproclefttype != procform->amprocrighttype)
96  {
97  ereport(INFO,
98  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
99  errmsg("operator family \"%s\" of access method %s contains support function %s with different left and right input types",
100  opfamilyname, "spgist",
101  format_procedure(procform->amproc))));
102  result = false;
103  }
104 
105  /* Check procedure numbers and function signatures */
106  switch (procform->amprocnum)
107  {
108  case SPGIST_CONFIG_PROC:
109  ok = check_amproc_signature(procform->amproc, VOIDOID, true,
110  2, 2, INTERNALOID, INTERNALOID);
111  configIn.attType = procform->amproclefttype;
112  memset(&configOut, 0, sizeof(configOut));
113 
114  OidFunctionCall2(procform->amproc,
115  PointerGetDatum(&configIn),
116  PointerGetDatum(&configOut));
117 
118  configOutLefttype = procform->amproclefttype;
119  configOutRighttype = procform->amprocrighttype;
120 
121  /*
122  * When leaf and attribute types are the same, compress
123  * function is not required and we set corresponding bit in
124  * functionset for later group consistency check.
125  */
126  if (!OidIsValid(configOut.leafType) ||
127  configOut.leafType == configIn.attType)
128  {
129  foreach(lc, grouplist)
130  {
131  OpFamilyOpFuncGroup *group = lfirst(lc);
132 
133  if (group->lefttype == procform->amproclefttype &&
134  group->righttype == procform->amprocrighttype)
135  {
136  group->functionset |=
137  ((uint64) 1) << SPGIST_COMPRESS_PROC;
138  break;
139  }
140  }
141  }
142  break;
143  case SPGIST_CHOOSE_PROC:
146  ok = check_amproc_signature(procform->amproc, VOIDOID, true,
147  2, 2, INTERNALOID, INTERNALOID);
148  break;
150  ok = check_amproc_signature(procform->amproc, BOOLOID, true,
151  2, 2, INTERNALOID, INTERNALOID);
152  break;
154  if (configOutLefttype != procform->amproclefttype ||
155  configOutRighttype != procform->amprocrighttype)
156  ok = false;
157  else
158  ok = check_amproc_signature(procform->amproc,
159  configOut.leafType, true,
160  1, 1, procform->amproclefttype);
161  break;
162  case SPGIST_OPTIONS_PROC:
163  ok = check_amoptsproc_signature(procform->amproc);
164  break;
165  default:
166  ereport(INFO,
167  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
168  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
169  opfamilyname, "spgist",
170  format_procedure(procform->amproc),
171  procform->amprocnum)));
172  result = false;
173  continue; /* don't want additional message */
174  }
175 
176  if (!ok)
177  {
178  ereport(INFO,
179  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
180  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
181  opfamilyname, "spgist",
182  format_procedure(procform->amproc),
183  procform->amprocnum)));
184  result = false;
185  }
186  }
187 
188  /* Check individual operators */
189  for (i = 0; i < oprlist->n_members; i++)
190  {
191  HeapTuple oprtup = &oprlist->members[i]->tuple;
192  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
193  Oid op_rettype;
194 
195  /* TODO: Check that only allowed strategy numbers exist */
196  if (oprform->amopstrategy < 1 || oprform->amopstrategy > 63)
197  {
198  ereport(INFO,
199  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
200  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
201  opfamilyname, "spgist",
202  format_operator(oprform->amopopr),
203  oprform->amopstrategy)));
204  result = false;
205  }
206 
207  /* spgist supports ORDER BY operators */
208  if (oprform->amoppurpose != AMOP_SEARCH)
209  {
210  /* ... and operator result must match the claimed btree opfamily */
211  op_rettype = get_op_rettype(oprform->amopopr);
212  if (!opfamily_can_sort_type(oprform->amopsortfamily, op_rettype))
213  {
214  ereport(INFO,
215  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
216  errmsg("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
217  opfamilyname, "spgist",
218  format_operator(oprform->amopopr))));
219  result = false;
220  }
221  }
222  else
223  op_rettype = BOOLOID;
224 
225  /* Check operator signature --- same for all spgist strategies */
226  if (!check_amop_signature(oprform->amopopr, op_rettype,
227  oprform->amoplefttype,
228  oprform->amoprighttype))
229  {
230  ereport(INFO,
231  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
232  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
233  opfamilyname, "spgist",
234  format_operator(oprform->amopopr))));
235  result = false;
236  }
237  }
238 
239  /* Now check for inconsistent groups of operators/functions */
240  opclassgroup = NULL;
241  foreach(lc, grouplist)
242  {
243  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
244 
245  /* Remember the group exactly matching the test opclass */
246  if (thisgroup->lefttype == opcintype &&
247  thisgroup->righttype == opcintype)
248  opclassgroup = thisgroup;
249 
250  /*
251  * Complain if there are any datatype pairs with functions but no
252  * operators. This is about the best we can do for now to detect
253  * missing operators.
254  */
255  if (thisgroup->operatorset == 0)
256  {
257  ereport(INFO,
258  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
259  errmsg("operator family \"%s\" of access method %s is missing operator(s) for types %s and %s",
260  opfamilyname, "spgist",
261  format_type_be(thisgroup->lefttype),
262  format_type_be(thisgroup->righttype))));
263  result = false;
264  }
265 
266  /*
267  * Complain if we're missing functions for any datatype, remembering
268  * that SP-GiST doesn't use cross-type support functions.
269  */
270  if (thisgroup->lefttype != thisgroup->righttype)
271  continue;
272 
273  for (i = 1; i <= SPGISTNProc; i++)
274  {
275  if ((thisgroup->functionset & (((uint64) 1) << i)) != 0)
276  continue; /* got it */
277  if (i == SPGIST_OPTIONS_PROC)
278  continue; /* optional method */
279  ereport(INFO,
280  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
281  errmsg("operator family \"%s\" of access method %s is missing support function %d for type %s",
282  opfamilyname, "spgist", i,
283  format_type_be(thisgroup->lefttype))));
284  result = false;
285  }
286  }
287 
288  /* Check that the originally-named opclass is supported */
289  /* (if group is there, we already checked it adequately above) */
290  if (!opclassgroup)
291  {
292  ereport(INFO,
293  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
294  errmsg("operator class \"%s\" of access method %s is missing operator(s)",
295  opclassname, "spgist")));
296  result = false;
297  }
298 
299  ReleaseCatCacheList(proclist);
300  ReleaseCatCacheList(oprlist);
301  ReleaseSysCache(familytup);
302  ReleaseSysCache(classtup);
303 
304  return result;
305 }
int n_members
Definition: catcache.h:176
#define SPGIST_OPTIONS_PROC
Definition: spgist.h:29
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:27
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:228
#define PointerGetDatum(X)
Definition: postgres.h:556
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
int errcode(int sqlerrcode)
Definition: elog.c:610
#define INFO
Definition: elog.h:33
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
char * format_operator(Oid operator_oid)
Definition: regproc.c:821
Oid attType
Definition: spgist.h:38
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1250
bool check_amoptsproc_signature(Oid funcid)
Definition: amvalidate.c:191
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1782
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
Definition: amvalidate.c:151
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:42
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:210
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:324
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
#define SPGIST_COMPRESS_PROC
Definition: spgist.h:28
#define SPGIST_CONFIG_PROC
Definition: spgist.h:23
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:205
#define OidFunctionCall2(functionId, arg1, arg2)
Definition: fmgr.h:664
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define SPGISTNProc
Definition: spgist.h:31
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:88
#define elog(elevel,...)
Definition: elog.h:214
int i
#define NameStr(name)
Definition: c.h:615
Oid leafType
Definition: spgist.h:45
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:26
HeapTupleData tuple
Definition: catcache.h:121
#define SPGIST_CHOOSE_PROC
Definition: spgist.h:24
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
#define SPGIST_PICKSPLIT_PROC
Definition: spgist.h:25
Definition: pg_list.h:50