PostgreSQL Source Code  git master
brin_validate.c File Reference
#include "postgres.h"
#include "access/amvalidate.h"
#include "access/brin_internal.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/syscache.h"
#include "utils/regproc.h"
Include dependency graph for brin_validate.c:

Go to the source code of this file.

Functions

bool brinvalidate (Oid opclassoid)
 

Function Documentation

◆ brinvalidate()

bool brinvalidate ( Oid  opclassoid)

Definition at line 38 of file brin_validate.c.

References AMOP_SEARCH, AMOPSTRATEGY, AMPROCNUM, BOOLOID, BRIN_FIRST_OPTIONAL_PROCNUM, BRIN_LAST_OPTIONAL_PROCNUM, BRIN_MANDATORY_NPROCS, BRIN_PROCNUM_ADDVALUE, BRIN_PROCNUM_CONSISTENT, BRIN_PROCNUM_OPCINFO, BRIN_PROCNUM_UNION, check_amop_signature(), check_amproc_signature(), CLAOID, elog, ereport, errcode(), errmsg(), ERROR, format_operator(), format_procedure(), format_type_be(), OpFamilyOpFuncGroup::functionset, GETSTRUCT, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, INTERNALOID, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, ObjectIdGetDatum, OidIsValid, OpFamilyOpFuncGroup::operatorset, OPFAMILYOID, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by brinhandler().

