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 (HeapTuple tuple, 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 154 of file amutils.c.

References AccessShareLock, IndexAmRoutine::amcanbackward, IndexAmRoutine::amcaninclude, 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_INCLUDE, 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(), INDEXRELID, lookup_prop_name(), ObjectIdGetDatum, OidIsValid, PG_RETURN_BOOL, PG_RETURN_NULL, am_propname::prop, ReleaseSysCache(), RELOID, SearchSysCache1(), and test_indoption().

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

157 {
158  bool res = false;
159  bool isnull = false;
160  int natts = 0;
161  IndexAMProperty prop;
162  IndexAmRoutine *routine;
163 
164  /* Try to convert property name to enum (no error if not known) */
165  prop = lookup_prop_name(propname);
166 
167  /* If we have an index OID, look up the AM, and get # of columns too */
168  if (OidIsValid(index_oid))
169  {
170  HeapTuple tuple;
171  Form_pg_class rd_rel;
172 
173  Assert(!OidIsValid(amoid));
174  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(index_oid));
175  if (!HeapTupleIsValid(tuple))
176  PG_RETURN_NULL();
177  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
178  if (rd_rel->relkind != RELKIND_INDEX &&
179  rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
180  {
181  ReleaseSysCache(tuple);
182  PG_RETURN_NULL();
183  }
184  amoid = rd_rel->relam;
185  natts = rd_rel->relnatts;
186  ReleaseSysCache(tuple);
187  }
188 
189  /*
190  * At this point, either index_oid == InvalidOid or it's a valid index OID.
191  * Also, after this test and the one below, either attno == 0 for
192  * index-wide or AM-wide tests, or it's a valid column number in a valid
193  * index.
194  */
195  if (attno < 0 || attno > natts)
196  PG_RETURN_NULL();
197 
198  /*
199  * Get AM information. If we don't have a valid AM OID, return NULL.
200  */
201  routine = GetIndexAmRoutineByAmId(amoid, true);
202  if (routine == NULL)
203  PG_RETURN_NULL();
204 
205  /*
206  * If there's an AM property routine, give it a chance to override the
207  * generic logic. Proceed if it returns false.
208  */
209  if (routine->amproperty &&
210  routine->amproperty(index_oid, attno, prop, propname,
211  &res, &isnull))
212  {
213  if (isnull)
214  PG_RETURN_NULL();
215  PG_RETURN_BOOL(res);
216  }
217 
218  if (attno > 0)
219  {
220  HeapTuple tuple;
221  Form_pg_index rd_index;
222  bool iskey = true;
223 
224  /*
225  * Handle column-level properties. Many of these need the pg_index row
226  * (which we also need to use to check for nonkey atts) so we fetch
227  * that first.
228  */
229  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
230  if (!HeapTupleIsValid(tuple))
231  PG_RETURN_NULL();
232  rd_index = (Form_pg_index) GETSTRUCT(tuple);
233 
234  Assert(index_oid == rd_index->indexrelid);
235  Assert(attno > 0 && attno <= rd_index->indnatts);
236 
237  isnull = true;
238 
239  /*
240  * If amcaninclude, we might be looking at an attno for a nonkey
241  * column, for which we (generically) assume that most properties are
242  * null.
243  */
244  if (routine->amcaninclude
245  && attno > rd_index->indnkeyatts)
246  iskey = false;
247 
248  switch (prop)
249  {
250  case AMPROP_ASC:
251  if (iskey &&
252  test_indoption(tuple, attno, routine->amcanorder,
253  INDOPTION_DESC, 0, &res))
254  isnull = false;
255  break;
256 
257  case AMPROP_DESC:
258  if (iskey &&
259  test_indoption(tuple, attno, routine->amcanorder,
260  INDOPTION_DESC, INDOPTION_DESC, &res))
261  isnull = false;
262  break;
263 
264  case AMPROP_NULLS_FIRST:
265  if (iskey &&
266  test_indoption(tuple, attno, routine->amcanorder,
267  INDOPTION_NULLS_FIRST, INDOPTION_NULLS_FIRST, &res))
268  isnull = false;
269  break;
270 
271  case AMPROP_NULLS_LAST:
272  if (iskey &&
273  test_indoption(tuple, attno, routine->amcanorder,
274  INDOPTION_NULLS_FIRST, 0, &res))
275  isnull = false;
276  break;
277 
278  case AMPROP_ORDERABLE:
279  /*
280  * generic assumption is that nonkey columns are not orderable
281  */
282  res = iskey ? routine->amcanorder : false;
283  isnull = false;
284  break;
285 
287 
288  /*
289  * The conditions for whether a column is distance-orderable
290  * are really up to the AM (at time of writing, only GiST
291  * supports it at all). The planner has its own idea based on
292  * whether it finds an operator with amoppurpose 'o', but
293  * getting there from just the index column type seems like a
294  * lot of work. So instead we expect the AM to handle this in
295  * its amproperty routine. The generic result is to return
296  * false if the AM says it never supports this, or if this is a
297  * nonkey column, and null otherwise (meaning we don't know).
298  */
299  if (!iskey || !routine->amcanorderbyop)
300  {
301  res = false;
302  isnull = false;
303  }
304  break;
305 
306  case AMPROP_RETURNABLE:
307 
308  /* note that we ignore iskey for this property */
309 
310  isnull = false;
311  res = false;
312 
313  if (routine->amcanreturn)
314  {
315  /*
316  * If possible, the AM should handle this test in its
317  * amproperty function without opening the rel. But this is the
318  * generic fallback if it does not.
319  */
320  Relation indexrel = index_open(index_oid, AccessShareLock);
321 
322  res = index_can_return(indexrel, attno);
323  index_close(indexrel, AccessShareLock);
324  }
325  break;
326 
327  case AMPROP_SEARCH_ARRAY:
328  if (iskey)
329  {
330  res = routine->amsearcharray;
331  isnull = false;
332  }
333  break;
334 
335  case AMPROP_SEARCH_NULLS:
336  if (iskey)
337  {
338  res = routine->amsearchnulls;
339  isnull = false;
340  }
341  break;
342 
343  default:
344  break;
345  }
346 
347  ReleaseSysCache(tuple);
348 
349  if (!isnull)
350  PG_RETURN_BOOL(res);
351  PG_RETURN_NULL();
352  }
353 
354  if (OidIsValid(index_oid))
355  {
356  /*
357  * Handle index-level properties. Currently, these only depend on the
358  * AM, but that might not be true forever, so we make users name an
359  * index not just an AM.
360  */
361  switch (prop)
362  {
363  case AMPROP_CLUSTERABLE:
364  PG_RETURN_BOOL(routine->amclusterable);
365 
366  case AMPROP_INDEX_SCAN:
367  PG_RETURN_BOOL(routine->amgettuple ? true : false);
368 
369  case AMPROP_BITMAP_SCAN:
370  PG_RETURN_BOOL(routine->amgetbitmap ? true : false);
371 
373  PG_RETURN_BOOL(routine->amcanbackward);
374 
375  default:
376  PG_RETURN_NULL();
377  }
378  }
379 
380  /*
381  * Handle AM-level properties (those that control what you can say in
382  * CREATE INDEX).
383  */
384  switch (prop)
385  {
386  case AMPROP_CAN_ORDER:
387  PG_RETURN_BOOL(routine->amcanorder);
388 
389  case AMPROP_CAN_UNIQUE:
390  PG_RETURN_BOOL(routine->amcanunique);
391 
393  PG_RETURN_BOOL(routine->amcanmulticol);
394 
395  case AMPROP_CAN_EXCLUDE:
396  PG_RETURN_BOOL(routine->amgettuple ? true : false);
397 
398  case AMPROP_CAN_INCLUDE:
399  PG_RETURN_BOOL(routine->amcaninclude);
400 
401  default:
402  PG_RETURN_NULL();
403  }
404 }
static IndexAMProperty lookup_prop_name(const char *name)
Definition: amutils.c:90
bool amcanmulticol
Definition: amapi.h:180
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
IndexAMProperty
Definition: amapi.h:34
amgettuple_function amgettuple
Definition: amapi.h:219
bool amcanorderbyop
Definition: amapi.h:174
amproperty_function amproperty
Definition: amapi.h:215
#define AccessShareLock
Definition: lockdefs.h:36
#define OidIsValid(objectId)
Definition: c.h:605
bool index_can_return(Relation indexRelation, int attno)
Definition: indexam.c:783
amgetbitmap_function amgetbitmap
Definition: amapi.h:220
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
bool amcaninclude
Definition: amapi.h:196
bool amcanunique
Definition: amapi.h:178
bool amcanbackward
Definition: amapi.h:176
static bool test_indoption(HeapTuple tuple, int attno, bool guard, int16 iopt_mask, int16 iopt_expect, bool *res)
Definition: amutils.c:117
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
bool amsearchnulls
Definition: amapi.h:186
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:324
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
bool amclusterable
Definition: amapi.h:190
bool amsearcharray
Definition: amapi.h:184
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
bool amcanorder
Definition: amapi.h:172
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
amcanreturn_function amcanreturn
Definition: amapi.h:212
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
#define PG_RETURN_NULL()
Definition: fmgr.h:310

◆ lookup_prop_name()

static IndexAMProperty lookup_prop_name ( const char *  name)
static

Definition at line 90 of file amutils.c.

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

Referenced by indexam_property().

91 {
92  int i;
93 
94  for (i = 0; i < lengthof(am_propnames); i++)
95  {
96  if (pg_strcasecmp(am_propnames[i].name, name) == 0)
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 }
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:629
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 434 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().

435 {
436  Oid relid = PG_GETARG_OID(0);
437  int32 attno = PG_GETARG_INT32(1);
438  char *propname = text_to_cstring(PG_GETARG_TEXT_PP(2));
439 
440  /* Reject attno 0 immediately, so that attno > 0 identifies this case */
441  if (attno <= 0)
442  PG_RETURN_NULL();
443 
444  return indexam_property(fcinfo, propname, InvalidOid, relid, attno);
445 }
#define PG_GETARG_INT32(n)
Definition: fmgr.h:239
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:313
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:278
#define PG_GETARG_OID(n)
Definition: fmgr.h:245
static Datum indexam_property(FunctionCallInfo fcinfo, const char *propname, Oid amoid, Oid index_oid, int attno)
Definition: amutils.c:154
#define InvalidOid
Definition: postgres_ext.h:36
char * text_to_cstring(const text *t)
Definition: varlena.c:182
#define PG_RETURN_NULL()
Definition: fmgr.h:310

◆ pg_index_has_property()

Datum pg_index_has_property ( PG_FUNCTION_ARGS  )

Definition at line 422 of file amutils.c.

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

423 {
424  Oid relid = PG_GETARG_OID(0);
425  char *propname = text_to_cstring(PG_GETARG_TEXT_PP(1));
426 
427  return indexam_property(fcinfo, propname, InvalidOid, relid, 0);
428 }
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:278
#define PG_GETARG_OID(n)
Definition: fmgr.h:245
static Datum indexam_property(FunctionCallInfo fcinfo, const char *propname, Oid amoid, Oid index_oid, int attno)
Definition: amutils.c:154
#define InvalidOid
Definition: postgres_ext.h:36
char * text_to_cstring(const text *t)
Definition: varlena.c:182

◆ pg_indexam_has_property()

Datum pg_indexam_has_property ( PG_FUNCTION_ARGS  )

Definition at line 410 of file amutils.c.

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

411 {
412  Oid amoid = PG_GETARG_OID(0);
413  char *propname = text_to_cstring(PG_GETARG_TEXT_PP(1));
414 
415  return indexam_property(fcinfo, propname, amoid, InvalidOid, 0);
416 }
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:278
#define PG_GETARG_OID(n)
Definition: fmgr.h:245
static Datum indexam_property(FunctionCallInfo fcinfo, const char *propname, Oid amoid, Oid index_oid, int attno)
Definition: amutils.c:154
#define InvalidOid
Definition: postgres_ext.h:36
char * text_to_cstring(const text *t)
Definition: varlena.c:182

◆ test_indoption()

static bool test_indoption ( HeapTuple  tuple,
int  attno,
bool  guard,
int16  iopt_mask,
int16  iopt_expect,
bool res 
)
static

Definition at line 117 of file amutils.c.

References Assert, DatumGetPointer, INDEXRELID, SysCacheGetAttr(), and int2vector::values.

Referenced by indexam_property().

120 {
121  Datum datum;
122  bool isnull;
123  int2vector *indoption;
124  int16 indoption_val;
125 
126  if (!guard)
127  {
128  *res = false;
129  return true;
130  }
131 
132  datum = SysCacheGetAttr(INDEXRELID, tuple,
133  Anum_pg_index_indoption, &isnull);
134  Assert(!isnull);
135 
136  indoption = ((int2vector *) DatumGetPointer(datum));
137  indoption_val = indoption->values[attno - 1];
138 
139  *res = (indoption_val & iopt_mask) == iopt_expect;
140 
141  return true;
142 }
signed short int16
Definition: c.h:312
Definition: c.h:544
uintptr_t Datum
Definition: postgres.h:365
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
#define Assert(condition)
Definition: c.h:699
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:552
#define DatumGetPointer(X)
Definition: postgres.h:532

Variable Documentation

◆ am_propnames

const struct am_propname am_propnames[]
static

Definition at line 31 of file amutils.c.