PostgreSQL Source Code  git master
nbtutils.c File Reference
#include "postgres.h"
#include <time.h>
#include "access/nbtree.h"
#include "access/reloptions.h"
#include "access/relscan.h"
#include "commands/progress.h"
#include "lib/qunique.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for nbtutils.c:

Go to the source code of this file.

Data Structures

struct  BTSortArrayContext
 
struct  BTOneVacInfo
 
struct  BTVacInfo
 

Typedefs

typedef struct BTSortArrayContext BTSortArrayContext
 
typedef struct BTOneVacInfo BTOneVacInfo
 
typedef struct BTVacInfo BTVacInfo
 

Functions

static Datum _bt_find_extreme_element (IndexScanDesc scan, ScanKey skey, StrategyNumber strat, Datum *elems, int nelems)
 
static int _bt_sort_array_elements (IndexScanDesc scan, ScanKey skey, bool reverse, Datum *elems, int nelems)
 
static int _bt_compare_array_elements (const void *a, const void *b, void *arg)
 
static bool _bt_compare_scankey_args (IndexScanDesc scan, ScanKey op, ScanKey leftarg, ScanKey rightarg, bool *result)
 
static bool _bt_fix_scankey_strategy (ScanKey skey, int16 *indoption)
 
static void _bt_mark_scankey_required (ScanKey skey)
 
static bool _bt_check_rowcompare (ScanKey skey, IndexTuple tuple, int tupnatts, TupleDesc tupdesc, ScanDirection dir, bool *continuescan)
 
static int _bt_keep_natts (Relation rel, IndexTuple lastleft, IndexTuple firstright, BTScanInsert itup_key)
 
BTScanInsert _bt_mkscankey (Relation rel, IndexTuple itup)
 
void _bt_freestack (BTStack stack)
 
void _bt_preprocess_array_keys (IndexScanDesc scan)
 
void _bt_start_array_keys (IndexScanDesc scan, ScanDirection dir)
 
bool _bt_advance_array_keys (IndexScanDesc scan, ScanDirection dir)
 
void _bt_mark_array_keys (IndexScanDesc scan)
 
void _bt_restore_array_keys (IndexScanDesc scan)
 
void _bt_preprocess_keys (IndexScanDesc scan)
 
bool _bt_checkkeys (IndexScanDesc scan, IndexTuple tuple, int tupnatts, ScanDirection dir, bool *continuescan)
 
void _bt_killitems (IndexScanDesc scan)
 
BTCycleId _bt_vacuum_cycleid (Relation rel)
 
BTCycleId _bt_start_vacuum (Relation rel)
 
void _bt_end_vacuum (Relation rel)
 
void _bt_end_vacuum_callback (int code, Datum arg)
 
Size BTreeShmemSize (void)
 
void BTreeShmemInit (void)
 
byteabtoptions (Datum reloptions, bool validate)
 