39 {
40  bool result = true;
41  HeapTuple classtup;
42  Form_pg_opclass classform;
43  Oid opfamilyoid;
44  Oid opcintype;
45  char *opclassname;
46  HeapTuple familytup;
47  Form_pg_opfamily familyform;
48  char *opfamilyname;
49  CatCList *proclist,
50  *oprlist;
51  uint64 allfuncs = 0;
52  uint64 allops = 0;
53  List *grouplist;
54  OpFamilyOpFuncGroup *opclassgroup;
55  int i;
56  ListCell *lc;
57 
58  /* Fetch opclass information */
59  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
60  if (!HeapTupleIsValid(classtup))
61  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
62  classform = (Form_pg_opclass) GETSTRUCT(classtup);
63 
64  opfamilyoid = classform->opcfamily;
65  opcintype = classform->opcintype;
66  opclassname = NameStr(classform->opcname);
67 
68  /* Fetch opfamily information */
69  familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
70  if (!HeapTupleIsValid(familytup))
71  elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
72  familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
73 
74  opfamilyname = NameStr(familyform->opfname);
75 
76  /* Fetch all operators and support functions of the opfamily */
77  oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
78  proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
79 
80  /* Check individual support functions */
81  for (i = 0; i < proclist->n_members; i++)
82  {
83  HeapTuple proctup = &proclist->members[i]->tuple;
84  Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
85  bool ok;
86 
87  /* Check procedure numbers and function signatures */
88  switch (procform->amprocnum)
89  {
91  ok = check_amproc_signature(procform->amproc, INTERNALOID, true,
92  1, 1, INTERNALOID);
93  break;
95  ok = check_amproc_signature(procform->amproc, BOOLOID, true,
96  4, 4, INTERNALOID, INTERNALOID,
98  break;
100  ok = check_amproc_signature(procform->amproc, BOOLOID, true,
101  3, 3, INTERNALOID, INTERNALOID,
102  INTERNALOID);
103  break;
104  case BRIN_PROCNUM_UNION:
105  ok = check_amproc_signature(procform->amproc, BOOLOID, true,
106  3, 3, INTERNALOID, INTERNALOID,
107  INTERNALOID);
108  break;
109  default:
110  /* Complain if it's not a valid optional proc number */
111  if (procform->amprocnum < BRIN_FIRST_OPTIONAL_PROCNUM ||
112  procform->amprocnum > BRIN_LAST_OPTIONAL_PROCNUM)
113  {
114  ereport(INFO,
115  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
116  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
117  opfamilyname, "brin",
118  format_procedure(procform->amproc),
119  procform->amprocnum)));
120  result = false;
121  continue; /* omit bad proc numbers from allfuncs */
122  }
123  /* Can't check signatures of optional procs, so assume OK */
124  ok = true;
125  break;
126  }
127 
128  if (!ok)
129  {
130  ereport(INFO,
131  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
132  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
133  opfamilyname, "brin",
134  format_procedure(procform->amproc),
135  procform->amprocnum)));
136  result = false;
137  }
138 
139  /* Track all valid procedure numbers seen in opfamily */
140  allfuncs |= ((uint64) 1) << procform->amprocnum;
141  }
142 
143  /* Check individual operators */
144  for (i = 0; i < oprlist->n_members; i++)
145  {
146  HeapTuple oprtup = &oprlist->members[i]->tuple;
147  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
148 
149  /* Check that only allowed strategy numbers exist */
150  if (oprform->amopstrategy < 1 || oprform->amopstrategy > 63)
151  {
152  ereport(INFO,
153  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
154  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
155  opfamilyname, "brin",
156  format_operator(oprform->amopopr),
157  oprform->amopstrategy)));
158  result = false;
159  }
160  else
161  {
162  /*
163  * The set of operators supplied varies across BRIN opfamilies.
164  * Our plan is to identify all operator strategy numbers used in
165  * the opfamily and then complain about datatype combinations that
166  * are missing any operator(s). However, consider only numbers
167  * that appear in some non-cross-type case, since cross-type
168  * operators may have unique strategies. (This is not a great
169  * heuristic, in particular an erroneous number used in a
170  * cross-type operator will not get noticed; but the core BRIN
171  * opfamilies are messy enough to make it necessary.)
172  */
173  if (oprform->amoplefttype == oprform->amoprighttype)
174  allops |= ((uint64) 1) << oprform->amopstrategy;
175  }
176 
177  /* brin doesn't support ORDER BY operators */
178  if (oprform->amoppurpose != AMOP_SEARCH ||
179  OidIsValid(oprform->amopsortfamily))
180  {
181  ereport(INFO,
182  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
183  errmsg("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
184  opfamilyname, "brin",
185  format_operator(oprform->amopopr))));
186  result = false;
187  }
188 
189  /* Check operator signature --- same for all brin strategies */
190  if (!check_amop_signature(oprform->amopopr, BOOLOID,
191  oprform->amoplefttype,
192  oprform->amoprighttype))
193  {
194  ereport(INFO,
195  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
196  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
197  opfamilyname, "brin",
198  format_operator(oprform->amopopr))));
199  result = false;
200  }
201  }
202 
203  /* Now check for inconsistent groups of operators/functions */
204  grouplist = identify_opfamily_groups(oprlist, proclist);
205  opclassgroup = NULL;
206  foreach(lc, grouplist)
207  {
208  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
209 
210  /* Remember the group exactly matching the test opclass */
211  if (thisgroup->lefttype == opcintype &&
212  thisgroup->righttype == opcintype)
213  opclassgroup = thisgroup;
214 
215  /*
216  * Some BRIN opfamilies expect cross-type support functions to exist,
217  * and some don't. We don't know exactly which are which, so if we
218  * find a cross-type operator for which there are no support functions
219  * at all, let it pass. (Don't expect that all operators exist for
220  * such cross-type cases, either.)
221  */
222  if (thisgroup->functionset == 0 &&
223  thisgroup->lefttype != thisgroup->righttype)
224  continue;
225 
226  /*
227  * Else complain if there seems to be an incomplete set of either
228  * operators or support functions for this datatype pair.
229  */
230  if (thisgroup->operatorset != allops)
231  {
232  ereport(INFO,
233  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
234  errmsg("operator family \"%s\" of access method %s is missing operator(s) for types %s and %s",
235  opfamilyname, "brin",
236  format_type_be(thisgroup->lefttype),
237  format_type_be(thisgroup->righttype))));
238  result = false;
239  }
240  if (thisgroup->functionset != allfuncs)
241  {
242  ereport(INFO,
243  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
244  errmsg("operator family \"%s\" of access method %s is missing support function(s) for types %s and %s",
245  opfamilyname, "brin",
246  format_type_be(thisgroup->lefttype),
247  format_type_be(thisgroup->righttype))));
248  result = false;
249  }
250  }
251 
252  /* Check that the originally-named opclass is complete */
253  if (!opclassgroup || opclassgroup->operatorset != allops)
254  {
255  ereport(INFO,
256  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
257  errmsg("operator class \"%s\" of access method %s is missing operator(s)",
258  opclassname, "brin")));
259  result = false;
260  }
261  for (i = 1; i <= BRIN_MANDATORY_NPROCS; i++)
262  {
263  if (opclassgroup &&
264  (opclassgroup->functionset & (((int64) 1) << i)) != 0)
265  continue; /* got it */
266  ereport(INFO,
267  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
268  errmsg("operator class \"%s\" of access method %s is missing support function %d",
269  opclassname, "brin", i)));
270  result = false;
271  }
272 
273  ReleaseCatCacheList(proclist);
274  ReleaseCatCacheList(oprlist);
275  ReleaseSysCache(familytup);
276  ReleaseSysCache(classtup);
277 
278  return result;
279 }
int n_members
Definition: catcache.h:176
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define AMOP_SEARCH
Definition: pg_amop.h:69
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:59
#define BRIN_PROCNUM_OPCINFO
Definition: brin_internal.h:67
int errcode(int sqlerrcode)
Definition: elog.c:575
#define INFO
Definition: elog.h:33
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
char * format_operator(Oid operator_oid)
Definition: regproc.c:820
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:586
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1795
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
#define BRIN_PROCNUM_ADDVALUE
Definition: brin_internal.h:68
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
#define BRIN_MANDATORY_NPROCS
Definition: brin_internal.h:71
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:41
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:209
#define ereport(elevel, rest)
Definition: elog.h:122
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:44
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define INTERNALOID
Definition: pg_type.h:698
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:323
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define lfirst(lc)
Definition: pg_list.h:106
#define BRIN_PROCNUM_CONSISTENT
Definition: brin_internal.h:69
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:194
#define BOOLOID
Definition: pg_type.h:288
#define BRIN_FIRST_OPTIONAL_PROCNUM
Definition: brin_internal.h:73
#define BRIN_LAST_OPTIONAL_PROCNUM
Definition: brin_internal.h:74
#define BRIN_PROCNUM_UNION
Definition: brin_internal.h:70
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:557
HeapTupleData tuple
Definition: catcache.h:121
#define elog
Definition: elog.h:219
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
Definition: pg_list.h:45