1/*-------------------------------------------------------------------------
4 * Opclass validator for btree.
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/nbtree/nbtvalidate.c
12 *-------------------------------------------------------------------------
32 * Validator for a btree 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.
58 /* Fetch opclass information */
61 elog(
ERROR,
"cache lookup failed for operator class %u", opclassoid);
64 opfamilyoid = classform->opcfamily;
65 opcintype = classform->opcintype;
66 opclassname =
NameStr(classform->opcname);
68 /* Fetch opfamily information */
71 /* Fetch all operators and support functions of the opfamily */
75 /* Check individual support functions */
82 /* Check procedure numbers and function signatures */
83 switch (procform->amprocnum)
87 2, 2, procform->amproclefttype,
88 procform->amprocrighttype);
97 procform->amproclefttype,
98 procform->amproclefttype,
99 procform->amprocrighttype,
115 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
116 errmsg(
"operator family \"%s\" of access method %s contains function %s with invalid support number %d",
117 opfamilyname,
"btree",
119 procform->amprocnum)));
121 continue;
/* don't want additional message */
127 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
128 errmsg(
"operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
129 opfamilyname,
"btree",
131 procform->amprocnum)));
136 /* Check individual operators */
142 /* Check that only allowed strategy numbers exist */
143 if (oprform->amopstrategy < 1 ||
147 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
148 errmsg(
"operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
149 opfamilyname,
"btree",
151 oprform->amopstrategy)));
155 /* btree doesn't support ORDER BY operators */
156 if (oprform->amoppurpose != AMOP_SEARCH ||
160 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
161 errmsg(
"operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
162 opfamilyname,
"btree",
167 /* Check operator signature --- same for all btree strategies */
169 oprform->amoplefttype,
170 oprform->amoprighttype))
173 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
174 errmsg(
"operator family \"%s\" of access method %s contains operator %s with wrong signature",
175 opfamilyname,
"btree",
181 /* Now check for inconsistent groups of operators/functions */
186 foreach(lc, grouplist)
191 * It is possible for an in_range support function to have a RHS type
192 * that is otherwise irrelevant to the opfamily --- for instance, SQL
193 * requires the datetime_ops opclass to have range support with an
194 * interval offset. So, if this group appears to contain only an
195 * in_range function, ignore it: it doesn't represent a pair of
202 /* Else count it as a relevant group */
205 /* Remember the group exactly matching the test opclass */
206 if (thisgroup->
lefttype == opcintype &&
208 opclassgroup = thisgroup;
211 * Identify all distinct data types handled in this opfamily. This
212 * implementation is O(N^2), but there aren't likely to be enough
213 * types in the family for it to matter.
219 * Complain if there seems to be an incomplete set of either operators
220 * or support functions for this datatype pair. The sortsupport,
221 * in_range, and equalimage functions are considered optional.
231 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
232 errmsg(
"operator family \"%s\" of access method %s is missing operator(s) for types %s and %s",
233 opfamilyname,
"btree",
241 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
242 errmsg(
"operator family \"%s\" of access method %s is missing support function for types %s and %s",
243 opfamilyname,
"btree",
250 /* Check that the originally-named opclass is supported */
251 /* (if group is there, we already checked it adequately above) */
255 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
256 errmsg(
"operator class \"%s\" of access method %s is missing operator(s)",
257 opclassname,
"btree")));
262 * Complain if the opfamily doesn't have entries for all possible
263 * combinations of its supported datatypes. While missing cross-type
264 * operators are not fatal, they do limit the planner's ability to derive
265 * additional qual clauses from equivalence classes, so it seems
266 * reasonable to insist that all built-in btree opfamilies be complete.
271 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
272 errmsg(
"operator family \"%s\" of access method %s is missing cross-type operator(s)",
273 opfamilyname,
"btree")));
285 * Prechecking function for adding operators/functions to a btree opfamily.
297 * Btree operators and comparison support functions are always "loose"
298 * members of the opfamily if they are cross-type. If they are not
299 * cross-type, we prefer to tie them to the appropriate opclass ... but if
300 * the user hasn't created one, we can't do that, and must fall back to
301 * using the opfamily dependency. (We mustn't force creation of an
302 * opclass in such a case, as leaving an incomplete opclass laying about
303 * would be bad. Throwing an error is another undesirable alternative.)
305 * This behavior results in a bit of a dump/reload hazard, in that the
306 * order of restoring objects could affect what dependencies we end up
307 * with. pg_dump's existing behavior will preserve the dependency choices
308 * in most cases, but not if a cross-type operator has been bound tightly
309 * into an opclass. That's a mistake anyway, so silently "fixing" it
312 * Optional support functions are always "loose" family members.
314 * To avoid repeated lookups, we remember the most recently used opclass's
319 /* During CREATE OPERATOR CLASS, need CCI to see the pg_opclass row */
327 * We handle operators and support functions almost identically, so rather
328 * than duplicate this code block, just join the lists.
336 /* Optional support proc, so always a soft family dependency */
343 /* Cross-type, so always a soft family dependency */
350 /* Not cross-type; is there a suitable opclass? */
353 /* Avoid repeating this expensive lookup, even if it fails */
361 /* Hard dependency on opclass */
368 /* 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 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)
Oid get_opclass_input_type(Oid opclass)
char * get_opfamily_name(Oid opfid, bool missing_ok)
#define BTEQUALIMAGE_PROC
#define BTSKIPSUPPORT_PROC
#define BTSORTSUPPORT_PROC
bool btvalidate(Oid opclassoid)
void btadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
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 BTGreaterStrategyNumber
#define BTMaxStrategyNumber
#define BTLessStrategyNumber
#define BTEqualStrategyNumber
#define BTLessEqualStrategyNumber
#define BTGreaterEqualStrategyNumber
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
#define SearchSysCacheList1(cacheId, key1)
void CommandCounterIncrement(void)