PostgreSQL Source Code git master
Loading...
Searching...
No Matches
amutils.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * amutils.c
4 * SQL-level APIs related to index access methods.
5 *
6 * Copyright (c) 2016-2026, PostgreSQL Global Development Group
7 *
8 *
9 * IDENTIFICATION
10 * src/backend/utils/adt/amutils.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
16#include "access/amapi.h"
17#include "access/htup_details.h"
18#include "catalog/pg_class.h"
19#include "catalog/pg_index.h"
20#include "utils/builtins.h"
21#include "utils/syscache.h"
22
23
24/* Convert string property name to enum, for efficiency */
26{
27 const char *name;
29};
30
31static const struct am_propname am_propnames[] =
32{
33 {
34 "asc", AMPROP_ASC
35 },
36 {
37 "desc", AMPROP_DESC
38 },
39 {
40 "nulls_first", AMPROP_NULLS_FIRST
41 },
42 {
43 "nulls_last", AMPROP_NULLS_LAST
44 },
45 {
46 "orderable", AMPROP_ORDERABLE
47 },
48 {
49 "distance_orderable", AMPROP_DISTANCE_ORDERABLE
50 },
51 {
52 "returnable", AMPROP_RETURNABLE
53 },
54 {
55 "search_array", AMPROP_SEARCH_ARRAY
56 },
57 {
58 "search_nulls", AMPROP_SEARCH_NULLS
59 },
60 {
61 "clusterable", AMPROP_CLUSTERABLE
62 },
63 {
64 "index_scan", AMPROP_INDEX_SCAN
65 },
66 {
67 "bitmap_scan", AMPROP_BITMAP_SCAN
68 },
69 {
70 "backward_scan", AMPROP_BACKWARD_SCAN
71 },
72 {
73 "can_order", AMPROP_CAN_ORDER
74 },
75 {
76 "can_unique", AMPROP_CAN_UNIQUE
77 },
78 {
79 "can_multi_col", AMPROP_CAN_MULTI_COL
80 },
81 {
82 "can_exclude", AMPROP_CAN_EXCLUDE
83 },
84 {
85 "can_include", AMPROP_CAN_INCLUDE
86 },
87};
88
89static IndexAMProperty
91{
92 int i;
93
94 for (i = 0; i < lengthof(am_propnames); i++)
95 {
97 return am_propnames[i].prop;
98 }
99
100 /* We do not throw an error, so that AMs can define their own properties */
101 return AMPROP_UNKNOWN;
102}
103
104/*
105 * Common code for properties that are just bit tests of indoptions.
106 *
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).
112 *
113 * Returns false to indicate a NULL result (for "unknown/inapplicable"),
114 * otherwise sets *res to the boolean value to return.
115 */
116static bool
117test_indoption(HeapTuple tuple, int attno, bool guard,
119 bool *res)
120{
121 Datum datum;
124
125 if (!guard)
126 {
127 *res = false;
128 return true;
129 }
130
132
133 indoption = ((int2vector *) DatumGetPointer(datum));
134 indoption_val = indoption->values[attno - 1];
135
136 *res = (indoption_val & iopt_mask) == iopt_expect;
137
138 return true;
139}
140
141
142/*
143 * Test property of an index AM, index, or index column.
144 *
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
148 * properties.
149 */
150static Datum
152 const char *propname,
153 Oid amoid, Oid index_oid, int attno)
154{
155 bool res = false;
156 bool isnull = false;
157 int natts = 0;
159 const IndexAmRoutine *routine;
160
161 /* Try to convert property name to enum (no error if not known) */
163
164 /* If we have an index OID, look up the AM, and get # of columns too */
166 {
167 HeapTuple tuple;
168 Form_pg_class rd_rel;
169
172 if (!HeapTupleIsValid(tuple))
174 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
175 if (rd_rel->relkind != RELKIND_INDEX &&
176 rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
177 {
178 ReleaseSysCache(tuple);
180 }
181 amoid = rd_rel->relam;
182 natts = rd_rel->relnatts;
183 ReleaseSysCache(tuple);
184 }
185
186 /*
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
190 * index.
191 */
192 if (attno < 0 || attno > natts)
194
195 /*
196 * Get AM information. If we don't have a valid AM OID, return NULL.
197 */
198 routine = GetIndexAmRoutineByAmId(amoid, true);
199 if (routine == NULL)
201
202 /*
203 * If there's an AM property routine, give it a chance to override the
204 * generic logic. Proceed if it returns false.
205 */
206 if (routine->amproperty &&
207 routine->amproperty(index_oid, attno, prop, propname,
208 &res, &isnull))
209 {
210 if (isnull)
212 PG_RETURN_BOOL(res);
213 }
214
215 if (attno > 0)
216 {
217 HeapTuple tuple;
218 Form_pg_index rd_index;
219 bool iskey = true;
220
221 /*
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
224 * that first.
225 */
227 if (!HeapTupleIsValid(tuple))
229 rd_index = (Form_pg_index) GETSTRUCT(tuple);
230
231 Assert(index_oid == rd_index->indexrelid);
233
234 isnull = true;
235
236 /*
237 * If amcaninclude, we might be looking at an attno for a nonkey
238 * column, for which we (generically) assume that most properties are
239 * null.
240 */
241 if (routine->amcaninclude
242 && attno > rd_index->indnkeyatts)
243 iskey = false;
244
245 switch (prop)
246 {
247 case AMPROP_ASC:
248 if (iskey &&
249 test_indoption(tuple, attno, routine->amcanorder,
250 INDOPTION_DESC, 0, &res))
251 isnull = false;
252 break;
253
254 case AMPROP_DESC:
255 if (iskey &&
256 test_indoption(tuple, attno, routine->amcanorder,
258 isnull = false;
259 break;
260
262 if (iskey &&
263 test_indoption(tuple, attno, routine->amcanorder,
265 isnull = false;
266 break;
267
269 if (iskey &&
270 test_indoption(tuple, attno, routine->amcanorder,
271 INDOPTION_NULLS_FIRST, 0, &res))
272 isnull = false;
273 break;
274
275 case AMPROP_ORDERABLE:
276
277 /*
278 * generic assumption is that nonkey columns are not orderable
279 */
280 res = iskey ? routine->amcanorder : false;
281 isnull = false;
282 break;
283
285
286 /*
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
296 * know).
297 */
298 if (!iskey || !routine->amcanorderbyop)
299 {
300 res = false;
301 isnull = false;
302 }
303 break;
304
306
307 /* note that we ignore iskey for this property */
308
309 isnull = false;
310 res = false;
311
312 if (routine->amcanreturn)
313 {
314 /*
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.
318 */
320
321 res = index_can_return(indexrel, attno);
322 index_close(indexrel, AccessShareLock);
323 }
324 break;
325
327 if (iskey)
328 {
329 res = routine->amsearcharray;
330 isnull = false;
331 }
332 break;
333
335 if (iskey)
336 {
337 res = routine->amsearchnulls;
338 isnull = false;
339 }
340 break;
341
342 default:
343 break;
344 }
345
346 ReleaseSysCache(tuple);
347
348 if (!isnull)
349 PG_RETURN_BOOL(res);
351 }
352
354 {
355 /*
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.
359 */
360 switch (prop)
361 {
364
366 PG_RETURN_BOOL(routine->amgettuple ? true : false);
367
369 PG_RETURN_BOOL(routine->amgetbitmap ? true : false);
370
373
374 default:
376 }
377 }
378
379 /*
380 * Handle AM-level properties (those that control what you can say in
381 * CREATE INDEX).
382 */
383 switch (prop)
384 {
385 case AMPROP_CAN_ORDER:
386 PG_RETURN_BOOL(routine->amcanorder);
387
389 PG_RETURN_BOOL(routine->amcanunique);
390
393
395 PG_RETURN_BOOL(routine->amgettuple ? true : false);
396
399
400 default:
402 }
403}
404
405/*
406 * Test property of an AM specified by AM OID
407 */
408Datum
416
417/*
418 * Test property of an index specified by index OID
419 */
420Datum
422{
423 Oid relid = PG_GETARG_OID(0);
425
426 return indexam_property(fcinfo, propname, InvalidOid, relid, 0);
427}
428
429/*
430 * Test property of an index column specified by index OID and column number
431 */
432Datum
434{
435 Oid relid = PG_GETARG_OID(0);
436 int32 attno = PG_GETARG_INT32(1);
438
439 /* Reject attno 0 immediately, so that attno > 0 identifies this case */
440 if (attno <= 0)
442
443 return indexam_property(fcinfo, propname, InvalidOid, relid, attno);
444}
445
446/*
447 * Return the name of the given phase, as used for progress reporting by the
448 * given AM.
449 */
450Datum
452{
455 const IndexAmRoutine *routine;
456 char *name;
457
458 routine = GetIndexAmRoutineByAmId(amoid, true);
459 if (routine == NULL || !routine->ambuildphasename)
461
462 name = routine->ambuildphasename(phasenum);
463 if (!name)
465
467}
const IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition amapi.c:69
IndexAMProperty
Definition amapi.h:39
@ AMPROP_BACKWARD_SCAN
Definition amapi.h:53
@ AMPROP_SEARCH_ARRAY
Definition amapi.h:48
@ AMPROP_CAN_MULTI_COL
Definition amapi.h:56
@ AMPROP_CAN_ORDER
Definition amapi.h:54
@ AMPROP_ORDERABLE
Definition amapi.h:45
@ AMPROP_ASC
Definition amapi.h:41
@ AMPROP_DISTANCE_ORDERABLE
Definition amapi.h:46
@ AMPROP_CAN_INCLUDE
Definition amapi.h:58
@ AMPROP_SEARCH_NULLS
Definition amapi.h:49
@ AMPROP_CAN_EXCLUDE
Definition amapi.h:57
@ AMPROP_UNKNOWN
Definition amapi.h:40
@ AMPROP_CAN_UNIQUE
Definition amapi.h:55
@ AMPROP_DESC
Definition amapi.h:42
@ AMPROP_NULLS_LAST
Definition amapi.h:44
@ AMPROP_INDEX_SCAN
Definition amapi.h:51
@ AMPROP_NULLS_FIRST
Definition amapi.h:43
@ AMPROP_CLUSTERABLE
Definition amapi.h:50
@ AMPROP_RETURNABLE
Definition amapi.h:47
@ AMPROP_BITMAP_SCAN
Definition amapi.h:52
static const struct am_propname am_propnames[]
Definition amutils.c:31
static Datum indexam_property(FunctionCallInfo fcinfo, const char *propname, Oid amoid, Oid index_oid, int attno)
Definition amutils.c:151
Datum pg_index_column_has_property(PG_FUNCTION_ARGS)
Definition amutils.c:433
Datum pg_indexam_progress_phasename(PG_FUNCTION_ARGS)
Definition amutils.c:451
Datum pg_index_has_property(PG_FUNCTION_ARGS)
Definition amutils.c:421
Datum pg_indexam_has_property(PG_FUNCTION_ARGS)
Definition amutils.c:409
static IndexAMProperty lookup_prop_name(const char *name)
Definition amutils.c:90
static bool test_indoption(HeapTuple tuple, int attno, bool guard, int16 iopt_mask, int16 iopt_expect, bool *res)
Definition amutils.c:117
#define CStringGetTextDatum(s)
Definition builtins.h:97
#define Assert(condition)
Definition c.h:873
int16_t int16
Definition c.h:541
int32_t int32
Definition c.h:542
#define lengthof(array)
Definition c.h:803
#define OidIsValid(objectId)
Definition c.h:788
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:177
bool index_can_return(Relation indexRelation, int attno)
Definition indexam.c:845
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:133
int i
Definition isn.c:77
#define AccessShareLock
Definition lockdefs.h:36
FormData_pg_class * Form_pg_class
Definition pg_class.h:156
FormData_pg_index * Form_pg_index
Definition pg_index.h:70
int pg_strcasecmp(const char *s1, const char *s2)
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
#define InvalidOid
unsigned int Oid
static int fb(int x)
ambuildphasename_function ambuildphasename
Definition amapi.h:306
bool amclusterable
Definition amapi.h:270
bool amcanorderbyop
Definition amapi.h:248
amgettuple_function amgettuple
Definition amapi.h:311
amcanreturn_function amcanreturn
Definition amapi.h:301
bool amcanunique
Definition amapi.h:258
amgetbitmap_function amgetbitmap
Definition amapi.h:312
amproperty_function amproperty
Definition amapi.h:305
bool amsearcharray
Definition amapi.h:264
bool amcanmulticol
Definition amapi.h:260
bool amcanorder
Definition amapi.h:246
bool amcanbackward
Definition amapi.h:256
bool amcaninclude
Definition amapi.h:278
bool amsearchnulls
Definition amapi.h:266
IndexAMProperty prop
Definition amutils.c:28
const char * name
Definition amutils.c:27
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625
char * text_to_cstring(const text *t)
Definition varlena.c:214
const char * name