PostgreSQL Source Code  git master
nodeIndexscan.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "access/relscan.h"
#include "access/tableam.h"
#include "catalog/pg_am.h"
#include "executor/execdebug.h"
#include "executor/nodeIndexscan.h"
#include "lib/pairingheap.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.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 nodeIndexscan.c:

Go to the source code of this file.

Data Structures

struct  ReorderTuple
 

Functions

static TupleTableSlotIndexNext (IndexScanState *node)
 
static TupleTableSlotIndexNextWithReorder (IndexScanState *node)
 
static void EvalOrderByExpressions (IndexScanState *node, ExprContext *econtext)
 
static bool IndexRecheck (IndexScanState *node, TupleTableSlot *slot)
 
static int cmp_orderbyvals (const Datum *adist, const bool *anulls, const Datum *bdist, const bool *bnulls, IndexScanState *node)
 
static int reorderqueue_cmp (const pairingheap_node *a, const pairingheap_node *b, void *arg)
 
static void reorderqueue_push (IndexScanState *node, TupleTableSlot *slot, Datum *orderbyvals, bool *orderbynulls)
 
static HeapTuple reorderqueue_pop (IndexScanState *node)
 
static TupleTableSlotExecIndexScan (PlanState *pstate)
 
void ExecReScanIndexScan (IndexScanState *node)
 
