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/regproc.h"
#include "utils/syscache.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 37 of file brin_validate.c.

References AMOPSTRATEGY, AMPROCNUM, 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, 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().

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