1 /*-------------------------------------------------------------------------
4 * Opclass validator for bloom.
6 * Copyright (c) 2016-2020, PostgreSQL Global Development Group
9 * contrib/bloom/blvalidate.c
11 *-------------------------------------------------------------------------
15 #include "access/amvalidate.h"
16 #include "access/htup_details.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"
29 * Validator for a bloom opclass.
32 blvalidate(Oid opclassoid
)
36 Form_pg_opclass classform
;
42 Form_pg_opfamily familyform
;
47 OpFamilyOpFuncGroup
*opclassgroup
;
51 /* Fetch opclass information */
52 classtup
= SearchSysCache1(CLAOID
, ObjectIdGetDatum(opclassoid
));
53 if (!HeapTupleIsValid(classtup
))
54 elog(ERROR
, "cache lookup failed for operator class %u", opclassoid
);
55 classform
= (Form_pg_opclass
) GETSTRUCT(classtup
);
57 opfamilyoid
= classform
->opcfamily
;
58 opcintype
= classform
->opcintype
;
59 opckeytype
= classform
->opckeytype
;
60 if (!OidIsValid(opckeytype
))
61 opckeytype
= opcintype
;
62 opclassname
= NameStr(classform
->opcname
);
64 /* Fetch opfamily information */
65 familytup
= SearchSysCache1(OPFAMILYOID
, ObjectIdGetDatum(opfamilyoid
));
66 if (!HeapTupleIsValid(familytup
))
67 elog(ERROR
, "cache lookup failed for operator family %u", opfamilyoid
);
68 familyform
= (Form_pg_opfamily
) GETSTRUCT(familytup
);
70 opfamilyname
= NameStr(familyform
->opfname
);
72 /* Fetch all operators and support functions of the opfamily */
73 oprlist
= SearchSysCacheList1(AMOPSTRATEGY
, ObjectIdGetDatum(opfamilyoid
));
74 proclist
= SearchSysCacheList1(AMPROCNUM
, ObjectIdGetDatum(opfamilyoid
));
76 /* Check individual support functions */
77 for (i
= 0; i
< proclist
->n_members
; i
++)
79 HeapTuple proctup
= &proclist
->members
[i
]->tuple
;
80 Form_pg_amproc procform
= (Form_pg_amproc
) GETSTRUCT(proctup
);
84 * All bloom support functions should be registered with matching
87 if (procform
->amproclefttype
!= procform
->amprocrighttype
)
90 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
91 errmsg("bloom opfamily %s contains support procedure %s with cross-type registration",
93 format_procedure(procform
->amproc
))));
98 * We can't check signatures except within the specific opclass, since
99 * we need to know the associated opckeytype in many cases.
101 if (procform
->amproclefttype
!= opcintype
)
104 /* Check procedure numbers and function signatures */
105 switch (procform
->amprocnum
)
107 case BLOOM_HASH_PROC
:
108 ok
= check_amproc_signature(procform
->amproc
, INT4OID
, false,
111 case BLOOM_OPTIONS_PROC
:
112 ok
= check_amoptsproc_signature(procform
->amproc
);
116 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
117 errmsg("bloom opfamily %s contains function %s with invalid support number %d",
119 format_procedure(procform
->amproc
),
120 procform
->amprocnum
)));
122 continue; /* don't want additional message */
128 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
129 errmsg("gist opfamily %s contains function %s with wrong signature for support number %d",
131 format_procedure(procform
->amproc
),
132 procform
->amprocnum
)));
137 /* Check individual operators */
138 for (i
= 0; i
< oprlist
->n_members
; i
++)
140 HeapTuple oprtup
= &oprlist
->members
[i
]->tuple
;
141 Form_pg_amop oprform
= (Form_pg_amop
) GETSTRUCT(oprtup
);
143 /* Check it's allowed strategy for bloom */
144 if (oprform
->amopstrategy
< 1 ||
145 oprform
->amopstrategy
> BLOOM_NSTRATEGIES
)
148 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
149 errmsg("bloom opfamily %s contains operator %s with invalid strategy number %d",
151 format_operator(oprform
->amopopr
),
152 oprform
->amopstrategy
)));
156 /* bloom doesn't support ORDER BY operators */
157 if (oprform
->amoppurpose
!= AMOP_SEARCH
||
158 OidIsValid(oprform
->amopsortfamily
))
161 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
162 errmsg("bloom opfamily %s contains invalid ORDER BY specification for operator %s",
164 format_operator(oprform
->amopopr
))));
168 /* Check operator signature --- same for all bloom strategies */
169 if (!check_amop_signature(oprform
->amopopr
, BOOLOID
,
170 oprform
->amoplefttype
,
171 oprform
->amoprighttype
))
174 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
175 errmsg("bloom opfamily %s contains operator %s with wrong signature",
177 format_operator(oprform
->amopopr
))));
182 /* Now check for inconsistent groups of operators/functions */
183 grouplist
= identify_opfamily_groups(oprlist
, proclist
);
185 foreach(lc
, grouplist
)
187 OpFamilyOpFuncGroup
*thisgroup
= (OpFamilyOpFuncGroup
*) lfirst(lc
);
189 /* Remember the group exactly matching the test opclass */
190 if (thisgroup
->lefttype
== opcintype
&&
191 thisgroup
->righttype
== opcintype
)
192 opclassgroup
= thisgroup
;
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.
204 /* Check that the originally-named opclass is complete */
205 for (i
= 1; i
<= BLOOM_NPROC
; i
++)
208 (opclassgroup
->functionset
& (((uint64
) 1) << i
)) != 0)
209 continue; /* got it */
210 if (i
== BLOOM_OPTIONS_PROC
)
211 continue; /* optional method */
213 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
214 errmsg("bloom opclass %s is missing support function %d",
219 ReleaseCatCacheList(proclist
);
220 ReleaseCatCacheList(oprlist
);
221 ReleaseSysCache(familytup
);
222 ReleaseSysCache(classtup
);