void ExecIndexEvalRuntimeKeys (ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
 
bool ExecIndexEvalArrayKeys (ExprContext *econtext, IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 
bool ExecIndexAdvanceArrayKeys (IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 
void ExecEndIndexScan (IndexScanState *node)
 
void ExecIndexMarkPos (IndexScanState *node)
 
void ExecIndexRestrPos (IndexScanState *node)
 
IndexScanStateExecInitIndexScan (IndexScan *node, EState *estate, int eflags)
 
void ExecIndexBuildScanKeys (PlanState *planstate, Relation index, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
 
void ExecIndexScanEstimate (IndexScanState *node, ParallelContext *pcxt)
 
void ExecIndexScanInitializeDSM (IndexScanState *node, ParallelContext *pcxt)
 
void ExecIndexScanReInitializeDSM (IndexScanState *node, ParallelContext *pcxt)
 
void ExecIndexScanInitializeWorker (IndexScanState *node, ParallelWorkerContext *pwcxt)
 

Function Documentation

◆ cmp_orderbyvals()

static int cmp_orderbyvals ( const Datum adist,
const bool anulls,
const Datum bdist,
const bool bnulls,
IndexScanState node 
)
static

Definition at line 406 of file nodeIndexscan.c.

409 {
410  int i;
411  int result;
412 
413  for (i = 0; i < node->iss_NumOrderByKeys; i++)
414  {
415  SortSupport ssup = &node->iss_SortSupport[i];
416 
417  /*
418  * Handle nulls. We only need to support NULLS LAST ordering, because
419  * match_pathkeys_to_index() doesn't consider indexorderby
420  * implementation otherwise.
421  */
422  if (anulls[i] && !bnulls[i])
423  return 1;
424  else if (!anulls[i] && bnulls[i])
425  return -1;
426  else if (anulls[i] && bnulls[i])
427  return 0;
428 
429  result = ssup->comparator(adist[i], bdist[i], ssup);
430  if (result != 0)
431  return result;
432  }
433 
434  return 0;
435 }
int i
Definition: isn.c:73
SortSupport iss_SortSupport
Definition: execnodes.h:1580
int iss_NumOrderByKeys
Definition: execnodes.h:1567
int(* comparator)(Datum x, Datum y, SortSupport ssup)
Definition: sortsupport.h:106

References SortSupportData::comparator, i, IndexScanState::iss_NumOrderByKeys, and IndexScanState::iss_SortSupport.

Referenced by IndexNextWithReorder(), and reorderqueue_cmp().

◆ EvalOrderByExpressions()

static void EvalOrderByExpressions ( IndexScanState node,
ExprContext econtext 
)
static

Definition at line 361 of file nodeIndexscan.c.

362 {
363  int i;
364  ListCell *l;
365  MemoryContext oldContext;
366 
367  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
368 
369  i = 0;
370  foreach(l, node->indexorderbyorig)
371  {
372  ExprState *orderby = (ExprState *) lfirst(l);
373 
374  node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
375  econtext,
376  &node->iss_OrderByNulls[i]);
377  i++;
378  }
379 
380  MemoryContextSwitchTo(oldContext);
381 }
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:332
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
#define lfirst(lc)
Definition: pg_list.h:172
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:257
List * indexorderbyorig
Definition: execnodes.h:1563
bool * iss_OrderByNulls
Definition: execnodes.h:1579
Datum * iss_OrderByValues
Definition: execnodes.h:1578

References ExprContext::ecxt_per_tuple_memory, ExecEvalExpr(), i, IndexScanState::indexorderbyorig, IndexScanState::iss_OrderByNulls, IndexScanState::iss_OrderByValues, lfirst, and MemoryContextSwitchTo().

Referenced by IndexNextWithReorder().

◆ ExecEndIndexScan()

void ExecEndIndexScan ( IndexScanState node)

Definition at line 786 of file nodeIndexscan.c.

787 {
788  Relation indexRelationDesc;
789  IndexScanDesc indexScanDesc;
790 
791  /*
792  * extract information from the node
793  */
794  indexRelationDesc = node->iss_RelationDesc;
795  indexScanDesc = node->iss_ScanDesc;
796 
797  /*
798  * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
799  */
800 #ifdef NOT_USED
801  ExecFreeExprContext(&node->ss.ps);
802  if (node->iss_RuntimeContext)
803  FreeExprContext(node->iss_RuntimeContext, true);
804 #endif
805 
806  /*
807  * clear out tuple table slots
808  */
809  if (node->ss.ps.ps_ResultTupleSlot)
812 
813  /*
814  * close the index relation (no-op if we didn't open it)
815  */
816  if (indexScanDesc)
817  index_endscan(indexScanDesc);
818  if (indexRelationDesc)
819  index_close(indexRelationDesc, NoLock);
820 }
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:419
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:658
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:327
#define NoLock
Definition: lockdefs.h:34
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1573
Relation iss_RelationDesc
Definition: execnodes.h:1572
ScanState ss
Definition: execnodes.h:1561
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1571
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1075
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1477
PlanState ps
Definition: execnodes.h:1474
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:432

References ExecClearTuple(), ExecFreeExprContext(), FreeExprContext(), index_close(), index_endscan(), IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeContext, IndexScanState::iss_ScanDesc, NoLock, ScanState::ps, PlanState::ps_ResultTupleSlot, IndexScanState::ss, and ScanState::ss_ScanTupleSlot.

Referenced by ExecEndNode().

◆ ExecIndexAdvanceArrayKeys()

bool ExecIndexAdvanceArrayKeys ( IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 741 of file nodeIndexscan.c.

742 {
743  bool found = false;
744  int j;
745 
746  /*
747  * Note we advance the rightmost array key most quickly, since it will
748  * correspond to the lowest-order index column among the available
749  * qualifications. This is hypothesized to result in better locality of
750  * access in the index.
751  */
752  for (j = numArrayKeys - 1; j >= 0; j--)
753  {
754  ScanKey scan_key = arrayKeys[j].scan_key;
755  int next_elem = arrayKeys[j].next_elem;
756  int num_elems = arrayKeys[j].num_elems;
757  Datum *elem_values = arrayKeys[j].elem_values;
758  bool *elem_nulls = arrayKeys[j].elem_nulls;
759 
760  if (next_elem >= num_elems)
761  {
762  next_elem = 0;
763  found = false; /* need to advance next array key */
764  }
765  else
766  found = true;
767  scan_key->sk_argument = elem_values[next_elem];
768  if (elem_nulls[next_elem])
769  scan_key->sk_flags |= SK_ISNULL;
770  else
771  scan_key->sk_flags &= ~SK_ISNULL;
772  arrayKeys[j].next_elem = next_elem + 1;
773  if (found)
774  break;
775  }
776 
777  return found;
778 }
int j
Definition: isn.c:74
uintptr_t Datum
Definition: postgres.h:64
#define SK_ISNULL
Definition: skey.h:115
Datum * elem_values
Definition: execnodes.h:1529
struct ScanKeyData * scan_key
Definition: execnodes.h:1525
int sk_flags
Definition: skey.h:66
Datum sk_argument
Definition: skey.h:72

References IndexArrayKeyInfo::elem_nulls, IndexArrayKeyInfo::elem_values, j, IndexArrayKeyInfo::next_elem, IndexArrayKeyInfo::num_elems, IndexArrayKeyInfo::scan_key, ScanKeyData::sk_argument, ScanKeyData::sk_flags, and SK_ISNULL.

Referenced by MultiExecBitmapIndexScan().

◆ ExecIndexBuildScanKeys()

void ExecIndexBuildScanKeys ( PlanState planstate,
Relation  index,
List quals,
bool  isorderby,
ScanKey scanKeys,
int *  numScanKeys,
IndexRuntimeKeyInfo **  runtimeKeys,
int *  numRuntimeKeys,
IndexArrayKeyInfo **  arrayKeys,
int *  numArrayKeys 
)

Definition at line 1152 of file nodeIndexscan.c.

1157 {
1158  ListCell *qual_cell;
1159  ScanKey scan_keys;
1160  IndexRuntimeKeyInfo *runtime_keys;
1161  IndexArrayKeyInfo *array_keys;
1162  int n_scan_keys;
1163  int n_runtime_keys;
1164  int max_runtime_keys;
1165  int n_array_keys;
1166  int j;
1167 
1168  /* Allocate array for ScanKey structs: one per qual */
1169  n_scan_keys = list_length(quals);
1170  scan_keys = (ScanKey) palloc(n_scan_keys * sizeof(ScanKeyData));
1171 
1172  /*
1173  * runtime_keys array is dynamically resized as needed. We handle it this
1174  * way so that the same runtime keys array can be shared between
1175  * indexquals and indexorderbys, which will be processed in separate calls
1176  * of this function. Caller must be sure to pass in NULL/0 for first
1177  * call.
1178  */
1179  runtime_keys = *runtimeKeys;
1180  n_runtime_keys = max_runtime_keys = *numRuntimeKeys;
1181 
1182  /* Allocate array_keys as large as it could possibly need to be */
1183  array_keys = (IndexArrayKeyInfo *)
1184  palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo));
1185  n_array_keys = 0;
1186 
1187  /*
1188  * for each opclause in the given qual, convert the opclause into a single
1189  * scan key
1190  */
1191  j = 0;
1192  foreach(qual_cell, quals)
1193  {
1194  Expr *clause = (Expr *) lfirst(qual_cell);
1195  ScanKey this_scan_key = &scan_keys[j++];
1196  Oid opno; /* operator's OID */
1197  RegProcedure opfuncid; /* operator proc id used in scan */
1198  Oid opfamily; /* opfamily of index column */
1199  int op_strategy; /* operator's strategy number */
1200  Oid op_lefttype; /* operator's declared input types */
1201  Oid op_righttype;
1202  Expr *leftop; /* expr on lhs of operator */
1203  Expr *rightop; /* expr on rhs ... */
1204  AttrNumber varattno; /* att number used in scan */
1205  int indnkeyatts;
1206 
1208  if (IsA(clause, OpExpr))
1209  {
1210  /* indexkey op const or indexkey op expression */
1211  int flags = 0;
1212  Datum scanvalue;
1213 
1214  opno = ((OpExpr *) clause)->opno;
1215  opfuncid = ((OpExpr *) clause)->opfuncid;
1216 
1217  /*
1218  * leftop should be the index key Var, possibly relabeled
1219  */
1220  leftop = (Expr *) get_leftop(clause);
1221 
1222  if (leftop && IsA(leftop, RelabelType))
1223  leftop = ((RelabelType *) leftop)->arg;
1224 
1225  Assert(leftop != NULL);
1226 
1227  if (!(IsA(leftop, Var) &&
1228  ((Var *) leftop)->varno == INDEX_VAR))
1229  elog(ERROR, "indexqual doesn't have key on left side");
1230 
1231  varattno = ((Var *) leftop)->varattno;
1232  if (varattno < 1 || varattno > indnkeyatts)
1233  elog(ERROR, "bogus index qualification");
1234 
1235  /*
1236  * We have to look up the operator's strategy number. This
1237  * provides a cross-check that the operator does match the index.
1238  */
1239  opfamily = index->rd_opfamily[varattno - 1];
1240 
1241  get_op_opfamily_properties(opno, opfamily, isorderby,
1242  &op_strategy,
1243  &op_lefttype,
1244  &op_righttype);
1245 
1246  if (isorderby)
1247  flags |= SK_ORDER_BY;
1248 
1249  /*
1250  * rightop is the constant or variable comparison value
1251  */
1252  rightop = (Expr *) get_rightop(clause);
1253 
1254  if (rightop && IsA(rightop, RelabelType))
1255  rightop = ((RelabelType *) rightop)->arg;
1256 
1257  Assert(rightop != NULL);
1258 
1259  if (IsA(rightop, Const))
1260  {
1261  /* OK, simple constant comparison value */
1262  scanvalue = ((Const *) rightop)->constvalue;
1263  if (((Const *) rightop)->constisnull)
1264  flags |= SK_ISNULL;
1265  }
1266  else
1267  {
1268  /* Need to treat this one as a runtime key */
1269  if (n_runtime_keys >= max_runtime_keys)
1270  {
1271  if (max_runtime_keys == 0)
1272  {
1273  max_runtime_keys = 8;
1274  runtime_keys = (IndexRuntimeKeyInfo *)
1275  palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1276  }
1277  else
1278  {
1279  max_runtime_keys *= 2;
1280  runtime_keys = (IndexRuntimeKeyInfo *)
1281  repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1282  }
1283  }
1284  runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1285  runtime_keys[n_runtime_keys].key_expr =
1286  ExecInitExpr(rightop, planstate);
1287  runtime_keys[n_runtime_keys].key_toastable =
1288  TypeIsToastable(op_righttype);
1289  n_runtime_keys++;
1290  scanvalue = (Datum) 0;
1291  }
1292 
1293  /*
1294  * initialize the scan key's fields appropriately
1295  */
1296  ScanKeyEntryInitialize(this_scan_key,
1297  flags,
1298  varattno, /* attribute number to scan */
1299  op_strategy, /* op's strategy */
1300  op_righttype, /* strategy subtype */
1301  ((OpExpr *) clause)->inputcollid, /* collation */
1302  opfuncid, /* reg proc to use */
1303  scanvalue); /* constant */
1304  }
1305  else if (IsA(clause, RowCompareExpr))
1306  {
1307  /* (indexkey, indexkey, ...) op (expression, expression, ...) */
1308  RowCompareExpr *rc = (RowCompareExpr *) clause;
1309  ScanKey first_sub_key;
1310  int n_sub_key;
1311  ListCell *largs_cell;
1312  ListCell *rargs_cell;
1313  ListCell *opnos_cell;
1314  ListCell *collids_cell;
1315 
1316  Assert(!isorderby);
1317 
1318  first_sub_key = (ScanKey)
1319  palloc(list_length(rc->opnos) * sizeof(ScanKeyData));
1320  n_sub_key = 0;
1321 
1322  /* Scan RowCompare columns and generate subsidiary ScanKey items */
1323  forfour(largs_cell, rc->largs, rargs_cell, rc->rargs,
1324  opnos_cell, rc->opnos, collids_cell, rc->inputcollids)
1325  {
1326  ScanKey this_sub_key = &first_sub_key[n_sub_key];
1327  int flags = SK_ROW_MEMBER;
1328  Datum scanvalue;
1329  Oid inputcollation;
1330 
1331  leftop = (Expr *) lfirst(largs_cell);
1332  rightop = (Expr *) lfirst(rargs_cell);
1333  opno = lfirst_oid(opnos_cell);
1334  inputcollation = lfirst_oid(collids_cell);
1335 
1336  /*
1337  * leftop should be the index key Var, possibly relabeled
1338  */
1339  if (leftop && IsA(leftop, RelabelType))
1340  leftop = ((RelabelType *) leftop)->arg;
1341 
1342  Assert(leftop != NULL);
1343 
1344  if (!(IsA(leftop, Var) &&
1345  ((Var *) leftop)->varno == INDEX_VAR))
1346  elog(ERROR, "indexqual doesn't have key on left side");
1347 
1348  varattno = ((Var *) leftop)->varattno;
1349 
1350  /*
1351  * We have to look up the operator's associated btree support
1352  * function
1353  */
1354  if (index->rd_rel->relam != BTREE_AM_OID ||
1355  varattno < 1 || varattno > indnkeyatts)
1356  elog(ERROR, "bogus RowCompare index qualification");
1357  opfamily = index->rd_opfamily[varattno - 1];
1358 
1359  get_op_opfamily_properties(opno, opfamily, isorderby,
1360  &op_strategy,
1361  &op_lefttype,
1362  &op_righttype);
1363 
1364  if (op_strategy != rc->rctype)
1365  elog(ERROR, "RowCompare index qualification contains wrong operator");
1366 
1367  opfuncid = get_opfamily_proc(opfamily,
1368  op_lefttype,
1369  op_righttype,
1370  BTORDER_PROC);
1371  if (!RegProcedureIsValid(opfuncid))
1372  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
1373  BTORDER_PROC, op_lefttype, op_righttype, opfamily);
1374 
1375  /*
1376  * rightop is the constant or variable comparison value
1377  */
1378  if (rightop && IsA(rightop, RelabelType))
1379  rightop = ((RelabelType *) rightop)->arg;
1380 
1381  Assert(rightop != NULL);
1382 
1383  if (IsA(rightop, Const))
1384  {
1385  /* OK, simple constant comparison value */
1386  scanvalue = ((Const *) rightop)->constvalue;
1387  if (((Const *) rightop)->constisnull)
1388  flags |= SK_ISNULL;
1389  }
1390  else
1391  {
1392  /* Need to treat this one as a runtime key */
1393  if (n_runtime_keys >= max_runtime_keys)
1394  {
1395  if (max_runtime_keys == 0)
1396  {
1397  max_runtime_keys = 8;
1398  runtime_keys = (IndexRuntimeKeyInfo *)
1399  palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1400  }
1401  else
1402  {
1403  max_runtime_keys *= 2;
1404  runtime_keys = (IndexRuntimeKeyInfo *)
1405  repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1406  }
1407  }
1408  runtime_keys[n_runtime_keys].scan_key = this_sub_key;
1409  runtime_keys[n_runtime_keys].key_expr =
1410  ExecInitExpr(rightop, planstate);
1411  runtime_keys[n_runtime_keys].key_toastable =
1412  TypeIsToastable(op_righttype);
1413  n_runtime_keys++;
1414  scanvalue = (Datum) 0;
1415  }
1416 
1417  /*
1418  * initialize the subsidiary scan key's fields appropriately
1419  */
1420  ScanKeyEntryInitialize(this_sub_key,
1421  flags,
1422  varattno, /* attribute number */
1423  op_strategy, /* op's strategy */
1424  op_righttype, /* strategy subtype */
1425  inputcollation, /* collation */
1426  opfuncid, /* reg proc to use */
1427  scanvalue); /* constant */
1428  n_sub_key++;
1429  }
1430 
1431  /* Mark the last subsidiary scankey correctly */
1432  first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END;
1433 
1434  /*
1435  * We don't use ScanKeyEntryInitialize for the header because it
1436  * isn't going to contain a valid sk_func pointer.
1437  */
1438  MemSet(this_scan_key, 0, sizeof(ScanKeyData));
1439  this_scan_key->sk_flags = SK_ROW_HEADER;
1440  this_scan_key->sk_attno = first_sub_key->sk_attno;
1441  this_scan_key->sk_strategy = rc->rctype;
1442  /* sk_subtype, sk_collation, sk_func not used in a header */
1443  this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
1444  }
1445  else if (IsA(clause, ScalarArrayOpExpr))
1446  {
1447  /* indexkey op ANY (array-expression) */
1448  ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
1449  int flags = 0;
1450  Datum scanvalue;
1451 
1452  Assert(!isorderby);
1453 
1454  Assert(saop->useOr);
1455  opno = saop->opno;
1456  opfuncid = saop->opfuncid;
1457 
1458  /*
1459  * leftop should be the index key Var, possibly relabeled
1460  */
1461  leftop = (Expr *) linitial(saop->args);
1462 
1463  if (leftop && IsA(leftop, RelabelType))
1464  leftop = ((RelabelType *) leftop)->arg;
1465 
1466  Assert(leftop != NULL);
1467 
1468  if (!(IsA(leftop, Var) &&
1469  ((Var *) leftop)->varno == INDEX_VAR))
1470  elog(ERROR, "indexqual doesn't have key on left side");
1471 
1472  varattno = ((Var *) leftop)->varattno;
1473  if (varattno < 1 || varattno > indnkeyatts)
1474  elog(ERROR, "bogus index qualification");
1475 
1476  /*
1477  * We have to look up the operator's strategy number. This
1478  * provides a cross-check that the operator does match the index.
1479  */
1480  opfamily = index->rd_opfamily[varattno - 1];
1481 
1482  get_op_opfamily_properties(opno, opfamily, isorderby,
1483  &op_strategy,
1484  &op_lefttype,
1485  &op_righttype);
1486 
1487  /*
1488  * rightop is the constant or variable array value
1489  */
1490  rightop = (Expr *) lsecond(saop->args);
1491 
1492  if (rightop && IsA(rightop, RelabelType))
1493  rightop = ((RelabelType *) rightop)->arg;
1494 
1495  Assert(rightop != NULL);
1496 
1497  if (index->rd_indam->amsearcharray)
1498  {
1499  /* Index AM will handle this like a simple operator */
1500  flags |= SK_SEARCHARRAY;
1501  if (IsA(rightop, Const))
1502  {
1503  /* OK, simple constant comparison value */
1504  scanvalue = ((Const *) rightop)->constvalue;
1505  if (((Const *) rightop)->constisnull)
1506  flags |= SK_ISNULL;
1507  }
1508  else
1509  {
1510  /* Need to treat this one as a runtime key */
1511  if (n_runtime_keys >= max_runtime_keys)
1512  {
1513  if (max_runtime_keys == 0)
1514  {
1515  max_runtime_keys = 8;
1516  runtime_keys = (IndexRuntimeKeyInfo *)
1517  palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1518  }
1519  else
1520  {
1521  max_runtime_keys *= 2;
1522  runtime_keys = (IndexRuntimeKeyInfo *)
1523  repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1524  }
1525  }
1526  runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1527  runtime_keys[n_runtime_keys].key_expr =
1528  ExecInitExpr(rightop, planstate);
1529 
1530  /*
1531  * Careful here: the runtime expression is not of
1532  * op_righttype, but rather is an array of same; so
1533  * TypeIsToastable() isn't helpful. However, we can
1534  * assume that all array types are toastable.
1535  */
1536  runtime_keys[n_runtime_keys].key_toastable = true;
1537  n_runtime_keys++;
1538  scanvalue = (Datum) 0;
1539  }
1540  }
1541  else
1542  {
1543  /* Executor has to expand the array value */
1544  array_keys[n_array_keys].scan_key = this_scan_key;
1545  array_keys[n_array_keys].array_expr =
1546  ExecInitExpr(rightop, planstate);
1547  /* the remaining fields were zeroed by palloc0 */
1548  n_array_keys++;
1549  scanvalue = (Datum) 0;
1550  }
1551 
1552  /*
1553  * initialize the scan key's fields appropriately
1554  */
1555  ScanKeyEntryInitialize(this_scan_key,
1556  flags,
1557  varattno, /* attribute number to scan */
1558  op_strategy, /* op's strategy */
1559  op_righttype, /* strategy subtype */
1560  saop->inputcollid, /* collation */
1561  opfuncid, /* reg proc to use */
1562  scanvalue); /* constant */
1563  }
1564  else if (IsA(clause, NullTest))
1565  {
1566  /* indexkey IS NULL or indexkey IS NOT NULL */
1567  NullTest *ntest = (NullTest *) clause;
1568  int flags;
1569 
1570  Assert(!isorderby);
1571 
1572  /*
1573  * argument should be the index key Var, possibly relabeled
1574  */
1575  leftop = ntest->arg;
1576 
1577  if (leftop && IsA(leftop, RelabelType))
1578  leftop = ((RelabelType *) leftop)->arg;
1579 
1580  Assert(leftop != NULL);
1581 
1582  if (!(IsA(leftop, Var) &&
1583  ((Var *) leftop)->varno == INDEX_VAR))
1584  elog(ERROR, "NullTest indexqual has wrong key");
1585 
1586  varattno = ((Var *) leftop)->varattno;
1587 
1588  /*
1589  * initialize the scan key's fields appropriately
1590  */
1591  switch (ntest->nulltesttype)
1592  {
1593  case IS_NULL:
1594  flags = SK_ISNULL | SK_SEARCHNULL;
1595  break;
1596  case IS_NOT_NULL:
1597  flags = SK_ISNULL | SK_SEARCHNOTNULL;
1598  break;
1599  default:
1600  elog(ERROR, "unrecognized nulltesttype: %d",
1601  (int) ntest->nulltesttype);
1602  flags = 0; /* keep compiler quiet */
1603  break;
1604  }
1605 
1606  ScanKeyEntryInitialize(this_scan_key,
1607  flags,
1608  varattno, /* attribute number to scan */
1609  InvalidStrategy, /* no strategy */
1610  InvalidOid, /* no strategy subtype */
1611  InvalidOid, /* no collation */
1612  InvalidOid, /* no reg proc for this */
1613  (Datum) 0); /* constant */
1614  }
1615  else
1616  elog(ERROR, "unsupported indexqual type: %d",
1617  (int) nodeTag(clause));
1618  }
1619 
1620  Assert(n_runtime_keys <= max_runtime_keys);
1621 
1622  /* Get rid of any unused arrays */
1623  if (n_array_keys == 0)
1624  {
1625  pfree(array_keys);
1626  array_keys = NULL;
1627  }
1628 
1629  /*
1630  * Return info to our caller.
1631  */
1632  *scanKeys = scan_keys;
1633  *numScanKeys = n_scan_keys;
1634  *runtimeKeys = runtime_keys;
1635  *numRuntimeKeys = n_runtime_keys;
1636  if (arrayKeys)
1637  {
1638  *arrayKeys = array_keys;
1639  *numArrayKeys = n_array_keys;
1640  }
1641  else if (n_array_keys != 0)
1642  elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
1643 }
int16 AttrNumber
Definition: attnum.h:21
#define RegProcedureIsValid(p)
Definition: c.h:766
regproc RegProcedure
Definition: c.h:639
#define MemSet(start, val, len)
Definition: c.h:1009
#define ERROR
Definition: elog.h:39
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:128
Assert(fmt[strlen(fmt) - 1] !='\n')
void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:135
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:795
#define TypeIsToastable(typid)
Definition: lsyscache.h:211
void pfree(void *pointer)
Definition: mcxt.c:1456
void * palloc0(Size size)
Definition: mcxt.c:1257
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1476
void * palloc(Size size)
Definition: mcxt.c:1226
#define BTORDER_PROC
Definition: nbtree.h:707
static Node * get_rightop(const void *clause)
Definition: nodeFuncs.h:93
static Node * get_leftop(const void *clause)
Definition: nodeFuncs.h:81
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#define nodeTag(nodeptr)
Definition: nodes.h:133
void * arg
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:524
#define lfirst_oid(lc)
Definition: pg_list.h:174
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
@ IS_NULL
Definition: primnodes.h:1686
@ IS_NOT_NULL
Definition: primnodes.h:1686
#define INDEX_VAR
Definition: primnodes.h:216
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:523
void ScanKeyEntryInitialize(ScanKey entry, int flags, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, Oid collation, RegProcedure procedure, Datum argument)
Definition: scankey.c:32
struct ScanKeyData ScanKeyData
#define SK_ORDER_BY
Definition: skey.h:123
#define SK_ROW_HEADER
Definition: skey.h:117
#define SK_SEARCHARRAY
Definition: skey.h:120
#define SK_ROW_MEMBER
Definition: skey.h:118
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_SEARCHNULL
Definition: skey.h:121
#define SK_ROW_END
Definition: skey.h:119
ScanKeyData * ScanKey
Definition: skey.h:75
#define InvalidStrategy
Definition: stratnum.h:24
ExprState * array_expr
Definition: execnodes.h:1526
ExprState * key_expr
Definition: execnodes.h:1519
struct ScanKeyData * scan_key
Definition: execnodes.h:1518
NullTestType nulltesttype
Definition: primnodes.h:1693
Expr * arg
Definition: primnodes.h:1692
RowCompareType rctype
Definition: primnodes.h:1395
StrategyNumber sk_strategy
Definition: skey.h:68
AttrNumber sk_attno
Definition: skey.h:67
Definition: primnodes.h:226
Definition: type.h:95

References arg, NullTest::arg, ScalarArrayOpExpr::args, IndexArrayKeyInfo::array_expr, Assert(), BTORDER_PROC, elog(), ERROR, ExecInitExpr(), forfour, get_leftop(), get_op_opfamily_properties(), get_opfamily_proc(), get_rightop(), INDEX_VAR, IndexRelationGetNumberOfKeyAttributes, InvalidOid, InvalidStrategy, IS_NOT_NULL, IS_NULL, IsA, j, IndexRuntimeKeyInfo::key_expr, IndexRuntimeKeyInfo::key_toastable, RowCompareExpr::largs, lfirst, lfirst_oid, linitial, list_length(), lsecond, MemSet, nodeTag, NullTest::nulltesttype, ScalarArrayOpExpr::opno, palloc(), palloc0(), pfree(), PointerGetDatum(), RowCompareExpr::rargs, RowCompareExpr::rctype, RegProcedureIsValid, repalloc(), IndexRuntimeKeyInfo::scan_key, IndexArrayKeyInfo::scan_key, ScanKeyEntryInitialize(), ScanKeyData::sk_argument, ScanKeyData::sk_attno, ScanKeyData::sk_flags, SK_ISNULL, SK_ORDER_BY, SK_ROW_END, SK_ROW_HEADER, SK_ROW_MEMBER, SK_SEARCHARRAY, SK_SEARCHNOTNULL, SK_SEARCHNULL, ScanKeyData::sk_strategy, TypeIsToastable, and ScalarArrayOpExpr::useOr.

Referenced by ExecInitBitmapIndexScan(), ExecInitIndexOnlyScan(), and ExecInitIndexScan().

◆ ExecIndexEvalArrayKeys()

bool ExecIndexEvalArrayKeys ( ExprContext econtext,
IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 662 of file nodeIndexscan.c.

664 {
665  bool result = true;
666  int j;
667  MemoryContext oldContext;
668 
669  /* We want to keep the arrays in per-tuple memory */
670  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
671 
672  for (j = 0; j < numArrayKeys; j++)
673  {
674  ScanKey scan_key = arrayKeys[j].scan_key;
675  ExprState *array_expr = arrayKeys[j].array_expr;
676  Datum arraydatum;
677  bool isNull;
678  ArrayType *arrayval;
679  int16 elmlen;
680  bool elmbyval;
681  char elmalign;
682  int num_elems;
683  Datum *elem_values;
684  bool *elem_nulls;
685 
686  /*
687  * Compute and deconstruct the array expression. (Notes in
688  * ExecIndexEvalRuntimeKeys() apply here too.)
689  */
690  arraydatum = ExecEvalExpr(array_expr,
691  econtext,
692  &isNull);
693  if (isNull)
694  {
695  result = false;
696  break; /* no point in evaluating more */
697  }
698  arrayval = DatumGetArrayTypeP(arraydatum);
699  /* We could cache this data, but not clear it's worth it */
701  &elmlen, &elmbyval, &elmalign);
702  deconstruct_array(arrayval,
703  ARR_ELEMTYPE(arrayval),
704  elmlen, elmbyval, elmalign,
705  &elem_values, &elem_nulls, &num_elems);
706  if (num_elems <= 0)
707  {
708  result = false;
709  break; /* no point in evaluating more */
710  }
711 
712  /*
713  * Note: we expect the previous array data, if any, to be
714  * automatically freed by resetting the per-tuple context; hence no
715  * pfree's here.
716  */
717  arrayKeys[j].elem_values = elem_values;
718  arrayKeys[j].elem_nulls = elem_nulls;
719  arrayKeys[j].num_elems = num_elems;
720  scan_key->sk_argument = elem_values[0];
721  if (elem_nulls[0])
722  scan_key->sk_flags |= SK_ISNULL;
723  else
724  scan_key->sk_flags &= ~SK_ISNULL;
725  arrayKeys[j].next_elem = 1;
726  }
727 
728  MemoryContextSwitchTo(oldContext);
729 
730  return result;
731 }
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_ELEMTYPE(a)
Definition: array.h:285
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3578
signed short int16
Definition: c.h:482
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2253

References ARR_ELEMTYPE, IndexArrayKeyInfo::array_expr, DatumGetArrayTypeP, deconstruct_array(), ExprContext::ecxt_per_tuple_memory, IndexArrayKeyInfo::elem_nulls, IndexArrayKeyInfo::elem_values, ExecEvalExpr(), get_typlenbyvalalign(), j, MemoryContextSwitchTo(), IndexArrayKeyInfo::next_elem, IndexArrayKeyInfo::num_elems, IndexArrayKeyInfo::scan_key, ScanKeyData::sk_argument, ScanKeyData::sk_flags, and SK_ISNULL.

Referenced by ExecReScanBitmapIndexScan().

◆ ExecIndexEvalRuntimeKeys()

void ExecIndexEvalRuntimeKeys ( ExprContext econtext,
IndexRuntimeKeyInfo runtimeKeys,
int  numRuntimeKeys 
)

Definition at line 600 of file nodeIndexscan.c.

602 {
603  int j;
604  MemoryContext oldContext;
605 
606  /* We want to keep the key values in per-tuple memory */
607  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
608 
609  for (j = 0; j < numRuntimeKeys; j++)
610  {
611  ScanKey scan_key = runtimeKeys[j].scan_key;
612  ExprState *key_expr = runtimeKeys[j].key_expr;
613  Datum scanvalue;
614  bool isNull;
615 
616  /*
617  * For each run-time key, extract the run-time expression and evaluate
618  * it with respect to the current context. We then stick the result
619  * into the proper scan key.
620  *
621  * Note: the result of the eval could be a pass-by-ref value that's
622  * stored in some outer scan's tuple, not in
623  * econtext->ecxt_per_tuple_memory. We assume that the outer tuple
624  * will stay put throughout our scan. If this is wrong, we could copy
625  * the result into our context explicitly, but I think that's not
626  * necessary.
627  *
628  * It's also entirely possible that the result of the eval is a
629  * toasted value. In this case we should forcibly detoast it, to
630  * avoid repeat detoastings each time the value is examined by an
631  * index support function.
632  */
633  scanvalue = ExecEvalExpr(key_expr,
634  econtext,
635  &isNull);
636  if (isNull)
637  {
638  scan_key->sk_argument = scanvalue;
639  scan_key->sk_flags |= SK_ISNULL;
640  }
641  else
642  {
643  if (runtimeKeys[j].key_toastable)
644  scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
645  scan_key->sk_argument = scanvalue;
646  scan_key->sk_flags &= ~SK_ISNULL;
647  }
648  }
649 
650  MemoryContextSwitchTo(oldContext);
651 }
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:240

References ExprContext::ecxt_per_tuple_memory, ExecEvalExpr(), j, IndexRuntimeKeyInfo::key_expr, MemoryContextSwitchTo(), PG_DETOAST_DATUM, PointerGetDatum(), IndexRuntimeKeyInfo::scan_key, ScanKeyData::sk_argument, ScanKeyData::sk_flags, and SK_ISNULL.

Referenced by ExecReScanBitmapIndexScan(), ExecReScanIndexOnlyScan(), and ExecReScanIndexScan().

◆ ExecIndexMarkPos()

void ExecIndexMarkPos ( IndexScanState node)

Definition at line 830 of file nodeIndexscan.c.

831 {
832  EState *estate = node->ss.ps.state;
833  EPQState *epqstate = estate->es_epq_active;
834 
835  if (epqstate != NULL)
836  {
837  /*
838  * We are inside an EvalPlanQual recheck. If a test tuple exists for
839  * this relation, then we shouldn't access the index at all. We would
840  * instead need to save, and later restore, the state of the
841  * relsubs_done flag, so that re-fetching the test tuple is possible.
842  * However, given the assumption that no caller sets a mark at the
843  * start of the scan, we can only get here with relsubs_done[i]
844  * already set, and so no state need be saved.
845  */
846  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
847 
848  Assert(scanrelid > 0);
849  if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
850  epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
851  {
852  /* Verify the claim above */
853  if (!epqstate->relsubs_done[scanrelid - 1])
854  elog(ERROR, "unexpected ExecIndexMarkPos call in EPQ recheck");
855  return;
856  }
857  }
858 
860 }
unsigned int Index
Definition: c.h:603
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:357
ExecAuxRowMark ** relsubs_rowmark
Definition: execnodes.h:1212
TupleTableSlot ** relsubs_slot
Definition: execnodes.h:1184
bool * relsubs_done
Definition: execnodes.h:1219
struct EPQState * es_epq_active
Definition: execnodes.h:691
Plan * plan
Definition: execnodes.h:1037
EState * state
Definition: execnodes.h:1039

References Assert(), elog(), ERROR, EState::es_epq_active, index_markpos(), IndexScanState::iss_ScanDesc, PlanState::plan, ScanState::ps, EPQState::relsubs_done, EPQState::relsubs_rowmark, EPQState::relsubs_slot, IndexScanState::ss, and PlanState::state.

Referenced by ExecMarkPos().

◆ ExecIndexRestrPos()

void ExecIndexRestrPos ( IndexScanState node)

Definition at line 867 of file nodeIndexscan.c.

868 {
869  EState *estate = node->ss.ps.state;
870  EPQState *epqstate = estate->es_epq_active;
871 
872  if (estate->es_epq_active != NULL)
873  {
874  /* See comments in ExecIndexMarkPos */
875  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
876 
877  Assert(scanrelid > 0);
878  if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
879  epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
880  {
881  /* Verify the claim above */
882  if (!epqstate->relsubs_done[scanrelid - 1])
883  elog(ERROR, "unexpected ExecIndexRestrPos call in EPQ recheck");
884  return;
885  }
886  }
887 
889 }
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:381

References Assert(), elog(), ERROR, EState::es_epq_active, index_restrpos(), IndexScanState::iss_ScanDesc, PlanState::plan, ScanState::ps, EPQState::relsubs_done, EPQState::relsubs_rowmark, EPQState::relsubs_slot, IndexScanState::ss, and PlanState::state.

Referenced by ExecRestrPos().

◆ ExecIndexScan()

static TupleTableSlot* ExecIndexScan ( PlanState pstate)
static

Definition at line 520 of file nodeIndexscan.c.

521 {
522  IndexScanState *node = castNode(IndexScanState, pstate);
523 
524  /*
525  * If we have runtime keys and they've not already been set up, do it now.
526  */
527  if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
528  ExecReScan((PlanState *) node);
529 
530  if (node->iss_NumOrderByKeys > 0)
531  return ExecScan(&node->ss,
534  else
535  return ExecScan(&node->ss,
538 }
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:157
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:472
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:473
static TupleTableSlot * IndexNextWithReorder(IndexScanState *node)
static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
static TupleTableSlot * IndexNext(IndexScanState *node)
Definition: nodeIndexscan.c:81
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
int iss_NumRuntimeKeys
Definition: execnodes.h:1569
bool iss_RuntimeKeysReady
Definition: execnodes.h:1570

References castNode, ExecReScan(), ExecScan(), IndexNext(), IndexNextWithReorder(), IndexRecheck(), IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_RuntimeKeysReady, and IndexScanState::ss.

Referenced by ExecInitIndexScan().

◆ ExecIndexScanEstimate()

void ExecIndexScanEstimate ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1658 of file nodeIndexscan.c.

1660 {
1661  EState *estate = node->ss.ps.state;
1662 
1664  estate->es_snapshot);
1666  shm_toc_estimate_keys(&pcxt->estimator, 1);
1667 }
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:406
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Snapshot es_snapshot
Definition: execnodes.h:616
shm_toc_estimator estimator
Definition: parallel.h:42

References EState::es_snapshot, ParallelContext::estimator, index_parallelscan_estimate(), IndexScanState::iss_PscanLen, IndexScanState::iss_RelationDesc, ScanState::ps, shm_toc_estimate_chunk, shm_toc_estimate_keys, IndexScanState::ss, and PlanState::state.

Referenced by ExecParallelEstimate().

◆ ExecIndexScanInitializeDSM()

void ExecIndexScanInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1676 of file nodeIndexscan.c.

1678 {
1679  EState *estate = node->ss.ps.state;
1680  ParallelIndexScanDesc piscan;
1681 
1682  piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1684  node->iss_RelationDesc,
1685  estate->es_snapshot,
1686  piscan);
1687  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1688  node->iss_ScanDesc =
1690  node->iss_RelationDesc,
1691  node->iss_NumScanKeys,
1692  node->iss_NumOrderByKeys,
1693  piscan);
1694 
1695  /*
1696  * If no run-time keys to calculate or they are ready, go ahead and pass
1697  * the scankeys to the index AM.
1698  */
1699  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1700  index_rescan(node->iss_ScanDesc,
1701  node->iss_ScanKeys, node->iss_NumScanKeys,
1702  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1703 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:492
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:441
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:301
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1564
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1566
shm_toc * toc
Definition: parallel.h:45
int plan_node_id
Definition: plannodes.h:152
Relation ss_currentRelation
Definition: execnodes.h:1475

References EState::es_snapshot, index_beginscan_parallel(), index_parallelscan_initialize(), index_rescan(), IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_PscanLen, IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, PlanState::plan, Plan::plan_node_id, ScanState::ps, shm_toc_allocate(), shm_toc_insert(), IndexScanState::ss, ScanState::ss_currentRelation, PlanState::state, and ParallelContext::toc.

Referenced by ExecParallelInitializeDSM().

◆ ExecIndexScanInitializeWorker()

void ExecIndexScanInitializeWorker ( IndexScanState node,
ParallelWorkerContext pwcxt 
)

Definition at line 1725 of file nodeIndexscan.c.

1727 {
1728  ParallelIndexScanDesc piscan;
1729 
1730  piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1731  node->iss_ScanDesc =
1733  node->iss_RelationDesc,
1734  node->iss_NumScanKeys,
1735  node->iss_NumOrderByKeys,
1736  piscan);
1737 
1738  /*
1739  * If no run-time keys to calculate or they are ready, go ahead and pass
1740  * the scankeys to the index AM.
1741  */
1742  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1743  index_rescan(node->iss_ScanDesc,
1744  node->iss_ScanKeys, node->iss_NumScanKeys,
1745  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1746 }
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

References index_beginscan_parallel(), index_rescan(), IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, PlanState::plan, Plan::plan_node_id, ScanState::ps, shm_toc_lookup(), IndexScanState::ss, ScanState::ss_currentRelation, and ParallelWorkerContext::toc.

Referenced by ExecParallelInitializeWorker().

◆ ExecIndexScanReInitializeDSM()

void ExecIndexScanReInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1712 of file nodeIndexscan.c.

1714 {
1716 }
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:474

References index_parallelrescan(), and IndexScanState::iss_ScanDesc.

Referenced by ExecParallelReInitializeDSM().

◆ ExecInitIndexScan()

IndexScanState* ExecInitIndexScan ( IndexScan node,
EState estate,
int  eflags 
)

Definition at line 903 of file nodeIndexscan.c.

904 {
905  IndexScanState *indexstate;
906  Relation currentRelation;
907  LOCKMODE lockmode;
908 
909  /*
910  * create state structure
911  */
912  indexstate = makeNode(IndexScanState);
913  indexstate->ss.ps.plan = (Plan *) node;
914  indexstate->ss.ps.state = estate;
915  indexstate->ss.ps.ExecProcNode = ExecIndexScan;
916 
917  /*
918  * Miscellaneous initialization
919  *
920  * create expression context for node
921  */
922  ExecAssignExprContext(estate, &indexstate->ss.ps);
923 
924  /*
925  * open the scan relation
926  */
927  currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
928 
929  indexstate->ss.ss_currentRelation = currentRelation;
930  indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
931 
932  /*
933  * get the scan type from the relation descriptor.
934  */
935  ExecInitScanTupleSlot(estate, &indexstate->ss,
936  RelationGetDescr(currentRelation),
937  table_slot_callbacks(currentRelation));
938 
939  /*
940  * Initialize result type and projection.
941  */
942  ExecInitResultTypeTL(&indexstate->ss.ps);
943  ExecAssignScanProjectionInfo(&indexstate->ss);
944 
945  /*
946  * initialize child expressions
947  *
948  * Note: we don't initialize all of the indexqual expression, only the
949  * sub-parts corresponding to runtime keys (see below). Likewise for
950  * indexorderby, if any. But the indexqualorig expression is always
951  * initialized even though it will only be used in some uncommon cases ---
952  * would be nice to improve that. (Problem is that any SubPlans present
953  * in the expression must be found now...)
954  */
955  indexstate->ss.ps.qual =
956  ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
957  indexstate->indexqualorig =
958  ExecInitQual(node->indexqualorig, (PlanState *) indexstate);
959  indexstate->indexorderbyorig =
960  ExecInitExprList(node->indexorderbyorig, (PlanState *) indexstate);
961 
962  /*
963  * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
964  * here. This allows an index-advisor plugin to EXPLAIN a plan containing
965  * references to nonexistent indexes.
966  */
967  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
968  return indexstate;
969 
970  /* Open the index relation. */
971  lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
972  indexstate->iss_RelationDesc = index_open(node->indexid, lockmode);
973 
974  /*
975  * Initialize index-specific scan state
976  */
977  indexstate->iss_RuntimeKeysReady = false;
978  indexstate->iss_RuntimeKeys = NULL;
979  indexstate->iss_NumRuntimeKeys = 0;
980 
981  /*
982  * build the index scan keys from the index qualification
983  */
984  ExecIndexBuildScanKeys((PlanState *) indexstate,
985  indexstate->iss_RelationDesc,
986  node->indexqual,
987  false,
988  &indexstate->iss_ScanKeys,
989  &indexstate->iss_NumScanKeys,
990  &indexstate->iss_RuntimeKeys,
991  &indexstate->iss_NumRuntimeKeys,
992  NULL, /* no ArrayKeys */
993  NULL);
994 
995  /*
996  * any ORDER BY exprs have to be turned into scankeys in the same way
997  */
998  ExecIndexBuildScanKeys((PlanState *) indexstate,
999  indexstate->iss_RelationDesc,
1000  node->indexorderby,
1001  true,
1002  &indexstate->iss_OrderByKeys,
1003  &indexstate->iss_NumOrderByKeys,
1004  &indexstate->iss_RuntimeKeys,
1005  &indexstate->iss_NumRuntimeKeys,
1006  NULL, /* no ArrayKeys */
1007  NULL);
1008 
1009  /* Initialize sort support, if we need to re-check ORDER BY exprs */
1010  if (indexstate->iss_NumOrderByKeys > 0)
1011  {
1012  int numOrderByKeys = indexstate->iss_NumOrderByKeys;
1013  int i;
1014  ListCell *lco;
1015  ListCell *lcx;
1016 
1017  /*
1018  * Prepare sort support, and look up the data type for each ORDER BY
1019  * expression.
1020  */
1021  Assert(numOrderByKeys == list_length(node->indexorderbyops));
1022  Assert(numOrderByKeys == list_length(node->indexorderbyorig));
1023  indexstate->iss_SortSupport = (SortSupportData *)
1024  palloc0(numOrderByKeys * sizeof(SortSupportData));
1025  indexstate->iss_OrderByTypByVals = (bool *)
1026  palloc(numOrderByKeys * sizeof(bool));
1027  indexstate->iss_OrderByTypLens = (int16 *)
1028  palloc(numOrderByKeys * sizeof(int16));
1029  i = 0;
1030  forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
1031  {
1032  Oid orderbyop = lfirst_oid(lco);
1033  Node *orderbyexpr = (Node *) lfirst(lcx);
1034  Oid orderbyType = exprType(orderbyexpr);
1035  Oid orderbyColl = exprCollation(orderbyexpr);
1036  SortSupport orderbysort = &indexstate->iss_SortSupport[i];
1037 
1038  /* Initialize sort support */
1039  orderbysort->ssup_cxt = CurrentMemoryContext;
1040  orderbysort->ssup_collation = orderbyColl;
1041  /* See cmp_orderbyvals() comments on NULLS LAST */
1042  orderbysort->ssup_nulls_first = false;
1043  /* ssup_attno is unused here and elsewhere */
1044  orderbysort->ssup_attno = 0;
1045  /* No abbreviation */
1046  orderbysort->abbreviate = false;
1047  PrepareSortSupportFromOrderingOp(orderbyop, orderbysort);
1048 
1049  get_typlenbyval(orderbyType,
1050  &indexstate->iss_OrderByTypLens[i],
1051  &indexstate->iss_OrderByTypByVals[i]);
1052  i++;
1053  }
1054 
1055  /* allocate arrays to hold the re-calculated distances */
1056  indexstate->iss_OrderByValues = (Datum *)
1057  palloc(numOrderByKeys * sizeof(Datum));
1058  indexstate->iss_OrderByNulls = (bool *)
1059  palloc(numOrderByKeys * sizeof(bool));
1060 
1061  /* and initialize the reorder queue */
1063  indexstate);
1064  }
1065 
1066  /*
1067  * If we have runtime keys, we need an ExprContext to evaluate them. The
1068  * node's standard context won't do because we want to reset that context
1069  * for every tuple. So, build another context just like the other one...
1070  * -tgl 7/11/00
1071  */
1072  if (indexstate->iss_NumRuntimeKeys != 0)
1073  {
1074  ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
1075 
1076  ExecAssignExprContext(estate, &indexstate->ss.ps);
1077  indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
1078  indexstate->ss.ps.ps_ExprContext = stdecontext;
1079  }
1080  else
1081  {
1082  indexstate->iss_RuntimeContext = NULL;
1083  }
1084 
1085  /*
1086  * all done.
1087  */
1088  return indexstate;
1089 }
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:323
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:214
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:271
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1812
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1756
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:488
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition: execUtils.c:728
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition: executor.h:587
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:65
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
int LOCKMODE
Definition: lockdefs.h:26
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2233
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:786
static TupleTableSlot * ExecIndexScan(PlanState *pstate)
void ExecIndexBuildScanKeys(PlanState *planstate, Relation index, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
static int reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
#define makeNode(_type_)
Definition: nodes.h:176
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:42
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
#define RelationGetDescr(relation)
Definition: rel.h:530
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:135
bool * iss_OrderByTypByVals
Definition: execnodes.h:1581
ExprState * indexqualorig
Definition: execnodes.h:1562
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1576
int16 * iss_OrderByTypLens
Definition: execnodes.h:1582
IndexRuntimeKeyInfo * iss_RuntimeKeys
Definition: execnodes.h:1568
List * indexorderby
Definition: plannodes.h:453
List * indexorderbyops
Definition: plannodes.h:455
Scan scan
Definition: plannodes.h:449
List * indexqualorig
Definition: plannodes.h:452
Oid indexid
Definition: plannodes.h:450
List * indexqual
Definition: plannodes.h:451
List * indexorderbyorig
Definition: plannodes.h:454
Definition: nodes.h:129
ExprState * qual
Definition: execnodes.h:1058
ExprContext * ps_ExprContext
Definition: execnodes.h:1076
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1043
struct TableScanDescData * ss_currentScanDesc
Definition: execnodes.h:1476
Index scanrelid
Definition: plannodes.h:387
AttrNumber ssup_attno
Definition: sortsupport.h:81
bool ssup_nulls_first
Definition: sortsupport.h:75
MemoryContext ssup_cxt
Definition: sortsupport.h:66
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:58

References SortSupportData::abbreviate, Assert(), CurrentMemoryContext, EXEC_FLAG_EXPLAIN_ONLY, exec_rt_fetch(), ExecAssignExprContext(), ExecAssignScanProjectionInfo(), ExecIndexBuildScanKeys(), ExecIndexScan(), ExecInitExprList(), ExecInitQual(), ExecInitResultTypeTL(), ExecInitScanTupleSlot(), ExecOpenScanRelation(), PlanState::ExecProcNode, exprCollation(), exprType(), forboth, get_typlenbyval(), i, index_open(), IndexScan::indexid, IndexScan::indexorderby, IndexScan::indexorderbyops, IndexScanState::indexorderbyorig, IndexScan::indexorderbyorig, IndexScan::indexqual, IndexScanState::indexqualorig, IndexScan::indexqualorig, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_OrderByNulls, IndexScanState::iss_OrderByTypByVals, IndexScanState::iss_OrderByTypLens, IndexScanState::iss_OrderByValues, IndexScanState::iss_RelationDesc, IndexScanState::iss_ReorderQueue, IndexScanState::iss_RuntimeContext, IndexScanState::iss_RuntimeKeys, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanKeys, IndexScanState::iss_SortSupport, lfirst, lfirst_oid, list_length(), makeNode, pairingheap_allocate(), palloc(), palloc0(), PlanState::plan, PrepareSortSupportFromOrderingOp(), ScanState::ps, PlanState::ps_ExprContext, PlanState::qual, RelationGetDescr, RangeTblEntry::rellockmode, reorderqueue_cmp(), IndexScan::scan, Scan::scanrelid, IndexScanState::ss, ScanState::ss_currentRelation, ScanState::ss_currentScanDesc, SortSupportData::ssup_attno, SortSupportData::ssup_collation, SortSupportData::ssup_cxt, SortSupportData::ssup_nulls_first, PlanState::state, and table_slot_callbacks().

Referenced by ExecInitNode().

◆ ExecReScanIndexScan()

void ExecReScanIndexScan ( IndexScanState node)

Definition at line 552 of file nodeIndexscan.c.

553 {
554  /*
555  * If we are doing runtime key calculations (ie, any of the index key
556  * values weren't simple Consts), compute the new key values. But first,
557  * reset the context so we don't leak memory as each outer tuple is
558  * scanned. Note this assumes that we will recalculate *all* runtime keys
559  * on each call.
560  */
561  if (node->iss_NumRuntimeKeys != 0)
562  {
563  ExprContext *econtext = node->iss_RuntimeContext;
564 
565  ResetExprContext(econtext);
566  ExecIndexEvalRuntimeKeys(econtext,
567  node->iss_RuntimeKeys,
568  node->iss_NumRuntimeKeys);
569  }
570  node->iss_RuntimeKeysReady = true;
571 
572  /* flush the reorder queue */
573  if (node->iss_ReorderQueue)
574  {
575  HeapTuple tuple;
576 
577  while (!pairingheap_is_empty(node->iss_ReorderQueue))
578  {
579  tuple = reorderqueue_pop(node);
580  heap_freetuple(tuple);
581  }
582  }
583 
584  /* reset index scan */
585  if (node->iss_ScanDesc)
587  node->iss_ScanKeys, node->iss_NumScanKeys,
588  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
589  node->iss_ReachedEnd = false;
590 
591  ExecScanReScan(&node->ss);
592 }
void ExecScanReScan(ScanState *node)
Definition: execScan.c:298
#define ResetExprContext(econtext)
Definition: executor.h:543
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1426
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
static HeapTuple reorderqueue_pop(IndexScanState *node)
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
bool iss_ReachedEnd
Definition: execnodes.h:1577

References ExecIndexEvalRuntimeKeys(), ExecScanReScan(), heap_freetuple(), index_rescan(), IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_ReachedEnd, IndexScanState::iss_ReorderQueue, IndexScanState::iss_RuntimeContext, IndexScanState::iss_RuntimeKeys, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, pairingheap_is_empty, reorderqueue_pop(), ResetExprContext, and IndexScanState::ss.

Referenced by ExecReScan().

◆ IndexNext()

static TupleTableSlot * IndexNext ( IndexScanState node)
static

Definition at line 81 of file nodeIndexscan.c.

82 {
83  EState *estate;
84  ExprContext *econtext;
85  ScanDirection direction;
86  IndexScanDesc scandesc;
87  TupleTableSlot *slot;
88 
89  /*
90  * extract necessary information from index scan node
91  */
92  estate = node->ss.ps.state;
93 
94  /*
95  * Determine which direction to scan the index in based on the plan's scan
96  * direction and the current direction of execution.
97  */
98  direction = ScanDirectionCombine(estate->es_direction,
99  ((IndexScan *) node->ss.ps.plan)->indexorderdir);
100  scandesc = node->iss_ScanDesc;
101  econtext = node->ss.ps.ps_ExprContext;
102  slot = node->ss.ss_ScanTupleSlot;
103 
104  if (scandesc == NULL)
105  {
106  /*
107  * We reach here if the index scan is not parallel, or if we're
108  * serially executing an index scan that was planned to be parallel.
109  */
110  scandesc = index_beginscan(node->ss.ss_currentRelation,
111  node->iss_RelationDesc,
112  estate->es_snapshot,
113  node->iss_NumScanKeys,
114  node->iss_NumOrderByKeys);
115 
116  node->iss_ScanDesc = scandesc;
117 
118  /*
119  * If no run-time keys to calculate or they are ready, go ahead and
120  * pass the scankeys to the index AM.
121  */
122  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
123  index_rescan(scandesc,
124  node->iss_ScanKeys, node->iss_NumScanKeys,
125  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
126  }
127 
128  /*
129  * ok, now that we have what we need, fetch the next tuple.
130  */
131  while (index_getnext_slot(scandesc, direction, slot))
132  {
134 
135  /*
136  * If the index was lossy, we have to recheck the index quals using
137  * the fetched tuple.
138  */
139  if (scandesc->xs_recheck)
140  {
141  econtext->ecxt_scantuple = slot;
142  if (!ExecQualAndReset(node->indexqualorig, econtext))
143  {
144  /* Fails recheck, so drop it and loop back for another */
145  InstrCountFiltered2(node, 1);
146  continue;
147  }
148  }
149 
150  return slot;
151  }
152 
153  /*
154  * if we get here it means the index scan failed so we are at the end of
155  * the scan..
156  */
157  node->iss_ReachedEnd = true;
158  return ExecClearTuple(slot);
159 }
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:1146
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:439
bool index_getnext_slot(IndexScanDesc scan, ScanDirection direction, TupleTableSlot *slot)
Definition: indexam.c:624
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:205
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
#define ScanDirectionCombine(a, b)
Definition: sdir.h:36
ScanDirection
Definition: sdir.h:25
ScanDirection es_direction
Definition: execnodes.h:615
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:249

References CHECK_FOR_INTERRUPTS, ExprContext::ecxt_scantuple, EState::es_direction, EState::es_snapshot, ExecClearTuple(), ExecQualAndReset(), index_beginscan(), index_getnext_slot(), index_rescan(), IndexScanState::indexqualorig, InstrCountFiltered2, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_ReachedEnd, IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, ScanDirectionCombine, IndexScanState::ss, ScanState::ss_currentRelation, ScanState::ss_ScanTupleSlot, PlanState::state, and IndexScanDescData::xs_recheck.

Referenced by ExecIndexScan().

◆ IndexNextWithReorder()

static TupleTableSlot * IndexNextWithReorder ( IndexScanState node)
static

Definition at line 169 of file nodeIndexscan.c.

170 {
171  EState *estate;
172  ExprContext *econtext;
173  IndexScanDesc scandesc;
174  TupleTableSlot *slot;
175  ReorderTuple *topmost = NULL;
176  bool was_exact;
177  Datum *lastfetched_vals;
178  bool *lastfetched_nulls;
179  int cmp;
180 
181  estate = node->ss.ps.state;
182 
183  /*
184  * Only forward scan is supported with reordering. Note: we can get away
185  * with just Asserting here because the system will not try to run the
186  * plan backwards if ExecSupportsBackwardScan() says it won't work.
187  * Currently, that is guaranteed because no index AMs support both
188  * amcanorderbyop and amcanbackward; if any ever do,
189  * ExecSupportsBackwardScan() will need to consider indexorderbys
190  * explicitly.
191  */
192  Assert(!ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir));
194 
195  scandesc = node->iss_ScanDesc;
196  econtext = node->ss.ps.ps_ExprContext;
197  slot = node->ss.ss_ScanTupleSlot;
198 
199  if (scandesc == NULL)
200  {
201  /*
202  * We reach here if the index scan is not parallel, or if we're
203  * serially executing an index scan that was planned to be parallel.
204  */
205  scandesc = index_beginscan(node->ss.ss_currentRelation,
206  node->iss_RelationDesc,
207  estate->es_snapshot,
208  node->iss_NumScanKeys,
209  node->iss_NumOrderByKeys);
210 
211  node->iss_ScanDesc = scandesc;
212 
213  /*
214  * If no run-time keys to calculate or they are ready, go ahead and
215  * pass the scankeys to the index AM.
216  */
217  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
218  index_rescan(scandesc,
219  node->iss_ScanKeys, node->iss_NumScanKeys,
220  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
221  }
222 
223  for (;;)
224  {
226 
227  /*
228  * Check the reorder queue first. If the topmost tuple in the queue
229  * has an ORDER BY value smaller than (or equal to) the value last
230  * returned by the index, we can return it now.
231  */
233  {
234  topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
235 
236  if (node->iss_ReachedEnd ||
237  cmp_orderbyvals(topmost->orderbyvals,
238  topmost->orderbynulls,
239  scandesc->xs_orderbyvals,
240  scandesc->xs_orderbynulls,
241  node) <= 0)
242  {
243  HeapTuple tuple;
244 
245  tuple = reorderqueue_pop(node);
246 
247  /* Pass 'true', as the tuple in the queue is a palloc'd copy */
248  ExecForceStoreHeapTuple(tuple, slot, true);
249  return slot;
250  }
251  }
252  else if (node->iss_ReachedEnd)
253  {
254  /* Queue is empty, and no more tuples from index. We're done. */
255  return ExecClearTuple(slot);
256  }
257 
258  /*
259  * Fetch next tuple from the index.
260  */
261 next_indextuple:
262  if (!index_getnext_slot(scandesc, ForwardScanDirection, slot))
263  {
264  /*
265  * No more tuples from the index. But we still need to drain any
266  * remaining tuples from the queue before we're done.
267  */
268  node->iss_ReachedEnd = true;
269  continue;
270  }
271 
272  /*
273  * If the index was lossy, we have to recheck the index quals and
274  * ORDER BY expressions using the fetched tuple.
275  */
276  if (scandesc->xs_recheck)
277  {
278  econtext->ecxt_scantuple = slot;
279  if (!ExecQualAndReset(node->indexqualorig, econtext))
280  {
281  /* Fails recheck, so drop it and loop back for another */
282  InstrCountFiltered2(node, 1);
283  /* allow this loop to be cancellable */
285  goto next_indextuple;
286  }
287  }
288 
289  if (scandesc->xs_recheckorderby)
290  {
291  econtext->ecxt_scantuple = slot;
292  ResetExprContext(econtext);
293  EvalOrderByExpressions(node, econtext);
294 
295  /*
296  * Was the ORDER BY value returned by the index accurate? The
297  * recheck flag means that the index can return inaccurate values,
298  * but then again, the value returned for any particular tuple
299  * could also be exactly correct. Compare the value returned by
300  * the index with the recalculated value. (If the value returned
301  * by the index happened to be exact right, we can often avoid
302  * pushing the tuple to the queue, just to pop it back out again.)
303  */
305  node->iss_OrderByNulls,
306  scandesc->xs_orderbyvals,
307  scandesc->xs_orderbynulls,
308  node);
309  if (cmp < 0)
310  elog(ERROR, "index returned tuples in wrong order");
311  else if (cmp == 0)
312  was_exact = true;
313  else
314  was_exact = false;
315  lastfetched_vals = node->iss_OrderByValues;
316  lastfetched_nulls = node->iss_OrderByNulls;
317  }
318  else
319  {
320  was_exact = true;
321  lastfetched_vals = scandesc->xs_orderbyvals;
322  lastfetched_nulls = scandesc->xs_orderbynulls;
323  }
324 
325  /*
326  * Can we return this tuple immediately, or does it need to be pushed
327  * to the reorder queue? If the ORDER BY expression values returned
328  * by the index were inaccurate, we can't return it yet, because the
329  * next tuple from the index might need to come before this one. Also,
330  * we can't return it yet if there are any smaller tuples in the queue
331  * already.
332  */
333  if (!was_exact || (topmost && cmp_orderbyvals(lastfetched_vals,
334  lastfetched_nulls,
335  topmost->orderbyvals,
336  topmost->orderbynulls,
337  node) > 0))
338  {
339  /* Put this tuple to the queue */
340  reorderqueue_push(node, slot, lastfetched_vals, lastfetched_nulls);
341  continue;
342  }
343  else
344  {
345  /* Can return this tuple immediately. */
346  return slot;
347  }
348  }
349 
350  /*
351  * if we get here it means the index scan failed so we are at the end of
352  * the scan..
353  */
354  return ExecClearTuple(slot);
355 }
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1470
static void reorderqueue_push(IndexScanState *node, TupleTableSlot *slot, Datum *orderbyvals, bool *orderbynulls)
static void EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
static int cmp_orderbyvals(const Datum *adist, const bool *anulls, const Datum *bdist, const bool *bnulls, IndexScanState *node)
pairingheap_node * pairingheap_first(pairingheap *heap)
Definition: pairingheap.c:130
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
#define ScanDirectionIsForward(direction)
Definition: sdir.h:64
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:50
@ ForwardScanDirection
Definition: sdir.h:28
bool * xs_orderbynulls
Definition: relscan.h:162
bool xs_recheckorderby
Definition: relscan.h:163
Datum * xs_orderbyvals
Definition: relscan.h:161
Datum * orderbyvals
Definition: nodeIndexscan.c:55
bool * orderbynulls
Definition: nodeIndexscan.c:56

References Assert(), CHECK_FOR_INTERRUPTS, cmp(), cmp_orderbyvals(), ExprContext::ecxt_scantuple, elog(), ERROR, EState::es_direction, EState::es_snapshot, EvalOrderByExpressions(), ExecClearTuple(), ExecForceStoreHeapTuple(), ExecQualAndReset(), ForwardScanDirection, index_beginscan(), index_getnext_slot(), index_rescan(), IndexScanState::indexqualorig, InstrCountFiltered2, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_OrderByNulls, IndexScanState::iss_OrderByValues, IndexScanState::iss_ReachedEnd, IndexScanState::iss_RelationDesc, IndexScanState::iss_ReorderQueue, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, ReorderTuple::orderbynulls, ReorderTuple::orderbyvals, pairingheap_first(), pairingheap_is_empty, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, reorderqueue_pop(), reorderqueue_push(), ResetExprContext, ScanDirectionIsBackward, ScanDirectionIsForward, IndexScanState::ss, ScanState::ss_currentRelation, ScanState::ss_ScanTupleSlot, PlanState::state, IndexScanDescData::xs_orderbynulls, IndexScanDescData::xs_orderbyvals, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_recheckorderby.

Referenced by ExecIndexScan().

◆ IndexRecheck()

static bool IndexRecheck ( IndexScanState node,
TupleTableSlot slot 
)
static

Definition at line 387 of file nodeIndexscan.c.

388 {
389  ExprContext *econtext;
390 
391  /*
392  * extract necessary information from index scan node
393  */
394  econtext = node->ss.ps.ps_ExprContext;
395 
396  /* Does the tuple meet the indexqual condition? */
397  econtext->ecxt_scantuple = slot;
398  return ExecQualAndReset(node->indexqualorig, econtext);
399 }

References ExprContext::ecxt_scantuple, ExecQualAndReset(), IndexScanState::indexqualorig, ScanState::ps, PlanState::ps_ExprContext, and IndexScanState::ss.

Referenced by ExecIndexScan().

◆ reorderqueue_cmp()

static int reorderqueue_cmp ( const pairingheap_node a,
const pairingheap_node b,
void *  arg 
)
static

Definition at line 442 of file nodeIndexscan.c.

444 {
445  ReorderTuple *rta = (ReorderTuple *) a;
446  ReorderTuple *rtb = (ReorderTuple *) b;
447  IndexScanState *node = (IndexScanState *) arg;
448 
449  /* exchange argument order to invert the sort order */
450  return cmp_orderbyvals(rtb->orderbyvals, rtb->orderbynulls,
451  rta->orderbyvals, rta->orderbynulls,
452  node);
453 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, arg, b, cmp_orderbyvals(), ReorderTuple::orderbynulls, and ReorderTuple::orderbyvals.

Referenced by ExecInitIndexScan().

◆ reorderqueue_pop()

static HeapTuple reorderqueue_pop ( IndexScanState node)
static

Definition at line 493 of file nodeIndexscan.c.

494 {
495  HeapTuple result;
496  ReorderTuple *topmost;
497  int i;
498 
500 
501  result = topmost->htup;
502  for (i = 0; i < node->iss_NumOrderByKeys; i++)
503  {
504  if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
505  pfree(DatumGetPointer(topmost->orderbyvals[i]));
506  }
507  pfree(topmost->orderbyvals);
508  pfree(topmost->orderbynulls);
509  pfree(topmost);
510 
511  return result;
512 }
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
HeapTuple htup
Definition: nodeIndexscan.c:54

References DatumGetPointer(), ReorderTuple::htup, i, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_OrderByTypByVals, IndexScanState::iss_ReorderQueue, ReorderTuple::orderbynulls, ReorderTuple::orderbyvals, pairingheap_remove_first(), and pfree().

Referenced by ExecReScanIndexScan(), and IndexNextWithReorder().

◆ reorderqueue_push()

static void reorderqueue_push ( IndexScanState node,
TupleTableSlot slot,
Datum orderbyvals,
bool orderbynulls 
)
static

Definition at line 459 of file nodeIndexscan.c.

461 {
462  IndexScanDesc scandesc = node->iss_ScanDesc;
463  EState *estate = node->ss.ps.state;
464  MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
465  ReorderTuple *rt;
466  int i;
467 
468  rt = (ReorderTuple *) palloc(sizeof(ReorderTuple));
469  rt->htup = ExecCopySlotHeapTuple(slot);
470  rt->orderbyvals =
471  (Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys);
472  rt->orderbynulls =
473  (bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys);
474  for (i = 0; i < node->iss_NumOrderByKeys; i++)
475  {
476  if (!orderbynulls[i])
477  rt->orderbyvals[i] = datumCopy(orderbyvals[i],
478  node->iss_OrderByTypByVals[i],
479  node->iss_OrderByTypLens[i]);
480  else
481  rt->orderbyvals[i] = (Datum) 0;
482  rt->orderbynulls[i] = orderbynulls[i];
483  }
485 
486  MemoryContextSwitchTo(oldContext);
487 }
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
MemoryContext es_query_cxt
Definition: execnodes.h:659
int numberOfOrderBys
Definition: relscan.h:121
pairingheap_node ph_node
Definition: nodeIndexscan.c:53
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition: tuptable.h:459

References datumCopy(), EState::es_query_cxt, ExecCopySlotHeapTuple(), ReorderTuple::htup, i, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_OrderByTypByVals, IndexScanState::iss_OrderByTypLens, IndexScanState::iss_ReorderQueue, IndexScanState::iss_ScanDesc, MemoryContextSwitchTo(), IndexScanDescData::numberOfOrderBys, ReorderTuple::orderbynulls, ReorderTuple::orderbyvals, pairingheap_add(), palloc(), ReorderTuple::ph_node, ScanState::ps, IndexScanState::ss, and PlanState::state.

Referenced by IndexNextWithReorder().