bool btproperty (Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
 
char * btbuildphasename (int64 phasenum)
 
IndexTuple _bt_truncate (Relation rel, IndexTuple lastleft, IndexTuple firstright, BTScanInsert itup_key)
 
int _bt_keep_natts_fast (Relation rel, IndexTuple lastleft, IndexTuple firstright)
 
bool _bt_check_natts (Relation rel, bool heapkeyspace, Page page, OffsetNumber offnum)
 
void _bt_check_third_page (Relation rel, Relation heap, bool needheaptidspace, Page page, IndexTuple newtup)
 

Variables

static BTVacInfobtvacinfo
 

Typedef Documentation

◆ BTOneVacInfo

typedef struct BTOneVacInfo BTOneVacInfo

◆ BTSortArrayContext

◆ BTVacInfo

typedef struct BTVacInfo BTVacInfo

Function Documentation

◆ _bt_advance_array_keys()

bool _bt_advance_array_keys ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 533 of file nbtutils.c.

References _bt_parallel_advance_array_keys(), BTScanOpaqueData::arrayKeyData, BTScanOpaqueData::arrayKeys, BTArrayKeyInfo::cur_elem, BTArrayKeyInfo::elem_values, i, BTArrayKeyInfo::num_elems, BTScanOpaqueData::numArrayKeys, IndexScanDescData::opaque, IndexScanDescData::parallel_scan, BTArrayKeyInfo::scan_key, ScanDirectionIsBackward, and ScanKeyData::sk_argument.

Referenced by btgetbitmap(), and btgettuple().

534 {
535  BTScanOpaque so = (BTScanOpaque) scan->opaque;
536  bool found = false;
537  int i;
538 
539  /*
540  * We must advance the last array key most quickly, since it will
541  * correspond to the lowest-order index column among the available
542  * qualifications. This is necessary to ensure correct ordering of output
543  * when there are multiple array keys.
544  */
545  for (i = so->numArrayKeys - 1; i >= 0; i--)
546  {
547  BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
548  ScanKey skey = &so->arrayKeyData[curArrayKey->scan_key];
549  int cur_elem = curArrayKey->cur_elem;
550  int num_elems = curArrayKey->num_elems;
551 
552  if (ScanDirectionIsBackward(dir))
553  {
554  if (--cur_elem < 0)
555  {
556  cur_elem = num_elems - 1;
557  found = false; /* need to advance next array key */
558  }
559  else
560  found = true;
561  }
562  else
563  {
564  if (++cur_elem >= num_elems)
565  {
566  cur_elem = 0;
567  found = false; /* need to advance next array key */
568  }
569  else
570  found = true;
571  }
572 
573  curArrayKey->cur_elem = cur_elem;
574  skey->sk_argument = curArrayKey->elem_values[cur_elem];
575  if (found)
576  break;
577  }
578 
579  /* advance parallel scan */
580  if (scan->parallel_scan != NULL)
582 
583  return found;
584 }
Datum * elem_values
Definition: nbtree.h:626
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:671
int cur_elem
Definition: nbtree.h:623
int numArrayKeys
Definition: nbtree.h:638
ScanKey arrayKeyData
Definition: nbtree.h:637
struct ParallelIndexScanDescData * parallel_scan
Definition: relscan.h:151
int num_elems
Definition: nbtree.h:625
void _bt_parallel_advance_array_keys(IndexScanDesc scan)
Definition: nbtree.c:763
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:642
int i
Datum sk_argument
Definition: skey.h:72
int scan_key
Definition: nbtree.h:622

◆ _bt_check_natts()

bool _bt_check_natts ( Relation  rel,
bool  heapkeyspace,
Page  page,
OffsetNumber  offnum 
)

Definition at line 2373 of file nbtutils.c.

References Assert, BT_N_KEYS_OFFSET_MASK, BTreeTupleGetHeapTID, BTreeTupleGetNAtts, FirstOffsetNumber, INDEX_ALT_TID_MASK, INDEX_MAX_KEYS, IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, ItemPointerGetOffsetNumber, P_FIRSTDATAKEY, P_HIKEY, P_IGNORE, P_ISLEAF, P_RIGHTMOST, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetSpecialPointer, StaticAssertStmt, IndexTupleData::t_info, and IndexTupleData::t_tid.

Referenced by _bt_compare(), and bt_target_page_check().

2374 {
2378  IndexTuple itup;
2379  int tupnatts;
2380 
2381  /*
2382  * We cannot reliably test a deleted or half-dead page, since they have
2383  * dummy high keys
2384  */
2385  if (P_IGNORE(opaque))
2386  return true;
2387 
2388  Assert(offnum >= FirstOffsetNumber &&
2389  offnum <= PageGetMaxOffsetNumber(page));
2390 
2391  /*
2392  * Mask allocated for number of keys in index tuple must be able to fit
2393  * maximum possible number of index attributes
2394  */
2396  "BT_N_KEYS_OFFSET_MASK can't fit INDEX_MAX_KEYS");
2397 
2398  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
2399  tupnatts = BTreeTupleGetNAtts(itup, rel);
2400 
2401  if (P_ISLEAF(opaque))
2402  {
2403  if (offnum >= P_FIRSTDATAKEY(opaque))
2404  {
2405  /*
2406  * Non-pivot tuples currently never use alternative heap TID
2407  * representation -- even those within heapkeyspace indexes
2408  */
2409  if ((itup->t_info & INDEX_ALT_TID_MASK) != 0)
2410  return false;
2411 
2412  /*
2413  * Leaf tuples that are not the page high key (non-pivot tuples)
2414  * should never be truncated. (Note that tupnatts must have been
2415  * inferred, rather than coming from an explicit on-disk
2416  * representation.)
2417  */
2418  return tupnatts == natts;
2419  }
2420  else
2421  {
2422  /*
2423  * Rightmost page doesn't contain a page high key, so tuple was
2424  * checked above as ordinary leaf tuple
2425  */
2426  Assert(!P_RIGHTMOST(opaque));
2427 
2428  /*
2429  * !heapkeyspace high key tuple contains only key attributes. Note
2430  * that tupnatts will only have been explicitly represented in
2431  * !heapkeyspace indexes that happen to have non-key attributes.
2432  */
2433  if (!heapkeyspace)
2434  return tupnatts == nkeyatts;
2435 
2436  /* Use generic heapkeyspace pivot tuple handling */
2437  }
2438  }
2439  else /* !P_ISLEAF(opaque) */
2440  {
2441  if (offnum == P_FIRSTDATAKEY(opaque))
2442  {
2443  /*
2444  * The first tuple on any internal page (possibly the first after
2445  * its high key) is its negative infinity tuple. Negative
2446  * infinity tuples are always truncated to zero attributes. They
2447  * are a particular kind of pivot tuple.
2448  */
2449  if (heapkeyspace)
2450  return tupnatts == 0;
2451 
2452  /*
2453  * The number of attributes won't be explicitly represented if the
2454  * negative infinity tuple was generated during a page split that
2455  * occurred with a version of Postgres before v11. There must be
2456  * a problem when there is an explicit representation that is
2457  * non-zero, or when there is no explicit representation and the
2458  * tuple is evidently not a pre-pg_upgrade tuple.
2459  *
2460  * Prior to v11, downlinks always had P_HIKEY as their offset. Use
2461  * that to decide if the tuple is a pre-v11 tuple.
2462  */
2463  return tupnatts == 0 ||
2464  ((itup->t_info & INDEX_ALT_TID_MASK) == 0 &&
2466  }
2467  else
2468  {
2469  /*
2470  * !heapkeyspace downlink tuple with separator key contains only
2471  * key attributes. Note that tupnatts will only have been
2472  * explicitly represented in !heapkeyspace indexes that happen to
2473  * have non-key attributes.
2474  */
2475  if (!heapkeyspace)
2476  return tupnatts == nkeyatts;
2477 
2478  /* Use generic heapkeyspace pivot tuple handling */
2479  }
2480 
2481  }
2482 
2483  /* Handle heapkeyspace pivot tuples (excluding minus infinity items) */
2484  Assert(heapkeyspace);
2485 
2486  /*
2487  * Explicit representation of the number of attributes is mandatory with
2488  * heapkeyspace index pivot tuples, regardless of whether or not there are
2489  * non-key attributes.
2490  */
2491  if ((itup->t_info & INDEX_ALT_TID_MASK) == 0)
2492  return false;
2493 
2494  /*
2495  * Heap TID is a tiebreaker key attribute, so it cannot be untruncated
2496  * when any other key attribute is truncated
2497  */
2498  if (BTreeTupleGetHeapTID(itup) != NULL && tupnatts != nkeyatts)
2499  return false;
2500 
2501  /*
2502  * Pivot tuple must have at least one untruncated key attribute (minus
2503  * infinity pivot tuples are the only exception). Pivot tuples can never
2504  * represent that there is a value present for a key attribute that
2505  * exceeds pg_index.indnkeyatts for the index.
2506  */
2507  return tupnatts > 0 && tupnatts <= nkeyatts;
2508 }
signed short int16
Definition: c.h:346
#define P_IGNORE(opaque)
Definition: nbtree.h:195
#define P_FIRSTDATAKEY(opaque)
Definition: nbtree.h:220
ItemPointerData t_tid
Definition: itup.h:37
#define BTreeTupleGetHeapTID(itup)
Definition: nbtree.h:347
#define BTreeTupleGetNAtts(itup, rel)
Definition: nbtree.h:328
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:69
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:849
#define INDEX_ALT_TID_MASK
Definition: nbtree.h:294
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:434
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:441
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define Assert(condition)
Definition: c.h:739
#define INDEX_MAX_KEYS
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define BT_N_KEYS_OFFSET_MASK
Definition: nbtree.h:298
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define P_HIKEY
Definition: nbtree.h:218
unsigned short t_info
Definition: itup.h:49
#define P_RIGHTMOST(opaque)
Definition: nbtree.h:189
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
#define P_ISLEAF(opaque)
Definition: nbtree.h:190

◆ _bt_check_rowcompare()

static bool _bt_check_rowcompare ( ScanKey  skey,
IndexTuple  tuple,
int  tupnatts,
TupleDesc  tupdesc,
ScanDirection  dir,
bool continuescan 
)
static

Definition at line 1510 of file nbtutils.c.

References Assert, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, DatumGetInt32, DatumGetPointer, elog, ERROR, FunctionCall2Coll(), index_getattr, INVERT_COMPARE_RESULT, ScanDirectionIsBackward, ScanDirectionIsForward, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_DESC, SK_BT_NULLS_FIRST, SK_BT_REQBKWD, SK_BT_REQFWD, ScanKeyData::sk_collation, ScanKeyData::sk_flags, ScanKeyData::sk_func, SK_ISNULL, SK_ROW_END, SK_ROW_MEMBER, and ScanKeyData::sk_strategy.

Referenced by _bt_checkkeys().

1512 {
1513  ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
1514  int32 cmpresult = 0;
1515  bool result;
1516 
1517  /* First subkey should be same as the header says */
1518  Assert(subkey->sk_attno == skey->sk_attno);
1519 
1520  /* Loop over columns of the row condition */
1521  for (;;)
1522  {
1523  Datum datum;
1524  bool isNull;
1525 
1526  Assert(subkey->sk_flags & SK_ROW_MEMBER);
1527 
1528  if (subkey->sk_attno > tupnatts)
1529  {
1530  /*
1531  * This attribute is truncated (must be high key). The value for
1532  * this attribute in the first non-pivot tuple on the page to the
1533  * right could be any possible value. Assume that truncated
1534  * attribute passes the qual.
1535  */
1537  cmpresult = 0;
1538  if (subkey->sk_flags & SK_ROW_END)
1539  break;
1540  subkey++;
1541  continue;
1542  }
1543 
1544  datum = index_getattr(tuple,
1545  subkey->sk_attno,
1546  tupdesc,
1547  &isNull);
1548 
1549  if (isNull)
1550  {
1551  if (subkey->sk_flags & SK_BT_NULLS_FIRST)
1552  {
1553  /*
1554  * Since NULLs are sorted before non-NULLs, we know we have
1555  * reached the lower limit of the range of values for this
1556  * index attr. On a backward scan, we can stop if this qual
1557  * is one of the "must match" subset. We can stop regardless
1558  * of whether the qual is > or <, so long as it's required,
1559  * because it's not possible for any future tuples to pass. On
1560  * a forward scan, however, we must keep going, because we may
1561  * have initially positioned to the start of the index.
1562  */
1563  if ((subkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)) &&
1565  *continuescan = false;
1566  }
1567  else
1568  {
1569  /*
1570  * Since NULLs are sorted after non-NULLs, we know we have
1571  * reached the upper limit of the range of values for this
1572  * index attr. On a forward scan, we can stop if this qual is
1573  * one of the "must match" subset. We can stop regardless of
1574  * whether the qual is > or <, so long as it's required,
1575  * because it's not possible for any future tuples to pass. On
1576  * a backward scan, however, we must keep going, because we
1577  * may have initially positioned to the end of the index.
1578  */
1579  if ((subkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)) &&
1581  *continuescan = false;
1582  }
1583 
1584  /*
1585  * In any case, this indextuple doesn't match the qual.
1586  */
1587  return false;
1588  }
1589 
1590  if (subkey->sk_flags & SK_ISNULL)
1591  {
1592  /*
1593  * Unlike the simple-scankey case, this isn't a disallowed case.
1594  * But it can never match. If all the earlier row comparison
1595  * columns are required for the scan direction, we can stop the
1596  * scan, because there can't be another tuple that will succeed.
1597  */
1598  if (subkey != (ScanKey) DatumGetPointer(skey->sk_argument))
1599  subkey--;
1600  if ((subkey->sk_flags & SK_BT_REQFWD) &&
1602  *continuescan = false;
1603  else if ((subkey->sk_flags & SK_BT_REQBKWD) &&
1605  *continuescan = false;
1606  return false;
1607  }
1608 
1609  /* Perform the test --- three-way comparison not bool operator */
1610  cmpresult = DatumGetInt32(FunctionCall2Coll(&subkey->sk_func,
1611  subkey->sk_collation,
1612  datum,
1613  subkey->sk_argument));
1614 
1615  if (subkey->sk_flags & SK_BT_DESC)
1616  INVERT_COMPARE_RESULT(cmpresult);
1617 
1618  /* Done comparing if unequal, else advance to next column */
1619  if (cmpresult != 0)
1620  break;
1621 
1622  if (subkey->sk_flags & SK_ROW_END)
1623  break;
1624  subkey++;
1625  }
1626 
1627  /*
1628  * At this point cmpresult indicates the overall result of the row
1629  * comparison, and subkey points to the deciding column (or the last
1630  * column if the result is "=").
1631  */
1632  switch (subkey->sk_strategy)
1633  {
1634  /* EQ and NE cases aren't allowed here */
1635  case BTLessStrategyNumber:
1636  result = (cmpresult < 0);
1637  break;
1639  result = (cmpresult <= 0);
1640  break;
1642  result = (cmpresult >= 0);
1643  break;
1645  result = (cmpresult > 0);
1646  break;
1647  default:
1648  elog(ERROR, "unrecognized RowCompareType: %d",
1649  (int) subkey->sk_strategy);
1650  result = 0; /* keep compiler quiet */
1651  break;
1652  }
1653 
1654  if (!result)
1655  {
1656  /*
1657  * Tuple fails this qual. If it's a required qual for the current
1658  * scan direction, then we can conclude no further tuples will pass,
1659  * either. Note we have to look at the deciding column, not
1660  * necessarily the first or last column of the row condition.
1661  */
1662  if ((subkey->sk_flags & SK_BT_REQFWD) &&
1664  *continuescan = false;
1665  else if ((subkey->sk_flags & SK_BT_REQBKWD) &&
1667  *continuescan = false;
1668  }
1669 
1670  return result;
1671 }
#define SK_ROW_MEMBER
Definition: skey.h:118
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
#define DatumGetInt32(X)
Definition: postgres.h:472
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
signed int int32
Definition: c.h:347
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
#define SK_ROW_END
Definition: skey.h:119
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
#define ERROR
Definition: elog.h:43
StrategyNumber sk_strategy
Definition: skey.h:68
ScanKeyData * ScanKey
Definition: skey.h:75
FmgrInfo sk_func
Definition: skey.h:71
#define SK_ISNULL
Definition: skey.h:115
#define SK_BT_NULLS_FIRST
Definition: nbtree.h:682
uintptr_t Datum
Definition: postgres.h:367
#define SK_BT_REQFWD
Definition: nbtree.h:678
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:739
#define SK_BT_DESC
Definition: nbtree.h:681
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
#define DatumGetPointer(X)
Definition: postgres.h:549
Oid sk_collation
Definition: skey.h:70
#define elog(elevel,...)
Definition: elog.h:228
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define SK_BT_REQBKWD
Definition: nbtree.h:679
Datum sk_argument
Definition: skey.h:72
#define INVERT_COMPARE_RESULT(var)
Definition: c.h:1075
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
AttrNumber sk_attno
Definition: skey.h:67

◆ _bt_check_third_page()

void _bt_check_third_page ( Relation  rel,
Relation  heap,
bool  needheaptidspace,
Page  page,
IndexTuple  newtup 
)

Definition at line 2523 of file nbtutils.c.

References BTMaxItemSize, BTMaxItemSizeNoHeapTid, BTREE_NOVAC_VERSION, BTREE_VERSION, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, errtableconstraint(), IndexTupleSize, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, MAXALIGN, P_ISLEAF, PageGetSpecialPointer, RelationGetRelationName, and IndexTupleData::t_tid.

Referenced by _bt_buildadd(), and _bt_findinsertloc().

2525 {
2526  Size itemsz;
2527  BTPageOpaque opaque;
2528 
2529  itemsz = MAXALIGN(IndexTupleSize(newtup));
2530 
2531  /* Double check item size against limit */
2532  if (itemsz <= BTMaxItemSize(page))
2533  return;
2534 
2535  /*
2536  * Tuple is probably too large to fit on page, but it's possible that the
2537  * index uses version 2 or version 3, or that page is an internal page, in
2538  * which case a slightly higher limit applies.
2539  */
2540  if (!needheaptidspace && itemsz <= BTMaxItemSizeNoHeapTid(page))
2541  return;
2542 
2543  /*
2544  * Internal page insertions cannot fail here, because that would mean that
2545  * an earlier leaf level insertion that should have failed didn't
2546  */
2547  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
2548  if (!P_ISLEAF(opaque))
2549  elog(ERROR, "cannot insert oversized tuple of size %zu on internal page of index \"%s\"",
2550  itemsz, RelationGetRelationName(rel));
2551 
2552  ereport(ERROR,
2553  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2554  errmsg("index row size %zu exceeds btree version %u maximum %zu for index \"%s\"",
2555  itemsz,
2556  needheaptidspace ? BTREE_VERSION : BTREE_NOVAC_VERSION,
2557  needheaptidspace ? BTMaxItemSize(page) :
2558  BTMaxItemSizeNoHeapTid(page),
2560  errdetail("Index row references tuple (%u,%u) in relation \"%s\".",
2561  ItemPointerGetBlockNumber(&newtup->t_tid),
2563  RelationGetRelationName(heap)),
2564  errhint("Values larger than 1/3 of a buffer page cannot be indexed.\n"
2565  "Consider a function index of an MD5 hash of the value, "
2566  "or use full text indexing."),
2568 }
int errhint(const char *fmt,...)
Definition: elog.c:1069
#define BTREE_VERSION
Definition: nbtree.h:134
ItemPointerData t_tid
Definition: itup.h:37
#define BTMaxItemSizeNoHeapTid(page)
Definition: nbtree.h:154
int errcode(int sqlerrcode)
Definition: elog.c:608
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:69
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:5272
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:955
#define RelationGetRelationName(relation)
Definition: rel.h:456
#define BTREE_NOVAC_VERSION
Definition: nbtree.h:136
#define ereport(elevel, rest)
Definition: elog.h:141
size_t Size
Definition: c.h:467
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define MAXALIGN(LEN)
Definition: c.h:692
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define BTMaxItemSize(page)
Definition: nbtree.h:148
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define IndexTupleSize(itup)
Definition: itup.h:71
#define P_ISLEAF(opaque)
Definition: nbtree.h:190

◆ _bt_checkkeys()

bool _bt_checkkeys ( IndexScanDesc  scan,
IndexTuple  tuple,
int  tupnatts,
ScanDirection  dir,
bool continuescan 
)

Definition at line 1344 of file nbtutils.c.

References _bt_check_rowcompare(), Assert, BTreeTupleGetNAtts, DatumGetBool, FunctionCall2Coll(), index_getattr, IndexScanDescData::indexRelation, sort-test::key, BTScanOpaqueData::keyData, BTScanOpaqueData::numberOfKeys, IndexScanDescData::opaque, RelationGetDescr, ScanDirectionIsBackward, ScanDirectionIsForward, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_NULLS_FIRST, SK_BT_REQBKWD, SK_BT_REQFWD, ScanKeyData::sk_collation, ScanKeyData::sk_flags, ScanKeyData::sk_func, SK_ISNULL, SK_ROW_HEADER, SK_SEARCHNOTNULL, SK_SEARCHNULL, and test().

Referenced by _bt_readpage().

1346 {
1347  TupleDesc tupdesc;
1348  BTScanOpaque so;
1349  int keysz;
1350  int ikey;
1351  ScanKey key;
1352 
1353  Assert(BTreeTupleGetNAtts(tuple, scan->indexRelation) == tupnatts);
1354 
1355  *continuescan = true; /* default assumption */
1356 
1357  tupdesc = RelationGetDescr(scan->indexRelation);
1358  so = (BTScanOpaque) scan->opaque;
1359  keysz = so->numberOfKeys;
1360 
1361  for (key = so->keyData, ikey = 0; ikey < keysz; key++, ikey++)
1362  {
1363  Datum datum;
1364  bool isNull;
1365  Datum test;
1366 
1367  if (key->sk_attno > tupnatts)
1368  {
1369  /*
1370  * This attribute is truncated (must be high key). The value for
1371  * this attribute in the first non-pivot tuple on the page to the
1372  * right could be any possible value. Assume that truncated
1373  * attribute passes the qual.
1374  */
1376  continue;
1377  }
1378 
1379  /* row-comparison keys need special processing */
1380  if (key->sk_flags & SK_ROW_HEADER)
1381  {
1382  if (_bt_check_rowcompare(key, tuple, tupnatts, tupdesc, dir,
1383  continuescan))
1384  continue;
1385  return false;
1386  }
1387 
1388  datum = index_getattr(tuple,
1389  key->sk_attno,
1390  tupdesc,
1391  &isNull);
1392 
1393  if (key->sk_flags & SK_ISNULL)
1394  {
1395  /* Handle IS NULL/NOT NULL tests */
1396  if (key->sk_flags & SK_SEARCHNULL)
1397  {
1398  if (isNull)
1399  continue; /* tuple satisfies this qual */
1400  }
1401  else
1402  {
1404  if (!isNull)
1405  continue; /* tuple satisfies this qual */
1406  }
1407 
1408  /*
1409  * Tuple fails this qual. If it's a required qual for the current
1410  * scan direction, then we can conclude no further tuples will
1411  * pass, either.
1412  */
1413  if ((key->sk_flags & SK_BT_REQFWD) &&
1415  *continuescan = false;
1416  else if ((key->sk_flags & SK_BT_REQBKWD) &&
1418  *continuescan = false;
1419 
1420  /*
1421  * In any case, this indextuple doesn't match the qual.
1422  */
1423  return false;
1424  }
1425 
1426  if (isNull)
1427  {
1428  if (key->sk_flags & SK_BT_NULLS_FIRST)
1429  {
1430  /*
1431  * Since NULLs are sorted before non-NULLs, we know we have
1432  * reached the lower limit of the range of values for this
1433  * index attr. On a backward scan, we can stop if this qual
1434  * is one of the "must match" subset. We can stop regardless
1435  * of whether the qual is > or <, so long as it's required,
1436  * because it's not possible for any future tuples to pass. On
1437  * a forward scan, however, we must keep going, because we may
1438  * have initially positioned to the start of the index.
1439  */
1440  if ((key->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)) &&
1442  *continuescan = false;
1443  }
1444  else
1445  {
1446  /*
1447  * Since NULLs are sorted after non-NULLs, we know we have
1448  * reached the upper limit of the range of values for this
1449  * index attr. On a forward scan, we can stop if this qual is
1450  * one of the "must match" subset. We can stop regardless of
1451  * whether the qual is > or <, so long as it's required,
1452  * because it's not possible for any future tuples to pass. On
1453  * a backward scan, however, we must keep going, because we
1454  * may have initially positioned to the end of the index.
1455  */
1456  if ((key->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)) &&
1458  *continuescan = false;
1459  }
1460 
1461  /*
1462  * In any case, this indextuple doesn't match the qual.
1463  */
1464  return false;
1465  }
1466 
1467  test = FunctionCall2Coll(&key->sk_func, key->sk_collation,
1468  datum, key->sk_argument);
1469 
1470  if (!DatumGetBool(test))
1471  {
1472  /*
1473  * Tuple fails this qual. If it's a required qual for the current
1474  * scan direction, then we can conclude no further tuples will
1475  * pass, either.
1476  *
1477  * Note: because we stop the scan as soon as any required equality
1478  * qual fails, it is critical that equality quals be used for the
1479  * initial positioning in _bt_first() when they are available. See
1480  * comments in _bt_first().
1481  */
1482  if ((key->sk_flags & SK_BT_REQFWD) &&
1484  *continuescan = false;
1485  else if ((key->sk_flags & SK_BT_REQBKWD) &&
1487  *continuescan = false;
1488 
1489  /*
1490  * In any case, this indextuple doesn't match the qual.
1491  */
1492  return false;
1493  }
1494  }
1495 
1496  /* If we get here, the tuple passes all index quals. */
1497  return true;
1498 }
static void test(void)
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
#define RelationGetDescr(relation)
Definition: rel.h:448
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
#define BTreeTupleGetNAtts(itup, rel)
Definition: nbtree.h:328
Relation indexRelation
Definition: relscan.h:103
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:671
FmgrInfo sk_func
Definition: skey.h:71
#define DatumGetBool(X)
Definition: postgres.h:393
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_ISNULL
Definition: skey.h:115
#define SK_ROW_HEADER
Definition: skey.h:117
#define SK_BT_NULLS_FIRST
Definition: nbtree.h:682
uintptr_t Datum
Definition: postgres.h:367
static bool _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, int tupnatts, TupleDesc tupdesc, ScanDirection dir, bool *continuescan)
Definition: nbtutils.c:1510
#define SK_BT_REQFWD
Definition: nbtree.h:678
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:739
int numberOfKeys
Definition: nbtree.h:633
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
ScanKey keyData
Definition: nbtree.h:634
Oid sk_collation
Definition: skey.h:70
#define SK_BT_REQBKWD
Definition: nbtree.h:679
Datum sk_argument
Definition: skey.h:72
#define SK_SEARCHNULL
Definition: skey.h:121
AttrNumber sk_attno
Definition: skey.h:67

◆ _bt_compare_array_elements()

static int _bt_compare_array_elements ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 485 of file nbtutils.c.

References BTSortArrayContext::collation, compare(), DatumGetInt32, BTSortArrayContext::flinfo, FunctionCall2Coll(), INVERT_COMPARE_RESULT, and BTSortArrayContext::reverse.

Referenced by _bt_sort_array_elements().

486 {
487  Datum da = *((const Datum *) a);
488  Datum db = *((const Datum *) b);
490  int32 compare;
491 
492  compare = DatumGetInt32(FunctionCall2Coll(&cxt->flinfo,
493  cxt->collation,
494  da, db));
495  if (cxt->reverse)
496  INVERT_COMPARE_RESULT(compare);
497  return compare;
498 }
#define DatumGetInt32(X)
Definition: postgres.h:472
FmgrInfo flinfo
Definition: nbtutils.c:35
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
signed int int32
Definition: c.h:347
static int compare(const void *arg1, const void *arg2)
Definition: geqo_pool.c:145
uintptr_t Datum
Definition: postgres.h:367
void * arg
#define INVERT_COMPARE_RESULT(var)
Definition: c.h:1075

◆ _bt_compare_scankey_args()

static bool _bt_compare_scankey_args ( IndexScanDesc  scan,
ScanKey  op,
ScanKey  leftarg,
ScanKey  rightarg,
bool result 
)
static

Definition at line 1021 of file nbtutils.c.

References Assert, BTCommuteStrategyNumber, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, DatumGetBool, elog, ERROR, FunctionCall2Coll(), get_opcode(), get_opfamily_member(), IndexScanDescData::indexRelation, InvalidOid, OidFunctionCall2Coll(), OidIsValid, RelationData::rd_opcintype, RelationData::rd_opfamily, RegProcedureIsValid, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_DESC, SK_BT_NULLS_FIRST, ScanKeyData::sk_collation, ScanKeyData::sk_flags, ScanKeyData::sk_func, SK_ISNULL, SK_SEARCHNOTNULL, SK_SEARCHNULL, ScanKeyData::sk_strategy, and ScanKeyData::sk_subtype.

Referenced by _bt_preprocess_keys().

1024 {
1025  Relation rel = scan->indexRelation;
1026  Oid lefttype,
1027  righttype,
1028  optype,
1029  opcintype,
1030  cmp_op;
1031  StrategyNumber strat;
1032 
1033  /*
1034  * First, deal with cases where one or both args are NULL. This should
1035  * only happen when the scankeys represent IS NULL/NOT NULL conditions.
1036  */
1037  if ((leftarg->sk_flags | rightarg->sk_flags) & SK_ISNULL)
1038  {
1039  bool leftnull,
1040  rightnull;
1041 
1042  if (leftarg->sk_flags & SK_ISNULL)
1043  {
1045  leftnull = true;
1046  }
1047  else
1048  leftnull = false;
1049  if (rightarg->sk_flags & SK_ISNULL)
1050  {
1051  Assert(rightarg->sk_flags & (SK_SEARCHNULL | SK_SEARCHNOTNULL));
1052  rightnull = true;
1053  }
1054  else
1055  rightnull = false;
1056 
1057  /*
1058  * We treat NULL as either greater than or less than all other values.
1059  * Since true > false, the tests below work correctly for NULLS LAST
1060  * logic. If the index is NULLS FIRST, we need to flip the strategy.
1061  */
1062  strat = op->sk_strategy;
1063  if (op->sk_flags & SK_BT_NULLS_FIRST)
1064  strat = BTCommuteStrategyNumber(strat);
1065 
1066  switch (strat)
1067  {
1068  case BTLessStrategyNumber:
1069  *result = (leftnull < rightnull);
1070  break;
1072  *result = (leftnull <= rightnull);
1073  break;
1074  case BTEqualStrategyNumber:
1075  *result = (leftnull == rightnull);
1076  break;
1078  *result = (leftnull >= rightnull);
1079  break;
1081  *result = (leftnull > rightnull);
1082  break;
1083  default:
1084  elog(ERROR, "unrecognized StrategyNumber: %d", (int) strat);
1085  *result = false; /* keep compiler quiet */
1086  break;
1087  }
1088  return true;
1089  }
1090 
1091  /*
1092  * The opfamily we need to worry about is identified by the index column.
1093  */
1094  Assert(leftarg->sk_attno == rightarg->sk_attno);
1095 
1096  opcintype = rel->rd_opcintype[leftarg->sk_attno - 1];
1097 
1098  /*
1099  * Determine the actual datatypes of the ScanKey arguments. We have to
1100  * support the convention that sk_subtype == InvalidOid means the opclass
1101  * input type; this is a hack to simplify life for ScanKeyInit().
1102  */
1103  lefttype = leftarg->sk_subtype;
1104  if (lefttype == InvalidOid)
1105  lefttype = opcintype;
1106  righttype = rightarg->sk_subtype;
1107  if (righttype == InvalidOid)
1108  righttype = opcintype;
1109  optype = op->sk_subtype;
1110  if (optype == InvalidOid)
1111  optype = opcintype;
1112 
1113  /*
1114  * If leftarg and rightarg match the types expected for the "op" scankey,
1115  * we can use its already-looked-up comparison function.
1116  */
1117  if (lefttype == opcintype && righttype == optype)
1118  {
1119  *result = DatumGetBool(FunctionCall2Coll(&op->sk_func,
1120  op->sk_collation,
1121  leftarg->sk_argument,
1122  rightarg->sk_argument));
1123  return true;
1124  }
1125 
1126  /*
1127  * Otherwise, we need to go to the syscache to find the appropriate
1128  * operator. (This cannot result in infinite recursion, since no
1129  * indexscan initiated by syscache lookup will use cross-data-type
1130  * operators.)
1131  *
1132  * If the sk_strategy was flipped by _bt_fix_scankey_strategy, we have to
1133  * un-flip it to get the correct opfamily member.
1134  */
1135  strat = op->sk_strategy;
1136  if (op->sk_flags & SK_BT_DESC)
1137  strat = BTCommuteStrategyNumber(strat);
1138 
1139  cmp_op = get_opfamily_member(rel->rd_opfamily[leftarg->sk_attno - 1],
1140  lefttype,
1141  righttype,
1142  strat);
1143  if (OidIsValid(cmp_op))
1144  {
1145  RegProcedure cmp_proc = get_opcode(cmp_op);
1146 
1147  if (RegProcedureIsValid(cmp_proc))
1148  {
1149  *result = DatumGetBool(OidFunctionCall2Coll(cmp_proc,
1150  op->sk_collation,
1151  leftarg->sk_argument,
1152  rightarg->sk_argument));
1153  return true;
1154  }
1155  }
1156 
1157  /* Can't make the comparison */
1158  *result = false; /* suppress compiler warnings */
1159  return false;
1160 }
Oid sk_subtype
Definition: skey.h:69
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
regproc RegProcedure
Definition: c.h:512
uint16 StrategyNumber
Definition: stratnum.h:22
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
Relation indexRelation
Definition: relscan.h:103
#define BTCommuteStrategyNumber(strat)
Definition: nbtree.h:375
#define ERROR
Definition: elog.h:43
StrategyNumber sk_strategy
Definition: skey.h:68
#define RegProcedureIsValid(p)
Definition: c.h:647
FmgrInfo sk_func
Definition: skey.h:71
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
#define DatumGetBool(X)
Definition: postgres.h:393
#define SK_SEARCHNOTNULL
Definition: skey.h:122
Oid * rd_opfamily
Definition: rel.h:158
#define SK_ISNULL
Definition: skey.h:115
Datum OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1422
#define SK_BT_NULLS_FIRST
Definition: nbtree.h:682
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1092
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:739
#define SK_BT_DESC
Definition: nbtree.h:681
Oid sk_collation
Definition: skey.h:70
#define elog(elevel,...)
Definition: elog.h:228
Oid * rd_opcintype
Definition: rel.h:159
#define BTLessStrategyNumber
Definition: stratnum.h:29
Datum sk_argument
Definition: skey.h:72
#define SK_SEARCHNULL
Definition: skey.h:121
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
AttrNumber sk_attno
Definition: skey.h:67

◆ _bt_end_vacuum()

void _bt_end_vacuum ( Relation  rel)

Definition at line 1937 of file nbtutils.c.

References LockRelId::dbId, i, LockInfoData::lockRelId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), BTVacInfo::num_vacuums, RelationData::rd_lockInfo, LockRelId::relId, BTOneVacInfo::relid, and BTVacInfo::vacuums.

Referenced by _bt_end_vacuum_callback(), and btbulkdelete().

1938 {
1939  int i;
1940 
1941  LWLockAcquire(BtreeVacuumLock, LW_EXCLUSIVE);
1942 
1943  /* Find the array entry */
1944  for (i = 0; i < btvacinfo->num_vacuums; i++)
1945  {
1946  BTOneVacInfo *vac = &btvacinfo->vacuums[i];
1947 
1948  if (vac->relid.relId == rel->rd_lockInfo.lockRelId.relId &&
1949  vac->relid.dbId == rel->rd_lockInfo.lockRelId.dbId)
1950  {
1951  /* Remove it by shifting down the last entry */
1952  *vac = btvacinfo->vacuums[btvacinfo->num_vacuums - 1];
1954  break;
1955  }
1956  }
1957 
1958  LWLockRelease(BtreeVacuumLock);
1959 }
LockRelId lockRelId
Definition: rel.h:43
static BTVacInfo * btvacinfo
Definition: nbtutils.c:1833
LockRelId relid
Definition: nbtutils.c:1821
Oid dbId
Definition: rel.h:38
BTOneVacInfo vacuums[FLEXIBLE_ARRAY_MEMBER]
Definition: nbtutils.c:1830
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
LockInfoData rd_lockInfo
Definition: rel.h:86
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int num_vacuums
Definition: nbtutils.c:1828
int i
Oid relId
Definition: rel.h:37

◆ _bt_end_vacuum_callback()

void _bt_end_vacuum_callback ( int  code,
Datum  arg 
)

Definition at line 1965 of file nbtutils.c.

References _bt_end_vacuum(), and DatumGetPointer.

Referenced by btbulkdelete().

1966 {
1968 }
void _bt_end_vacuum(Relation rel)
Definition: nbtutils.c:1937
#define DatumGetPointer(X)
Definition: postgres.h:549
void * arg

◆ _bt_find_extreme_element()

static Datum _bt_find_extreme_element ( IndexScanDesc  scan,
ScanKey  skey,
StrategyNumber  strat,
Datum elems,
int  nelems 
)
static

Definition at line 364 of file nbtutils.c.

References Assert, DatumGetBool, elog, ERROR, BTSortArrayContext::flinfo, fmgr_info(), FunctionCall2Coll(), get_opcode(), get_opfamily_member(), i, IndexScanDescData::indexRelation, InvalidOid, OidIsValid, RelationData::rd_opcintype, RelationData::rd_opfamily, RegProcedureIsValid, ScanKeyData::sk_attno, ScanKeyData::sk_collation, and ScanKeyData::sk_subtype.

Referenced by _bt_preprocess_array_keys().

367 {
368  Relation rel = scan->indexRelation;
369  Oid elemtype,
370  cmp_op;
371  RegProcedure cmp_proc;
372  FmgrInfo flinfo;
373  Datum result;
374  int i;
375 
376  /*
377  * Determine the nominal datatype of the array elements. We have to
378  * support the convention that sk_subtype == InvalidOid means the opclass
379  * input type; this is a hack to simplify life for ScanKeyInit().
380  */
381  elemtype = skey->sk_subtype;
382  if (elemtype == InvalidOid)
383  elemtype = rel->rd_opcintype[skey->sk_attno - 1];
384 
385  /*
386  * Look up the appropriate comparison operator in the opfamily.
387  *
388  * Note: it's possible that this would fail, if the opfamily is
389  * incomplete, but it seems quite unlikely that an opfamily would omit
390  * non-cross-type comparison operators for any datatype that it supports
391  * at all.
392  */
393  cmp_op = get_opfamily_member(rel->rd_opfamily[skey->sk_attno - 1],
394  elemtype,
395  elemtype,
396  strat);
397  if (!OidIsValid(cmp_op))
398  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
399  strat, elemtype, elemtype,
400  rel->rd_opfamily[skey->sk_attno - 1]);
401  cmp_proc = get_opcode(cmp_op);
402  if (!RegProcedureIsValid(cmp_proc))
403  elog(ERROR, "missing oprcode for operator %u", cmp_op);
404 
405  fmgr_info(cmp_proc, &flinfo);
406 
407  Assert(nelems > 0);
408  result = elems[0];
409  for (i = 1; i < nelems; i++)
410  {
411  if (DatumGetBool(FunctionCall2Coll(&flinfo,
412  skey->sk_collation,
413  elems[i],
414  result)))
415  result = elems[i];
416  }
417 
418  return result;
419 }
Oid sk_subtype
Definition: skey.h:69
Definition: fmgr.h:56
regproc RegProcedure
Definition: c.h:512
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
Relation indexRelation
Definition: relscan.h:103
#define ERROR
Definition: elog.h:43
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:124
#define RegProcedureIsValid(p)
Definition: c.h:647
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
#define DatumGetBool(X)
Definition: postgres.h:393
Oid * rd_opfamily
Definition: rel.h:158
uintptr_t Datum
Definition: postgres.h:367
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1092
#define Assert(condition)
Definition: c.h:739
Oid sk_collation
Definition: skey.h:70
#define elog(elevel,...)
Definition: elog.h:228
int i
Oid * rd_opcintype
Definition: rel.h:159
AttrNumber sk_attno
Definition: skey.h:67

◆ _bt_fix_scankey_strategy()

static bool _bt_fix_scankey_strategy ( ScanKey  skey,
int16 indoption 
)
static

Definition at line 1185 of file nbtutils.c.

References Assert, BTCommuteStrategyNumber, BTEqualStrategyNumber, BTGreaterStrategyNumber, BTLessStrategyNumber, DatumGetPointer, InvalidOid, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_DESC, SK_BT_INDOPTION_SHIFT, SK_BT_NULLS_FIRST, ScanKeyData::sk_collation, ScanKeyData::sk_flags, SK_ISNULL, SK_ROW_END, SK_ROW_HEADER, SK_ROW_MEMBER, SK_SEARCHNOTNULL, SK_SEARCHNULL, ScanKeyData::sk_strategy, and ScanKeyData::sk_subtype.

Referenced by _bt_preprocess_keys().

1186 {
1187  int addflags;
1188 
1189  addflags = indoption[skey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
1190 
1191  /*
1192  * We treat all btree operators as strict (even if they're not so marked
1193  * in pg_proc). This means that it is impossible for an operator condition
1194  * with a NULL comparison constant to succeed, and we can reject it right
1195  * away.
1196  *
1197  * However, we now also support "x IS NULL" clauses as search conditions,
1198  * so in that case keep going. The planner has not filled in any
1199  * particular strategy in this case, so set it to BTEqualStrategyNumber
1200  * --- we can treat IS NULL as an equality operator for purposes of search
1201  * strategy.
1202  *
1203  * Likewise, "x IS NOT NULL" is supported. We treat that as either "less
1204  * than NULL" in a NULLS LAST index, or "greater than NULL" in a NULLS
1205  * FIRST index.
1206  *
1207  * Note: someday we might have to fill in sk_collation from the index
1208  * column's collation. At the moment this is a non-issue because we'll
1209  * never actually call the comparison operator on a NULL.
1210  */
1211  if (skey->sk_flags & SK_ISNULL)
1212  {
1213  /* SK_ISNULL shouldn't be set in a row header scankey */
1214  Assert(!(skey->sk_flags & SK_ROW_HEADER));
1215 
1216  /* Set indoption flags in scankey (might be done already) */
1217  skey->sk_flags |= addflags;
1218 
1219  /* Set correct strategy for IS NULL or NOT NULL search */
1220  if (skey->sk_flags & SK_SEARCHNULL)
1221  {
1223  skey->sk_subtype = InvalidOid;
1224  skey->sk_collation = InvalidOid;
1225  }
1226  else if (skey->sk_flags & SK_SEARCHNOTNULL)
1227  {
1228  if (skey->sk_flags & SK_BT_NULLS_FIRST)
1230  else
1232  skey->sk_subtype = InvalidOid;
1233  skey->sk_collation = InvalidOid;
1234  }
1235  else
1236  {
1237  /* regular qual, so it cannot be satisfied */
1238  return false;
1239  }
1240 
1241  /* Needn't do the rest */
1242  return true;
1243  }
1244 
1245  /* Adjust strategy for DESC, if we didn't already */
1246  if ((addflags & SK_BT_DESC) && !(skey->sk_flags & SK_BT_DESC))
1248  skey->sk_flags |= addflags;
1249 
1250  /* If it's a row header, fix row member flags and strategies similarly */
1251  if (skey->sk_flags & SK_ROW_HEADER)
1252  {
1253  ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
1254 
1255  for (;;)
1256  {
1257  Assert(subkey->sk_flags & SK_ROW_MEMBER);
1258  addflags = indoption[subkey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
1259  if ((addflags & SK_BT_DESC) && !(subkey->sk_flags & SK_BT_DESC))
1260  subkey->sk_strategy = BTCommuteStrategyNumber(subkey->sk_strategy);
1261  subkey->sk_flags |= addflags;
1262  if (subkey->sk_flags & SK_ROW_END)
1263  break;
1264  subkey++;
1265  }
1266  }
1267 
1268  return true;
1269 }
#define SK_BT_INDOPTION_SHIFT
Definition: nbtree.h:680
Oid sk_subtype
Definition: skey.h:69
#define SK_ROW_MEMBER
Definition: skey.h:118
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define SK_ROW_END
Definition: skey.h:119
#define BTCommuteStrategyNumber(strat)
Definition: nbtree.h:375
StrategyNumber sk_strategy
Definition: skey.h:68
ScanKeyData * ScanKey
Definition: skey.h:75
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_ISNULL
Definition: skey.h:115
#define SK_ROW_HEADER
Definition: skey.h:117
#define SK_BT_NULLS_FIRST
Definition: nbtree.h:682
#define InvalidOid
Definition: postgres_ext.h:36
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:739
#define SK_BT_DESC
Definition: nbtree.h:681
#define DatumGetPointer(X)
Definition: postgres.h:549
Oid sk_collation
Definition: skey.h:70
#define BTLessStrategyNumber
Definition: stratnum.h:29
Datum sk_argument
Definition: skey.h:72
#define SK_SEARCHNULL
Definition: skey.h:121
#define BTEqualStrategyNumber
Definition: stratnum.h:31
AttrNumber sk_attno
Definition: skey.h:67

◆ _bt_freestack()

void _bt_freestack ( BTStack  stack)

Definition at line 164 of file nbtutils.c.

References BTStackData::bts_parent, and pfree().

Referenced by _bt_doinsert(), _bt_first(), and bt_rootdescend().

165 {
166  BTStack ostack;
167 
168  while (stack != NULL)
169  {
170  ostack = stack;
171  stack = stack->bts_parent;
172  pfree(ostack);
173  }
174 }
void pfree(void *pointer)
Definition: mcxt.c:1056
struct BTStackData * bts_parent
Definition: nbtree.h:420

◆ _bt_keep_natts()

static int _bt_keep_natts ( Relation  rel,
IndexTuple  lastleft,
IndexTuple  firstright,
BTScanInsert  itup_key 
)
static

Definition at line 2257 of file nbtutils.c.

References Assert, attnum, DatumGetInt32, FunctionCall2Coll(), BTScanInsertData::heapkeyspace, index_getattr, IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, RelationGetDescr, BTScanInsertData::scankeys, ScanKeyData::sk_collation, and ScanKeyData::sk_func.

Referenced by _bt_truncate().

2259 {
2260  int nkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
2261  TupleDesc itupdesc = RelationGetDescr(rel);
2262  int keepnatts;
2263  ScanKey scankey;
2264 
2265  /*
2266  * Be consistent about the representation of BTREE_VERSION 2/3 tuples
2267  * across Postgres versions; don't allow new pivot tuples to have
2268  * truncated key attributes there. _bt_compare() treats truncated key
2269  * attributes as having the value minus infinity, which would break
2270  * searches within !heapkeyspace indexes.
2271  */
2272  if (!itup_key->heapkeyspace)
2273  {
2274  Assert(nkeyatts != IndexRelationGetNumberOfAttributes(rel));
2275  return nkeyatts;
2276  }
2277 
2278  scankey = itup_key->scankeys;
2279  keepnatts = 1;
2280  for (int attnum = 1; attnum <= nkeyatts; attnum++, scankey++)
2281  {
2282  Datum datum1,
2283  datum2;
2284  bool isNull1,
2285  isNull2;
2286 
2287  datum1 = index_getattr(lastleft, attnum, itupdesc, &isNull1);
2288  datum2 = index_getattr(firstright, attnum, itupdesc, &isNull2);
2289 
2290  if (isNull1 != isNull2)
2291  break;
2292 
2293  if (!isNull1 &&
2295  scankey->sk_collation,
2296  datum1,
2297  datum2)) != 0)
2298  break;
2299 
2300  keepnatts++;
2301  }
2302 
2303  return keepnatts;
2304 }
#define DatumGetInt32(X)
Definition: postgres.h:472
#define RelationGetDescr(relation)
Definition: rel.h:448
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
FmgrInfo sk_func
Definition: skey.h:71
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:434
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:441
uintptr_t Datum
Definition: postgres.h:367
int16 attnum
Definition: pg_attribute.h:79
#define Assert(condition)
Definition: c.h:739
bool heapkeyspace
Definition: nbtree.h:472
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
ScanKeyData scankeys[INDEX_MAX_KEYS]
Definition: nbtree.h:478
Oid sk_collation
Definition: skey.h:70

◆ _bt_keep_natts_fast()

int _bt_keep_natts_fast ( Relation  rel,
IndexTuple  lastleft,
IndexTuple  firstright 
)

Definition at line 2326 of file nbtutils.c.

References attnum, datum_image_eq(), index_getattr, IndexRelationGetNumberOfKeyAttributes, RelationGetDescr, and TupleDescAttr.

Referenced by _bt_afternewitemoff(), _bt_split_penalty(), and _bt_strategy().

2327 {
2328  TupleDesc itupdesc = RelationGetDescr(rel);
2329  int keysz = IndexRelationGetNumberOfKeyAttributes(rel);
2330  int keepnatts;
2331 
2332  keepnatts = 1;
2333  for (int attnum = 1; attnum <= keysz; attnum++)
2334  {
2335  Datum datum1,
2336  datum2;
2337  bool isNull1,
2338  isNull2;
2339  Form_pg_attribute att;
2340 
2341  datum1 = index_getattr(lastleft, attnum, itupdesc, &isNull1);
2342  datum2 = index_getattr(firstright, attnum, itupdesc, &isNull2);
2343  att = TupleDescAttr(itupdesc, attnum - 1);
2344 
2345  if (isNull1 != isNull2)
2346  break;
2347 
2348  if (!isNull1 &&
2349  !datum_image_eq(datum1, datum2, att->attbyval, att->attlen))
2350  break;
2351 
2352  keepnatts++;
2353  }
2354 
2355  return keepnatts;
2356 }
#define RelationGetDescr(relation)
Definition: rel.h:448
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:441
uintptr_t Datum
Definition: postgres.h:367
int16 attnum
Definition: pg_attribute.h:79
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
bool datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:264

◆ _bt_killitems()

void _bt_killitems ( IndexScanDesc  scan)

Definition at line 1705 of file nbtutils.c.

References _bt_getbuf(), _bt_relbuf(), Assert, BT_READ, BTP_HAS_GARBAGE, BTScanPosIsPinned, BTScanPosIsValid, buf, BTScanPosData::buf, BUFFER_LOCK_UNLOCK, BufferGetLSNAtomic(), BufferGetPage, BufferIsValid, BTScanPosData::currPage, BTScanOpaqueData::currPos, BTScanPosData::firstItem, BTScanPosItem::heapTid, i, BTScanPosItem::indexOffset, IndexScanDescData::indexRelation, ItemIdMarkDead, ItemPointerEquals(), BTScanPosData::items, BTScanOpaqueData::killedItems, LockBuffer(), BTScanPosData::lsn, MarkBufferDirtyHint(), BTScanOpaqueData::numKilled, OffsetNumberNext, IndexScanDescData::opaque, P_FIRSTDATAKEY, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetSpecialPointer, and IndexTupleData::t_tid.

Referenced by _bt_steppage(), btendscan(), btrescan(), and btrestrpos().

1706 {
1707  BTScanOpaque so = (BTScanOpaque) scan->opaque;
1708  Page page;
1709  BTPageOpaque opaque;
1710  OffsetNumber minoff;
1711  OffsetNumber maxoff;
1712  int i;
1713  int numKilled = so->numKilled;
1714  bool killedsomething = false;
1715 
1717 
1718  /*
1719  * Always reset the scan state, so we don't look for same items on other
1720  * pages.
1721  */
1722  so->numKilled = 0;
1723 
1724  if (BTScanPosIsPinned(so->currPos))
1725  {
1726  /*
1727  * We have held the pin on this page since we read the index tuples,
1728  * so all we need to do is lock it. The pin will have prevented
1729  * re-use of any TID on the page, so there is no need to check the
1730  * LSN.
1731  */
1732  LockBuffer(so->currPos.buf, BT_READ);
1733 
1734  page = BufferGetPage(so->currPos.buf);
1735  }
1736  else
1737  {
1738  Buffer buf;
1739 
1740  /* Attempt to re-read the buffer, getting pin and lock. */
1741  buf = _bt_getbuf(scan->indexRelation, so->currPos.currPage, BT_READ);
1742 
1743  /* It might not exist anymore; in which case we can't hint it. */
1744  if (!BufferIsValid(buf))
1745  return;
1746 
1747  page = BufferGetPage(buf);
1748  if (BufferGetLSNAtomic(buf) == so->currPos.lsn)
1749  so->currPos.buf = buf;
1750  else
1751  {
1752  /* Modified while not pinned means hinting is not safe. */
1753  _bt_relbuf(scan->indexRelation, buf);
1754  return;
1755  }
1756  }
1757 
1758  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1759  minoff = P_FIRSTDATAKEY(opaque);
1760  maxoff = PageGetMaxOffsetNumber(page);
1761 
1762  for (i = 0; i < numKilled; i++)
1763  {
1764  int itemIndex = so->killedItems[i];
1765  BTScanPosItem *kitem = &so->currPos.items[itemIndex];
1766  OffsetNumber offnum = kitem->indexOffset;
1767 
1768  Assert(itemIndex >= so->currPos.firstItem &&
1769  itemIndex <= so->currPos.lastItem);
1770  if (offnum < minoff)
1771  continue; /* pure paranoia */
1772  while (offnum <= maxoff)
1773  {
1774  ItemId iid = PageGetItemId(page, offnum);
1775  IndexTuple ituple = (IndexTuple) PageGetItem(page, iid);
1776 
1777  if (ItemPointerEquals(&ituple->t_tid, &kitem->heapTid))
1778  {
1779  /* found the item */
1780  ItemIdMarkDead(iid);
1781  killedsomething = true;
1782  break; /* out of inner search loop */
1783  }
1784  offnum = OffsetNumberNext(offnum);
1785  }
1786  }
1787 
1788  /*
1789  * Since this can be redone later if needed, mark as dirty hint.
1790  *
1791  * Whenever we mark anything LP_DEAD, we also set the page's
1792  * BTP_HAS_GARBAGE flag, which is likewise just a hint.
1793  */
1794  if (killedsomething)
1795  {
1796  opaque->btpo_flags |= BTP_HAS_GARBAGE;
1797  MarkBufferDirtyHint(so->currPos.buf, true);
1798  }
1799 
1801 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
BTScanPosItem items[MaxIndexTuplesPerPage]
Definition: nbtree.h:582
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:3435
#define ItemIdMarkDead(itemId)
Definition: itemid.h:179
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition: nbtpage.c:757
#define P_FIRSTDATAKEY(opaque)
Definition: nbtree.h:220
ItemPointerData t_tid
Definition: itup.h:37
BlockNumber currPage
Definition: nbtree.h:553
#define BTScanPosIsValid(scanpos)
Definition: nbtree.h:604
OffsetNumber indexOffset
Definition: nbtree.h:544
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:69
Relation indexRelation
Definition: relscan.h:103
uint16 OffsetNumber
Definition: off.h:24
#define BT_READ
Definition: nbtree.h:403
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:671
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:2876
static char * buf
Definition: pg_test_fsync.c:67
#define BTScanPosIsPinned(scanpos)
Definition: nbtree.h:587
IndexTupleData * IndexTuple
Definition: itup.h:53
int firstItem
Definition: nbtree.h:578
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:912
int * killedItems
Definition: nbtree.h:646
#define Assert(condition)
Definition: c.h:739
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
ItemPointerData heapTid
Definition: nbtree.h:543
BTScanPosData currPos
Definition: nbtree.h:667
int i
XLogRecPtr lsn
Definition: nbtree.h:552
Buffer buf
Definition: nbtree.h:550
int Buffer
Definition: buf.h:23
#define BTP_HAS_GARBAGE
Definition: nbtree.h:78
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78

◆ _bt_mark_array_keys()

void _bt_mark_array_keys ( IndexScanDesc  scan)

Definition at line 592 of file nbtutils.c.

References BTScanOpaqueData::arrayKeys, BTArrayKeyInfo::cur_elem, i, BTArrayKeyInfo::mark_elem, BTScanOpaqueData::numArrayKeys, and IndexScanDescData::opaque.

Referenced by btmarkpos().

593 {
594  BTScanOpaque so = (BTScanOpaque) scan->opaque;
595  int i;
596 
597  for (i = 0; i < so->numArrayKeys; i++)
598  {
599  BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
600 
601  curArrayKey->mark_elem = curArrayKey->cur_elem;
602  }
603 }
int mark_elem
Definition: nbtree.h:624
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:671
int cur_elem
Definition: nbtree.h:623
int numArrayKeys
Definition: nbtree.h:638
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:642
int i

◆ _bt_mark_scankey_required()

static void _bt_mark_scankey_required ( ScanKey  skey)
static

Definition at line 1287 of file nbtutils.c.

References Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, DatumGetPointer, elog, ERROR, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_REQBKWD, SK_BT_REQFWD, ScanKeyData::sk_flags, SK_ROW_HEADER, SK_ROW_MEMBER, and ScanKeyData::sk_strategy.

Referenced by _bt_preprocess_keys().

1288 {
1289  int addflags;
1290 
1291  switch (skey->sk_strategy)
1292  {
1293  case BTLessStrategyNumber:
1295  addflags = SK_BT_REQFWD;
1296  break;
1297  case BTEqualStrategyNumber:
1298  addflags = SK_BT_REQFWD | SK_BT_REQBKWD;
1299  break;
1302  addflags = SK_BT_REQBKWD;
1303  break;
1304  default:
1305  elog(ERROR, "unrecognized StrategyNumber: %d",
1306  (int) skey->sk_strategy);
1307  addflags = 0; /* keep compiler quiet */
1308  break;
1309  }
1310 
1311  skey->sk_flags |= addflags;
1312 
1313  if (skey->sk_flags & SK_ROW_HEADER)
1314  {
1315  ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
1316 
1317  /* First subkey should be same column/operator as the header */
1318  Assert(subkey->sk_flags & SK_ROW_MEMBER);
1319  Assert(subkey->sk_attno == skey->sk_attno);
1320  Assert(subkey->sk_strategy == skey->sk_strategy);
1321  subkey->sk_flags |= addflags;
1322  }
1323 }
#define SK_ROW_MEMBER
Definition: skey.h:118
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
#define ERROR
Definition: elog.h:43
StrategyNumber sk_strategy
Definition: skey.h:68
ScanKeyData * ScanKey
Definition: skey.h:75
#define SK_ROW_HEADER
Definition: skey.h:117
#define SK_BT_REQFWD
Definition: nbtree.h:678
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:739
#define DatumGetPointer(X)
Definition: postgres.h:549
#define elog(elevel,...)
Definition: elog.h:228
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define SK_BT_REQBKWD
Definition: nbtree.h:679
Datum sk_argument
Definition: skey.h:72
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
AttrNumber sk_attno
Definition: skey.h:67

◆ _bt_mkscankey()

BTScanInsert _bt_mkscankey ( Relation  rel,
IndexTuple  itup 
)

Definition at line 86 of file nbtutils.c.

References _bt_heapkeyspace(), BTScanInsertData::anynullkeys, arg, Assert, BTORDER_PROC, BTreeTupleGetHeapTID, BTreeTupleGetNAtts, BTScanInsertData::heapkeyspace, i, index_getattr, index_getprocinfo(), IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, InvalidOid, InvalidStrategy, sort-test::key, BTScanInsertData::keysz, Min, BTScanInsertData::nextkey, offsetof, palloc(), BTScanInsertData::pivotsearch, RelationData::rd_indcollation, RelationData::rd_indoption, RelationGetDescr, ScanKeyEntryInitializeWithInfo(), BTScanInsertData::scankeys, BTScanInsertData::scantid, SK_BT_INDOPTION_SHIFT, and SK_ISNULL.

Referenced by _bt_doinsert(), _bt_leafbuild(), _bt_pagedel(), bt_mkscankey_pivotsearch(), bt_rootdescend(), tuplesort_begin_cluster(), and tuplesort_begin_index_btree().

87 {
89  ScanKey skey;
90  TupleDesc itupdesc;
91  int indnkeyatts;
92  int16 *indoption;
93  int tupnatts;
94  int i;
95 
96  itupdesc = RelationGetDescr(rel);
97  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
98  indoption = rel->rd_indoption;
99  tupnatts = itup ? BTreeTupleGetNAtts(itup, rel) : 0;
100 
101  Assert(tupnatts <= IndexRelationGetNumberOfAttributes(rel));
102 
103  /*
104  * We'll execute search using scan key constructed on key columns.
105  * Truncated attributes and non-key attributes are omitted from the final
106  * scan key.
107  */
108  key = palloc(offsetof(BTScanInsertData, scankeys) +
109  sizeof(ScanKeyData) * indnkeyatts);
110  key->heapkeyspace = itup == NULL || _bt_heapkeyspace(rel);
111  key->anynullkeys = false; /* initial assumption */
112  key->nextkey = false;
113  key->pivotsearch = false;
114  key->keysz = Min(indnkeyatts, tupnatts);
115  key->scantid = key->heapkeyspace && itup ?
116  BTreeTupleGetHeapTID(itup) : NULL;
117  skey = key->scankeys;
118  for (i = 0; i < indnkeyatts; i++)
119  {
120  FmgrInfo *procinfo;
121  Datum arg;
122  bool null;
123  int flags;
124 
125  /*
126  * We can use the cached (default) support procs since no cross-type
127  * comparison can be needed.
128  */
129  procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
130 
131  /*
132  * Key arguments built from truncated attributes (or when caller
133  * provides no tuple) are defensively represented as NULL values. They
134  * should never be used.
135  */
136  if (i < tupnatts)
137  arg = index_getattr(itup, i + 1, itupdesc, &null);
138  else
139  {
140  arg = (Datum) 0;
141  null = true;
142  }
143  flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
145  flags,
146  (AttrNumber) (i + 1),
148  InvalidOid,
149  rel->rd_indcollation[i],
150  procinfo,
151  arg);
152  /* Record if any key attribute is NULL (or truncated) */
153  if (null)
154  key->anynullkeys = true;
155  }
156 
157  return key;
158 }
#define SK_BT_INDOPTION_SHIFT
Definition: nbtree.h:680
signed short int16
Definition: c.h:346
#define InvalidStrategy
Definition: stratnum.h:24
Definition: fmgr.h:56
#define BTORDER_PROC
Definition: nbtree.h:393
int16 * rd_indoption
Definition: rel.h:162
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:794
void ScanKeyEntryInitializeWithInfo(ScanKey entry, int flags, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, Oid collation, FmgrInfo *finfo, Datum argument)
Definition: scankey.c:101
#define RelationGetDescr(relation)
Definition: rel.h:448
ItemPointer scantid
Definition: nbtree.h:476
#define Min(x, y)
Definition: c.h:911
#define BTreeTupleGetHeapTID(itup)
Definition: nbtree.h:347
#define BTreeTupleGetNAtts(itup, rel)
Definition: nbtree.h:328
Oid * rd_indcollation
Definition: rel.h:168
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:434
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:441
#define SK_ISNULL
Definition: skey.h:115
bool pivotsearch
Definition: nbtree.h:475
bool anynullkeys
Definition: nbtree.h:473
uintptr_t Datum
Definition: postgres.h:367
bool _bt_heapkeyspace(Relation rel)
Definition: nbtpage.c:636
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:739
bool heapkeyspace
Definition: nbtree.h:472
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
ScanKeyData scankeys[INDEX_MAX_KEYS]
Definition: nbtree.h:478
void * palloc(Size size)
Definition: mcxt.c:949
int i
void * arg
int16 AttrNumber
Definition: attnum.h:21
#define offsetof(type, field)
Definition: c.h:662

◆ _bt_preprocess_array_keys()

void _bt_preprocess_array_keys ( IndexScanDesc  scan)

Definition at line 192 of file nbtutils.c.

References _bt_find_extreme_element(), _bt_sort_array_elements(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, ARR_ELEMTYPE, BTScanOpaqueData::arrayContext, BTScanOpaqueData::arrayKeyData, BTScanOpaqueData::arrayKeys, Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, cur, CurrentMemoryContext, DatumGetArrayTypeP, deconstruct_array(), BTArrayKeyInfo::elem_values, elog, ERROR, get_typlenbyvalalign(), i, IndexScanDescData::indexRelation, IndexScanDescData::keyData, MemoryContextReset(), MemoryContextSwitchTo(), BTArrayKeyInfo::num_elems, BTScanOpaqueData::numArrayKeys, IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, palloc(), palloc0(), RelationData::rd_indoption, BTArrayKeyInfo::scan_key, SK_ISNULL, SK_ROW_HEADER, SK_SEARCHARRAY, SK_SEARCHNOTNULL, and SK_SEARCHNULL.

Referenced by btrescan().

193 {
194  BTScanOpaque so = (BTScanOpaque) scan->opaque;
195  int numberOfKeys = scan->numberOfKeys;
196  int16 *indoption = scan->indexRelation->rd_indoption;
197  int numArrayKeys;
198  ScanKey cur;
199  int i;
200  MemoryContext oldContext;
201 
202  /* Quick check to see if there are any array keys */
203  numArrayKeys = 0;
204  for (i = 0; i < numberOfKeys; i++)
205  {
206  cur = &scan->keyData[i];
207  if (cur->sk_flags & SK_SEARCHARRAY)
208  {
209  numArrayKeys++;
210  Assert(!(cur->sk_flags & (SK_ROW_HEADER | SK_SEARCHNULL | SK_SEARCHNOTNULL)));
211  /* If any arrays are null as a whole, we can quit right now. */
212  if (cur->sk_flags & SK_ISNULL)
213  {
214  so->numArrayKeys = -1;
215  so->arrayKeyData = NULL;
216  return;
217  }
218  }
219  }
220 
221  /* Quit if nothing to do. */
222  if (numArrayKeys == 0)
223  {
224  so->numArrayKeys = 0;
225  so->arrayKeyData = NULL;
226  return;
227  }
228 
229  /*
230  * Make a scan-lifespan context to hold array-associated data, or reset it
231  * if we already have one from a previous rescan cycle.
232  */
233  if (so->arrayContext == NULL)
235  "BTree array context",
237  else
239 
240  oldContext = MemoryContextSwitchTo(so->arrayContext);
241 
242  /* Create modifiable copy of scan->keyData in the workspace context */
243  so->arrayKeyData = (ScanKey) palloc(scan->numberOfKeys * sizeof(ScanKeyData));
244  memcpy(so->arrayKeyData,
245  scan->keyData,
246  scan->numberOfKeys * sizeof(ScanKeyData));
247 
248  /* Allocate space for per-array data in the workspace context */
249  so->arrayKeys = (BTArrayKeyInfo *) palloc0(numArrayKeys * sizeof(BTArrayKeyInfo));
250 
251  /* Now process each array key */
252  numArrayKeys = 0;
253  for (i = 0; i < numberOfKeys; i++)
254  {
255  ArrayType *arrayval;
256  int16 elmlen;
257  bool elmbyval;
258  char elmalign;
259  int num_elems;
260  Datum *elem_values;
261  bool *elem_nulls;
262  int num_nonnulls;
263  int j;
264 
265  cur = &so->arrayKeyData[i];
266  if (!(cur->sk_flags & SK_SEARCHARRAY))
267  continue;
268 
269  /*
270  * First, deconstruct the array into elements. Anything allocated
271  * here (including a possibly detoasted array value) is in the
272  * workspace context.
273  */
274  arrayval = DatumGetArrayTypeP(cur->sk_argument);
275  /* We could cache this data, but not clear it's worth it */
277  &elmlen, &elmbyval, &elmalign);
278  deconstruct_array(arrayval,
279  ARR_ELEMTYPE(arrayval),
280  elmlen, elmbyval, elmalign,
281  &elem_values, &elem_nulls, &num_elems);
282 
283  /*
284  * Compress out any null elements. We can ignore them since we assume
285  * all btree operators are strict.
286  */
287  num_nonnulls = 0;
288  for (j = 0; j < num_elems; j++)
289  {
290  if (!elem_nulls[j])
291  elem_values[num_nonnulls++] = elem_values[j];
292  }
293 
294  /* We could pfree(elem_nulls) now, but not worth the cycles */
295 
296  /* If there's no non-nulls, the scan qual is unsatisfiable */
297  if (num_nonnulls == 0)
298  {
299  numArrayKeys = -1;
300  break;
301  }
302 
303  /*
304  * If the comparison operator is not equality, then the array qual
305  * degenerates to a simple comparison against the smallest or largest
306  * non-null array element, as appropriate.
307  */
308  switch (cur->sk_strategy)
309  {
312  cur->sk_argument =
315  elem_values, num_nonnulls);
316  continue;
318  /* proceed with rest of loop */
319  break;
322  cur->sk_argument =
325  elem_values, num_nonnulls);
326  continue;
327  default:
328  elog(ERROR, "unrecognized StrategyNumber: %d",
329  (int) cur->sk_strategy);
330  break;
331  }
332 
333  /*
334  * Sort the non-null elements and eliminate any duplicates. We must
335  * sort in the same ordering used by the index column, so that the
336  * successive primitive indexscans produce data in index order.
337  */
338  num_elems = _bt_sort_array_elements(scan, cur,
339  (indoption[cur->sk_attno - 1] & INDOPTION_DESC) != 0,
340  elem_values, num_nonnulls);
341 
342  /*
343  * And set up the BTArrayKeyInfo data.
344  */
345  so->arrayKeys[numArrayKeys].scan_key = i;
346  so->arrayKeys[numArrayKeys].num_elems = num_elems;
347  so->arrayKeys[numArrayKeys].elem_values = elem_values;
348  numArrayKeys++;
349  }
350 
351  so->numArrayKeys = numArrayKeys;
352 
353  MemoryContextSwitchTo(oldContext);
354 }
signed short int16
Definition: c.h:346
#define AllocSetContextCreate
Definition: memutils.h:170
int16 * rd_indoption
Definition: rel.h:162
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
MemoryContext arrayContext
Definition: nbtree.h:643
static int _bt_sort_array_elements(IndexScanDesc scan, ScanKey skey, bool reverse, Datum *elems, int nelems)
Definition: nbtutils.c:431
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2049
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
struct cursor * cur
Definition: ecpg.c:28
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
Datum * elem_values
Definition: nbtree.h:626
#define SK_SEARCHARRAY
Definition: skey.h:120
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
Relation indexRelation
Definition: relscan.h:103
static Datum _bt_find_extreme_element(IndexScanDesc scan, ScanKey skey, StrategyNumber strat, Datum *elems, int nelems)
Definition: nbtutils.c:364
#define ERROR
Definition: elog.h:43
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:671
int numArrayKeys
Definition: nbtree.h:638
ScanKeyData * ScanKey
Definition: skey.h:75
#define SK_SEARCHNOTNULL
Definition: skey.h:122
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define SK_ISNULL
Definition: skey.h:115
ScanKey arrayKeyData
Definition: nbtree.h:637
#define SK_ROW_HEADER
Definition: skey.h:117
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
int num_elems
Definition: nbtree.h:625
#define Assert(condition)
Definition: c.h:739
struct ScanKeyData * keyData
Definition: relscan.h:107
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3461
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:642
int i
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define ARR_ELEMTYPE(a)
Definition: array.h:280
int scan_key
Definition: nbtree.h:622
#define SK_SEARCHNULL
Definition: skey.h:121
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
#define DatumGetArrayTypeP(X)
Definition: array.h:249

◆ _bt_preprocess_keys()

void _bt_preprocess_keys ( IndexScanDesc  scan)

Definition at line 731 of file nbtutils.c.

References _bt_compare_scankey_args(), _bt_fix_scankey_strategy(), _bt_mark_scankey_required(), BTScanOpaqueData::arrayKeyData, Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, BTMaxStrategyNumber, cur, elog, ERROR, i, IndexScanDescData::indexRelation, IndexScanDescData::keyData, BTScanOpaqueData::keyData, IndexScanDescData::numberOfKeys, BTScanOpaqueData::numberOfKeys, IndexScanDescData::opaque, BTScanOpaqueData::qual_ok, RelationData::rd_indoption, ScanKeyData::sk_flags, SK_ROW_HEADER, and SK_SEARCHNULL.

Referenced by _bt_first(), and _bt_restore_array_keys().

732 {
733  BTScanOpaque so = (BTScanOpaque) scan->opaque;
734  int numberOfKeys = scan->numberOfKeys;
735  int16 *indoption = scan->indexRelation->rd_indoption;
736  int new_numberOfKeys;
737  int numberOfEqualCols;
738  ScanKey inkeys;
739  ScanKey outkeys;
740  ScanKey cur;
742  bool test_result;
743  int i,
744  j;
745  AttrNumber attno;
746 
747  /* initialize result variables */
748  so->qual_ok = true;
749  so->numberOfKeys = 0;
750 
751  if (numberOfKeys < 1)
752  return; /* done if qual-less scan */
753 
754  /*
755  * Read so->arrayKeyData if array keys are present, else scan->keyData
756  */
757  if (so->arrayKeyData != NULL)
758  inkeys = so->arrayKeyData;
759  else
760  inkeys = scan->keyData;
761 
762  outkeys = so->keyData;
763  cur = &inkeys[0];
764  /* we check that input keys are correctly ordered */
765  if (cur->sk_attno < 1)
766  elog(ERROR, "btree index keys must be ordered by attribute");
767 
768  /* We can short-circuit most of the work if there's just one key */
769  if (numberOfKeys == 1)
770  {
771  /* Apply indoption to scankey (might change sk_strategy!) */
772  if (!_bt_fix_scankey_strategy(cur, indoption))
773  so->qual_ok = false;
774  memcpy(outkeys, cur, sizeof(ScanKeyData));
775  so->numberOfKeys = 1;
776  /* We can mark the qual as required if it's for first index col */
777  if (cur->sk_attno == 1)
778  _bt_mark_scankey_required(outkeys);
779  return;
780  }
781 
782  /*
783  * Otherwise, do the full set of pushups.
784  */
785  new_numberOfKeys = 0;
786  numberOfEqualCols = 0;
787 
788  /*
789  * Initialize for processing of keys for attr 1.
790  *
791  * xform[i] points to the currently best scan key of strategy type i+1; it
792  * is NULL if we haven't yet found such a key for this attr.
793  */
794  attno = 1;
795  memset(xform, 0, sizeof(xform));
796 
797  /*
798  * Loop iterates from 0 to numberOfKeys inclusive; we use the last pass to
799  * handle after-last-key processing. Actual exit from the loop is at the
800  * "break" statement below.
801  */
802  for (i = 0;; cur++, i++)
803  {
804  if (i < numberOfKeys)
805  {
806  /* Apply indoption to scankey (might change sk_strategy!) */
807  if (!_bt_fix_scankey_strategy(cur, indoption))
808  {
809  /* NULL can't be matched, so give up */
810  so->qual_ok = false;
811  return;
812  }
813  }
814 
815  /*
816  * If we are at the end of the keys for a particular attr, finish up
817  * processing and emit the cleaned-up keys.
818  */
819  if (i == numberOfKeys || cur->sk_attno != attno)
820  {
821  int priorNumberOfEqualCols = numberOfEqualCols;
822 
823  /* check input keys are correctly ordered */
824  if (i < numberOfKeys && cur->sk_attno < attno)
825  elog(ERROR, "btree index keys must be ordered by attribute");
826 
827  /*
828  * If = has been specified, all other keys can be eliminated as
829  * redundant. If we have a case like key = 1 AND key > 2, we can
830  * set qual_ok to false and abandon further processing.
831  *
832  * We also have to deal with the case of "key IS NULL", which is
833  * unsatisfiable in combination with any other index condition. By
834  * the time we get here, that's been classified as an equality
835  * check, and we've rejected any combination of it with a regular
836  * equality condition; but not with other types of conditions.
837  */
838  if (xform[BTEqualStrategyNumber - 1])
839  {
840  ScanKey eq = xform[BTEqualStrategyNumber - 1];
841 
842  for (j = BTMaxStrategyNumber; --j >= 0;)
843  {
844  ScanKey chk = xform[j];
845 
846  if (!chk || j == (BTEqualStrategyNumber - 1))
847  continue;
848 
849  if (eq->sk_flags & SK_SEARCHNULL)
850  {
851  /* IS NULL is contradictory to anything else */
852  so->qual_ok = false;
853  return;
854  }
855 
856  if (_bt_compare_scankey_args(scan, chk, eq, chk,
857  &test_result))
858  {
859  if (!test_result)
860  {
861  /* keys proven mutually contradictory */
862  so->qual_ok = false;
863  return;
864  }
865  /* else discard the redundant non-equality key */
866  xform[j] = NULL;
867  }
868  /* else, cannot determine redundancy, keep both keys */
869  }
870  /* track number of attrs for which we have "=" keys */
871  numberOfEqualCols++;
872  }
873 
874  /* try to keep only one of <, <= */
875  if (xform[BTLessStrategyNumber - 1]
876  && xform[BTLessEqualStrategyNumber - 1])
877  {
878  ScanKey lt = xform[BTLessStrategyNumber - 1];
879  ScanKey le = xform[BTLessEqualStrategyNumber - 1];
880 
881  if (_bt_compare_scankey_args(scan, le, lt, le,
882  &test_result))
883  {
884  if (test_result)
885  xform[BTLessEqualStrategyNumber - 1] = NULL;
886  else
887  xform[BTLessStrategyNumber - 1] = NULL;
888  }
889  }
890 
891  /* try to keep only one of >, >= */
892  if (xform[BTGreaterStrategyNumber - 1]
893  && xform[BTGreaterEqualStrategyNumber - 1])
894  {
895  ScanKey gt = xform[BTGreaterStrategyNumber - 1];
896  ScanKey ge = xform[BTGreaterEqualStrategyNumber - 1];
897 
898  if (_bt_compare_scankey_args(scan, ge, gt, ge,
899  &test_result))
900  {
901  if (test_result)
902  xform[BTGreaterEqualStrategyNumber - 1] = NULL;
903  else
904  xform[BTGreaterStrategyNumber - 1] = NULL;
905  }
906  }
907 
908  /*
909  * Emit the cleaned-up keys into the outkeys[] array, and then
910  * mark them if they are required. They are required (possibly
911  * only in one direction) if all attrs before this one had "=".
912  */
913  for (j = BTMaxStrategyNumber; --j >= 0;)
914  {
915  if (xform[j])
916  {
917  ScanKey outkey = &outkeys[new_numberOfKeys++];
918 
919  memcpy(outkey, xform[j], sizeof(ScanKeyData));
920  if (priorNumberOfEqualCols == attno - 1)
922  }
923  }
924 
925  /*
926  * Exit loop here if done.
927  */
928  if (i == numberOfKeys)
929  break;
930 
931  /* Re-initialize for new attno */
932  attno = cur->sk_attno;
933  memset(xform, 0, sizeof(xform));
934  }
935 
936  /* check strategy this key's operator corresponds to */
937  j = cur->sk_strategy - 1;
938 
939  /* if row comparison, push it directly to the output array */
940  if (cur->sk_flags & SK_ROW_HEADER)
941  {
942  ScanKey outkey = &outkeys[new_numberOfKeys++];
943 
944  memcpy(outkey, cur, sizeof(ScanKeyData));
945  if (numberOfEqualCols == attno - 1)
947 
948  /*
949  * We don't support RowCompare using equality; such a qual would
950  * mess up the numberOfEqualCols tracking.
951  */
952  Assert(j != (BTEqualStrategyNumber - 1));
953  continue;
954  }
955 
956  /* have we seen one of these before? */
957  if (xform[j] == NULL)
958  {
959  /* nope, so remember this scankey */
960  xform[j] = cur;
961  }
962  else
963  {
964  /* yup, keep only the more restrictive key */
965  if (_bt_compare_scankey_args(scan, cur, cur, xform[j],
966  &test_result))
967  {
968  if (test_result)
969  xform[j] = cur;
970  else if (j == (BTEqualStrategyNumber - 1))
971  {
972  /* key == a && key == b, but a != b */
973  so->qual_ok = false;
974  return;
975  }
976  /* else old key is more restrictive, keep it */
977  }
978  else
979  {
980  /*
981  * We can't determine which key is more restrictive. Keep the
982  * previous one in xform[j] and push this one directly to the
983  * output array.
984  */
985  ScanKey outkey = &outkeys[new_numberOfKeys++];
986 
987  memcpy(outkey, cur, sizeof(ScanKeyData));
988  if (numberOfEqualCols == attno - 1)
990  }
991  }
992  }
993 
994  so->numberOfKeys = new_numberOfKeys;
995 }
signed short int16
Definition: c.h:346
static void _bt_mark_scankey_required(ScanKey skey)
Definition: nbtutils.c:1287
int16 * rd_indoption
Definition: rel.h:162
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
struct cursor * cur
Definition: ecpg.c:28
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
Relation indexRelation
Definition: relscan.h:103
#define ERROR
Definition: elog.h:43
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:671
ScanKey arrayKeyData
Definition: nbtree.h:637
#define SK_ROW_HEADER
Definition: skey.h:117
static bool _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
Definition: nbtutils.c:1185
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:739
int numberOfKeys
Definition: nbtree.h:633
struct ScanKeyData * keyData
Definition: relscan.h:107
ScanKey keyData
Definition: nbtree.h:634
#define elog(elevel,...)
Definition: elog.h:228
int i
#define BTMaxStrategyNumber
Definition: stratnum.h:35
static bool _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op, ScanKey leftarg, ScanKey rightarg, bool *result)
Definition: nbtutils.c:1021
#define BTLessStrategyNumber
Definition: stratnum.h:29
int16 AttrNumber
Definition: attnum.h:21
#define SK_SEARCHNULL
Definition: skey.h:121
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32

◆ _bt_restore_array_keys()

void _bt_restore_array_keys ( IndexScanDesc  scan)

Definition at line 611 of file nbtutils.c.

References _bt_preprocess_keys(), BTScanOpaqueData::arrayKeyData, BTScanOpaqueData::arrayKeys, Assert, BTArrayKeyInfo::cur_elem, BTArrayKeyInfo::elem_values, i, BTArrayKeyInfo::mark_elem, BTScanOpaqueData::numArrayKeys, IndexScanDescData::opaque, BTScanOpaqueData::qual_ok, BTArrayKeyInfo::scan_key, and ScanKeyData::sk_argument.

Referenced by btrestrpos().

612 {
613  BTScanOpaque so = (BTScanOpaque) scan->opaque;
614  bool changed = false;
615  int i;
616 
617  /* Restore each array key to its position when the mark was set */
618  for (i = 0; i < so->numArrayKeys; i++)
619  {
620  BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
621  ScanKey skey = &so->arrayKeyData[curArrayKey->scan_key];
622  int mark_elem = curArrayKey->mark_elem;
623 
624  if (curArrayKey->cur_elem != mark_elem)
625  {
626  curArrayKey->cur_elem = mark_elem;
627  skey->sk_argument = curArrayKey->elem_values[mark_elem];
628  changed = true;
629  }
630  }
631 
632  /*
633  * If we changed any keys, we must redo _bt_preprocess_keys. That might
634  * sound like overkill, but in cases with multiple keys per index column
635  * it seems necessary to do the full set of pushups.
636  */
637  if (changed)
638  {
639  _bt_preprocess_keys(scan);
640  /* The mark should have been set on a consistent set of keys... */
641  Assert(so->qual_ok);
642  }
643 }
int mark_elem
Definition: nbtree.h:624
Datum * elem_values
Definition: nbtree.h:626
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:671
int cur_elem
Definition: nbtree.h:623
int numArrayKeys
Definition: nbtree.h:638
ScanKey arrayKeyData
Definition: nbtree.h:637
void _bt_preprocess_keys(IndexScanDesc scan)
Definition: nbtutils.c:731
#define Assert(condition)
Definition: c.h:739
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:642
int i
Datum sk_argument
Definition: skey.h:72
int scan_key
Definition: nbtree.h:622

◆ _bt_sort_array_elements()

static int _bt_sort_array_elements ( IndexScanDesc  scan,
ScanKey  skey,
bool  reverse,
Datum elems,
int  nelems 
)
static

Definition at line 431 of file nbtutils.c.

References _bt_compare_array_elements(), BTORDER_PROC, BTSortArrayContext::collation, elog, ERROR, BTSortArrayContext::flinfo, fmgr_info(), get_opfamily_proc(), IndexScanDescData::indexRelation, InvalidOid, qsort_arg(), qunique_arg(), RelationData::rd_opcintype, RelationData::rd_opfamily, RegProcedureIsValid, BTSortArrayContext::reverse, ScanKeyData::sk_attno, ScanKeyData::sk_collation, and ScanKeyData::sk_subtype.

Referenced by _bt_preprocess_array_keys().

434 {
435  Relation rel = scan->indexRelation;
436  Oid elemtype;
437  RegProcedure cmp_proc;
438  BTSortArrayContext cxt;
439 
440  if (nelems <= 1)
441  return nelems; /* no work to do */
442 
443  /*
444  * Determine the nominal datatype of the array elements. We have to
445  * support the convention that sk_subtype == InvalidOid means the opclass
446  * input type; this is a hack to simplify life for ScanKeyInit().
447  */
448  elemtype = skey->sk_subtype;
449  if (elemtype == InvalidOid)
450  elemtype = rel->rd_opcintype[skey->sk_attno - 1];
451 
452  /*
453  * Look up the appropriate comparison function in the opfamily.
454  *
455  * Note: it's possible that this would fail, if the opfamily is
456  * incomplete, but it seems quite unlikely that an opfamily would omit
457  * non-cross-type support functions for any datatype that it supports at
458  * all.
459  */
460  cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
461  elemtype,
462  elemtype,
463  BTORDER_PROC);
464  if (!RegProcedureIsValid(cmp_proc))
465  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
466  BTORDER_PROC, elemtype, elemtype,
467  rel->rd_opfamily[skey->sk_attno - 1]);
468 
469  /* Sort the array elements */
470  fmgr_info(cmp_proc, &cxt.flinfo);
471  cxt.collation = skey->sk_collation;
472  cxt.reverse = reverse;
473  qsort_arg((void *) elems, nelems, sizeof(Datum),
474  _bt_compare_array_elements, (void *) &cxt);
475 
476  /* Now scan the sorted elements and remove duplicates */
477  return qunique_arg(elems, nelems, sizeof(Datum),
479 }
Oid sk_subtype
Definition: skey.h:69
#define BTORDER_PROC
Definition: nbtree.h:393
static size_t qunique_arg(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *, void *), void *arg)
Definition: qunique.h:45
regproc RegProcedure
Definition: c.h:512
FmgrInfo flinfo
Definition: nbtutils.c:35
unsigned int Oid
Definition: postgres_ext.h:31
Relation indexRelation
Definition: relscan.h:103
#define ERROR
Definition: elog.h:43
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:124
#define RegProcedureIsValid(p)
Definition: c.h:647
Oid * rd_opfamily
Definition: rel.h:158
static int _bt_compare_array_elements(const void *a, const void *b, void *arg)
Definition: nbtutils.c:485
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
Definition: qsort_arg.c:113
uintptr_t Datum
Definition: postgres.h:367
#define InvalidOid
Definition: postgres_ext.h:36
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:744
Oid sk_collation
Definition: skey.h:70
#define elog(elevel,...)
Definition: elog.h:228
Oid * rd_opcintype
Definition: rel.h:159
AttrNumber sk_attno
Definition: skey.h:67

◆ _bt_start_array_keys()

void _bt_start_array_keys ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 507 of file nbtutils.c.

References BTScanOpaqueData::arrayKeyData, BTScanOpaqueData::arrayKeys, Assert, BTArrayKeyInfo::cur_elem, BTArrayKeyInfo::elem_values, i, BTArrayKeyInfo::num_elems, BTScanOpaqueData::numArrayKeys, IndexScanDescData::opaque, BTArrayKeyInfo::scan_key, ScanDirectionIsBackward, and ScanKeyData::sk_argument.

Referenced by btgetbitmap(), and btgettuple().

508 {
509  BTScanOpaque so = (BTScanOpaque) scan->opaque;
510  int i;
511 
512  for (i = 0; i < so->numArrayKeys; i++)
513  {
514  BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
515  ScanKey skey = &so->arrayKeyData[curArrayKey->scan_key];
516 
517  Assert(curArrayKey->num_elems > 0);
518  if (ScanDirectionIsBackward(dir))
519  curArrayKey->cur_elem = curArrayKey->num_elems - 1;
520  else
521  curArrayKey->cur_elem = 0;
522  skey->sk_argument = curArrayKey->elem_values[curArrayKey->cur_elem];
523  }
524 }
Datum * elem_values
Definition: nbtree.h:626
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:671
int cur_elem
Definition: nbtree.h:623
int numArrayKeys
Definition: nbtree.h:638
ScanKey arrayKeyData
Definition: nbtree.h:637
int num_elems
Definition: nbtree.h:625
#define Assert(condition)
Definition: c.h:739
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:642
int i
Datum sk_argument
Definition: skey.h:72
int scan_key
Definition: nbtree.h:622

◆ _bt_start_vacuum()

BTCycleId _bt_start_vacuum ( Relation  rel)

Definition at line 1880 of file nbtutils.c.

References BTVacInfo::cycle_ctr, BTOneVacInfo::cycleid, LockRelId::dbId, elog, ERROR, i, LockInfoData::lockRelId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAX_BT_CYCLE_ID, BTVacInfo::max_vacuums, BTVacInfo::num_vacuums, RelationData::rd_lockInfo, RelationGetRelationName, LockRelId::relId, BTOneVacInfo::relid, and BTVacInfo::vacuums.

Referenced by btbulkdelete().

1881 {
1882  BTCycleId result;
1883  int i;
1884  BTOneVacInfo *vac;
1885 
1886  LWLockAcquire(BtreeVacuumLock, LW_EXCLUSIVE);
1887 
1888  /*
1889  * Assign the next cycle ID, being careful to avoid zero as well as the
1890  * reserved high values.
1891  */
1892  result = ++(btvacinfo->cycle_ctr);
1893  if (result == 0 || result > MAX_BT_CYCLE_ID)
1894  result = btvacinfo->cycle_ctr = 1;
1895 
1896  /* Let's just make sure there's no entry already for this index */
1897  for (i = 0; i < btvacinfo->num_vacuums; i++)
1898  {
1899  vac = &btvacinfo->vacuums[i];
1900  if (vac->relid.relId == rel->rd_lockInfo.lockRelId.relId &&
1901  vac->relid.dbId == rel->rd_lockInfo.lockRelId.dbId)
1902  {
1903  /*
1904  * Unlike most places in the backend, we have to explicitly
1905  * release our LWLock before throwing an error. This is because
1906  * we expect _bt_end_vacuum() to be called before transaction
1907  * abort cleanup can run to release LWLocks.
1908  */
1909  LWLockRelease(BtreeVacuumLock);
1910  elog(ERROR, "multiple active vacuums for index \"%s\"",
1912  }
1913  }
1914 
1915  /* OK, add an entry */
1917  {
1918  LWLockRelease(BtreeVacuumLock);
1919  elog(ERROR, "out of btvacinfo slots");
1920  }
1922  vac->relid = rel->rd_lockInfo.lockRelId;
1923  vac->cycleid = result;
1925 
1926  LWLockRelease(BtreeVacuumLock);
1927  return result;
1928 }
LockRelId lockRelId
Definition: rel.h:43
static BTVacInfo * btvacinfo
Definition: nbtutils.c:1833
LockRelId relid
Definition: nbtutils.c:1821
Oid dbId
Definition: rel.h:38
BTCycleId cycle_ctr
Definition: nbtutils.c:1827
BTOneVacInfo vacuums[FLEXIBLE_ARRAY_MEMBER]
Definition: nbtutils.c:1830
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define ERROR
Definition: elog.h:43
uint16 BTCycleId
Definition: nbtree.h:28
LockInfoData rd_lockInfo
Definition: rel.h:86
#define RelationGetRelationName(relation)
Definition: rel.h:456
BTCycleId cycleid
Definition: nbtutils.c:1822
#define MAX_BT_CYCLE_ID
Definition: nbtree.h:88
int max_vacuums
Definition: nbtutils.c:1829
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int num_vacuums
Definition: nbtutils.c:1828
#define elog(elevel,...)
Definition: elog.h:228
int i
Oid relId
Definition: rel.h:37

◆ _bt_truncate()

IndexTuple _bt_truncate ( Relation  rel,
IndexTuple  lastleft,
IndexTuple  firstright,
BTScanInsert  itup_key 
)

Definition at line 2109 of file nbtutils.c.

References _bt_keep_natts(), Assert, BTreeTupleGetNAtts, BTreeTupleSetAltHeapTID, BTreeTupleSetNAtts, BTScanInsertData::heapkeyspace, INDEX_SIZE_MASK, index_truncate_tuple(), IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, IndexTupleSize, ItemPointerCompare(), ItemPointerCopy, ItemPointerGetOffsetNumber, ItemPointerSetOffsetNumber, MAXALIGN, OffsetNumberPrev, palloc0(), pfree(), RelationGetDescr, IndexTupleData::t_info, and IndexTupleData::t_tid.

Referenced by _bt_buildadd(), and _bt_split().

2111 {
2112  TupleDesc itupdesc = RelationGetDescr(rel);
2115  int keepnatts;
2116  IndexTuple pivot;
2117  ItemPointer pivotheaptid;
2118  Size newsize;
2119 
2120  /*
2121  * We should only ever truncate leaf index tuples. It's never okay to
2122  * truncate a second time.
2123  */
2124  Assert(BTreeTupleGetNAtts(lastleft, rel) == natts);
2125  Assert(BTreeTupleGetNAtts(firstright, rel) == natts);
2126 
2127  /* Determine how many attributes must be kept in truncated tuple */
2128  keepnatts = _bt_keep_natts(rel, lastleft, firstright, itup_key);
2129 
2130 #ifdef DEBUG_NO_TRUNCATE
2131  /* Force truncation to be ineffective for testing purposes */
2132  keepnatts = nkeyatts + 1;
2133 #endif
2134 
2135  if (keepnatts <= natts)
2136  {
2137  IndexTuple tidpivot;
2138 
2139  pivot = index_truncate_tuple(itupdesc, firstright, keepnatts);
2140 
2141  /*
2142  * If there is a distinguishing key attribute within new pivot tuple,
2143  * there is no need to add an explicit heap TID attribute
2144  */
2145  if (keepnatts <= nkeyatts)
2146  {
2147  BTreeTupleSetNAtts(pivot, keepnatts);
2148  return pivot;
2149  }
2150 
2151  /*
2152  * Only truncation of non-key attributes was possible, since key
2153  * attributes are all equal. It's necessary to add a heap TID
2154  * attribute to the new pivot tuple.
2155  */
2156  Assert(natts != nkeyatts);
2157  newsize = IndexTupleSize(pivot) + MAXALIGN(sizeof(ItemPointerData));
2158  tidpivot = palloc0(newsize);
2159  memcpy(tidpivot, pivot, IndexTupleSize(pivot));
2160  /* cannot leak memory here */
2161  pfree(pivot);
2162  pivot = tidpivot;
2163  }
2164  else
2165  {
2166  /*
2167  * No truncation was possible, since key attributes are all equal.
2168  * It's necessary to add a heap TID attribute to the new pivot tuple.
2169  */
2170  Assert(natts == nkeyatts);
2171  newsize = IndexTupleSize(firstright) + MAXALIGN(sizeof(ItemPointerData));
2172  pivot = palloc0(newsize);
2173  memcpy(pivot, firstright, IndexTupleSize(firstright));
2174  }
2175 
2176  /*
2177  * We have to use heap TID as a unique-ifier in the new pivot tuple, since
2178  * no non-TID key attribute in the right item readily distinguishes the
2179  * right side of the split from the left side. Use enlarged space that
2180  * holds a copy of first right tuple; place a heap TID value within the
2181  * extra space that remains at the end.
2182  *
2183  * nbtree conceptualizes this case as an inability to truncate away any
2184  * key attribute. We must use an alternative representation of heap TID
2185  * within pivots because heap TID is only treated as an attribute within
2186  * nbtree (e.g., there is no pg_attribute entry).
2187  */
2188  Assert(itup_key->heapkeyspace);
2189  pivot->t_info &= ~INDEX_SIZE_MASK;
2190  pivot->t_info |= newsize;
2191 
2192  /*
2193  * Lehman & Yao use lastleft as the leaf high key in all cases, but don't
2194  * consider suffix truncation. It seems like a good idea to follow that
2195  * example in cases where no truncation takes place -- use lastleft's heap
2196  * TID. (This is also the closest value to negative infinity that's
2197  * legally usable.)
2198  */
2199  pivotheaptid = (ItemPointer) ((char *) pivot + newsize -
2200  sizeof(ItemPointerData));
2201  ItemPointerCopy(&lastleft->t_tid, pivotheaptid);
2202 
2203  /*
2204  * Lehman and Yao require that the downlink to the right page, which is to
2205  * be inserted into the parent page in the second phase of a page split be
2206  * a strict lower bound on items on the right page, and a non-strict upper
2207  * bound for items on the left page. Assert that heap TIDs follow these
2208  * invariants, since a heap TID value is apparently needed as a
2209  * tiebreaker.
2210  */
2211 #ifndef DEBUG_NO_TRUNCATE
2212  Assert(ItemPointerCompare(&lastleft->t_tid, &firstright->t_tid) < 0);
2213  Assert(ItemPointerCompare(pivotheaptid, &lastleft->t_tid) >= 0);
2214  Assert(ItemPointerCompare(pivotheaptid, &firstright->t_tid) < 0);
2215 #else
2216 
2217  /*
2218  * Those invariants aren't guaranteed to hold for lastleft + firstright
2219  * heap TID attribute values when they're considered here only because
2220  * DEBUG_NO_TRUNCATE is defined (a heap TID is probably not actually
2221  * needed as a tiebreaker). DEBUG_NO_TRUNCATE must therefore use a heap
2222  * TID value that always works as a strict lower bound for items to the
2223  * right. In particular, it must avoid using firstright's leading key
2224  * attribute values along with lastleft's heap TID value when lastleft's
2225  * TID happens to be greater than firstright's TID.
2226  */
2227  ItemPointerCopy(&firstright->t_tid, pivotheaptid);
2228 
2229  /*
2230  * Pivot heap TID should never be fully equal to firstright. Note that
2231  * the pivot heap TID will still end up equal to lastleft's heap TID when
2232  * that's the only usable value.
2233  */
2234  ItemPointerSetOffsetNumber(pivotheaptid,
2236  Assert(ItemPointerCompare(pivotheaptid, &firstright->t_tid) < 0);
2237 #endif
2238 
2239  BTreeTupleSetNAtts(pivot, nkeyatts);
2240  BTreeTupleSetAltHeapTID(pivot);
2241 
2242  return pivot;
2243 }
static int _bt_keep_natts(Relation rel, IndexTuple lastleft, IndexTuple firstright, BTScanInsert itup_key)
Definition: nbtutils.c:2257
int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
Definition: itemptr.c:52
signed short int16
Definition: c.h:346
#define RelationGetDescr(relation)
Definition: rel.h:448
ItemPointerData t_tid
Definition: itup.h:37
#define INDEX_SIZE_MASK
Definition: itup.h:65
#define BTreeTupleGetNAtts(itup, rel)
Definition: nbtree.h:328
#define BTreeTupleSetNAtts(itup, n)
Definition: nbtree.h:337
ItemPointerData * ItemPointer
Definition: itemptr.h:49
void pfree(void *pointer)
Definition: mcxt.c:1056
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:434
IndexTuple index_truncate_tuple(TupleDesc sourceDescriptor, IndexTuple source, int leavenatts)
Definition: indextuple.c:538
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:441
void * palloc0(Size size)
Definition: mcxt.c:980
#define Assert(condition)
Definition: c.h:739
bool heapkeyspace
Definition: nbtree.h:472
struct ItemPointerData ItemPointerData
size_t Size
Definition: c.h:467
#define OffsetNumberPrev(offsetNumber)
Definition: off.h:54
#define MAXALIGN(LEN)
Definition: c.h:692
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define BTreeTupleSetAltHeapTID(itup)
Definition: nbtree.h:361
#define ItemPointerSetOffsetNumber(pointer, offsetNumber)
Definition: itemptr.h:148
unsigned short t_info
Definition: itup.h:49
#define IndexTupleSize(itup)
Definition: itup.h:71
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:161

◆ _bt_vacuum_cycleid()

BTCycleId _bt_vacuum_cycleid ( Relation  rel)

Definition at line 1846 of file nbtutils.c.

References BTOneVacInfo::cycleid, LockRelId::dbId, i, LockInfoData::lockRelId, LW_SHARED, LWLockAcquire(), LWLockRelease(), BTVacInfo::num_vacuums, RelationData::rd_lockInfo, LockRelId::relId, BTOneVacInfo::relid, and BTVacInfo::vacuums.

Referenced by _bt_split().

1847 {
1848  BTCycleId result = 0;
1849  int i;
1850 
1851  /* Share lock is enough since this is a read-only operation */
1852  LWLockAcquire(BtreeVacuumLock, LW_SHARED);
1853 
1854  for (i = 0; i < btvacinfo->num_vacuums; i++)
1855  {
1856  BTOneVacInfo *vac = &btvacinfo->vacuums[i];
1857 
1858  if (vac->relid.relId == rel->rd_lockInfo.lockRelId.relId &&
1859  vac->relid.dbId == rel->rd_lockInfo.lockRelId.dbId)
1860  {
1861  result = vac->cycleid;
1862  break;
1863  }
1864  }
1865 
1866  LWLockRelease(BtreeVacuumLock);
1867  return result;
1868 }
LockRelId lockRelId
Definition: rel.h:43
static BTVacInfo * btvacinfo
Definition: nbtutils.c:1833
LockRelId relid
Definition: nbtutils.c:1821
Oid dbId
Definition: rel.h:38
BTOneVacInfo vacuums[FLEXIBLE_ARRAY_MEMBER]
Definition: nbtutils.c:1830
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
uint16 BTCycleId
Definition: nbtree.h:28
LockInfoData rd_lockInfo
Definition: rel.h:86
BTCycleId cycleid
Definition: nbtutils.c:1822
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int num_vacuums
Definition: nbtutils.c:1828
int i
Oid relId
Definition: rel.h:37

◆ btbuildphasename()

char* btbuildphasename ( int64  phasenum)

Definition at line 2061 of file nbtutils.c.

References PROGRESS_BTREE_PHASE_INDEXBUILD_TABLESCAN, PROGRESS_BTREE_PHASE_LEAF_LOAD, PROGRESS_BTREE_PHASE_PERFORMSORT_1, PROGRESS_BTREE_PHASE_PERFORMSORT_2, and PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE.

Referenced by bthandler().

2062 {
2063  switch (phasenum)
2064  {
2066  return "initializing";
2068  return "scanning table";
2070  return "sorting live tuples";
2072  return "sorting dead tuples";
2074  return "loading tuples in tree";
2075  default:
2076  return NULL;
2077  }
2078 }
#define PROGRESS_BTREE_PHASE_INDEXBUILD_TABLESCAN
Definition: nbtree.h:706
#define PROGRESS_BTREE_PHASE_PERFORMSORT_1
Definition: nbtree.h:707
#define PROGRESS_BTREE_PHASE_PERFORMSORT_2
Definition: nbtree.h:708
#define PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE
Definition: progress.h:87
#define PROGRESS_BTREE_PHASE_LEAF_LOAD
Definition: nbtree.h:709

◆ btoptions()

bytea* btoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 2015 of file nbtutils.c.

References build_reloptions(), fillfactor, lengthof, offsetof, RELOPT_KIND_BTREE, RELOPT_TYPE_INT, RELOPT_TYPE_REAL, and vacuum_cleanup_index_scale_factor.

Referenced by bthandler().

2016 {
2017  static const relopt_parse_elt tab[] = {
2018  {"fillfactor", RELOPT_TYPE_INT, offsetof(BTOptions, fillfactor)},
2019  {"vacuum_cleanup_index_scale_factor", RELOPT_TYPE_REAL,
2021 
2022  };
2023 
2024  return (bytea *) build_reloptions(reloptions, validate,
2026  sizeof(BTOptions),
2027  tab, lengthof(tab));
2028 
2029 }
double vacuum_cleanup_index_scale_factor
Definition: globals.c:150
#define lengthof(array)
Definition: c.h:669
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
Definition: reloptions.c:1552
int fillfactor
Definition: pgbench.c:160
Definition: c.h:556
#define offsetof(type, field)
Definition: c.h:662

◆ btproperty()

bool btproperty ( Oid  index_oid,
int  attno,
IndexAMProperty  prop,
const char *  propname,
bool res,
bool isnull 
)

Definition at line 2038 of file nbtutils.c.

References AMPROP_RETURNABLE.

Referenced by bthandler().

2041 {
2042  switch (prop)
2043  {
2044  case AMPROP_RETURNABLE:
2045  /* answer only for columns, not AM or whole index */
2046  if (attno == 0)
2047  return false;
2048  /* otherwise, btree can always return data */
2049  *res = true;
2050  return true;
2051 
2052  default:
2053  return false; /* punt to generic code */
2054  }
2055 }

◆ BTreeShmemInit()

void BTreeShmemInit ( void  )

Definition at line 1987 of file nbtutils.c.

References Assert, BTreeShmemSize(), BTVacInfo::cycle_ctr, IsUnderPostmaster, BTVacInfo::max_vacuums, MaxBackends, BTVacInfo::num_vacuums, and ShmemInitStruct().

Referenced by CreateSharedMemoryAndSemaphores().

1988 {
1989  bool found;
1990 
1991  btvacinfo = (BTVacInfo *) ShmemInitStruct("BTree Vacuum State",
1992  BTreeShmemSize(),
1993  &found);
1994 
1995  if (!IsUnderPostmaster)
1996  {
1997  /* Initialize shared memory area */
1998  Assert(!found);
1999 
2000  /*
2001  * It doesn't really matter what the cycle counter starts at, but
2002  * having it always start the same doesn't seem good. Seed with
2003  * low-order bits of time() instead.
2004  */
2005  btvacinfo->cycle_ctr = (BTCycleId) time(NULL);
2006 
2007  btvacinfo->num_vacuums = 0;
2009  }
2010  else
2011  Assert(found);
2012 }
static BTVacInfo * btvacinfo
Definition: nbtutils.c:1833
BTCycleId cycle_ctr
Definition: nbtutils.c:1827
Size BTreeShmemSize(void)
Definition: nbtutils.c:1974
uint16 BTCycleId
Definition: nbtree.h:28
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
int MaxBackends
Definition: globals.c:135
bool IsUnderPostmaster
Definition: globals.c:109
int max_vacuums
Definition: nbtutils.c:1829
#define Assert(condition)
Definition: c.h:739
int num_vacuums
Definition: nbtutils.c:1828

◆ BTreeShmemSize()

Size BTreeShmemSize ( void  )

Definition at line 1974 of file nbtutils.c.

References add_size(), MaxBackends, mul_size(), and offsetof.

Referenced by BTreeShmemInit(), and CreateSharedMemoryAndSemaphores().

1975 {
1976  Size size;
1977 
1978  size = offsetof(BTVacInfo, vacuums);
1979  size = add_size(size, mul_size(MaxBackends, sizeof(BTOneVacInfo)));
1980  return size;
1981 }
int MaxBackends
Definition: globals.c:135
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
size_t Size
Definition: c.h:467
#define offsetof(type, field)
Definition: c.h:662

Variable Documentation

◆ btvacinfo

BTVacInfo* btvacinfo
static

Definition at line 1833 of file nbtutils.c.