PostgreSQL Source Code  git master
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/regproc.h"
#include "utils/syscache.h"
Include dependency graph for ginvalidate.c:

Go to the source code of this file.

Functions

bool ginvalidate (Oid opclassoid)
 
void ginadjustmembers (Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
 

Function Documentation

◆ ginadjustmembers()

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

Definition at line 277 of file ginvalidate.c.

281 {
282  ListCell *lc;
283 
284  /*
285  * Operator members of a GIN opfamily should never have hard dependencies,
286  * since their connection to the opfamily depends only on what the support
287  * functions think, and that can be altered. For consistency, we make all
288  * soft dependencies point to the opfamily, though a soft dependency on
289  * the opclass would work as well in the CREATE OPERATOR CLASS case.
290  */
291  foreach(lc, operators)
292  {
293  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
294 
295  op->ref_is_hard = false;
296  op->ref_is_family = true;
297  op->refobjid = opfamilyoid;
298  }
299 
300  /*
301  * Required support functions should have hard dependencies. Preferably
302  * those are just dependencies on the opclass, but if we're in ALTER
303  * OPERATOR FAMILY, we leave the dependency pointing at the whole
304  * opfamily. (Given that GIN opclasses generally don't share opfamilies,
305  * it seems unlikely to be worth working harder.)
306  */
307  foreach(lc, functions)
308  {
309  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
310 
311  switch (op->number)
312  {
315  /* Required support function */
316  op->ref_is_hard = true;
317  break;
318  case GIN_COMPARE_PROC:
319  case GIN_CONSISTENT_PROC:
322  case GIN_OPTIONS_PROC:
323  /* Optional, so force it to be a soft family dependency */
324  op->ref_is_hard = false;
325  op->ref_is_family = true;
326  op->refobjid = opfamilyoid;
327  break;
328  default:
329  ereport(ERROR,
330  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
331  errmsg("support function number %d is invalid for access method %s",
332  op->number, "gin")));
333  break;
334  }
335  }
336 }
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define GIN_COMPARE_PROC
Definition: gin.h:22
#define GIN_CONSISTENT_PROC
Definition: gin.h:25
#define GIN_EXTRACTQUERY_PROC
Definition: gin.h:24
#define GIN_EXTRACTVALUE_PROC
Definition: gin.h:23
#define GIN_TRICONSISTENT_PROC
Definition: gin.h:27
#define GIN_COMPARE_PARTIAL_PROC
Definition: gin.h:26
#define GIN_OPTIONS_PROC
Definition: gin.h:28
#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, GIN_COMPARE_PARTIAL_PROC, GIN_COMPARE_PROC, GIN_CONSISTENT_PROC, GIN_EXTRACTQUERY_PROC, GIN_EXTRACTVALUE_PROC, GIN_OPTIONS_PROC, GIN_TRICONSISTENT_PROC, lfirst, OpFamilyMember::number, OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, and OpFamilyMember::refobjid.

Referenced by ginhandler().

◆ ginvalidate()

bool ginvalidate ( Oid  opclassoid)

Definition at line 31 of file ginvalidate.c.

