PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
ginvalidate.c File Reference
#include "postgres.h"
#include "access/amvalidate.h"
#include "access/gin_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/syscache.h"
#include "utils/regproc.h"
Include dependency graph for ginvalidate.c:

Go to the source code of this file.

Functions

bool ginvalidate (Oid opclassoid)
 

Function Documentation

bool ginvalidate ( Oid  opclassoid)

Definition at line 34 of file ginvalidate.c.

References AMOP_SEARCH, AMOPSTRATEGY, AMPROCNUM, BOOLOID, CHAROID, check_amop_signature(), check_amproc_signature(), CLAOID, elog, ereport, errcode(), errmsg(), ERROR, format_operator(), format_procedure(), OpFamilyOpFuncGroup::functionset, GETSTRUCT, GIN_COMPARE_PARTIAL_PROC, GIN_COMPARE_PROC, GIN_CONSISTENT_PROC, GIN_EXTRACTQUERY_PROC, GIN_EXTRACTVALUE_PROC, GIN_TRICONSISTENT_PROC, GINNProcs, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, INT2OID, INT4OID, INTERNALOID, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, NULL, ObjectIdGetDatum, OidIsValid, OPFAMILYOID, ReleaseCatCacheList(), ReleaseSysCache(), result, OpFamilyOpFuncGroup::righttype, SearchSysCache1, SearchSysCacheList1, and catctup::tuple.

Referenced by ginhandler().

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 GIN 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("gin 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  {
109  case GIN_COMPARE_PROC:
110  ok = check_amproc_signature(procform->amproc, INT4OID, false,
111  2, 2, opckeytype, opckeytype);
112  break;
114  /* Some opclasses omit nullFlags */
115  ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
116  2, 3, opcintype, INTERNALOID,
117  INTERNALOID);
118  break;
120  /* Some opclasses omit nullFlags and searchMode */
121  ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
122  5, 7, opcintype, INTERNALOID,
125  break;
126  case GIN_CONSISTENT_PROC:
127  /* Some opclasses omit queryKeys and nullFlags */
128  ok = check_amproc_signature(procform->amproc, BOOLOID, false,
129  6, 8, INTERNALOID, INT2OID,
130  opcintype, INT4OID,
133  break;
135  ok = check_amproc_signature(procform->amproc, INT4OID, false,
136  4, 4, opckeytype, opckeytype,
138  break;
140  ok = check_amproc_signature(procform->amproc, CHAROID, false,
141  7, 7, INTERNALOID, INT2OID,
142  opcintype, INT4OID,
144  INTERNALOID);
145  break;
146  default:
147  ereport(INFO,
148  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
149  errmsg("gin operator family \"%s\" contains function %s with invalid support number %d",
150  opfamilyname,
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("gin operator family \"%s\" contains function %s with wrong signature for support number %d",
162  opfamilyname,
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 
175  /* TODO: Check that only allowed strategy numbers exist */
176  if (oprform->amopstrategy < 1 || oprform->amopstrategy > 63)
177  {
178  ereport(INFO,
179  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
180  errmsg("gin operator family \"%s\" contains operator %s with invalid strategy number %d",
181  opfamilyname,
182  format_operator(oprform->amopopr),
183  oprform->amopstrategy)));
184  result = false;
185  }
186 
187  /* gin doesn't support ORDER BY operators */
188  if (oprform->amoppurpose != AMOP_SEARCH ||
189  OidIsValid(oprform->amopsortfamily))
190  {
191  ereport(INFO,
192  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
193  errmsg("gin operator family \"%s\" contains invalid ORDER BY specification for operator %s",
194  opfamilyname,
195  format_operator(oprform->amopopr))));
196  result = false;
197  }
198 
199  /* Check operator signature --- same for all gin strategies */
200  if (!check_amop_signature(oprform->amopopr, BOOLOID,
201  oprform->amoplefttype,
202  oprform->amoprighttype))
203  {
204  ereport(INFO,
205  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
206  errmsg("gin operator family \"%s\" contains operator %s with wrong signature",
207  opfamilyname,
208  format_operator(oprform->amopopr))));
209  result = false;
210  }
211  }
212 
213  /* Now check for inconsistent groups of operators/functions */
214  grouplist = identify_opfamily_groups(oprlist, proclist);
215  opclassgroup = NULL;
216  foreach(lc, grouplist)
217  {
218  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
219 
220  /* Remember the group exactly matching the test opclass */
221  if (thisgroup->lefttype == opcintype &&
222  thisgroup->righttype == opcintype)
223  opclassgroup = thisgroup;
224 
225  /*
226  * There is not a lot we can do to check the operator sets, since each
227  * GIN opclass is more or less a law unto itself, and some contain
228  * only operators that are binary-compatible with the opclass datatype
229  * (meaning that empty operator sets can be OK). That case also means
230  * that we shouldn't insist on nonempty function sets except for the
231  * opclass's own group.
232  */
233  }
234 
235  /* Check that the originally-named opclass is complete */
236  for (i = 1; i <= GINNProcs; i++)
237  {
238  if (opclassgroup &&
239  (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
240  continue; /* got it */
242  continue; /* optional method */
244  continue; /* don't need both, see check below loop */
245  ereport(INFO,
246  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
247  errmsg("gin operator class \"%s\" is missing support function %d",
248  opclassname, i)));
249  result = false;
250  }
251  if (!opclassgroup ||
252  ((opclassgroup->functionset & (1 << GIN_CONSISTENT_PROC)) == 0 &&
253  (opclassgroup->functionset & (1 << GIN_TRICONSISTENT_PROC)) == 0))
254  {
255  ereport(INFO,
256  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
257  errmsg("gin operator class \"%s\" is missing support function %d or %d",
258  opclassname,
260  result = false;
261  }
262 
263 
264  ReleaseCatCacheList(proclist);
265  ReleaseCatCacheList(oprlist);
266  ReleaseSysCache(familytup);
267  ReleaseSysCache(classtup);
268 
269  return result;
270 }
int n_members
Definition: catcache.h:154
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define GIN_EXTRACTQUERY_PROC
Definition: gin.h:24
#define AMOP_SEARCH
Definition: pg_amop.h:69
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:59
#define INT4OID
Definition: pg_type.h:316
int errcode(int sqlerrcode)
Definition: elog.c:575
#define INFO
Definition: elog.h:33
return result
Definition: formatting.c:1632
#define GIN_TRICONSISTENT_PROC
Definition: gin.h:27
char * format_operator(Oid operator_oid)
Definition: regproc.c:819
#define GIN_COMPARE_PARTIAL_PROC
Definition: gin.h:26
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1651
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 ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:41
#define INT2OID
Definition: pg_type.h:308
#define GIN_CONSISTENT_PROC
Definition: gin.h:25
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:201
#define GINNProcs
Definition: gin.h:28
#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:1117
#define CHAROID
Definition: pg_type.h:296
#define INTERNALOID
Definition: pg_type.h:698
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:322
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define GIN_EXTRACTVALUE_PROC
Definition: gin.h:23
#define lfirst(lc)
Definition: pg_list.h:106
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:194
#define BOOLOID
Definition: pg_type.h:288
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 elog
Definition: elog.h:219
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
Definition: pg_list.h:45
#define GIN_COMPARE_PROC
Definition: gin.h:22