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