Age Owner Branch data TLA Line data Source code
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 : : */
29 : : bool
3445 teodor@sigaev.ru 30 :CBC 2 : blvalidate(Oid opclassoid)
31 : : {
32 : 2 : 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 : 2 : classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
49 [ - + ]: 2 : if (!HeapTupleIsValid(classtup))
3445 teodor@sigaev.ru 50 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
3445 teodor@sigaev.ru 51 :CBC 2 : classform = (Form_pg_opclass) GETSTRUCT(classtup);
52 : :
53 : 2 : opfamilyoid = classform->opcfamily;
54 : 2 : opcintype = classform->opcintype;
55 : 2 : opckeytype = classform->opckeytype;
56 [ + - ]: 2 : if (!OidIsValid(opckeytype))
57 : 2 : opckeytype = opcintype;
58 : 2 : opclassname = NameStr(classform->opcname);
59 : :
60 : : /* Fetch opfamily information */
225 peter@eisentraut.org 61 : 2 : opfamilyname = get_opfamily_name(opfamilyoid, false);
62 : :
63 : : /* Fetch all operators and support functions of the opfamily */
3445 teodor@sigaev.ru 64 : 2 : oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
65 : 2 : proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
66 : :
67 : : /* Check individual support functions */
68 [ + + ]: 4 : for (i = 0; i < proclist->n_members; i++)
69 : : {
70 : 2 : HeapTuple proctup = &proclist->members[i]->tuple;
71 : 2 : 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 [ - + ]: 2 : if (procform->amproclefttype != procform->amprocrighttype)
79 : : {
3445 teodor@sigaev.ru 80 [ # # ]:UBC 0 : ereport(INFO,
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 : 0 : 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 : : */
3445 teodor@sigaev.ru 92 [ - + ]:CBC 2 : if (procform->amproclefttype != opcintype)
3445 teodor@sigaev.ru 93 :UBC 0 : continue;
94 : :
95 : : /* Check procedure numbers and function signatures */
3445 teodor@sigaev.ru 96 [ + - - ]:CBC 2 : switch (procform->amprocnum)
97 : : {
98 : 2 : case BLOOM_HASH_PROC:
99 : 2 : ok = check_amproc_signature(procform->amproc, INT4OID, false,
100 : : 1, 1, opckeytype);
101 : 2 : break;
1986 akorotkov@postgresql 102 :UBC 0 : case BLOOM_OPTIONS_PROC:
103 : 0 : ok = check_amoptsproc_signature(procform->amproc);
104 : 0 : break;
3445 teodor@sigaev.ru 105 : 0 : default:
106 [ # # ]: 0 : ereport(INFO,
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 : 0 : result = false;
113 : 0 : continue; /* don't want additional message */
114 : : }
115 : :
3445 teodor@sigaev.ru 116 [ - + ]:CBC 2 : if (!ok)
117 : : {
3445 teodor@sigaev.ru 118 [ # # ]:UBC 0 : ereport(INFO,
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 : 0 : result = false;
125 : : }
126 : : }
127 : :
128 : : /* Check individual operators */
3445 teodor@sigaev.ru 129 [ + + ]:CBC 4 : for (i = 0; i < oprlist->n_members; i++)
130 : : {
131 : 2 : HeapTuple oprtup = &oprlist->members[i]->tuple;
132 : 2 : Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
133 : :
134 : : /* Check it's allowed strategy for bloom */
135 [ + - ]: 2 : if (oprform->amopstrategy < 1 ||
136 [ - + ]: 2 : oprform->amopstrategy > BLOOM_NSTRATEGIES)
137 : : {
3445 teodor@sigaev.ru 138 [ # # ]:UBC 0 : ereport(INFO,
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 : 0 : result = false;
145 : : }
146 : :
147 : : /* bloom doesn't support ORDER BY operators */
3445 teodor@sigaev.ru 148 [ + - ]:CBC 2 : if (oprform->amoppurpose != AMOP_SEARCH ||
149 [ - + ]: 2 : OidIsValid(oprform->amopsortfamily))
150 : : {
3445 teodor@sigaev.ru 151 [ # # ]:UBC 0 : ereport(INFO,
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 : 0 : result = false;
157 : : }
158 : :
159 : : /* Check operator signature --- same for all bloom strategies */
3445 teodor@sigaev.ru 160 [ - + ]:CBC 2 : if (!check_amop_signature(oprform->amopopr, BOOLOID,
161 : : oprform->amoplefttype,
162 : : oprform->amoprighttype))
163 : : {
3445 teodor@sigaev.ru 164 [ # # ]:UBC 0 : ereport(INFO,
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 : 0 : result = false;
170 : : }
171 : : }
172 : :
173 : : /* Now check for inconsistent groups of operators/functions */
3445 teodor@sigaev.ru 174 :CBC 2 : grouplist = identify_opfamily_groups(oprlist, proclist);
175 : 2 : opclassgroup = NULL;
176 [ + - + + : 4 : foreach(lc, grouplist)
+ + ]
177 : : {
178 : 2 : OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
179 : :
180 : : /* Remember the group exactly matching the test opclass */
181 [ + - ]: 2 : if (thisgroup->lefttype == opcintype &&
182 [ + - ]: 2 : thisgroup->righttype == opcintype)
183 : 2 : 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 [ + + ]: 6 : for (i = 1; i <= BLOOM_NPROC; i++)
197 : : {
198 [ + - ]: 4 : if (opclassgroup &&
199 [ + + ]: 4 : (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
200 : 2 : continue; /* got it */
1986 akorotkov@postgresql 201 [ + - ]: 2 : if (i == BLOOM_OPTIONS_PROC)
202 : 2 : continue; /* optional method */
3445 teodor@sigaev.ru 203 [ # # ]:UBC 0 : ereport(INFO,
204 : : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
205 : : errmsg("bloom opclass %s is missing support function %d",
206 : : opclassname, i)));
207 : 0 : result = false;
208 : : }
209 : :
3445 teodor@sigaev.ru 210 :CBC 2 : ReleaseCatCacheList(proclist);
211 : 2 : ReleaseCatCacheList(oprlist);
212 : 2 : ReleaseSysCache(classtup);
213 : :
214 : 2 : return result;
215 : : }
|