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

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

References BRIN_FIRST_OPTIONAL_PROCNUM, BRIN_LAST_OPTIONAL_PROCNUM, BRIN_MANDATORY_NPROCS, BRIN_PROCNUM_ADDVALUE, BRIN_PROCNUM_CONSISTENT, BRIN_PROCNUM_OPCINFO, BRIN_PROCNUM_OPTIONS, BRIN_PROCNUM_UNION, check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), 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, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by brinhandler().