PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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

bool btvalidate ( Oid  opclassoid)

Definition at line 38 of file nbtvalidate.c.

References AMOP_SEARCH, AMOPSTRATEGY, AMPROCNUM, BOOLOID, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, BTMaxStrategyNumber, BTORDER_PROC, BTSORTSUPPORT_PROC, 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, INT4OID, INTERNALOID, OpFamilyOpFuncGroup::lefttype, lfirst, list_append_unique_oid(), list_length(), catclist::members, catclist::n_members, NameStr, NIL, NULL, ObjectIdGetDatum, OidIsValid, OpFamilyOpFuncGroup::operatorset, OPFAMILYOID, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1, SearchSysCacheList1, catctup::tuple, and VOIDOID.

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 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  {
89  case BTORDER_PROC:
90  ok = check_amproc_signature(procform->amproc, INT4OID, true,
91  2, 2, procform->amproclefttype,
92  procform->amprocrighttype);
93  break;
94  case BTSORTSUPPORT_PROC:
95  ok = check_amproc_signature(procform->amproc, VOIDOID, true,
96  1, 1, INTERNALOID);
97  break;
98  default:
99  ereport(INFO,
100  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
101  errmsg("btree operator family \"%s\" contains function %s with invalid support number %d",
102  opfamilyname,
103  format_procedure(procform->amproc),
104  procform->amprocnum)));
105  result = false;
106  continue; /* don't want additional message */
107  }
108 
109  if (!ok)
110  {
111  ereport(INFO,
112  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
113  errmsg("btree operator family \"%s\" contains function %s with wrong signature for support number %d",
114  opfamilyname,
115  format_procedure(procform->amproc),
116  procform->amprocnum)));
117  result = false;
118  }
119  }
120 
121  /* Check individual operators */
122  for (i = 0; i < oprlist->n_members; i++)
123  {
124  HeapTuple oprtup = &oprlist->members[i]->tuple;
125  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
126 
127  /* Check that only allowed strategy numbers exist */
128  if (oprform->amopstrategy < 1 ||
129  oprform->amopstrategy > BTMaxStrategyNumber)
130  {
131  ereport(INFO,
132  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
133  errmsg("btree operator family \"%s\" contains operator %s with invalid strategy number %d",
134  opfamilyname,
135  format_operator(oprform->amopopr),
136  oprform->amopstrategy)));
137  result = false;
138  }
139 
140  /* btree doesn't support ORDER BY operators */
141  if (oprform->amoppurpose != AMOP_SEARCH ||
142  OidIsValid(oprform->amopsortfamily))
143  {
144  ereport(INFO,
145  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
146  errmsg("btree operator family \"%s\" contains invalid ORDER BY specification for operator %s",
147  opfamilyname,
148  format_operator(oprform->amopopr))));
149  result = false;
150  }
151 
152  /* Check operator signature --- same for all btree strategies */
153  if (!check_amop_signature(oprform->amopopr, BOOLOID,
154  oprform->amoplefttype,
155  oprform->amoprighttype))
156  {
157  ereport(INFO,
158  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
159  errmsg("btree operator family \"%s\" contains operator %s with wrong signature",
160  opfamilyname,
161  format_operator(oprform->amopopr))));
162  result = false;
163  }
164  }
165 
166  /* Now check for inconsistent groups of operators/functions */
167  grouplist = identify_opfamily_groups(oprlist, proclist);
168  opclassgroup = NULL;
169  familytypes = NIL;
170  foreach(lc, grouplist)
171  {
172  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
173 
174  /* Remember the group exactly matching the test opclass */
175  if (thisgroup->lefttype == opcintype &&
176  thisgroup->righttype == opcintype)
177  opclassgroup = thisgroup;
178 
179  /*
180  * Identify all distinct data types handled in this opfamily. This
181  * implementation is O(N^2), but there aren't likely to be enough
182  * types in the family for it to matter.
183  */
184  familytypes = list_append_unique_oid(familytypes, thisgroup->lefttype);
185  familytypes = list_append_unique_oid(familytypes, thisgroup->righttype);
186 
187  /*
188  * Complain if there seems to be an incomplete set of either operators
189  * or support functions for this datatype pair. The only thing that
190  * is considered optional is the sortsupport function.
191  */
192  if (thisgroup->operatorset !=
193  ((1 << BTLessStrategyNumber) |
195  (1 << BTEqualStrategyNumber) |
197  (1 << BTGreaterStrategyNumber)))
198  {
199  ereport(INFO,
200  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
201  errmsg("btree operator family \"%s\" is missing operator(s) for types %s and %s",
202  opfamilyname,
203  format_type_be(thisgroup->lefttype),
204  format_type_be(thisgroup->righttype))));
205  result = false;
206  }
207  if ((thisgroup->functionset & (1 << BTORDER_PROC)) == 0)
208  {
209  ereport(INFO,
210  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
211  errmsg("btree operator family \"%s\" is missing support function for types %s and %s",
212  opfamilyname,
213  format_type_be(thisgroup->lefttype),
214  format_type_be(thisgroup->righttype))));
215  result = false;
216  }
217  }
218 
219  /* Check that the originally-named opclass is supported */
220  /* (if group is there, we already checked it adequately above) */
221  if (!opclassgroup)
222  {
223  ereport(INFO,
224  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
225  errmsg("btree operator class \"%s\" is missing operator(s)",
226  opclassname)));
227  result = false;
228  }
229 
230  /*
231  * Complain if the opfamily doesn't have entries for all possible
232  * combinations of its supported datatypes. While missing cross-type
233  * operators are not fatal, they do limit the planner's ability to derive
234  * additional qual clauses from equivalence classes, so it seems
235  * reasonable to insist that all built-in btree opfamilies be complete.
236  */
237  if (list_length(grouplist) !=
238  list_length(familytypes) * list_length(familytypes))
239  {
240  ereport(INFO,
241  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
242  errmsg("btree operator family \"%s\" is missing cross-type operator(s)",
243  opfamilyname)));
244  result = false;
245  }
246 
247  ReleaseCatCacheList(proclist);
248  ReleaseCatCacheList(oprlist);
249  ReleaseSysCache(familytup);
250  ReleaseSysCache(classtup);
251 
252  return result;
253 }
#define NIL
Definition: pg_list.h:69
int n_members
Definition: catcache.h:154
#define BTORDER_PROC
Definition: nbtree.h:229
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:999
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define AMOP_SEARCH
Definition: pg_amop.h:69
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:230
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
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
char * format_operator(Oid operator_oid)
Definition: regproc.c:904
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:534
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1665
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 VOIDOID
Definition: pg_type.h:678
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:41
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:194
#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:1083
#define INTERNALOID
Definition: pg_type.h:686
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:367
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
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:495
#define BTMaxStrategyNumber
Definition: stratnum.h:35
HeapTupleData tuple
Definition: catcache.h:116
#define elog
Definition: elog.h:219
#define BTLessStrategyNumber
Definition: stratnum.h:29
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32