1/*-------------------------------------------------------------------------
4 * Opclass validator for hash.
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/backend/access/hash/hashvalidate.c
12 *-------------------------------------------------------------------------
32 * Validator for a hash opclass.
34 * Some of the checks done here cover the whole opfamily, and therefore are
35 * redundant when checking each opclass in a family. But they don't run long
36 * enough to be much of a problem, so we accept the duplication rather than
37 * complicate the amvalidate API.
57 /* Fetch opclass information */
60 elog(
ERROR,
"cache lookup failed for operator class %u", opclassoid);
63 opfamilyoid = classform->opcfamily;
64 opcintype = classform->opcintype;
65 opclassname =
NameStr(classform->opcname);
67 /* Fetch opfamily information */
70 /* Fetch all operators and support functions of the opfamily */
74 /* Check individual support functions */
82 * All hash functions should be registered with matching left/right
85 if (procform->amproclefttype != procform->amprocrighttype)
88 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
89 errmsg(
"operator family \"%s\" of access method %s contains support function %s with different left and right input types",
95 /* Check procedure numbers and function signatures */
96 switch (procform->amprocnum)
100 1, 1, procform->amproclefttype);
104 2, 2, procform->amproclefttype, INT8OID);
111 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
112 errmsg(
"operator family \"%s\" of access method %s contains function %s with invalid support number %d",
113 opfamilyname,
"hash",
115 procform->amprocnum)));
117 continue;
/* don't want additional message */
123 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
124 errmsg(
"operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
125 opfamilyname,
"hash",
127 procform->amprocnum)));
131 /* Remember which types we can hash */
138 /* Check individual operators */
144 /* Check that only allowed strategy numbers exist */
145 if (oprform->amopstrategy < 1 ||
149 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
150 errmsg(
"operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
151 opfamilyname,
"hash",
153 oprform->amopstrategy)));
157 /* hash doesn't support ORDER BY operators */
158 if (oprform->amoppurpose != AMOP_SEARCH ||
162 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
163 errmsg(
"operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
164 opfamilyname,
"hash",
169 /* Check operator signature --- same for all hash strategies */
171 oprform->amoplefttype,
172 oprform->amoprighttype))
175 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
176 errmsg(
"operator family \"%s\" of access method %s contains operator %s with wrong signature",
177 opfamilyname,
"hash",
182 /* There should be relevant hash functions for each datatype */
187 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
188 errmsg(
"operator family \"%s\" of access method %s lacks support function for operator %s",
189 opfamilyname,
"hash",
195 /* Now check for inconsistent groups of operators/functions */
198 foreach(lc, grouplist)
202 /* Remember the group exactly matching the test opclass */
203 if (thisgroup->
lefttype == opcintype &&
205 opclassgroup = thisgroup;
208 * Complain if there seems to be an incomplete set of operators for
209 * this datatype pair (implying that we have a hash function but no
215 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
216 errmsg(
"operator family \"%s\" of access method %s is missing operator(s) for types %s and %s",
217 opfamilyname,
"hash",
224 /* Check that the originally-named opclass is supported */
225 /* (if group is there, we already checked it adequately above) */
229 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
230 errmsg(
"operator class \"%s\" of access method %s is missing operator(s)",
231 opclassname,
"hash")));
236 * Complain if the opfamily doesn't have entries for all possible
237 * combinations of its supported datatypes. While missing cross-type
238 * operators are not fatal, it seems reasonable to insist that all
239 * built-in hash opfamilies be complete.
245 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
246 errmsg(
"operator family \"%s\" of access method %s is missing cross-type operator(s)",
247 opfamilyname,
"hash")));
260 * Prechecking function for adding operators/functions to a hash opfamily.
272 * Hash operators and required support functions are always "loose"
273 * members of the opfamily if they are cross-type. If they are not
274 * cross-type, we prefer to tie them to the appropriate opclass ... but if
275 * the user hasn't created one, we can't do that, and must fall back to
276 * using the opfamily dependency. (We mustn't force creation of an
277 * opclass in such a case, as leaving an incomplete opclass laying about
278 * would be bad. Throwing an error is another undesirable alternative.)
280 * This behavior results in a bit of a dump/reload hazard, in that the
281 * order of restoring objects could affect what dependencies we end up
282 * with. pg_dump's existing behavior will preserve the dependency choices
283 * in most cases, but not if a cross-type operator has been bound tightly
284 * into an opclass. That's a mistake anyway, so silently "fixing" it
287 * Optional support functions are always "loose" family members.
289 * To avoid repeated lookups, we remember the most recently used opclass's
294 /* During CREATE OPERATOR CLASS, need CCI to see the pg_opclass row */
302 * We handle operators and support functions almost identically, so rather
303 * than duplicate this code block, just join the lists.
311 /* Optional support proc, so always a soft family dependency */
318 /* Cross-type, so always a soft family dependency */
325 /* Not cross-type; is there a suitable opclass? */
328 /* Avoid repeating this expensive lookup, even if it fails */
336 /* Hard dependency on opclass */
343 /* We're stuck, so make a soft dependency on the opfamily */
Oid opclass_for_family_datatype(Oid amoid, Oid opfamilyoid, Oid datatypeoid)
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
bool check_amoptsproc_signature(Oid funcid)
#define OidIsValid(objectId)
void ReleaseCatCacheList(CatCList *list)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define HASHSTANDARD_PROC
#define HASHEXTENDED_PROC
void hashadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
bool hashvalidate(Oid opclassoid)
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
List * list_concat_copy(const List *list1, const List *list2)
List * list_append_unique_oid(List *list, Oid datum)
bool list_member_oid(const List *list, Oid datum)
Oid get_opclass_input_type(Oid opclass)
char * get_opfamily_name(Oid opfid, bool missing_ok)
FormData_pg_amop * Form_pg_amop
FormData_pg_amproc * Form_pg_amproc
static int list_length(const List *l)
FormData_pg_opclass * Form_pg_opclass
static Datum ObjectIdGetDatum(Oid X)
static const struct fns functions
char * format_procedure(Oid procedure_oid)
char * format_operator(Oid operator_oid)
#define HTMaxStrategyNumber
#define HTEqualStrategyNumber
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
#define SearchSysCacheList1(cacheId, key1)
void CommandCounterIncrement(void)