1/*-------------------------------------------------------------------------
4 * Support routines for index access methods' amvalidate and
5 * amadjustmembers functions.
7 * Copyright (c) 2016-2025, PostgreSQL Global Development Group
11 * src/backend/access/index/amvalidate.c
13 *-------------------------------------------------------------------------
31 * identify_opfamily_groups() returns a List of OpFamilyOpFuncGroup structs,
32 * one for each combination of lefttype/righttype present in the family's
33 * operator and support function lists. If amopstrategy K is present for
34 * this datatype combination, we set bit 1 << K in operatorset, and similarly
35 * for the support functions. With uint64 fields we can handle operator and
36 * function numbers up to 63, which is plenty for the foreseeable future.
38 * The given CatCLists are expected to represent a single opfamily fetched
39 * from the AMOPSTRATEGY and AMPROCNUM caches, so that they will be in
40 * order by those caches' second and third cache keys, namely the datatypes.
52 /* We need the lists to be ordered; should be true in normal operation */
54 elog(
ERROR,
"cannot validate operator family without ordered data");
57 * Advance through the lists concurrently. Thanks to the ordering, we
58 * should see all operators and functions of a given datatype pair
63 if (io < oprlist->n_members)
70 if (ip < proclist->n_members)
78 while (oprform || procform)
80 if (oprform && thisgroup &&
81 oprform->amoplefttype == thisgroup->
lefttype &&
82 oprform->amoprighttype == thisgroup->
righttype)
84 /* Operator belongs to current group; include it and advance */
86 /* Ignore strategy numbers outside supported range */
87 if (oprform->amopstrategy > 0 && oprform->amopstrategy < 64)
90 if (io < oprlist->n_members)
100 if (procform && thisgroup &&
101 procform->amproclefttype == thisgroup->
lefttype &&
102 procform->amprocrighttype == thisgroup->
righttype)
104 /* Procedure belongs to current group; include it and advance */
106 /* Ignore function numbers outside supported range */
107 if (procform->amprocnum > 0 && procform->amprocnum < 64)
110 if (ip < proclist->n_members)
120 /* Time for a new group */
124 (oprform->amoplefttype < procform->amproclefttype ||
125 (oprform->amoplefttype == procform->amproclefttype &&
126 oprform->amoprighttype < procform->amprocrighttype))))
128 thisgroup->
lefttype = oprform->amoplefttype;
129 thisgroup->
righttype = oprform->amoprighttype;
133 thisgroup->
lefttype = procform->amproclefttype;
134 thisgroup->
righttype = procform->amprocrighttype;
137 result =
lappend(result, thisgroup);
144 * Validate the signature (argument and result types) of an opclass support
145 * function. Return true if OK, false if not.
147 * The "..." represents maxargs argument-type OIDs. If "exact" is true, they
148 * must match the function arg types exactly, else only binary-coercibly.
149 * In any case the function result type must match restype exactly.
153 int minargs,
int maxargs,...)
163 elog(
ERROR,
"cache lookup failed for function %u", funcid);
166 if (procform->prorettype != restype || procform->proretset ||
167 procform->pronargs < minargs || procform->pronargs > maxargs)
170 va_start(ap, maxargs);
171 for (
i = 0;
i < maxargs;
i++)
173 Oid argtype = va_arg(ap,
Oid);
175 if (
i >= procform->pronargs)
177 if (exact ? (argtype != procform->proargtypes.values[
i]) :
188 * Validate the signature of an opclass options support function, that should
189 * be 'void(internal)'.
198 * Validate the signature (argument and result types) of an opclass operator.
199 * Return true if OK, false if not.
201 * Currently, we can hard-wire this as accepting only binary operators. Also,
202 * we can insist on exact type matches, since the given lefttype/righttype
203 * come from pg_amop and should always match the operator exactly.
214 elog(
ERROR,
"cache lookup failed for operator %u", opno);
217 if (opform->oprresult != restype || opform->oprkind !=
'b' ||
218 opform->oprleft != lefttype || opform->oprright != righttype)
226 * Get the OID of the opclass belonging to an opfamily and accepting
227 * the specified type as input type. Returns InvalidOid if no such opclass.
229 * If there is more than one such opclass, you get a random one of them.
230 * Since that shouldn't happen, we don't waste cycles checking.
232 * We could look up the AM's OID from the opfamily, but all existing callers
233 * know that or can get it without an extra lookup, so we make them pass it.
243 * We search through all the AM's opclasses to see if one matches. This
244 * is a bit inefficient but there is no better index available. It also
245 * saves making an explicit check that the opfamily belongs to the AM.
254 if (classform->opcfamily == opfamilyoid &&
255 classform->opcintype == datatypeoid)
257 result = classform->oid;
268 * Is the datatype a legitimate input type for the btree 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 opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
bool check_amoptsproc_signature(Oid funcid)
#define OidIsValid(objectId)
void ReleaseCatCacheList(CatCList *list)
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
List * lappend(List *list, void *datum)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
FormData_pg_amop * Form_pg_amop
FormData_pg_amproc * Form_pg_amproc
FormData_pg_opclass * Form_pg_opclass
FormData_pg_operator * Form_pg_operator
FormData_pg_proc * Form_pg_proc
static Datum ObjectIdGetDatum(Oid X)
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
#define SearchSysCacheList1(cacheId, key1)