1/*-------------------------------------------------------------------------
4 * SQL-level APIs related to index access methods.
6 * Copyright (c) 2016-2025, PostgreSQL Global Development Group
10 * src/backend/utils/adt/amutils.c
12 *-------------------------------------------------------------------------
24/* Convert string property name to enum, for efficiency */
100 /* We do not throw an error, so that AMs can define their own properties */
105 * Common code for properties that are just bit tests of indoptions.
107 * tuple: the pg_index heaptuple
108 * attno: identify the index column to test the indoptions of.
109 * guard: if false, a boolean false result is forced (saves code in caller).
110 * iopt_mask: mask for interesting indoption bit.
111 * iopt_expect: value for a "true" result (should be 0 or iopt_mask).
113 * Returns false to indicate a NULL result (for "unknown/inapplicable"),
114 * otherwise sets *res to the boolean value to return.
134 indoption_val = indoption->
values[attno - 1];
136 *res = (indoption_val & iopt_mask) == iopt_expect;
143 * Test property of an index AM, index, or index column.
145 * This is common code for different SQL-level funcs, so the amoid and
146 * index_oid parameters are mutually exclusive; we look up the amoid from the
147 * index_oid if needed, or if no index oid is given, we're looking at AM-wide
152 const char *propname,
153 Oid amoid,
Oid index_oid,
int attno)
161 /* Try to convert property name to enum (no error if not known) */
164 /* If we have an index OID, look up the AM, and get # of columns too */
175 if (rd_rel->relkind != RELKIND_INDEX &&
176 rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
181 amoid = rd_rel->relam;
182 natts = rd_rel->relnatts;
187 * At this point, either index_oid == InvalidOid or it's a valid index
188 * OID. Also, after this test and the one below, either attno == 0 for
189 * index-wide or AM-wide tests, or it's a valid column number in a valid
192 if (attno < 0 || attno > natts)
196 * Get AM information. If we don't have a valid AM OID, return NULL.
203 * If there's an AM property routine, give it a chance to override the
204 * generic logic. Proceed if it returns false.
222 * Handle column-level properties. Many of these need the pg_index row
223 * (which we also need to use to check for nonkey atts) so we fetch
231 Assert(index_oid == rd_index->indexrelid);
232 Assert(attno > 0 && attno <= rd_index->indnatts);
237 * If amcaninclude, we might be looking at an attno for a nonkey
238 * column, for which we (generically) assume that most properties are
242 && attno > rd_index->indnkeyatts)
250 INDOPTION_DESC, 0, &res))
257 INDOPTION_DESC, INDOPTION_DESC, &res))
264 INDOPTION_NULLS_FIRST, INDOPTION_NULLS_FIRST, &res))
271 INDOPTION_NULLS_FIRST, 0, &res))
278 * generic assumption is that nonkey columns are not orderable
287 * The conditions for whether a column is distance-orderable
288 * are really up to the AM (at time of writing, only GiST
289 * supports it at all). The planner has its own idea based on
290 * whether it finds an operator with amoppurpose 'o', but
291 * getting there from just the index column type seems like a
292 * lot of work. So instead we expect the AM to handle this in
293 * its amproperty routine. The generic result is to return
294 * false if the AM says it never supports this, or if this is
295 * a nonkey column, and null otherwise (meaning we don't
307 /* note that we ignore iskey for this property */
315 * If possible, the AM should handle this test in its
316 * amproperty function without opening the rel. But this
317 * is the generic fallback if it does not.
356 * Handle index-level properties. Currently, these only depend on the
357 * AM, but that might not be true forever, so we make users name an
358 * index not just an AM.
380 * Handle AM-level properties (those that control what you can say in
406 * Test property of an AM specified by AM OID
418 * Test property of an index specified by index OID
430 * Test property of an index column specified by index OID and column number
439 /* Reject attno 0 immediately, so that attno > 0 identifies this case */
447 * Return the name of the given phase, as used for progress reporting by the
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
@ AMPROP_DISTANCE_ORDERABLE
static const struct am_propname am_propnames[]
static Datum indexam_property(FunctionCallInfo fcinfo, const char *propname, Oid amoid, Oid index_oid, int attno)
Datum pg_index_column_has_property(PG_FUNCTION_ARGS)
Datum pg_indexam_progress_phasename(PG_FUNCTION_ARGS)
Datum pg_index_has_property(PG_FUNCTION_ARGS)
Datum pg_indexam_has_property(PG_FUNCTION_ARGS)
static IndexAMProperty lookup_prop_name(const char *name)
static bool test_indoption(HeapTuple tuple, int attno, bool guard, int16 iopt_mask, int16 iopt_expect, bool *res)
#define CStringGetTextDatum(s)
#define OidIsValid(objectId)
#define PG_GETARG_TEXT_PP(n)
#define PG_GETARG_INT32(n)
#define PG_RETURN_DATUM(x)
#define PG_RETURN_BOOL(x)
Assert(PointerIsAligned(start, uint64))
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
void index_close(Relation relation, LOCKMODE lockmode)
bool index_can_return(Relation indexRelation, int attno)
Relation index_open(Oid relationId, LOCKMODE lockmode)
FormData_pg_class * Form_pg_class
FormData_pg_index * Form_pg_index
int pg_strcasecmp(const char *s1, const char *s2)
static Datum ObjectIdGetDatum(Oid X)
static Pointer DatumGetPointer(Datum X)
ambuildphasename_function ambuildphasename
amgettuple_function amgettuple
amcanreturn_function amcanreturn
amgetbitmap_function amgetbitmap
amproperty_function amproperty
int16 values[FLEXIBLE_ARRAY_MEMBER]
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
char * text_to_cstring(const text *t)