PostgreSQL Source Code  git master
nbtvalidate.c File Reference
#include "postgres.h"
#include "access/amvalidate.h"
#include "access/htup_details.h"
#include "access/nbtree.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 nbtvalidate.c:

Go to the source code of this file.

Functions

bool btvalidate (Oid opclassoid)
 

Function Documentation

◆ btvalidate()

bool btvalidate ( Oid  opclassoid)

Definition at line 38 of file nbtvalidate.c.

References AMOPSTRATEGY, AMPROCNUM, BTEQUALIMAGE_PROC, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTINRANGE_PROC, BTLessEqualStrategyNumber, BTLessStrategyNumber, BTMaxStrategyNumber, BTOPTIONS_PROC, BTORDER_PROC, BTSORTSUPPORT_PROC, check_amop_signature(), check_amoptsproc_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, list_append_unique_oid(), list_length(), catclist::members, catclist::n_members, NameStr, NIL, ObjectIdGetDatum, OidIsValid, OpFamilyOpFuncGroup::operatorset, OPFAMILYOID, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by bthandler().

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  List *grouplist;
52  OpFamilyOpFuncGroup *opclassgroup;
53  List *familytypes;
54  int usefulgroups;
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  {
90  case BTORDER_PROC:
91  ok = check_amproc_signature(procform->amproc, INT4OID, true,
92  2, 2, procform->amproclefttype,
93  procform->amprocrighttype);
94  break;
95  case BTSORTSUPPORT_PROC:
96  ok = check_amproc_signature(procform->amproc, VOIDOID, true,
97  1, 1, INTERNALOID);
98  break;
99  case BTINRANGE_PROC:
100  ok = check_amproc_signature(procform->amproc, BOOLOID, true,
101  5, 5,
102  procform->amproclefttype,
103  procform->amproclefttype,
104  procform->amprocrighttype,
105  BOOLOID, BOOLOID);
106  break;
107  case BTEQUALIMAGE_PROC:
108  ok = check_amproc_signature(procform->amproc, BOOLOID, true,
109  1, 1, OIDOID);
110  break;
111  case BTOPTIONS_PROC:
112  ok = check_amoptsproc_signature(procform->amproc);
113  break;
114  default:
115  ereport(INFO,
116  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
117  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
118  opfamilyname, "btree",
119  format_procedure(procform->amproc),
120  procform->amprocnum)));
121  result = false;
122  continue; /* don't want additional message */
123  }
124 
125  if (!ok)
126  {
127  ereport(INFO,
128  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
129  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
130  opfamilyname, "btree",
131  format_procedure(procform->amproc),
132  procform->amprocnum)));
133  result = false;
134  }
135  }
136 
137  /* Check individual operators */
138  for (i = 0; i < oprlist->n_members; i++)
139  {
140  HeapTuple oprtup = &oprlist->members[i]->tuple;
141  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
142 
143  /* Check that only allowed strategy numbers exist */
144  if (oprform->amopstrategy < 1 ||
145  oprform->amopstrategy > BTMaxStrategyNumber)
146  {
147  ereport(INFO,
148  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
149  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
150  opfamilyname, "btree",
151  format_operator(oprform->amopopr),
152  oprform->amopstrategy)));
153  result = false;
154  }
155 
156  /* btree doesn't support ORDER BY operators */
157  if (oprform->amoppurpose != AMOP_SEARCH ||
158  OidIsValid(oprform->amopsortfamily))
159  {
160  ereport(INFO,
161  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
162  errmsg("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
163  opfamilyname, "btree",
164  format_operator(oprform->amopopr))));
165  result = false;
166  }
167 
168  /* Check operator signature --- same for all btree strategies */
169  if (!check_amop_signature(oprform->amopopr, BOOLOID,
170  oprform->amoplefttype,
171  oprform->amoprighttype))
172  {
173  ereport(INFO,
174  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
175  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
176  opfamilyname, "btree",
177  format_operator(oprform->amopopr))));
178  result = false;
179  }
180  }
181 
182  /* Now check for inconsistent groups of operators/functions */
183  grouplist = identify_opfamily_groups(oprlist, proclist);
184  usefulgroups = 0;
185  opclassgroup = NULL;
186  familytypes = NIL;
187  foreach(lc, grouplist)
188  {
189  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
190 
191  /*
192  * It is possible for an in_range support function to have a RHS type
193  * that is otherwise irrelevant to the opfamily --- for instance, SQL
194  * requires the datetime_ops opclass to have range support with an
195  * interval offset. So, if this group appears to contain only an
196  * in_range function, ignore it: it doesn't represent a pair of
197  * supported types.
198  */
199  if (thisgroup->operatorset == 0 &&
200  thisgroup->functionset == (1 << BTINRANGE_PROC))
201  continue;
202 
203  /* Else count it as a relevant group */
204  usefulgroups++;
205 
206  /* Remember the group exactly matching the test opclass */
207  if (thisgroup->lefttype == opcintype &&
208  thisgroup->righttype == opcintype)
209  opclassgroup = thisgroup;
210 
211  /*
212  * Identify all distinct data types handled in this opfamily. This
213  * implementation is O(N^2), but there aren't likely to be enough
214  * types in the family for it to matter.
215  */
216  familytypes = list_append_unique_oid(familytypes, thisgroup->lefttype);
217  familytypes = list_append_unique_oid(familytypes, thisgroup->righttype);
218 
219  /*
220  * Complain if there seems to be an incomplete set of either operators
221  * or support functions for this datatype pair. The sortsupport,
222  * in_range, and equalimage functions are considered optional.
223  */
224  if (thisgroup->operatorset !=
225  ((1 << BTLessStrategyNumber) |
227  (1 << BTEqualStrategyNumber) |
229  (1 << BTGreaterStrategyNumber)))
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, "btree",
235  format_type_be(thisgroup->lefttype),
236  format_type_be(thisgroup->righttype))));
237  result = false;
238  }
239  if ((thisgroup->functionset & (1 << BTORDER_PROC)) == 0)
240  {
241  ereport(INFO,
242  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
243  errmsg("operator family \"%s\" of access method %s is missing support function for types %s and %s",
244  opfamilyname, "btree",
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 supported */
252  /* (if group is there, we already checked it adequately above) */
253  if (!opclassgroup)
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, "btree")));
259  result = false;
260  }
261 
262  /*
263  * Complain if the opfamily doesn't have entries for all possible
264  * combinations of its supported datatypes. While missing cross-type
265  * operators are not fatal, they do limit the planner's ability to derive
266  * additional qual clauses from equivalence classes, so it seems
267  * reasonable to insist that all built-in btree opfamilies be complete.
268  */
269  if (usefulgroups != (list_length(familytypes) * list_length(familytypes)))
270  {
271  ereport(INFO,
272  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
273  errmsg("operator family \"%s\" of access method %s is missing cross-type operator(s)",
274  opfamilyname, "btree")));
275  result = false;
276  }
277 
278  ReleaseCatCacheList(proclist);
279  ReleaseCatCacheList(oprlist);
280  ReleaseSysCache(familytup);
281  ReleaseSysCache(classtup);
282 
283  return result;
284 }
#define NIL
Definition: pg_list.h:65
int n_members
Definition: catcache.h:176
#define BTORDER_PROC
Definition: nbtree.h:575
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1217
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define BTEQUALIMAGE_PROC
Definition: nbtree.h:578
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:576
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
int errcode(int sqlerrcode)
Definition: elog.c:610
#define INFO
Definition: elog.h:33
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
char * format_operator(Oid operator_oid)
Definition: regproc.c:821
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
bool check_amoptsproc_signature(Oid funcid)
Definition: amvalidate.c:191
#define BTOPTIONS_PROC
Definition: nbtree.h:579
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1782
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
Definition: amvalidate.c:151
#define BTINRANGE_PROC
Definition: nbtree.h:577
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:42
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:210
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
#define ereport(elevel,...)
Definition: elog.h:144
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:324
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:205
int errmsg(const char *fmt,...)
Definition: elog.c:824
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:88
#define elog(elevel,...)
Definition: elog.h:214
int i
#define NameStr(name)
Definition: c.h:615
#define BTMaxStrategyNumber
Definition: stratnum.h:35
HeapTupleData tuple
Definition: catcache.h:121
#define BTLessStrategyNumber
Definition: stratnum.h:29
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32