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 "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 546 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().

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

◆ _bt_check_natts()

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

Definition at line 2377 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().

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

◆ _bt_check_rowcompare()

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

Definition at line 1523 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().

1525 {
1526  ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
1527  int32 cmpresult = 0;
1528  bool result;
1529 
1530  /* First subkey should be same as the header says */
1531  Assert(subkey->sk_attno == skey->sk_attno);
1532 
1533  /* Loop over columns of the row condition */
1534  for (;;)
1535  {
1536  Datum datum;
1537  bool isNull;
1538 
1539  Assert(subkey->sk_flags & SK_ROW_MEMBER);
1540 
1541  if (subkey->sk_attno > tupnatts)
1542  {
1543  /*
1544  * This attribute is truncated (must be high key). The value for
1545  * this attribute in the first non-pivot tuple on the page to the
1546  * right could be any possible value. Assume that truncated
1547  * attribute passes the qual.
1548  */
1550  cmpresult = 0;
1551  if (subkey->sk_flags & SK_ROW_END)
1552  break;
1553  subkey++;
1554  continue;
1555  }
1556 
1557  datum = index_getattr(tuple,
1558  subkey->sk_attno,
1559  tupdesc,
1560  &isNull);
1561 
1562  if (isNull)
1563  {
1564  if (subkey->sk_flags & SK_BT_NULLS_FIRST)
1565  {
1566  /*
1567  * Since NULLs are sorted before non-NULLs, we know we have
1568  * reached the lower limit of the range of values for this
1569  * index attr. On a backward scan, we can stop if this qual
1570  * is one of the "must match" subset. We can stop regardless
1571  * of whether the qual is > or <, so long as it's required,
1572  * because it's not possible for any future tuples to pass. On
1573  * a forward scan, however, we must keep going, because we may
1574  * have initially positioned to the start of the index.
1575  */
1576  if ((subkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)) &&
1578  *continuescan = false;
1579  }
1580  else
1581  {
1582  /*
1583  * Since NULLs are sorted after non-NULLs, we know we have
1584  * reached the upper limit of the range of values for this
1585  * index attr. On a forward scan, we can stop if this qual is
1586  * one of the "must match" subset. We can stop regardless of
1587  * whether the qual is > or <, so long as it's required,
1588  * because it's not possible for any future tuples to pass. On
1589  * a backward scan, however, we must keep going, because we
1590  * may have initially positioned to the end of the index.
1591  */
1592  if ((subkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)) &&
1594  *continuescan = false;
1595  }
1596 
1597  /*
1598  * In any case, this indextuple doesn't match the qual.
1599  */
1600  return false;
1601  }
1602 
1603  if (subkey->sk_flags & SK_ISNULL)
1604  {
1605  /*
1606  * Unlike the simple-scankey case, this isn't a disallowed case.
1607  * But it can never match. If all the earlier row comparison
1608  * columns are required for the scan direction, we can stop the
1609  * scan, because there can't be another tuple that will succeed.
1610  */
1611  if (subkey != (ScanKey) DatumGetPointer(skey->sk_argument))
1612  subkey--;
1613  if ((subkey->sk_flags & SK_BT_REQFWD) &&
1615  *continuescan = false;
1616  else if ((subkey->sk_flags & SK_BT_REQBKWD) &&
1618  *continuescan = false;
1619  return false;
1620  }
1621 
1622  /* Perform the test --- three-way comparison not bool operator */
1623  cmpresult = DatumGetInt32(FunctionCall2Coll(&subkey->sk_func,
1624  subkey->sk_collation,
1625  datum,
1626  subkey->sk_argument));
1627 
1628  if (subkey->sk_flags & SK_BT_DESC)
1629  INVERT_COMPARE_RESULT(cmpresult);
1630 
1631  /* Done comparing if unequal, else advance to next column */
1632  if (cmpresult != 0)
1633  break;
1634 
1635  if (subkey->sk_flags & SK_ROW_END)
1636  break;
1637  subkey++;
1638  }
1639 
1640  /*
1641  * At this point cmpresult indicates the overall result of the row
1642  * comparison, and subkey points to the deciding column (or the last
1643  * column if the result is "=").
1644  */
1645  switch (subkey->sk_strategy)
1646  {
1647  /* EQ and NE cases aren't allowed here */
1648  case BTLessStrategyNumber:
1649  result = (cmpresult < 0);
1650  break;
1652  result = (cmpresult <= 0);
1653  break;
1655  result = (cmpresult >= 0);
1656  break;
1658  result = (cmpresult > 0);
1659  break;
1660  default:
1661  elog(ERROR, "unrecognized RowCompareType: %d",
1662  (int) subkey->sk_strategy);
1663  result = 0; /* keep compiler quiet */
1664  break;
1665  }
1666 
1667  if (!result)
1668  {
1669  /*
1670  * Tuple fails this qual. If it's a required qual for the current
1671  * scan direction, then we can conclude no further tuples will pass,
1672  * either. Note we have to look at the deciding column, not
1673  * necessarily the first or last column of the row condition.
1674  */
1675  if ((subkey->sk_flags & SK_BT_REQFWD) &&
1677  *continuescan = false;
1678  else if ((subkey->sk_flags & SK_BT_REQBKWD) &&
1680  *continuescan = false;
1681  }
1682 
1683  return result;
1684 }
#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:346
#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:681
uintptr_t Datum
Definition: postgres.h:367
#define SK_BT_REQFWD
Definition: nbtree.h:677
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:732
#define SK_BT_DESC
Definition: nbtree.h:680
#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:226
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define SK_BT_REQBKWD
Definition: nbtree.h:678
Datum sk_argument
Definition: skey.h:72
#define INVERT_COMPARE_RESULT(var)
Definition: c.h:1044
#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 2527 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().

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

◆ _bt_checkkeys()

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

Definition at line 1357 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().

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

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

Referenced by _bt_sort_array_elements().

499 {
500  Datum da = *((const Datum *) a);
501  Datum db = *((const Datum *) b);
503  int32 compare;
504 
505  compare = DatumGetInt32(FunctionCall2Coll(&cxt->flinfo,
506  cxt->collation,
507  da, db));
508  if (cxt->reverse)
509  INVERT_COMPARE_RESULT(compare);
510  return compare;
511 }
#define DatumGetInt32(X)
Definition: postgres.h:472
FmgrInfo flinfo
Definition: nbtutils.c:34
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
signed int int32
Definition: c.h:346
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:1044

◆ _bt_compare_scankey_args()

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

Definition at line 1034 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().

1037 {
1038  Relation rel = scan->indexRelation;
1039  Oid lefttype,
1040  righttype,
1041  optype,
1042  opcintype,
1043  cmp_op;
1044  StrategyNumber strat;
1045 
1046  /*
1047  * First, deal with cases where one or both args are NULL. This should
1048  * only happen when the scankeys represent IS NULL/NOT NULL conditions.
1049  */
1050  if ((leftarg->sk_flags | rightarg->sk_flags) & SK_ISNULL)
1051  {
1052  bool leftnull,
1053  rightnull;
1054 
1055  if (leftarg->sk_flags & SK_ISNULL)
1056  {
1058  leftnull = true;
1059  }
1060  else
1061  leftnull = false;
1062  if (rightarg->sk_flags & SK_ISNULL)
1063  {
1064  Assert(rightarg->sk_flags & (SK_SEARCHNULL | SK_SEARCHNOTNULL));
1065  rightnull = true;
1066  }
1067  else
1068  rightnull = false;
1069 
1070  /*
1071  * We treat NULL as either greater than or less than all other values.
1072  * Since true > false, the tests below work correctly for NULLS LAST
1073  * logic. If the index is NULLS FIRST, we need to flip the strategy.
1074  */
1075  strat = op->sk_strategy;
1076  if (op->sk_flags & SK_BT_NULLS_FIRST)
1077  strat = BTCommuteStrategyNumber(strat);
1078 
1079  switch (strat)
1080  {
1081  case BTLessStrategyNumber:
1082  *result = (leftnull < rightnull);
1083  break;
1085  *result = (leftnull <= rightnull);
1086  break;
1087  case BTEqualStrategyNumber:
1088  *result = (leftnull == rightnull);
1089  break;
1091  *result = (leftnull >= rightnull);
1092  break;
1094  *result = (leftnull > rightnull);
1095  break;
1096  default:
1097  elog(ERROR, "unrecognized StrategyNumber: %d", (int) strat);
1098  *result = false; /* keep compiler quiet */
1099  break;
1100  }
1101  return true;
1102  }
1103 
1104  /*
1105  * The opfamily we need to worry about is identified by the index column.
1106  */
1107  Assert(leftarg->sk_attno == rightarg->sk_attno);
1108 
1109  opcintype = rel->rd_opcintype[leftarg->sk_attno - 1];
1110 
1111  /*
1112  * Determine the actual datatypes of the ScanKey arguments. We have to
1113  * support the convention that sk_subtype == InvalidOid means the opclass
1114  * input type; this is a hack to simplify life for ScanKeyInit().
1115  */
1116  lefttype = leftarg->sk_subtype;
1117  if (lefttype == InvalidOid)
1118  lefttype = opcintype;
1119  righttype = rightarg->sk_subtype;
1120  if (righttype == InvalidOid)
1121  righttype = opcintype;
1122  optype = op->sk_subtype;
1123  if (optype == InvalidOid)
1124  optype = opcintype;
1125 
1126  /*
1127  * If leftarg and rightarg match the types expected for the "op" scankey,
1128  * we can use its already-looked-up comparison function.
1129  */
1130  if (lefttype == opcintype && righttype == optype)
1131  {
1132  *result = DatumGetBool(FunctionCall2Coll(&op->sk_func,
1133  op->sk_collation,
1134  leftarg->sk_argument,
1135  rightarg->sk_argument));
1136  return true;
1137  }
1138 
1139  /*
1140  * Otherwise, we need to go to the syscache to find the appropriate
1141  * operator. (This cannot result in infinite recursion, since no
1142  * indexscan initiated by syscache lookup will use cross-data-type
1143  * operators.)
1144  *
1145  * If the sk_strategy was flipped by _bt_fix_scankey_strategy, we have to
1146  * un-flip it to get the correct opfamily member.
1147  */
1148  strat = op->sk_strategy;
1149  if (op->sk_flags & SK_BT_DESC)
1150  strat = BTCommuteStrategyNumber(strat);
1151 
1152  cmp_op = get_opfamily_member(rel->rd_opfamily[leftarg->sk_attno - 1],
1153  lefttype,
1154  righttype,
1155  strat);
1156  if (OidIsValid(cmp_op))
1157  {
1158  RegProcedure cmp_proc = get_opcode(cmp_op);
1159 
1160  if (RegProcedureIsValid(cmp_proc))
1161  {
1162  *result = DatumGetBool(OidFunctionCall2Coll(cmp_proc,
1163  op->sk_collation,
1164  leftarg->sk_argument,
1165  rightarg->sk_argument));
1166  return true;
1167  }
1168  }
1169 
1170  /* Can't make the comparison */
1171  *result = false; /* suppress compiler warnings */
1172  return false;
1173 }
Oid sk_subtype
Definition: skey.h:69
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
regproc RegProcedure
Definition: c.h:505
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:638
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
Relation indexRelation
Definition: relscan.h:103
#define BTCommuteStrategyNumber(strat)
Definition: nbtree.h:374
#define ERROR
Definition: elog.h:43
StrategyNumber sk_strategy
Definition: skey.h:68
#define RegProcedureIsValid(p)
Definition: c.h:640
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:681
#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:732
#define SK_BT_DESC
Definition: nbtree.h:680
Oid sk_collation
Definition: skey.h:70
#define elog(elevel,...)
Definition: elog.h:226
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 1950 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().

1951 {
1952  int i;
1953 
1954  LWLockAcquire(BtreeVacuumLock, LW_EXCLUSIVE);
1955 
1956  /* Find the array entry */
1957  for (i = 0; i < btvacinfo->num_vacuums; i++)
1958  {
1959  BTOneVacInfo *vac = &btvacinfo->vacuums[i];
1960 
1961  if (vac->relid.relId == rel->rd_lockInfo.lockRelId.relId &&
1962  vac->relid.dbId == rel->rd_lockInfo.lockRelId.dbId)
1963  {
1964  /* Remove it by shifting down the last entry */
1965  *vac = btvacinfo->vacuums[btvacinfo->num_vacuums - 1];
1967  break;
1968  }
1969  }
1970 
1971  LWLockRelease(BtreeVacuumLock);
1972 }
LockRelId lockRelId
Definition: rel.h:43
static BTVacInfo * btvacinfo
Definition: nbtutils.c:1846
LockRelId relid
Definition: nbtutils.c:1834
Oid dbId
Definition: rel.h:38
BTOneVacInfo vacuums[FLEXIBLE_ARRAY_MEMBER]
Definition: nbtutils.c:1843
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:1841
int i
Oid relId
Definition: rel.h:37

◆ _bt_end_vacuum_callback()

void _bt_end_vacuum_callback ( int  code,
Datum  arg 
)

Definition at line 1978 of file nbtutils.c.

References _bt_end_vacuum(), and DatumGetPointer.

Referenced by btbulkdelete().

1979 {
1981 }
void _bt_end_vacuum(Relation rel)
Definition: nbtutils.c:1950
#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 363 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().

366 {
367  Relation rel = scan->indexRelation;
368  Oid elemtype,
369  cmp_op;
370  RegProcedure cmp_proc;
371  FmgrInfo flinfo;
372  Datum result;
373  int i;
374 
375  /*
376  * Determine the nominal datatype of the array elements. We have to
377  * support the convention that sk_subtype == InvalidOid means the opclass
378  * input type; this is a hack to simplify life for ScanKeyInit().
379  */
380  elemtype = skey->sk_subtype;
381  if (elemtype == InvalidOid)
382  elemtype = rel->rd_opcintype[skey->sk_attno - 1];
383 
384  /*
385  * Look up the appropriate comparison operator in the opfamily.
386  *
387  * Note: it's possible that this would fail, if the opfamily is
388  * incomplete, but it seems quite unlikely that an opfamily would omit
389  * non-cross-type comparison operators for any datatype that it supports
390  * at all.
391  */
392  cmp_op = get_opfamily_member(rel->rd_opfamily[skey->sk_attno - 1],
393  elemtype,
394  elemtype,
395  strat);
396  if (!OidIsValid(cmp_op))
397  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
398  strat, elemtype, elemtype,
399  rel->rd_opfamily[skey->sk_attno - 1]);
400  cmp_proc = get_opcode(cmp_op);
401  if (!RegProcedureIsValid(cmp_proc))
402  elog(ERROR, "missing oprcode for operator %u", cmp_op);
403 
404  fmgr_info(cmp_proc, &flinfo);
405 
406  Assert(nelems > 0);
407  result = elems[0];
408  for (i = 1; i < nelems; i++)
409  {
410  if (DatumGetBool(FunctionCall2Coll(&flinfo,
411  skey->sk_collation,
412  elems[i],
413  result)))
414  result = elems[i];
415  }
416 
417  return result;
418 }
Oid sk_subtype
Definition: skey.h:69
Definition: fmgr.h:56
regproc RegProcedure
Definition: c.h:505
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:638
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:640
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:732
Oid sk_collation
Definition: skey.h:70
#define elog(elevel,...)
Definition: elog.h:226
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 1198 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().

1199 {
1200  int addflags;
1201 
1202  addflags = indoption[skey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
1203 
1204  /*
1205  * We treat all btree operators as strict (even if they're not so marked
1206  * in pg_proc). This means that it is impossible for an operator condition
1207  * with a NULL comparison constant to succeed, and we can reject it right
1208  * away.
1209  *
1210  * However, we now also support "x IS NULL" clauses as search conditions,
1211  * so in that case keep going. The planner has not filled in any
1212  * particular strategy in this case, so set it to BTEqualStrategyNumber
1213  * --- we can treat IS NULL as an equality operator for purposes of search
1214  * strategy.
1215  *
1216  * Likewise, "x IS NOT NULL" is supported. We treat that as either "less
1217  * than NULL" in a NULLS LAST index, or "greater than NULL" in a NULLS
1218  * FIRST index.
1219  *
1220  * Note: someday we might have to fill in sk_collation from the index
1221  * column's collation. At the moment this is a non-issue because we'll
1222  * never actually call the comparison operator on a NULL.
1223  */
1224  if (skey->sk_flags & SK_ISNULL)
1225  {
1226  /* SK_ISNULL shouldn't be set in a row header scankey */
1227  Assert(!(skey->sk_flags & SK_ROW_HEADER));
1228 
1229  /* Set indoption flags in scankey (might be done already) */
1230  skey->sk_flags |= addflags;
1231 
1232  /* Set correct strategy for IS NULL or NOT NULL search */
1233  if (skey->sk_flags & SK_SEARCHNULL)
1234  {
1236  skey->sk_subtype = InvalidOid;
1237  skey->sk_collation = InvalidOid;
1238  }
1239  else if (skey->sk_flags & SK_SEARCHNOTNULL)
1240  {
1241  if (skey->sk_flags & SK_BT_NULLS_FIRST)
1243  else
1245  skey->sk_subtype = InvalidOid;
1246  skey->sk_collation = InvalidOid;
1247  }
1248  else
1249  {
1250  /* regular qual, so it cannot be satisfied */
1251  return false;
1252  }
1253 
1254  /* Needn't do the rest */
1255  return true;
1256  }
1257 
1258  /* Adjust strategy for DESC, if we didn't already */
1259  if ((addflags & SK_BT_DESC) && !(skey->sk_flags & SK_BT_DESC))
1261  skey->sk_flags |= addflags;
1262 
1263  /* If it's a row header, fix row member flags and strategies similarly */
1264  if (skey->sk_flags & SK_ROW_HEADER)
1265  {
1266  ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
1267 
1268  for (;;)
1269  {
1270  Assert(subkey->sk_flags & SK_ROW_MEMBER);
1271  addflags = indoption[subkey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
1272  if ((addflags & SK_BT_DESC) && !(subkey->sk_flags & SK_BT_DESC))
1273  subkey->sk_strategy = BTCommuteStrategyNumber(subkey->sk_strategy);
1274  subkey->sk_flags |= addflags;
1275  if (subkey->sk_flags & SK_ROW_END)
1276  break;
1277  subkey++;
1278  }
1279  }
1280 
1281  return true;
1282 }
#define SK_BT_INDOPTION_SHIFT
Definition: nbtree.h:679
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:374
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:681
#define InvalidOid
Definition: postgres_ext.h:36
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:732
#define SK_BT_DESC
Definition: nbtree.h:680
#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 163 of file nbtutils.c.

References BTStackData::bts_parent, and pfree().

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

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

◆ _bt_keep_natts()

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

Definition at line 2259 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().

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

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

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

2331 {
2332  TupleDesc itupdesc = RelationGetDescr(rel);
2333  int keysz = IndexRelationGetNumberOfKeyAttributes(rel);
2334  int keepnatts;
2335 
2336  keepnatts = 1;
2337  for (int attnum = 1; attnum <= keysz; attnum++)
2338  {
2339  Datum datum1,
2340  datum2;
2341  bool isNull1,
2342  isNull2;
2343  Form_pg_attribute att;
2344 
2345  datum1 = index_getattr(lastleft, attnum, itupdesc, &isNull1);
2346  datum2 = index_getattr(firstright, attnum, itupdesc, &isNull2);
2347  att = TupleDescAttr(itupdesc, attnum - 1);
2348 
2349  if (isNull1 != isNull2)
2350  break;
2351 
2352  if (!isNull1 &&
2353  !datumIsEqual(datum1, datum2, att->attbyval, att->attlen))
2354  break;
2355 
2356  keepnatts++;
2357  }
2358 
2359  return keepnatts;
2360 }
#define RelationGetDescr(relation)
Definition: rel.h:445
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:221
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:438
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

◆ _bt_killitems()

void _bt_killitems ( IndexScanDesc  scan)

Definition at line 1718 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().

1719 {
1720  BTScanOpaque so = (BTScanOpaque) scan->opaque;
1721  Page page;
1722  BTPageOpaque opaque;
1723  OffsetNumber minoff;
1724  OffsetNumber maxoff;
1725  int i;
1726  int numKilled = so->numKilled;
1727  bool killedsomething = false;
1728 
1730 
1731  /*
1732  * Always reset the scan state, so we don't look for same items on other
1733  * pages.
1734  */
1735  so->numKilled = 0;
1736 
1737  if (BTScanPosIsPinned(so->currPos))
1738  {
1739  /*
1740  * We have held the pin on this page since we read the index tuples,
1741  * so all we need to do is lock it. The pin will have prevented
1742  * re-use of any TID on the page, so there is no need to check the
1743  * LSN.
1744  */
1745  LockBuffer(so->currPos.buf, BT_READ);
1746 
1747  page = BufferGetPage(so->currPos.buf);
1748  }
1749  else
1750  {
1751  Buffer buf;
1752 
1753  /* Attempt to re-read the buffer, getting pin and lock. */
1754  buf = _bt_getbuf(scan->indexRelation, so->currPos.currPage, BT_READ);
1755 
1756  /* It might not exist anymore; in which case we can't hint it. */
1757  if (!BufferIsValid(buf))
1758  return;
1759 
1760  page = BufferGetPage(buf);
1761  if (BufferGetLSNAtomic(buf) == so->currPos.lsn)
1762  so->currPos.buf = buf;
1763  else
1764  {
1765  /* Modified while not pinned means hinting is not safe. */
1766  _bt_relbuf(scan->indexRelation, buf);
1767  return;
1768  }
1769  }
1770 
1771  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1772  minoff = P_FIRSTDATAKEY(opaque);
1773  maxoff = PageGetMaxOffsetNumber(page);
1774 
1775  for (i = 0; i < numKilled; i++)
1776  {
1777  int itemIndex = so->killedItems[i];
1778  BTScanPosItem *kitem = &so->currPos.items[itemIndex];
1779  OffsetNumber offnum = kitem->indexOffset;
1780 
1781  Assert(itemIndex >= so->currPos.firstItem &&
1782  itemIndex <= so->currPos.lastItem);
1783  if (offnum < minoff)
1784  continue; /* pure paranoia */
1785  while (offnum <= maxoff)
1786  {
1787  ItemId iid = PageGetItemId(page, offnum);
1788  IndexTuple ituple = (IndexTuple) PageGetItem(page, iid);
1789 
1790  if (ItemPointerEquals(&ituple->t_tid, &kitem->heapTid))
1791  {
1792  /* found the item */
1793  ItemIdMarkDead(iid);
1794  killedsomething = true;
1795  break; /* out of inner search loop */
1796  }
1797  offnum = OffsetNumberNext(offnum);
1798  }
1799  }
1800 
1801  /*
1802  * Since this can be redone later if needed, mark as dirty hint.
1803  *
1804  * Whenever we mark anything LP_DEAD, we also set the page's
1805  * BTP_HAS_GARBAGE flag, which is likewise just a hint.
1806  */
1807  if (killedsomething)
1808  {
1809  opaque->btpo_flags |= BTP_HAS_GARBAGE;
1810  MarkBufferDirtyHint(so->currPos.buf, true);
1811  }
1812 
1814 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
BTScanPosItem items[MaxIndexTuplesPerPage]
Definition: nbtree.h:581
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:219
ItemPointerData t_tid
Definition: itup.h:37
BlockNumber currPage
Definition: nbtree.h:552
#define BTScanPosIsValid(scanpos)
Definition: nbtree.h:603
OffsetNumber indexOffset
Definition: nbtree.h:543
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
Relation indexRelation
Definition: relscan.h:103
uint16 OffsetNumber
Definition: off.h:24
#define BT_READ
Definition: nbtree.h:402
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:670
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:2876
static char * buf
Definition: pg_test_fsync.c:68
#define BTScanPosIsPinned(scanpos)
Definition: nbtree.h:586
IndexTupleData * IndexTuple
Definition: itup.h:53
int firstItem
Definition: nbtree.h:577
#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:645
#define Assert(condition)
Definition: c.h:732
#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:542
BTScanPosData currPos
Definition: nbtree.h:666
int i
XLogRecPtr lsn
Definition: nbtree.h:551
Buffer buf
Definition: nbtree.h:549
int Buffer
Definition: buf.h:23
#define BTP_HAS_GARBAGE
Definition: nbtree.h:77
#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 605 of file nbtutils.c.

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

Referenced by btmarkpos().

606 {
607  BTScanOpaque so = (BTScanOpaque) scan->opaque;
608  int i;
609 
610  for (i = 0; i < so->numArrayKeys; i++)
611  {
612  BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
613 
614  curArrayKey->mark_elem = curArrayKey->cur_elem;
615  }
616 }
int mark_elem
Definition: nbtree.h:623
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:670
int cur_elem
Definition: nbtree.h:622
int numArrayKeys
Definition: nbtree.h:637
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:641
int i

◆ _bt_mark_scankey_required()

static void _bt_mark_scankey_required ( ScanKey  skey)
static

Definition at line 1300 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().

1301 {
1302  int addflags;
1303 
1304  switch (skey->sk_strategy)
1305  {
1306  case BTLessStrategyNumber:
1308  addflags = SK_BT_REQFWD;
1309  break;
1310  case BTEqualStrategyNumber:
1311  addflags = SK_BT_REQFWD | SK_BT_REQBKWD;
1312  break;
1315  addflags = SK_BT_REQBKWD;
1316  break;
1317  default:
1318  elog(ERROR, "unrecognized StrategyNumber: %d",
1319  (int) skey->sk_strategy);
1320  addflags = 0; /* keep compiler quiet */
1321  break;
1322  }
1323 
1324  skey->sk_flags |= addflags;
1325 
1326  if (skey->sk_flags & SK_ROW_HEADER)
1327  {
1328  ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
1329 
1330  /* First subkey should be same column/operator as the header */
1331  Assert(subkey->sk_flags & SK_ROW_MEMBER);
1332  Assert(subkey->sk_attno == skey->sk_attno);
1333  Assert(subkey->sk_strategy == skey->sk_strategy);
1334  subkey->sk_flags |= addflags;
1335  }
1336 }
#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:677
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:732
#define DatumGetPointer(X)
Definition: postgres.h:549
#define elog(elevel,...)
Definition: elog.h:226
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define SK_BT_REQBKWD
Definition: nbtree.h:678
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 85 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().

86 {
88  ScanKey skey;
89  TupleDesc itupdesc;
90  int indnkeyatts;
91  int16 *indoption;
92  int tupnatts;
93  int i;
94 
95  itupdesc = RelationGetDescr(rel);
96  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
97  indoption = rel->rd_indoption;
98  tupnatts = itup ? BTreeTupleGetNAtts(itup, rel) : 0;
99 
100  Assert(tupnatts <= IndexRelationGetNumberOfAttributes(rel));
101 
102  /*
103  * We'll execute search using scan key constructed on key columns.
104  * Truncated attributes and non-key attributes are omitted from the final
105  * scan key.
106  */
107  key = palloc(offsetof(BTScanInsertData, scankeys) +
108  sizeof(ScanKeyData) * indnkeyatts);
109  key->heapkeyspace = itup == NULL || _bt_heapkeyspace(rel);
110  key->anynullkeys = false; /* initial assumption */
111  key->nextkey = false;
112  key->pivotsearch = false;
113  key->keysz = Min(indnkeyatts, tupnatts);
114  key->scantid = key->heapkeyspace && itup ?
115  BTreeTupleGetHeapTID(itup) : NULL;
116  skey = key->scankeys;
117  for (i = 0; i < indnkeyatts; i++)
118  {
119  FmgrInfo *procinfo;
120  Datum arg;
121  bool null;
122  int flags;
123 
124  /*
125  * We can use the cached (default) support procs since no cross-type
126  * comparison can be needed.
127  */
128  procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
129 
130  /*
131  * Key arguments built from truncated attributes (or when caller
132  * provides no tuple) are defensively represented as NULL values. They
133  * should never be used.
134  */
135  if (i < tupnatts)
136  arg = index_getattr(itup, i + 1, itupdesc, &null);
137  else
138  {
139  arg = (Datum) 0;
140  null = true;
141  }
142  flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
144  flags,
145  (AttrNumber) (i + 1),
147  InvalidOid,
148  rel->rd_indcollation[i],
149  procinfo,
150  arg);
151  /* Record if any key attribute is NULL (or truncated) */
152  if (null)
153  key->anynullkeys = true;
154  }
155 
156  return key;
157 }
#define SK_BT_INDOPTION_SHIFT
Definition: nbtree.h:679
signed short int16
Definition: c.h:345
#define InvalidStrategy
Definition: stratnum.h:24
Definition: fmgr.h:56
#define BTORDER_PROC
Definition: nbtree.h:392
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:445
ItemPointer scantid
Definition: nbtree.h:475
#define Min(x, y)
Definition: c.h:904
#define BTreeTupleGetHeapTID(itup)
Definition: nbtree.h:346
#define BTreeTupleGetNAtts(itup, rel)
Definition: nbtree.h:327
Oid * rd_indcollation
Definition: rel.h:168
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:431
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:438
#define SK_ISNULL
Definition: skey.h:115
bool pivotsearch
Definition: nbtree.h:474
bool anynullkeys
Definition: nbtree.h:472
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:732
bool heapkeyspace
Definition: nbtree.h:471
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
ScanKeyData scankeys[INDEX_MAX_KEYS]
Definition: nbtree.h:477
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:655

◆ _bt_preprocess_array_keys()

void _bt_preprocess_array_keys ( IndexScanDesc  scan)

Definition at line 191 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().

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

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

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

◆ _bt_sort_array_elements()

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

Definition at line 430 of file nbtutils.c.

References _bt_compare_array_elements(), BTORDER_PROC, BTSortArrayContext::collation, compare(), DatumGetInt32, elog, ERROR, BTSortArrayContext::flinfo, fmgr_info(), FunctionCall2Coll(), get_opfamily_proc(), i, IndexScanDescData::indexRelation, InvalidOid, qsort_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().

433 {
434  Relation rel = scan->indexRelation;
435  Oid elemtype;
436  RegProcedure cmp_proc;
437  BTSortArrayContext cxt;
438  int last_non_dup;
439  int i;
440 
441  if (nelems <= 1)
442  return nelems; /* no work to do */
443 
444  /*
445  * Determine the nominal datatype of the array elements. We have to
446  * support the convention that sk_subtype == InvalidOid means the opclass
447  * input type; this is a hack to simplify life for ScanKeyInit().
448  */
449  elemtype = skey->sk_subtype;
450  if (elemtype == InvalidOid)
451  elemtype = rel->rd_opcintype[skey->sk_attno - 1];
452 
453  /*
454  * Look up the appropriate comparison function in the opfamily.
455  *
456  * Note: it's possible that this would fail, if the opfamily is
457  * incomplete, but it seems quite unlikely that an opfamily would omit
458  * non-cross-type support functions for any datatype that it supports at
459  * all.
460  */
461  cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
462  elemtype,
463  elemtype,
464  BTORDER_PROC);
465  if (!RegProcedureIsValid(cmp_proc))
466  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
467  BTORDER_PROC, elemtype, elemtype,
468  rel->rd_opfamily[skey->sk_attno - 1]);
469 
470  /* Sort the array elements */
471  fmgr_info(cmp_proc, &cxt.flinfo);
472  cxt.collation = skey->sk_collation;
473  cxt.reverse = reverse;
474  qsort_arg((void *) elems, nelems, sizeof(Datum),
475  _bt_compare_array_elements, (void *) &cxt);
476 
477  /* Now scan the sorted elements and remove duplicates */
478  last_non_dup = 0;
479  for (i = 1; i < nelems; i++)
480  {
481  int32 compare;
482 
483  compare = DatumGetInt32(FunctionCall2Coll(&cxt.flinfo,
484  cxt.collation,
485  elems[last_non_dup],
486  elems[i]));
487  if (compare != 0)
488  elems[++last_non_dup] = elems[i];
489  }
490 
491  return last_non_dup + 1;
492 }
Oid sk_subtype
Definition: skey.h:69
#define BTORDER_PROC
Definition: nbtree.h:392
#define DatumGetInt32(X)
Definition: postgres.h:472
regproc RegProcedure
Definition: c.h:505
FmgrInfo flinfo
Definition: nbtutils.c:34
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:346
Relation indexRelation
Definition: relscan.h:103
static int compare(const void *arg1, const void *arg2)
Definition: geqo_pool.c:145
#define ERROR
Definition: elog.h:43
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:124
#define RegProcedureIsValid(p)
Definition: c.h:640
Oid * rd_opfamily
Definition: rel.h:158
static int _bt_compare_array_elements(const void *a, const void *b, void *arg)
Definition: nbtutils.c:498
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:226
int i
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 520 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().

521 {
522  BTScanOpaque so = (BTScanOpaque) scan->opaque;
523  int i;
524 
525  for (i = 0; i < so->numArrayKeys; i++)
526  {
527  BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
528  ScanKey skey = &so->arrayKeyData[curArrayKey->scan_key];
529 
530  Assert(curArrayKey->num_elems > 0);
531  if (ScanDirectionIsBackward(dir))
532  curArrayKey->cur_elem = curArrayKey->num_elems - 1;
533  else
534  curArrayKey->cur_elem = 0;
535  skey->sk_argument = curArrayKey->elem_values[curArrayKey->cur_elem];
536  }
537 }
Datum * elem_values
Definition: nbtree.h:625
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:670
int cur_elem
Definition: nbtree.h:622
int numArrayKeys
Definition: nbtree.h:637
ScanKey arrayKeyData
Definition: nbtree.h:636
int num_elems
Definition: nbtree.h:624
#define Assert(condition)
Definition: c.h:732
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:641
int i
Datum sk_argument
Definition: skey.h:72
int scan_key
Definition: nbtree.h:621

◆ _bt_start_vacuum()

BTCycleId _bt_start_vacuum ( Relation  rel)

Definition at line 1893 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().

1894 {
1895  BTCycleId result;
1896  int i;
1897  BTOneVacInfo *vac;
1898 
1899  LWLockAcquire(BtreeVacuumLock, LW_EXCLUSIVE);
1900 
1901  /*
1902  * Assign the next cycle ID, being careful to avoid zero as well as the
1903  * reserved high values.
1904  */
1905  result = ++(btvacinfo->cycle_ctr);
1906  if (result == 0 || result > MAX_BT_CYCLE_ID)
1907  result = btvacinfo->cycle_ctr = 1;
1908 
1909  /* Let's just make sure there's no entry already for this index */
1910  for (i = 0; i < btvacinfo->num_vacuums; i++)
1911  {
1912  vac = &btvacinfo->vacuums[i];
1913  if (vac->relid.relId == rel->rd_lockInfo.lockRelId.relId &&
1914  vac->relid.dbId == rel->rd_lockInfo.lockRelId.dbId)
1915  {
1916  /*
1917  * Unlike most places in the backend, we have to explicitly
1918  * release our LWLock before throwing an error. This is because
1919  * we expect _bt_end_vacuum() to be called before transaction
1920  * abort cleanup can run to release LWLocks.
1921  */
1922  LWLockRelease(BtreeVacuumLock);
1923  elog(ERROR, "multiple active vacuums for index \"%s\"",
1925  }
1926  }
1927 
1928  /* OK, add an entry */
1930  {
1931  LWLockRelease(BtreeVacuumLock);
1932  elog(ERROR, "out of btvacinfo slots");
1933  }
1935  vac->relid = rel->rd_lockInfo.lockRelId;
1936  vac->cycleid = result;
1938 
1939  LWLockRelease(BtreeVacuumLock);
1940  return result;
1941 }
LockRelId lockRelId
Definition: rel.h:43
static BTVacInfo * btvacinfo
Definition: nbtutils.c:1846
LockRelId relid
Definition: nbtutils.c:1834
Oid dbId
Definition: rel.h:38
BTCycleId cycle_ctr
Definition: nbtutils.c:1840
BTOneVacInfo vacuums[FLEXIBLE_ARRAY_MEMBER]
Definition: nbtutils.c:1843
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define ERROR
Definition: elog.h:43
uint16 BTCycleId
Definition: nbtree.h:27
LockInfoData rd_lockInfo
Definition: rel.h:86
#define RelationGetRelationName(relation)
Definition: rel.h:453
BTCycleId cycleid
Definition: nbtutils.c:1835
#define MAX_BT_CYCLE_ID
Definition: nbtree.h:87
int max_vacuums
Definition: nbtutils.c:1842
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int num_vacuums
Definition: nbtutils.c:1841
#define elog(elevel,...)
Definition: elog.h:226
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 2111 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().

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

1860 {
1861  BTCycleId result = 0;
1862  int i;
1863 
1864  /* Share lock is enough since this is a read-only operation */
1865  LWLockAcquire(BtreeVacuumLock, LW_SHARED);
1866 
1867  for (i = 0; i < btvacinfo->num_vacuums; i++)
1868  {
1869  BTOneVacInfo *vac = &btvacinfo->vacuums[i];
1870 
1871  if (vac->relid.relId == rel->rd_lockInfo.lockRelId.relId &&
1872  vac->relid.dbId == rel->rd_lockInfo.lockRelId.dbId)
1873  {
1874  result = vac->cycleid;
1875  break;
1876  }
1877  }
1878 
1879  LWLockRelease(BtreeVacuumLock);
1880  return result;
1881 }
LockRelId lockRelId
Definition: rel.h:43
static BTVacInfo * btvacinfo
Definition: nbtutils.c:1846
LockRelId relid
Definition: nbtutils.c:1834
Oid dbId
Definition: rel.h:38
BTOneVacInfo vacuums[FLEXIBLE_ARRAY_MEMBER]
Definition: nbtutils.c:1843
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
uint16 BTCycleId
Definition: nbtree.h:27
LockInfoData rd_lockInfo
Definition: rel.h:86
BTCycleId cycleid
Definition: nbtutils.c:1835
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int num_vacuums
Definition: nbtutils.c:1841
int i
Oid relId
Definition: rel.h:37

◆ btbuildphasename()

char* btbuildphasename ( int64  phasenum)

Definition at line 2063 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().

2064 {
2065  switch (phasenum)
2066  {
2068  return "initializing";
2070  return "scanning table";
2072  return "sorting live tuples";
2074  return "sorting dead tuples";
2076  return "loading tuples in tree";
2077  default:
2078  return NULL;
2079  }
2080 }
#define PROGRESS_BTREE_PHASE_INDEXBUILD_TABLESCAN
Definition: nbtree.h:688
#define PROGRESS_BTREE_PHASE_PERFORMSORT_1
Definition: nbtree.h:689
#define PROGRESS_BTREE_PHASE_PERFORMSORT_2
Definition: nbtree.h:690
#define PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE
Definition: progress.h:87
#define PROGRESS_BTREE_PHASE_LEAF_LOAD
Definition: nbtree.h:691

◆ btoptions()

bytea* btoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 2028 of file nbtutils.c.

References default_reloptions(), and RELOPT_KIND_BTREE.

Referenced by bthandler().

2029 {
2030  return default_reloptions(reloptions, validate, RELOPT_KIND_BTREE);
2031 }
bytea * default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
Definition: reloptions.c:1475

◆ btproperty()

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

Definition at line 2040 of file nbtutils.c.

References AMPROP_RETURNABLE.

Referenced by bthandler().

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

◆ BTreeShmemInit()

void BTreeShmemInit ( void  )

Definition at line 2000 of file nbtutils.c.

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

Referenced by CreateSharedMemoryAndSemaphores().

2001 {
2002  bool found;
2003 
2004  btvacinfo = (BTVacInfo *) ShmemInitStruct("BTree Vacuum State",
2005  BTreeShmemSize(),
2006  &found);
2007 
2008  if (!IsUnderPostmaster)
2009  {
2010  /* Initialize shared memory area */
2011  Assert(!found);
2012 
2013  /*
2014  * It doesn't really matter what the cycle counter starts at, but
2015  * having it always start the same doesn't seem good. Seed with
2016  * low-order bits of time() instead.
2017  */
2018  btvacinfo->cycle_ctr = (BTCycleId) time(NULL);
2019 
2020  btvacinfo->num_vacuums = 0;
2022  }
2023  else
2024  Assert(found);
2025 }
static BTVacInfo * btvacinfo
Definition: nbtutils.c:1846
BTCycleId cycle_ctr
Definition: nbtutils.c:1840
Size BTreeShmemSize(void)
Definition: nbtutils.c:1987
uint16 BTCycleId
Definition: nbtree.h:27
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:1842
#define Assert(condition)
Definition: c.h:732
int num_vacuums
Definition: nbtutils.c:1841

◆ BTreeShmemSize()

Size BTreeShmemSize ( void  )

Definition at line 1987 of file nbtutils.c.

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

Referenced by BTreeShmemInit(), and CreateSharedMemoryAndSemaphores().

1988 {
1989  Size size;
1990 
1991  size = offsetof(BTVacInfo, vacuums);
1992  size = add_size(size, mul_size(MaxBackends, sizeof(BTOneVacInfo)));
1993  return size;
1994 }
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:466
#define offsetof(type, field)
Definition: c.h:655

Variable Documentation

◆ btvacinfo

BTVacInfo* btvacinfo
static

Definition at line 1846 of file nbtutils.c.