PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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)
 

Function Documentation

bool gistvalidate ( Oid  opclassoid)

Definition at line 34 of file gistvalidate.c.

References AMOP_SEARCH, AMOPSTRATEGY, AMPROCNUM, BOOLOID, check_amop_signature(), check_amproc_signature(), CLAOID, elog, ereport, errcode(), errmsg(), ERROR, FLOAT8OID, 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_PENALTY_PROC, GIST_PICKSPLIT_PROC, GIST_UNION_PROC, GISTNProcs, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, INT2OID, INTERNALOID, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, NULL, ObjectIdGetDatum, OidIsValid, OIDOID, opfamily_can_sort_type(), OPFAMILYOID, ReleaseCatCacheList(), ReleaseSysCache(), result, 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("gist operator family \"%s\" contains support procedure %s with cross-type registration",
94  opfamilyname,
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,
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,
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,
142  break;
143  default:
144  ereport(INFO,
145  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
146  errmsg("gist operator family \"%s\" contains function %s with invalid support number %d",
147  opfamilyname,
148  format_procedure(procform->amproc),
149  procform->amprocnum)));
150  result = false;
151  continue; /* don't want additional message */
152  }
153 
154  if (!ok)
155  {
156  ereport(INFO,
157  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
158  errmsg("gist operator family \"%s\" contains function %s with wrong signature for support number %d",
159  opfamilyname,
160  format_procedure(procform->amproc),
161  procform->amprocnum)));
162  result = false;
163  }
164  }
165 
166  /* Check individual operators */
167  for (i = 0; i < oprlist->n_members; i++)
168  {
169  HeapTuple oprtup = &oprlist->members[i]->tuple;
170  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
171  Oid op_rettype;
172 
173  /* TODO: Check that only allowed strategy numbers exist */
174  if (oprform->amopstrategy < 1)
175  {
176  ereport(INFO,
177  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
178  errmsg("gist operator family \"%s\" contains operator %s with invalid strategy number %d",
179  opfamilyname,
180  format_operator(oprform->amopopr),
181  oprform->amopstrategy)));
182  result = false;
183  }
184 
185  /* GiST supports ORDER BY operators */
186  if (oprform->amoppurpose != AMOP_SEARCH)
187  {
188  /* ... but must have matching distance proc */
189  if (!OidIsValid(get_opfamily_proc(opfamilyoid,
190  oprform->amoplefttype,
191  oprform->amoplefttype,
193  {
194  ereport(INFO,
195  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
196  errmsg("gist operator family \"%s\" contains unsupported ORDER BY specification for operator %s",
197  opfamilyname,
198  format_operator(oprform->amopopr))));
199  result = false;
200  }
201  /* ... and operator result must match the claimed btree opfamily */
202  op_rettype = get_op_rettype(oprform->amopopr);
203  if (!opfamily_can_sort_type(oprform->amopsortfamily, op_rettype))
204  {
205  ereport(INFO,
206  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
207  errmsg("gist operator family \"%s\" contains incorrect ORDER BY opfamily specification for operator %s",
208  opfamilyname,
209  format_operator(oprform->amopopr))));
210  result = false;
211  }
212  }
213  else
214  {
215  /* Search operators must always return bool */
216  op_rettype = BOOLOID;
217  }
218 
219  /* Check operator signature */
220  if (!check_amop_signature(oprform->amopopr, op_rettype,
221  oprform->amoplefttype,
222  oprform->amoprighttype))
223  {
224  ereport(INFO,
225  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
226  errmsg("gist operator family \"%s\" contains operator %s with wrong signature",
227  opfamilyname,
228  format_operator(oprform->amopopr))));
229  result = false;
230  }
231  }
232 
233  /* Now check for inconsistent groups of operators/functions */
234  grouplist = identify_opfamily_groups(oprlist, proclist);
235  opclassgroup = NULL;
236  foreach(lc, grouplist)
237  {
238  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
239 
240  /* Remember the group exactly matching the test opclass */
241  if (thisgroup->lefttype == opcintype &&
242  thisgroup->righttype == opcintype)
243  opclassgroup = thisgroup;
244 
245  /*
246  * There is not a lot we can do to check the operator sets, since each
247  * GiST opclass is more or less a law unto itself, and some contain
248  * only operators that are binary-compatible with the opclass datatype
249  * (meaning that empty operator sets can be OK). That case also means
250  * that we shouldn't insist on nonempty function sets except for the
251  * opclass's own group.
252  */
253  }
254 
255  /* Check that the originally-named opclass is complete */
256  for (i = 1; i <= GISTNProcs; i++)
257  {
258  if (opclassgroup &&
259  (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
260  continue; /* got it */
261  if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC)
262  continue; /* optional methods */
263  ereport(INFO,
264  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
265  errmsg("gist operator class \"%s\" is missing support function %d",
266  opclassname, i)));
267  result = false;
268  }
269 
270  ReleaseCatCacheList(proclist);
271  ReleaseCatCacheList(oprlist);
272  ReleaseSysCache(familytup);
273  ReleaseSysCache(classtup);
274 
275  return result;
276 }
int n_members
Definition: catcache.h:154
#define GIST_FETCH_PROC
Definition: gist.h:36
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:217
#define AMOP_SEARCH
Definition: pg_amop.h:69
#define OIDOID
Definition: pg_type.h:328
#define GIST_EQUAL_PROC
Definition: gist.h:34
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
return result
Definition: formatting.c:1618
char * format_operator(Oid operator_oid)
Definition: regproc.c:904
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1110
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1665
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 GIST_PICKSPLIT_PROC
Definition: gist.h:33
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define GIST_COMPRESS_PROC
Definition: gist.h:30
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:41
#define INT2OID
Definition: pg_type.h:308
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:197
#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:1116
#define INTERNALOID
Definition: pg_type.h:694
#define GIST_CONSISTENT_PROC
Definition: gist.h:28
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:367
#define GIST_UNION_PROC
Definition: gist.h:29
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:744
#define GIST_PENALTY_PROC
Definition: gist.h:32
#define FLOAT8OID
Definition: pg_type.h:415
#define GIST_DISTANCE_PROC
Definition: gist.h:35
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:194
#define BOOLOID
Definition: pg_type.h:288
#define GISTNProcs
Definition: gist.h:37
int errmsg(const char *fmt,...)
Definition: elog.c:797
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:77
int i
#define NameStr(name)
Definition: c.h:499
HeapTupleData tuple
Definition: catcache.h:116
#define GIST_DECOMPRESS_PROC
Definition: gist.h:31
#define elog
Definition: elog.h:219
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
Definition: pg_list.h:45