PostgreSQL Source Code  git master
gistvalidate.c File Reference
#include "postgres.h"
#include "access/amvalidate.h"
#include "access/gist_private.h"
#include "access/htup_details.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 gistvalidate.c:

Go to the source code of this file.

Functions

bool gistvalidate (Oid opclassoid)
 
void gistadjustmembers (Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
 

Function Documentation

◆ gistadjustmembers()

void gistadjustmembers ( Oid  opfamilyoid,
Oid  opclassoid,
List operators,
List functions 
)

Definition at line 296 of file gistvalidate.c.

300 {
301  ListCell *lc;
302 
303  /*
304  * Operator members of a GiST opfamily should never have hard
305  * dependencies, since their connection to the opfamily depends only on
306  * what the support functions think, and that can be altered. For
307  * consistency, we make all soft dependencies point to the opfamily,
308  * though a soft dependency on the opclass would work as well in the
309  * CREATE OPERATOR CLASS case.
310  */
311  foreach(lc, operators)
312  {
313  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
314 
315  op->ref_is_hard = false;
316  op->ref_is_family = true;
317  op->refobjid = opfamilyoid;
318  }
319 
320  /*
321  * Required support functions should have hard dependencies. Preferably
322  * those are just dependencies on the opclass, but if we're in ALTER
323  * OPERATOR FAMILY, we leave the dependency pointing at the whole
324  * opfamily. (Given that GiST opclasses generally don't share opfamilies,
325  * it seems unlikely to be worth working harder.)
326  */
327  foreach(lc, functions)
328  {
329  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
330 
331  switch (op->number)
332  {
334  case GIST_UNION_PROC:
335  case GIST_PENALTY_PROC:
336  case GIST_PICKSPLIT_PROC:
337  case GIST_EQUAL_PROC:
338  /* Required support function */
339  op->ref_is_hard = true;
340  break;
341  case GIST_COMPRESS_PROC:
343  case GIST_DISTANCE_PROC:
344  case GIST_FETCH_PROC:
345  case GIST_OPTIONS_PROC:
347  case GIST_STRATNUM_PROC:
348  /* Optional, so force it to be a soft family dependency */
349  op->ref_is_hard = false;
350  op->ref_is_family = true;
351  op->refobjid = opfamilyoid;
352  break;
353  default:
354  ereport(ERROR,
355  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
356  errmsg("support function number %d is invalid for access method %s",
357  op->number, "gist")));
358  break;
359  }
360  }
361 }
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define GIST_STRATNUM_PROC
Definition: gist.h:42
#define GIST_DECOMPRESS_PROC
Definition: gist.h:34
#define GIST_PICKSPLIT_PROC
Definition: gist.h:36
#define GIST_CONSISTENT_PROC
Definition: gist.h:31
#define GIST_UNION_PROC
Definition: gist.h:32
#define GIST_FETCH_PROC
Definition: gist.h:39
#define GIST_SORTSUPPORT_PROC
Definition: gist.h:41
#define GIST_COMPRESS_PROC
Definition: gist.h:33
#define GIST_PENALTY_PROC
Definition: gist.h:35
#define GIST_OPTIONS_PROC
Definition: gist.h:40
#define GIST_DISTANCE_PROC
Definition: gist.h:38
#define GIST_EQUAL_PROC
Definition: gist.h:37
#define lfirst(lc)
Definition: pg_list.h:172
static const struct fns functions
Definition: regcomp.c:356
Oid refobjid
Definition: amapi.h:90
bool ref_is_family
Definition: amapi.h:89
int number
Definition: amapi.h:84
bool ref_is_hard
Definition: amapi.h:88

References ereport, errcode(), errmsg(), ERROR, functions, GIST_COMPRESS_PROC, GIST_CONSISTENT_PROC, GIST_DECOMPRESS_PROC, GIST_DISTANCE_PROC, GIST_EQUAL_PROC, GIST_FETCH_PROC, GIST_OPTIONS_PROC, GIST_PENALTY_PROC, GIST_PICKSPLIT_PROC, GIST_SORTSUPPORT_PROC, GIST_STRATNUM_PROC, GIST_UNION_PROC, lfirst, OpFamilyMember::number, OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, and OpFamilyMember::refobjid.

Referenced by gisthandler().

◆ gistvalidate()

bool gistvalidate ( Oid  opclassoid)

Definition at line 34 of file gistvalidate.c.

