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 287 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().

291 {
292  ListCell *lc;
293 
294  /*
295  * Operator members of a GiST opfamily should never have hard
296  * dependencies, since their connection to the opfamily depends only on
297  * what the support functions think, and that can be altered. For
298  * consistency, we make all soft dependencies point to the opfamily,
299  * though a soft dependency on the opclass would work as well in the
300  * CREATE OPERATOR CLASS case.
301  */
302  foreach(lc, operators)
303  {
304  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
305 
306  op->ref_is_hard = false;
307  op->ref_is_family = true;
308  op->refobjid = opfamilyoid;
309  }
310 
311  /*
312  * Required support functions should have hard dependencies. Preferably
313  * those are just dependencies on the opclass, but if we're in ALTER
314  * OPERATOR FAMILY, we leave the dependency pointing at the whole
315  * opfamily. (Given that GiST opclasses generally don't share opfamilies,
316  * it seems unlikely to be worth working harder.)
317  */
318  foreach(lc, functions)
319  {
320  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
321 
322  switch (op->number)
323  {
325  case GIST_UNION_PROC:
326  case GIST_PENALTY_PROC:
327  case GIST_PICKSPLIT_PROC:
328  case GIST_EQUAL_PROC:
329  /* Required support function */
330  op->ref_is_hard = true;
331  break;
332  case GIST_COMPRESS_PROC:
334  case GIST_DISTANCE_PROC:
335  case GIST_FETCH_PROC:
336  case GIST_OPTIONS_PROC:
337  /* Optional, so force it to be a soft family dependency */
338  op->ref_is_hard = false;
339  op->ref_is_family = true;
340  op->refobjid = opfamilyoid;
341  break;
342  default:
343  ereport(ERROR,
344  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
345  errmsg("support function number %d is invalid for access method %s",
346  op->number, "gist")));
347  break;
348  }
349  }
350 }
#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:190
#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:824
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_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;
146  default:
147  ereport(INFO,
148  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
149  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
150  opfamilyname, "gist",
151  format_procedure(procform->amproc),
152  procform->amprocnum)));
153  result = false;
154  continue; /* don't want additional message */
155  }
156 
157  if (!ok)
158  {
159  ereport(INFO,
160  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
161  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
162  opfamilyname, "gist",
163  format_procedure(procform->amproc),
164  procform->amprocnum)));
165  result = false;
166  }
167  }
168 
169  /* Check individual operators */
170  for (i = 0; i < oprlist->n_members; i++)
171  {
172  HeapTuple oprtup = &oprlist->members[i]->tuple;
173  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
174  Oid op_rettype;
175 
176  /* TODO: Check that only allowed strategy numbers exist */
177  if (oprform->amopstrategy < 1)
178  {
179  ereport(INFO,
180  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
181  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
182  opfamilyname, "gist",
183  format_operator(oprform->amopopr),
184  oprform->amopstrategy)));
185  result = false;
186  }
187 
188  /* GiST supports ORDER BY operators */
189  if (oprform->amoppurpose != AMOP_SEARCH)
190  {
191  /* ... but must have matching distance proc */
192  if (!OidIsValid(get_opfamily_proc(opfamilyoid,
193  oprform->amoplefttype,
194  oprform->amoplefttype,
196  {
197  ereport(INFO,
198  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
199  errmsg("operator family \"%s\" of access method %s contains unsupported ORDER BY specification for operator %s",
200  opfamilyname, "gist",
201  format_operator(oprform->amopopr))));
202  result = false;
203  }
204  /* ... and operator result must match the claimed btree opfamily */
205  op_rettype = get_op_rettype(oprform->amopopr);
206  if (!opfamily_can_sort_type(oprform->amopsortfamily, op_rettype))
207  {
208  ereport(INFO,
209  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
210  errmsg("operator family \"%s\" of access method %s contains incorrect ORDER BY opfamily specification for operator %s",
211  opfamilyname, "gist",
212  format_operator(oprform->amopopr))));
213  result = false;
214  }
215  }
216  else
217  {
218  /* Search operators must always return bool */
219  op_rettype = BOOLOID;
220  }
221 
222  /* Check operator signature */
223  if (!check_amop_signature(oprform->amopopr, op_rettype,
224  oprform->amoplefttype,
225  oprform->amoprighttype))
226  {
227  ereport(INFO,
228  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
229  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
230  opfamilyname, "gist",
231  format_operator(oprform->amopopr))));
232  result = false;
233  }
234  }
235 
236  /* Now check for inconsistent groups of operators/functions */
237  grouplist = identify_opfamily_groups(oprlist, proclist);
238  opclassgroup = NULL;
239  foreach(lc, grouplist)
240  {
241  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
242 
243  /* Remember the group exactly matching the test opclass */
244  if (thisgroup->lefttype == opcintype &&
245  thisgroup->righttype == opcintype)
246  opclassgroup = thisgroup;
247 
248  /*
249  * There is not a lot we can do to check the operator sets, since each
250  * GiST opclass is more or less a law unto itself, and some contain
251  * only operators that are binary-compatible with the opclass datatype
252  * (meaning that empty operator sets can be OK). That case also means
253  * that we shouldn't insist on nonempty function sets except for the
254  * opclass's own group.
255  */
256  }
257 
258  /* Check that the originally-named opclass is complete */
259  for (i = 1; i <= GISTNProcs; i++)
260  {
261  if (opclassgroup &&
262  (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
263  continue; /* got it */
264  if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC ||
266  i == GIST_OPTIONS_PROC)
267  continue; /* optional methods */
268  ereport(INFO,
269  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
270  errmsg("operator class \"%s\" of access method %s is missing support function %d",
271  opclassname, "gist", i)));
272  result = false;
273  }
274 
275  ReleaseCatCacheList(proclist);
276  ReleaseCatCacheList(oprlist);
277  ReleaseSysCache(familytup);
278  ReleaseSysCache(classtup);
279 
280  return result;
281 }
#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
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:651
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:190
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:40
int errmsg(const char *fmt,...)
Definition: elog.c:824
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:622
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