PostgreSQL Source Code git master
blvalidate.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * blvalidate.c
4 * Opclass validator for bloom.
5 *
6 * Copyright (c) 2016-2025, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * contrib/bloom/blvalidate.c
10 *
11 *-------------------------------------------------------------------------
12 */
13#include "postgres.h"
14
15#include "access/amvalidate.h"
16#include "access/htup_details.h"
17#include "bloom.h"
18#include "catalog/pg_amop.h"
19#include "catalog/pg_amproc.h"
20#include "catalog/pg_opclass.h"
21#include "catalog/pg_type.h"
22#include "utils/lsyscache.h"
23#include "utils/regproc.h"
24#include "utils/syscache.h"
25
26/*
27 * Validator for a bloom opclass.
28 */
29bool
30blvalidate(Oid opclassoid)
31{
32 bool result = true;
33 HeapTuple classtup;
34 Form_pg_opclass classform;
35 Oid opfamilyoid;
36 Oid opcintype;
37 Oid opckeytype;
38 char *opclassname;
39 char *opfamilyname;
40 CatCList *proclist,
41 *oprlist;
42 List *grouplist;
43 OpFamilyOpFuncGroup *opclassgroup;
44 int i;
45 ListCell *lc;
46
47 /* Fetch opclass information */
48 classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
49 if (!HeapTupleIsValid(classtup))
50 elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
51 classform = (Form_pg_opclass) GETSTRUCT(classtup);
52
53 opfamilyoid = classform->opcfamily;
54 opcintype = classform->opcintype;
55 opckeytype = classform->opckeytype;
56 if (!OidIsValid(opckeytype))
57 opckeytype = opcintype;
58 opclassname = NameStr(classform->opcname);
59
60 /* Fetch opfamily information */
61 opfamilyname = get_opfamily_name(opfamilyoid, false);
62
63 /* Fetch all operators and support functions of the opfamily */
64 oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
65 proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
66
67 /* Check individual support functions */
68 for (i = 0; i < proclist->n_members; i++)
69 {
70 HeapTuple proctup = &proclist->members[i]->tuple;
71 Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
72 bool ok;
73
74 /*
75 * All bloom support functions should be registered with matching
76 * left/right types
77 */
78 if (procform->amproclefttype != procform->amprocrighttype)
79 {
81 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
82 errmsg("bloom opfamily %s contains support procedure %s with cross-type registration",
83 opfamilyname,
84 format_procedure(procform->amproc))));
85 result = false;
86 }
87
88 /*
89 * We can't check signatures except within the specific opclass, since
90 * we need to know the associated opckeytype in many cases.
91 */
92 if (procform->amproclefttype != opcintype)
93 continue;
94
95 /* Check procedure numbers and function signatures */
96 switch (procform->amprocnum)
97 {
98 case BLOOM_HASH_PROC:
99 ok = check_amproc_signature(procform->amproc, INT4OID, false,
100 1, 1, opckeytype);
101 break;
103 ok = check_amoptsproc_signature(procform->amproc);
104 break;
105 default:
107 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
108 errmsg("bloom opfamily %s contains function %s with invalid support number %d",
109 opfamilyname,
110 format_procedure(procform->amproc),
111 procform->amprocnum)));
112 result = false;
113 continue; /* don't want additional message */
114 }
115
116 if (!ok)
117 {
119 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
120 errmsg("bloom opfamily %s contains function %s with wrong signature for support number %d",
121 opfamilyname,
122 format_procedure(procform->amproc),
123 procform->amprocnum)));
124 result = false;
125 }
126 }
127
128 /* Check individual operators */
129 for (i = 0; i < oprlist->n_members; i++)
130 {
131 HeapTuple oprtup = &oprlist->members[i]->tuple;
132 Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
133
134 /* Check it's allowed strategy for bloom */
135 if (oprform->amopstrategy < 1 ||
136 oprform->amopstrategy > BLOOM_NSTRATEGIES)
137 {
139 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
140 errmsg("bloom opfamily %s contains operator %s with invalid strategy number %d",
141 opfamilyname,
142 format_operator(oprform->amopopr),
143 oprform->amopstrategy)));
144 result = false;
145 }
146
147 /* bloom doesn't support ORDER BY operators */
148 if (oprform->amoppurpose != AMOP_SEARCH ||
149 OidIsValid(oprform->amopsortfamily))
150 {
152 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
153 errmsg("bloom opfamily %s contains invalid ORDER BY specification for operator %s",
154 opfamilyname,
155 format_operator(oprform->amopopr))));
156 result = false;
157 }
158
159 /* Check operator signature --- same for all bloom strategies */
160 if (!check_amop_signature(oprform->amopopr, BOOLOID,
161 oprform->amoplefttype,
162 oprform->amoprighttype))
163 {
165 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
166 errmsg("bloom opfamily %s contains operator %s with wrong signature",
167 opfamilyname,
168 format_operator(oprform->amopopr))));
169 result = false;
170 }
171 }
172
173 /* Now check for inconsistent groups of operators/functions */
174 grouplist = identify_opfamily_groups(oprlist, proclist);
175 opclassgroup = NULL;
176 foreach(lc, grouplist)
177 {
179
180 /* Remember the group exactly matching the test opclass */
181 if (thisgroup->lefttype == opcintype &&
182 thisgroup->righttype == opcintype)
183 opclassgroup = thisgroup;
184
185 /*
186 * There is not a lot we can do to check the operator sets, since each
187 * bloom opclass is more or less a law unto itself, and some contain
188 * only operators that are binary-compatible with the opclass datatype
189 * (meaning that empty operator sets can be OK). That case also means
190 * that we shouldn't insist on nonempty function sets except for the
191 * opclass's own group.
192 */
193 }
194
195 /* Check that the originally-named opclass is complete */
196 for (i = 1; i <= BLOOM_NPROC; i++)
197 {
198 if (opclassgroup &&
199 (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
200 continue; /* got it */
201 if (i == BLOOM_OPTIONS_PROC)
202 continue; /* optional method */
204 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
205 errmsg("bloom opclass %s is missing support function %d",
206 opclassname, i)));
207 result = false;
208 }
209
210 ReleaseCatCacheList(proclist);
211 ReleaseCatCacheList(oprlist);
212 ReleaseSysCache(classtup);
213
214 return result;
215}
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 BLOOM_HASH_PROC
Definition: bloom.h:24
#define BLOOM_NPROC
Definition: bloom.h:26
#define BLOOM_NSTRATEGIES
Definition: bloom.h:30
#define BLOOM_OPTIONS_PROC
Definition: bloom.h:25
bool blvalidate(Oid opclassoid)
Definition: blvalidate.c:30
#define NameStr(name)
Definition: c.h:703
uint64_t uint64
Definition: c.h:489
#define OidIsValid(objectId)
Definition: c.h:732
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:2071
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
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
int i
Definition: isn.c:72
char * get_opfamily_name(Oid opfid, bool missing_ok)
Definition: lsyscache.c:1280
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
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
unsigned int Oid
Definition: postgres_ext.h:32
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