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 291 of file gistvalidate.c.

References ereport, errcode(), errmsg(), ERROR, 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_UNION_PROC, lfirst, OpFamilyMember::number, OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, and OpFamilyMember::refobjid.

Referenced by gisthandler().

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

◆ gistvalidate()

bool gistvalidate ( Oid  opclassoid)

Definition at line 34 of file gistvalidate.c.

References AMOPSTRATEGY, AMPROCNUM, check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), CLAOID, 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_UNION_PROC, GISTNProcs, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, ObjectIdGetDatum, OidIsValid, opfamily_can_sort_type(), OPFAMILYOID, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by gisthandler().

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  default:
151  ereport(INFO,
152  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
153  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
154  opfamilyname, "gist",
155  format_procedure(procform->amproc),
156  procform->amprocnum)));
157  result = false;
158  continue; /* don't want additional message */
159  }
160 
161  if (!ok)
162  {
163  ereport(INFO,
164  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
165  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
166  opfamilyname, "gist",
167  format_procedure(procform->amproc),
168  procform->amprocnum)));
169  result = false;
170  }
171  }
172 
173  /* Check individual operators */
174  for (i = 0; i < oprlist->n_members; i++)
175  {
176  HeapTuple oprtup = &oprlist->members[i]->tuple;
177  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
178  Oid op_rettype;
179 
180  /* TODO: Check that only allowed strategy numbers exist */
181  if (oprform->amopstrategy < 1)
182  {
183  ereport(INFO,
184  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
185  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
186  opfamilyname, "gist",
187  format_operator(oprform->amopopr),
188  oprform->amopstrategy)));
189  result = false;
190  }
191 
192  /* GiST supports ORDER BY operators */
193  if (oprform->amoppurpose != AMOP_SEARCH)
194  {
195  /* ... but must have matching distance proc */
196  if (!OidIsValid(get_opfamily_proc(opfamilyoid,
197  oprform->amoplefttype,
198  oprform->amoplefttype,
200  {
201  ereport(INFO,
202  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
203  errmsg("operator family \"%s\" of access method %s contains unsupported ORDER BY specification for operator %s",
204  opfamilyname, "gist",
205  format_operator(oprform->amopopr))));
206  result = false;
207  }
208  /* ... and operator result must match the claimed btree opfamily */
209  op_rettype = get_op_rettype(oprform->amopopr);
210  if (!opfamily_can_sort_type(oprform->amopsortfamily, op_rettype))
211  {
212  ereport(INFO,
213  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
214  errmsg("operator family \"%s\" of access method %s contains incorrect ORDER BY opfamily specification for operator %s",
215  opfamilyname, "gist",
216  format_operator(oprform->amopopr))));
217  result = false;
218  }
219  }
220  else
221  {
222  /* Search operators must always return bool */
223  op_rettype = BOOLOID;
224  }
225 
226  /* Check operator signature */
227  if (!check_amop_signature(oprform->amopopr, op_rettype,
228  oprform->amoplefttype,
229  oprform->amoprighttype))
230  {
231  ereport(INFO,
232  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
233  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
234  opfamilyname, "gist",
235  format_operator(oprform->amopopr))));
236  result = false;
237  }
238  }
239 
240  /* Now check for inconsistent groups of operators/functions */
241  grouplist = identify_opfamily_groups(oprlist, proclist);
242  opclassgroup = NULL;
243  foreach(lc, grouplist)
244  {
245  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
246 
247  /* Remember the group exactly matching the test opclass */
248  if (thisgroup->lefttype == opcintype &&
249  thisgroup->righttype == opcintype)
250  opclassgroup = thisgroup;
251 
252  /*
253  * There is not a lot we can do to check the operator sets, since each
254  * GiST opclass is more or less a law unto itself, and some contain
255  * only operators that are binary-compatible with the opclass datatype
256  * (meaning that empty operator sets can be OK). That case also means
257  * that we shouldn't insist on nonempty function sets except for the
258  * opclass's own group.
259  */
260  }
261 
262  /* Check that the originally-named opclass is complete */
263  for (i = 1; i <= GISTNProcs; i++)
264  {
265  if (opclassgroup &&
266  (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
267  continue; /* got it */
268  if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC ||
271  continue; /* optional methods */
272  ereport(INFO,
273  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
274  errmsg("operator class \"%s\" of access method %s is missing support function %d",
275  opclassname, "gist", i)));
276  result = false;
277  }
278 
279  ReleaseCatCacheList(proclist);
280  ReleaseCatCacheList(oprlist);
281  ReleaseSysCache(familytup);
282  ReleaseSysCache(classtup);
283 
284  return result;
285 }
#define GIST_OPTIONS_PROC
Definition: gist.h:39
int n_members
Definition: catcache.h:176
#define GIST_FETCH_PROC
Definition: gist.h:38
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:271
#define GIST_EQUAL_PROC
Definition: gist.h:36
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
#define GIST_SORTSUPPORT_PROC
Definition: gist.h:40
int errcode(int sqlerrcode)
Definition: elog.c:610
#define INFO
Definition: elog.h:33
char * format_operator(Oid operator_oid)
Definition: regproc.c:851
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:652
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1250
bool check_amoptsproc_signature(Oid funcid)
Definition: amvalidate.c:192
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:152
#define GIST_PICKSPLIT_PROC
Definition: gist.h:35
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define GIST_COMPRESS_PROC
Definition: gist.h:32
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:43
#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 ereport(elevel,...)
Definition: elog.h:144
#define GIST_CONSISTENT_PROC
Definition: gist.h:30
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:322
#define GIST_UNION_PROC
Definition: gist.h:31
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:169
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:794
#define GIST_PENALTY_PROC
Definition: gist.h:34
#define GIST_DISTANCE_PROC
Definition: gist.h:37
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:206
#define GISTNProcs
Definition: gist.h:41
int errmsg(const char *fmt,...)
Definition: elog.c:821
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:623
HeapTupleData tuple
Definition: catcache.h:121
#define GIST_DECOMPRESS_PROC
Definition: gist.h:33
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
Definition: pg_list.h:50