PostgreSQL Source Code  git master
amutils.c File Reference
#include "postgres.h"
#include "access/amapi.h"
#include "access/htup_details.h"
#include "catalog/pg_class.h"
#include "catalog/pg_index.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
Include dependency graph for amutils.c:

Go to the source code of this file.

Data Structures

struct  am_propname
 

Functions

static IndexAMProperty lookup_prop_name (const char *name)
 
static bool test_indoption (Oid relid, int attno, bool guard, int16 iopt_mask, int16 iopt_expect, bool *res)
 
static Datum indexam_property (FunctionCallInfo fcinfo, const char *propname, Oid amoid, Oid index_oid, int attno)
 
Datum pg_indexam_has_property (PG_FUNCTION_ARGS)
 
Datum pg_index_has_property (PG_FUNCTION_ARGS)
 
Datum pg_index_column_has_property (PG_FUNCTION_ARGS)
 

Variables

static const struct am_propname am_propnames []
 

Function Documentation

◆ indexam_property()

static Datum indexam_property ( FunctionCallInfo  fcinfo,
const char *  propname,
Oid  amoid,
Oid  index_oid,
int  attno 
)
static

Definition at line 162 of file amutils.c.

References AccessShareLock, IndexAmRoutine::amcanbackward, IndexAmRoutine::amcanmulticol, IndexAmRoutine::amcanorder, IndexAmRoutine::amcanorderbyop, IndexAmRoutine::amcanreturn, IndexAmRoutine::amcanunique, IndexAmRoutine::amclusterable, IndexAmRoutine::amgetbitmap, IndexAmRoutine::amgettuple, AMPROP_ASC, AMPROP_BACKWARD_SCAN, AMPROP_BITMAP_SCAN, AMPROP_CAN_EXCLUDE, AMPROP_CAN_MULTI_COL, AMPROP_CAN_ORDER, AMPROP_CAN_UNIQUE, AMPROP_CLUSTERABLE, AMPROP_DESC, AMPROP_DISTANCE_ORDERABLE, AMPROP_INDEX_SCAN, AMPROP_NULLS_FIRST, AMPROP_NULLS_LAST, AMPROP_ORDERABLE, AMPROP_RETURNABLE, AMPROP_SEARCH_ARRAY, AMPROP_SEARCH_NULLS, IndexAmRoutine::amproperty, IndexAmRoutine::amsearcharray, IndexAmRoutine::amsearchnulls, Assert, GetIndexAmRoutineByAmId(), GETSTRUCT, HeapTupleIsValid, index_can_return(), index_close(), index_open(), INDOPTION_DESC, INDOPTION_NULLS_FIRST, lookup_prop_name(), ObjectIdGetDatum, OidIsValid, PG_RETURN_BOOL, PG_RETURN_NULL, am_propname::prop, ReleaseSysCache(), RELKIND_INDEX, RELKIND_PARTITIONED_INDEX, RELOID, SearchSysCache1(), and test_indoption().

Referenced by pg_index_column_has_property(), pg_index_has_property(), and pg_indexam_has_property().