32 {
33  bool result = true;
34  HeapTuple classtup;
35  Form_pg_opclass classform;
36  Oid opfamilyoid;
37  Oid opcintype;
38  Oid opckeytype;
39  char *opclassname;
40  HeapTuple familytup;
41  Form_pg_opfamily familyform;
42  char *opfamilyname;
43  CatCList *proclist,
44  *oprlist;
45  List *grouplist;
46  OpFamilyOpFuncGroup *opclassgroup;
47  int i;
48  ListCell *lc;
49 
50  /* Fetch opclass information */
51  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
52  if (!HeapTupleIsValid(classtup))
53  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
54  classform = (Form_pg_opclass) GETSTRUCT(classtup);
55 
56  opfamilyoid = classform->opcfamily;
57  opcintype = classform->opcintype;
58  opckeytype = classform->opckeytype;
59  if (!OidIsValid(opckeytype))
60  opckeytype = opcintype;
61  opclassname = NameStr(classform->opcname);
62 
63  /* Fetch opfamily information */
64  familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
65  if (!HeapTupleIsValid(familytup))
66  elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
67  familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
68 
69  opfamilyname = NameStr(familyform->opfname);
70 
71  /* Fetch all operators and support functions of the opfamily */
72  oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
73  proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
74 
75  /* Check individual support functions */
76  for (i = 0; i < proclist->n_members; i++)
77  {
78  HeapTuple proctup = &proclist->members[i]->tuple;
79  Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
80  bool ok;
81 
82  /*
83  * All GIN support functions should be registered with matching
84  * left/right types
85  */
86  if (procform->amproclefttype != procform->amprocrighttype)
87  {
88  ereport(INFO,
89  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
90  errmsg("operator family \"%s\" of access method %s contains support function %s with different left and right input types",
91  opfamilyname, "gin",
92  format_procedure(procform->amproc))));
93  result = false;
94  }
95 
96  /*
97  * We can't check signatures except within the specific opclass, since
98  * we need to know the associated opckeytype in many cases.
99  */
100  if (procform->amproclefttype != opcintype)
101  continue;
102 
103  /* Check procedure numbers and function signatures */
104  switch (procform->amprocnum)
105  {
106  case GIN_COMPARE_PROC:
107  ok = check_amproc_signature(procform->amproc, INT4OID, false,
108  2, 2, opckeytype, opckeytype);
109  break;
111  /* Some opclasses omit nullFlags */
112  ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
113  2, 3, opcintype, INTERNALOID,
114  INTERNALOID);
115  break;
117  /* Some opclasses omit nullFlags and searchMode */
118  ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
119  5, 7, opcintype, INTERNALOID,
120  INT2OID, INTERNALOID, INTERNALOID,
121  INTERNALOID, INTERNALOID);
122  break;
123  case GIN_CONSISTENT_PROC:
124  /* Some opclasses omit queryKeys and nullFlags */
125  ok = check_amproc_signature(procform->amproc, BOOLOID, false,
126  6, 8, INTERNALOID, INT2OID,
127  opcintype, INT4OID,
128  INTERNALOID, INTERNALOID,
129  INTERNALOID, INTERNALOID);
130  break;
132  ok = check_amproc_signature(procform->amproc, INT4OID, false,
133  4, 4, opckeytype, opckeytype,
134  INT2OID, INTERNALOID);
135  break;
137  ok = check_amproc_signature(procform->amproc, CHAROID, false,
138  7, 7, INTERNALOID, INT2OID,
139  opcintype, INT4OID,
140  INTERNALOID, INTERNALOID,
141  INTERNALOID);
142  break;
143  case GIN_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, "gin",
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, "gin",
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("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
181  opfamilyname, "gin",
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("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
194  opfamilyname, "gin",
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("operator family \"%s\" of access method %s contains operator %s with wrong signature",
207  opfamilyname, "gin",
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  i == GIN_OPTIONS_PROC)
243  continue; /* optional method */
245  continue; /* don't need both, see check below loop */
246  ereport(INFO,
247  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
248  errmsg("operator class \"%s\" of access method %s is missing support function %d",
249  opclassname, "gin", i)));
250  result = false;
251  }
252  if (!opclassgroup ||
253  ((opclassgroup->functionset & (1 << GIN_CONSISTENT_PROC)) == 0 &&
254  (opclassgroup->functionset & (1 << GIN_TRICONSISTENT_PROC)) == 0))
255  {
256  ereport(INFO,
257  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
258  errmsg("operator class \"%s\" of access method %s is missing support function %d or %d",
259  opclassname, "gin",
261  result = false;
262  }
263 
264 
265  ReleaseCatCacheList(proclist);
266  ReleaseCatCacheList(oprlist);
267  ReleaseSysCache(familytup);
268  ReleaseSysCache(classtup);
269 
270  return result;
271 }
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 check_amoptsproc_signature(Oid funcid)
Definition: amvalidate.c:192
#define NameStr(name)
Definition: c.h:733
#define OidIsValid(objectId)
Definition: c.h:762
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1889
#define elog(elevel,...)
Definition: elog.h:224
#define INFO
Definition: elog.h:34
#define GINNProcs
Definition: gin.h:29
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
int i
Definition: isn.c:73
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:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
#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, GETSTRUCT, GIN_COMPARE_PARTIAL_PROC, GIN_COMPARE_PROC, GIN_CONSISTENT_PROC, GIN_EXTRACTQUERY_PROC, GIN_EXTRACTVALUE_PROC, GIN_OPTIONS_PROC, GIN_TRICONSISTENT_PROC, GINNProcs, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, ObjectIdGetDatum(), OidIsValid, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by ginhandler().