35 {
36  bool result = true;
37  HeapTuple classtup;
38  Form_pg_opclass classform;
39  Oid opfamilyoid;
40  Oid opcintype;
41  Oid opckeytype;
42  char *opclassname;
43  HeapTuple familytup;
44  Form_pg_opfamily familyform;
45  char *opfamilyname;
46  CatCList *proclist,
47  *oprlist;
48  List *grouplist;
49  OpFamilyOpFuncGroup *opclassgroup;
50  int i;
51  ListCell *lc;
52 
53  /* Fetch opclass information */
54  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
55  if (!HeapTupleIsValid(classtup))
56  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
57  classform = (Form_pg_opclass) GETSTRUCT(classtup);
58 
59  opfamilyoid = classform->opcfamily;
60  opcintype = classform->opcintype;
61  opckeytype = classform->opckeytype;
62  if (!OidIsValid(opckeytype))
63  opckeytype = 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 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 function %s with different left and right input types",
94  opfamilyname, "gist",
95  format_procedure(procform->amproc))));
96  result = false;
97  }
98 
99  /*
100  * We can't check signatures except within the specific opclass, since
101  * we need to know the associated opckeytype in many cases.
102  */
103  if (procform->amproclefttype != opcintype)
104  continue;
105 
106  /* Check procedure numbers and function signatures */
107  switch (procform->amprocnum)
108  {
110  ok = check_amproc_signature(procform->amproc, BOOLOID, false,
111  5, 5, INTERNALOID, opcintype,
112  INT2OID, OIDOID, INTERNALOID);
113  break;
114  case GIST_UNION_PROC:
115  ok = check_amproc_signature(procform->amproc, opckeytype, false,
116  2, 2, INTERNALOID, INTERNALOID);
117  break;
118  case GIST_COMPRESS_PROC:
120  case GIST_FETCH_PROC:
121  ok = check_amproc_signature(procform->amproc, INTERNALOID, true,
122  1, 1, INTERNALOID);
123  break;
124  case GIST_PENALTY_PROC:
125  ok = check_amproc_signature(procform->amproc, INTERNALOID, true,
126  3, 3, INTERNALOID,
127  INTERNALOID, INTERNALOID);
128  break;
129  case GIST_PICKSPLIT_PROC:
130  ok = check_amproc_signature(procform->amproc, INTERNALOID, true,
131  2, 2, INTERNALOID, INTERNALOID);
132  break;
133  case GIST_EQUAL_PROC:
134  ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
135  3, 3, opckeytype, opckeytype,
136  INTERNALOID);
137  break;
138  case GIST_DISTANCE_PROC:
139  ok = check_amproc_signature(procform->amproc, FLOAT8OID, false,
140  5, 5, INTERNALOID, opcintype,
141  INT2OID, OIDOID, INTERNALOID);
142  break;
143  case GIST_OPTIONS_PROC:
144  ok = check_amoptsproc_signature(procform->amproc);
145  break;
147  ok = check_amproc_signature(procform->amproc, VOIDOID, true,
148  1, 1, INTERNALOID);
149  break;
150  case GIST_STRATNUM_PROC:
151  ok = check_amproc_signature(procform->amproc, INT2OID, true,
152  1, 1, INT2OID);
153  break;
154  default:
155  ereport(INFO,
156  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
157  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
158  opfamilyname, "gist",
159  format_procedure(procform->amproc),
160  procform->amprocnum)));
161  result = false;
162  continue; /* don't want additional message */
163  }
164 
165  if (!ok)
166  {
167  ereport(INFO,
168  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
169  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
170  opfamilyname, "gist",
171  format_procedure(procform->amproc),
172  procform->amprocnum)));
173  result = false;
174  }
175  }
176 
177  /* Check individual operators */
178  for (i = 0; i < oprlist->n_members; i++)
179  {
180  HeapTuple oprtup = &oprlist->members[i]->tuple;
181  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
182  Oid op_rettype;
183 
184  /* TODO: Check that only allowed strategy numbers exist */
185  if (oprform->amopstrategy < 1)
186  {
187  ereport(INFO,
188  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
189  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
190  opfamilyname, "gist",
191  format_operator(oprform->amopopr),
192  oprform->amopstrategy)));
193  result = false;
194  }
195 
196  /* GiST supports ORDER BY operators */
197  if (oprform->amoppurpose != AMOP_SEARCH)
198  {
199  /* ... but must have matching distance proc */
200  if (!OidIsValid(get_opfamily_proc(opfamilyoid,
201  oprform->amoplefttype,
202  oprform->amoplefttype,
204  {
205  ereport(INFO,
206  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
207  errmsg("operator family \"%s\" of access method %s contains unsupported ORDER BY specification for operator %s",
208  opfamilyname, "gist",
209  format_operator(oprform->amopopr))));
210  result = false;
211  }
212  /* ... and operator result must match the claimed btree opfamily */
213  op_rettype = get_op_rettype(oprform->amopopr);
214  if (!opfamily_can_sort_type(oprform->amopsortfamily, op_rettype))
215  {
216  ereport(INFO,
217  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
218  errmsg("operator family \"%s\" of access method %s contains incorrect ORDER BY opfamily specification for operator %s",
219  opfamilyname, "gist",
220  format_operator(oprform->amopopr))));
221  result = false;
222  }
223  }
224  else
225  {
226  /* Search operators must always return bool */
227  op_rettype = BOOLOID;
228  }
229 
230  /* Check operator signature */
231  if (!check_amop_signature(oprform->amopopr, op_rettype,
232  oprform->amoplefttype,
233  oprform->amoprighttype))
234  {
235  ereport(INFO,
236  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
237  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
238  opfamilyname, "gist",
239  format_operator(oprform->amopopr))));
240  result = false;
241  }
242  }
243 
244  /* Now check for inconsistent groups of operators/functions */
245  grouplist = identify_opfamily_groups(oprlist, proclist);
246  opclassgroup = NULL;
247  foreach(lc, grouplist)
248  {
249  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
250 
251  /* Remember the group exactly matching the test opclass */
252  if (thisgroup->lefttype == opcintype &&
253  thisgroup->righttype == opcintype)
254  opclassgroup = thisgroup;
255 
256  /*
257  * There is not a lot we can do to check the operator sets, since each
258  * GiST opclass is more or less a law unto itself, and some contain
259  * only operators that are binary-compatible with the opclass datatype
260  * (meaning that empty operator sets can be OK). That case also means
261  * that we shouldn't insist on nonempty function sets except for the
262  * opclass's own group.
263  */
264  }
265 
266  /* Check that the originally-named opclass is complete */
267  for (i = 1; i <= GISTNProcs; i++)
268  {
269  if (opclassgroup &&
270  (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
271  continue; /* got it */
272  if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC ||
276  continue; /* optional methods */
277  ereport(INFO,
278  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
279  errmsg("operator class \"%s\" of access method %s is missing support function %d",
280  opclassname, "gist", i)));
281  result = false;
282  }
283 
284  ReleaseCatCacheList(proclist);
285  ReleaseCatCacheList(oprlist);
286  ReleaseSysCache(familytup);
287  ReleaseSysCache(classtup);
288 
289  return result;
290 }
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
Definition: amvalidate.c:152
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:206
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:43
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:271
bool check_amoptsproc_signature(Oid funcid)
Definition: amvalidate.c:192
#define NameStr(name)
Definition: c.h:735
#define OidIsValid(objectId)
Definition: c.h:764
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1891
#define INFO
Definition: elog.h:34
#define GISTNProcs
Definition: gist.h:43
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
int i
Definition: isn.c:73
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:795
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1310
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:88
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
char * format_operator(Oid operator_oid)
Definition: regproc.c:793
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:299
Definition: pg_list.h:54
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
int n_members
Definition: catcache.h:176
HeapTupleData tuple
Definition: catcache.h:121
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:267
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:219
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:122

References check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), elog(), ereport, errcode(), errmsg(), ERROR, format_operator(), format_procedure(), OpFamilyOpFuncGroup::functionset, get_op_rettype(), get_opfamily_proc(), GETSTRUCT, GIST_COMPRESS_PROC, GIST_CONSISTENT_PROC, GIST_DECOMPRESS_PROC, GIST_DISTANCE_PROC, GIST_EQUAL_PROC, GIST_FETCH_PROC, GIST_OPTIONS_PROC, GIST_PENALTY_PROC, GIST_PICKSPLIT_PROC, GIST_SORTSUPPORT_PROC, GIST_STRATNUM_PROC, GIST_UNION_PROC, GISTNProcs, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, ObjectIdGetDatum(), OidIsValid, opfamily_can_sort_type(), ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by gisthandler().