165 {
166  bool res = false;
167  bool isnull = false;
168  int natts = 0;
169  IndexAMProperty prop;
170  IndexAmRoutine *routine;
171 
172  /* Try to convert property name to enum (no error if not known) */
173  prop = lookup_prop_name(propname);
174 
175  /* If we have an index OID, look up the AM, and get # of columns too */
176  if (OidIsValid(index_oid))
177  {
178  HeapTuple tuple;
179  Form_pg_class rd_rel;
180 
181  Assert(!OidIsValid(amoid));
182  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(index_oid));
183  if (!HeapTupleIsValid(tuple))
184  PG_RETURN_NULL();
185  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
186  if (rd_rel->relkind != RELKIND_INDEX &&
187  rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
188  {
189  ReleaseSysCache(tuple);
190  PG_RETURN_NULL();
191  }
192  amoid = rd_rel->relam;
193  natts = rd_rel->relnatts;
194  ReleaseSysCache(tuple);
195  }
196 
197  /*
198  * At this point, either index_oid == InvalidOid or it's a valid index
199  * OID. Also, after this test, either attno == 0 for index-wide or
200  * AM-wide tests, or it's a valid column number in a valid index.
201  */
202  if (attno < 0 || attno > natts)
203  PG_RETURN_NULL();
204 
205  /*
206  * Get AM information. If we don't have a valid AM OID, return NULL.
207  */
208  routine = GetIndexAmRoutineByAmId(amoid, true);
209  if (routine == NULL)
210  PG_RETURN_NULL();
211 
212  /*
213  * If there's an AM property routine, give it a chance to override the
214  * generic logic. Proceed if it returns false.
215  */
216  if (routine->amproperty &&
217  routine->amproperty(index_oid, attno, prop, propname,
218  &res, &isnull))
219  {
220  if (isnull)
221  PG_RETURN_NULL();
222  PG_RETURN_BOOL(res);
223  }
224 
225  if (attno > 0)
226  {
227  /* Handle column-level properties */
228  switch (prop)
229  {
230  case AMPROP_ASC:
231  if (test_indoption(index_oid, attno, routine->amcanorder,
232  INDOPTION_DESC, 0, &res))
233  PG_RETURN_BOOL(res);
234  PG_RETURN_NULL();
235 
236  case AMPROP_DESC:
237  if (test_indoption(index_oid, attno, routine->amcanorder,
239  PG_RETURN_BOOL(res);
240  PG_RETURN_NULL();
241 
242  case AMPROP_NULLS_FIRST:
243  if (test_indoption(index_oid, attno, routine->amcanorder,
245  PG_RETURN_BOOL(res);
246  PG_RETURN_NULL();
247 
248  case AMPROP_NULLS_LAST:
249  if (test_indoption(index_oid, attno, routine->amcanorder,
250  INDOPTION_NULLS_FIRST, 0, &res))
251  PG_RETURN_BOOL(res);
252  PG_RETURN_NULL();
253 
254  case AMPROP_ORDERABLE:
255  PG_RETURN_BOOL(routine->amcanorder);
256 
258 
259  /*
260  * The conditions for whether a column is distance-orderable
261  * are really up to the AM (at time of writing, only GiST
262  * supports it at all). The planner has its own idea based on
263  * whether it finds an operator with amoppurpose 'o', but
264  * getting there from just the index column type seems like a
265  * lot of work. So instead we expect the AM to handle this in
266  * its amproperty routine. The generic result is to return
267  * false if the AM says it never supports this, and null
268  * otherwise (meaning we don't know).
269  */
270  if (!routine->amcanorderbyop)
271  PG_RETURN_BOOL(false);
272  PG_RETURN_NULL();
273 
274  case AMPROP_RETURNABLE:
275  if (!routine->amcanreturn)
276  PG_RETURN_BOOL(false);
277 
278  /*
279  * If possible, the AM should handle this test in its
280  * amproperty function without opening the rel. But this is
281  * the generic fallback if it does not.
282  */
283  {
284  Relation indexrel = index_open(index_oid, AccessShareLock);
285 
286  res = index_can_return(indexrel, attno);
287  index_close(indexrel, AccessShareLock);
288  }
289 
290  PG_RETURN_BOOL(res);
291 
292  case AMPROP_SEARCH_ARRAY:
293  PG_RETURN_BOOL(routine->amsearcharray);
294 
295  case AMPROP_SEARCH_NULLS:
296  PG_RETURN_BOOL(routine->amsearchnulls);
297 
298  default:
299  PG_RETURN_NULL();
300  }
301  }
302 
303  if (OidIsValid(index_oid))
304  {
305  /*
306  * Handle index-level properties. Currently, these only depend on the
307  * AM, but that might not be true forever, so we make users name an
308  * index not just an AM.
309  */
310  switch (prop)
311  {
312  case AMPROP_CLUSTERABLE:
313  PG_RETURN_BOOL(routine->amclusterable);
314 
315  case AMPROP_INDEX_SCAN:
316  PG_RETURN_BOOL(routine->amgettuple ? true : false);
317 
318  case AMPROP_BITMAP_SCAN:
319  PG_RETURN_BOOL(routine->amgetbitmap ? true : false);
320 
322  PG_RETURN_BOOL(routine->amcanbackward);
323 
324  default:
325  PG_RETURN_NULL();
326  }
327  }
328 
329  /*
330  * Handle AM-level properties (those that control what you can say in
331  * CREATE INDEX).
332  */
333  switch (prop)
334  {
335  case AMPROP_CAN_ORDER:
336  PG_RETURN_BOOL(routine->amcanorder);
337 
338  case AMPROP_CAN_UNIQUE:
339  PG_RETURN_BOOL(routine->amcanunique);
340 
342  PG_RETURN_BOOL(routine->amcanmulticol);
343 
344  case AMPROP_CAN_EXCLUDE:
345  PG_RETURN_BOOL(routine->amgettuple ? true : false);
346 
347  default:
348  PG_RETURN_NULL();
349  }
350 }
static IndexAMProperty lookup_prop_name(const char *name)
Definition: amutils.c:87
#define INDOPTION_NULLS_FIRST
Definition: pg_index.h:100
bool amcanmulticol
Definition: amapi.h:179
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
IndexAMProperty
Definition: amapi.h:34
amgettuple_function amgettuple
Definition: amapi.h:210
bool amcanorderbyop
Definition: amapi.h:173
amproperty_function amproperty
Definition: amapi.h:206
#define AccessShareLock
Definition: lockdefs.h:36
#define OidIsValid(objectId)
Definition: c.h:594
bool index_can_return(Relation indexRelation, int attno)
Definition: indexam.c:784
amgetbitmap_function amgetbitmap
Definition: amapi.h:211
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
bool amcanunique
Definition: amapi.h:177
bool amcanbackward
Definition: amapi.h:175
#define RELKIND_PARTITIONED_INDEX
Definition: pg_class.h:169
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
bool amsearchnulls
Definition: amapi.h:185
static bool test_indoption(Oid relid, int attno, bool guard, int16 iopt_mask, int16 iopt_expect, bool *res)
Definition: amutils.c:113
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
bool amclusterable
Definition: amapi.h:189
bool amsearcharray
Definition: amapi.h:183
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:688
#define INDOPTION_DESC
Definition: pg_index.h:99
bool amcanorder
Definition: amapi.h:171
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define RELKIND_INDEX
Definition: pg_class.h:161
amcanreturn_function amcanreturn
Definition: amapi.h:203
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
#define PG_RETURN_NULL()
Definition: fmgr.h:305

◆ lookup_prop_name()

static IndexAMProperty lookup_prop_name ( const char *  name)
static

Definition at line 87 of file amutils.c.

References AMPROP_UNKNOWN, i, lengthof, pg_strcasecmp(), and am_propname::prop.

Referenced by indexam_property().

88 {
89  int i;
90 
91  for (i = 0; i < lengthof(am_propnames); i++)
92  {
93  if (pg_strcasecmp(am_propnames[i].name, name) == 0)
94  return am_propnames[i].prop;
95  }
96 
97  /* We do not throw an error, so that AMs can define their own properties */
98  return AMPROP_UNKNOWN;
99 }
static const struct am_propname am_propnames[]
Definition: amutils.c:31
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define lengthof(array)
Definition: c.h:618
const char * name
Definition: encode.c:521
int i

◆ pg_index_column_has_property()

Datum pg_index_column_has_property ( PG_FUNCTION_ARGS  )

Definition at line 380 of file amutils.c.

References indexam_property(), InvalidOid, PG_GETARG_INT32, PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_NULL, and text_to_cstring().

381 {
382  Oid relid = PG_GETARG_OID(0);
383  int32 attno = PG_GETARG_INT32(1);
384  char *propname = text_to_cstring(PG_GETARG_TEXT_PP(2));
385 
386  /* Reject attno 0 immediately, so that attno > 0 identifies this case */
387  if (attno <= 0)
388  PG_RETURN_NULL();
389 
390  return indexam_property(fcinfo, propname, InvalidOid, relid, attno);
391 }
#define PG_GETARG_INT32(n)
Definition: fmgr.h:234
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:302
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
static Datum indexam_property(FunctionCallInfo fcinfo, const char *propname, Oid amoid, Oid index_oid, int attno)
Definition: amutils.c:162
#define InvalidOid
Definition: postgres_ext.h:36
char * text_to_cstring(const text *t)
Definition: varlena.c:183
#define PG_RETURN_NULL()
Definition: fmgr.h:305

◆ pg_index_has_property()

Datum pg_index_has_property ( PG_FUNCTION_ARGS  )

Definition at line 368 of file amutils.c.

References indexam_property(), InvalidOid, PG_GETARG_OID, PG_GETARG_TEXT_PP, and text_to_cstring().

369 {
370  Oid relid = PG_GETARG_OID(0);
371  char *propname = text_to_cstring(PG_GETARG_TEXT_PP(1));
372 
373  return indexam_property(fcinfo, propname, InvalidOid, relid, 0);
374 }
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
static Datum indexam_property(FunctionCallInfo fcinfo, const char *propname, Oid amoid, Oid index_oid, int attno)
Definition: amutils.c:162
#define InvalidOid
Definition: postgres_ext.h:36
char * text_to_cstring(const text *t)
Definition: varlena.c:183

◆ pg_indexam_has_property()

Datum pg_indexam_has_property ( PG_FUNCTION_ARGS  )

Definition at line 356 of file amutils.c.

References indexam_property(), InvalidOid, PG_GETARG_OID, PG_GETARG_TEXT_PP, and text_to_cstring().

357 {
358  Oid amoid = PG_GETARG_OID(0);
359  char *propname = text_to_cstring(PG_GETARG_TEXT_PP(1));
360 
361  return indexam_property(fcinfo, propname, amoid, InvalidOid, 0);
362 }
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
static Datum indexam_property(FunctionCallInfo fcinfo, const char *propname, Oid amoid, Oid index_oid, int attno)
Definition: amutils.c:162
#define InvalidOid
Definition: postgres_ext.h:36
char * text_to_cstring(const text *t)
Definition: varlena.c:183

◆ test_indoption()

static bool test_indoption ( Oid  relid,
int  attno,
bool  guard,
int16  iopt_mask,
int16  iopt_expect,
bool res 
)
static

Definition at line 113 of file amutils.c.

References Anum_pg_index_indoption, Assert, DatumGetPointer, GETSTRUCT, HeapTupleIsValid, INDEXRELID, ObjectIdGetDatum, PG_USED_FOR_ASSERTS_ONLY, ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttr(), and int2vector::values.

Referenced by indexam_property().

116 {
117  HeapTuple tuple;
119  Datum datum;
120  bool isnull;
121  int2vector *indoption;
122  int16 indoption_val;
123 
124  if (!guard)
125  {
126  *res = false;
127  return true;
128  }
129 
131  if (!HeapTupleIsValid(tuple))
132  return false;
133  rd_index = (Form_pg_index) GETSTRUCT(tuple);
134 
135  Assert(relid == rd_index->indexrelid);
136  Assert(attno > 0 && attno <= rd_index->indnatts);
137 
138  datum = SysCacheGetAttr(INDEXRELID, tuple,
139  Anum_pg_index_indoption, &isnull);
140  Assert(!isnull);
141 
142  indoption = ((int2vector *) DatumGetPointer(datum));
143  indoption_val = indoption->values[attno - 1];
144 
145  *res = (indoption_val & iopt_mask) == iopt_expect;
146 
147  ReleaseSysCache(tuple);
148 
149  return true;
150 }
signed short int16
Definition: c.h:301
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
Definition: c.h:533
uintptr_t Datum
Definition: postgres.h:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:688
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:541
#define DatumGetPointer(X)
Definition: postgres.h:532
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:123
#define Anum_pg_index_indoption
Definition: pg_index.h:90

Variable Documentation

◆ am_propnames

const struct am_propname am_propnames[]
static

Definition at line 31 of file amutils.c.