PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nbtvalidate.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * nbtvalidate.c
4  * Opclass validator for btree.
5  *
6  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/access/nbtree/nbtvalidate.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "access/amvalidate.h"
17 #include "access/htup_details.h"
18 #include "access/nbtree.h"
19 #include "catalog/pg_amop.h"
20 #include "catalog/pg_amproc.h"
21 #include "catalog/pg_opclass.h"
22 #include "catalog/pg_opfamily.h"
23 #include "catalog/pg_type.h"
24 #include "utils/builtins.h"
25 #include "utils/syscache.h"
26 
27 
28 /*
29  * Validator for a btree opclass.
30  *
31  * Some of the checks done here cover the whole opfamily, and therefore are
32  * redundant when checking each opclass in a family. But they don't run long
33  * enough to be much of a problem, so we accept the duplication rather than
34  * complicate the amvalidate API.
35  */
36 bool
37 btvalidate(Oid opclassoid)
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  List *grouplist;
51  OpFamilyOpFuncGroup *opclassgroup;
52  List *familytypes;
53  int i;
54  ListCell *lc;
55 
56  /* Fetch opclass information */
57  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
58  if (!HeapTupleIsValid(classtup))
59  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
60  classform = (Form_pg_opclass) GETSTRUCT(classtup);
61 
62  opfamilyoid = classform->opcfamily;
63  opcintype = classform->opcintype;
64  opclassname = NameStr(classform->opcname);
65 
66  /* Fetch opfamily information */
67  familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
68  if (!HeapTupleIsValid(familytup))
69  elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
70  familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
71 
72  opfamilyname = NameStr(familyform->opfname);
73 
74  /* Fetch all operators and support functions of the opfamily */
75  oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
76  proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
77 
78  /* Check individual support functions */
79  for (i = 0; i < proclist->n_members; i++)
80  {
81  HeapTuple proctup = &proclist->members[i]->tuple;
82  Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
83  bool ok;
84 
85  /* Check procedure numbers and function signatures */
86  switch (procform->amprocnum)
87  {
88  case BTORDER_PROC:
89  ok = check_amproc_signature(procform->amproc, INT4OID, true,
90  2, 2, procform->amproclefttype,
91  procform->amprocrighttype);
92  break;
93  case BTSORTSUPPORT_PROC:
94  ok = check_amproc_signature(procform->amproc, VOIDOID, true,
95  1, 1, INTERNALOID);
96  break;
97  default:
98  ereport(INFO,
99  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
100  errmsg("btree opfamily %s contains function %s with invalid support number %d",
101  opfamilyname,
102  format_procedure(procform->amproc),
103  procform->amprocnum)));
104  result = false;
105  continue; /* don't want additional message */
106  }
107 
108  if (!ok)
109  {
110  ereport(INFO,
111  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
112  errmsg("btree opfamily %s contains function %s with wrong signature for support number %d",
113  opfamilyname,
114  format_procedure(procform->amproc),
115  procform->amprocnum)));
116  result = false;
117  }
118  }
119 
120  /* Check individual operators */
121  for (i = 0; i < oprlist->n_members; i++)
122  {
123  HeapTuple oprtup = &oprlist->members[i]->tuple;
124  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
125 
126  /* Check that only allowed strategy numbers exist */
127  if (oprform->amopstrategy < 1 ||
128  oprform->amopstrategy > BTMaxStrategyNumber)
129  {
130  ereport(INFO,
131  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
132  errmsg("btree opfamily %s contains operator %s with invalid strategy number %d",
133  opfamilyname,
134  format_operator(oprform->amopopr),
135  oprform->amopstrategy)));
136  result = false;
137  }
138 
139  /* btree doesn't support ORDER BY operators */
140  if (oprform->amoppurpose != AMOP_SEARCH ||
141  OidIsValid(oprform->amopsortfamily))
142  {
143  ereport(INFO,
144  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
145  errmsg("btree opfamily %s contains invalid ORDER BY specification for operator %s",
146  opfamilyname,
147  format_operator(oprform->amopopr))));
148  result = false;
149  }
150 
151  /* Check operator signature --- same for all btree strategies */
152  if (!check_amop_signature(oprform->amopopr, BOOLOID,
153  oprform->amoplefttype,
154  oprform->amoprighttype))
155  {
156  ereport(INFO,
157  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
158  errmsg("btree opfamily %s contains operator %s with wrong signature",
159  opfamilyname,
160  format_operator(oprform->amopopr))));
161  result = false;
162  }
163  }
164 
165  /* Now check for inconsistent groups of operators/functions */
166  grouplist = identify_opfamily_groups(oprlist, proclist);
167  opclassgroup = NULL;
168  familytypes = NIL;
169  foreach(lc, grouplist)
170  {
171  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
172 
173  /* Remember the group exactly matching the test opclass */
174  if (thisgroup->lefttype == opcintype &&
175  thisgroup->righttype == opcintype)
176  opclassgroup = thisgroup;
177 
178  /*
179  * Identify all distinct data types handled in this opfamily. This
180  * implementation is O(N^2), but there aren't likely to be enough
181  * types in the family for it to matter.
182  */
183  familytypes = list_append_unique_oid(familytypes, thisgroup->lefttype);
184  familytypes = list_append_unique_oid(familytypes, thisgroup->righttype);
185 
186  /*
187  * Complain if there seems to be an incomplete set of either operators
188  * or support functions for this datatype pair. The only thing that
189  * is considered optional is the sortsupport function.
190  */
191  if (thisgroup->operatorset !=
192  ((1 << BTLessStrategyNumber) |
194  (1 << BTEqualStrategyNumber) |
196  (1 << BTGreaterStrategyNumber)))
197  {
198  ereport(INFO,
199  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
200  errmsg("btree opfamily %s is missing operator(s) for types %s and %s",
201  opfamilyname,
202  format_type_be(thisgroup->lefttype),
203  format_type_be(thisgroup->righttype))));
204  result = false;
205  }
206  if ((thisgroup->functionset & (1 << BTORDER_PROC)) == 0)
207  {
208  ereport(INFO,
209  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
210  errmsg("btree opfamily %s is missing support function for types %s and %s",
211  opfamilyname,
212  format_type_be(thisgroup->lefttype),
213  format_type_be(thisgroup->righttype))));
214  result = false;
215  }
216  }
217 
218  /* Check that the originally-named opclass is supported */
219  /* (if group is there, we already checked it adequately above) */
220  if (!opclassgroup)
221  {
222  ereport(INFO,
223  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
224  errmsg("btree opclass %s is missing operator(s)",
225  opclassname)));
226  result = false;
227  }
228 
229  /*
230  * Complain if the opfamily doesn't have entries for all possible
231  * combinations of its supported datatypes. While missing cross-type
232  * operators are not fatal, they do limit the planner's ability to derive
233  * additional qual clauses from equivalence classes, so it seems
234  * reasonable to insist that all built-in btree opfamilies be complete.
235  */
236  if (list_length(grouplist) !=
237  list_length(familytypes) * list_length(familytypes))
238  {
239  ereport(INFO,
240  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
241  errmsg("btree opfamily %s is missing cross-type operator(s)",
242  opfamilyname)));
243  result = false;
244  }
245 
246  ReleaseCatCacheList(proclist);
247  ReleaseCatCacheList(oprlist);
248  ReleaseSysCache(familytup);
249  ReleaseSysCache(classtup);
250 
251  return result;
252 }
#define NIL
Definition: pg_list.h:69
int n_members
Definition: catcache.h:149
#define BTORDER_PROC
Definition: nbtree.h:455
#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:631
#define AMOP_SEARCH
Definition: pg_amop.h:69
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:456
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:902
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:530
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:141
bool btvalidate(Oid opclassoid)
Definition: nbtvalidate.c:37
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1672
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:150
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:186
#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:990
#define INTERNALOID
Definition: pg_type.h:686
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:365
#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:494
#define BTMaxStrategyNumber
Definition: stratnum.h:35
HeapTupleData tuple
Definition: catcache.h:111
#define elog
Definition: elog.h:218
#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