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 408 of file nodeIndexscan.c.

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

Referenced by IndexNextWithReorder(), and reorderqueue_cmp().

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

◆ EvalOrderByExpressions()

static void EvalOrderByExpressions ( IndexScanState node,
ExprContext econtext 
)
static

Definition at line 363 of file nodeIndexscan.c.

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

Referenced by IndexNextWithReorder().

364 {
365  int i;
366  ListCell *l;
367  MemoryContext oldContext;
368 
369  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
370 
371  i = 0;
372  foreach(l, node->indexorderbyorig)
373  {
374  ExprState *orderby = (ExprState *) lfirst(l);
375 
376  node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
377  econtext,
378  &node->iss_OrderByNulls[i]);
379  i++;
380  }
381 
382  MemoryContextSwitchTo(oldContext);
383 }
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * indexorderbyorig
Definition: execnodes.h:1369
bool * iss_OrderByNulls
Definition: execnodes.h:1385
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:285
#define lfirst(lc)
Definition: pg_list.h:190
int i
Datum * iss_OrderByValues
Definition: execnodes.h:1384

◆ ExecEndIndexScan()

void ExecEndIndexScan ( IndexScanState node)

Definition at line 783 of file nodeIndexscan.c.

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

784 {
785  Relation indexRelationDesc;
786  IndexScanDesc indexScanDesc;
787 
788  /*
789  * extract information from the node
790  */
791  indexRelationDesc = node->iss_RelationDesc;
792  indexScanDesc = node->iss_ScanDesc;
793 
794  /*
795  * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
796  */
797 #ifdef NOT_USED
798  ExecFreeExprContext(&node->ss.ps);
799  if (node->iss_RuntimeContext)
800  FreeExprContext(node->iss_RuntimeContext, true);
801 #endif
802 
803  /*
804  * clear out tuple table slots
805  */
806  if (node->ss.ps.ps_ResultTupleSlot)
809 
810  /*
811  * close the index relation (no-op if we didn't open it)
812  */
813  if (indexScanDesc)
814  index_endscan(indexScanDesc);
815  if (indexRelationDesc)
816  index_close(indexRelationDesc, NoLock);
817 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:616
PlanState ps
Definition: execnodes.h:1280
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:983
#define NoLock
Definition: lockdefs.h:34
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:315
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:377
ScanState ss
Definition: execnodes.h:1367
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1377
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1379
Relation iss_RelationDesc
Definition: execnodes.h:1378

◆ ExecIndexAdvanceArrayKeys()

bool ExecIndexAdvanceArrayKeys ( IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 738 of file nodeIndexscan.c.

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

Referenced by MultiExecBitmapIndexScan().

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

◆ 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 1145 of file nodeIndexscan.c.

References IndexAmRoutine::amsearcharray, 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, ScalarArrayOpExpr::inputcollid, RowCompareExpr::inputcollids, InvalidOid, InvalidStrategy, IS_NOT_NULL, IS_NULL, IsA, IndexRuntimeKeyInfo::key_expr, IndexRuntimeKeyInfo::key_toastable, RowCompareExpr::largs, lfirst, lfirst_oid, linitial, list_length(), lsecond, MemSet, nodeTag, NullTest::nulltesttype, ScalarArrayOpExpr::opfuncid, ScalarArrayOpExpr::opno, RowCompareExpr::opnos, palloc(), palloc0(), pfree(), PointerGetDatum, RowCompareExpr::rargs, RowCompareExpr::rctype, RelationData::rd_indam, RelationData::rd_opfamily, RelationData::rd_rel, 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().

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

◆ ExecIndexEvalArrayKeys()

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

Definition at line 659 of file nodeIndexscan.c.

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

Referenced by ExecReScanBitmapIndexScan().

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

◆ ExecIndexEvalRuntimeKeys()

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

Definition at line 597 of file nodeIndexscan.c.

References ExprContext::ecxt_per_tuple_memory, ExecEvalExpr(), 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().

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

◆ ExecIndexMarkPos()

void ExecIndexMarkPos ( IndexScanState node)

Definition at line 827 of file nodeIndexscan.c.

References Assert, elog, ERROR, EState::es_epqScanDone, EState::es_epqTupleSlot, index_markpos(), IndexScanState::iss_ScanDesc, PlanState::plan, ScanState::ps, IndexScanState::ss, and PlanState::state.

Referenced by ExecMarkPos().

828 {
829  EState *estate = node->ss.ps.state;
830 
831  if (estate->es_epqTupleSlot != NULL)
832  {
833  /*
834  * We are inside an EvalPlanQual recheck. If a test tuple exists for
835  * this relation, then we shouldn't access the index at all. We would
836  * instead need to save, and later restore, the state of the
837  * es_epqScanDone flag, so that re-fetching the test tuple is
838  * possible. However, given the assumption that no caller sets a mark
839  * at the start of the scan, we can only get here with es_epqScanDone
840  * already set, and so no state need be saved.
841  */
842  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
843 
844  Assert(scanrelid > 0);
845  if (estate->es_epqTupleSlot[scanrelid - 1] != NULL)
846  {
847  /* Verify the claim above */
848  if (!estate->es_epqScanDone[scanrelid - 1])
849  elog(ERROR, "unexpected ExecIndexMarkPos call in EPQ recheck");
850  return;
851  }
852  }
853 
855 }
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:345
EState * state
Definition: execnodes.h:947
PlanState ps
Definition: execnodes.h:1280
#define ERROR
Definition: elog.h:43
unsigned int Index
Definition: c.h:475
Plan * plan
Definition: execnodes.h:945
ScanState ss
Definition: execnodes.h:1367
#define Assert(condition)
Definition: c.h:732
TupleTableSlot ** es_epqTupleSlot
Definition: execnodes.h:583
#define elog(elevel,...)
Definition: elog.h:226
bool * es_epqScanDone
Definition: execnodes.h:584
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1379

◆ ExecIndexRestrPos()

void ExecIndexRestrPos ( IndexScanState node)

Definition at line 862 of file nodeIndexscan.c.

References Assert, elog, ERROR, EState::es_epqScanDone, EState::es_epqTupleSlot, index_restrpos(), IndexScanState::iss_ScanDesc, PlanState::plan, ScanState::ps, IndexScanState::ss, and PlanState::state.

Referenced by ExecRestrPos().

863 {
864  EState *estate = node->ss.ps.state;
865 
866  if (estate->es_epqTupleSlot != NULL)
867  {
868  /* See comments in ExecIndexMarkPos */
869  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
870 
871  Assert(scanrelid > 0);
872  if (estate->es_epqTupleSlot[scanrelid - 1] != NULL)
873  {
874  /* Verify the claim above */
875  if (!estate->es_epqScanDone[scanrelid - 1])
876  elog(ERROR, "unexpected ExecIndexRestrPos call in EPQ recheck");
877  return;
878  }
879  }
880 
882 }
EState * state
Definition: execnodes.h:947
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:369
PlanState ps
Definition: execnodes.h:1280
#define ERROR
Definition: elog.h:43
unsigned int Index
Definition: c.h:475
Plan * plan
Definition: execnodes.h:945
ScanState ss
Definition: execnodes.h:1367
#define Assert(condition)
Definition: c.h:732
TupleTableSlot ** es_epqTupleSlot
Definition: execnodes.h:583
#define elog(elevel,...)
Definition: elog.h:226
bool * es_epqScanDone
Definition: execnodes.h:584
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1379

◆ ExecIndexScan()

static TupleTableSlot* ExecIndexScan ( PlanState pstate)
static

Definition at line 522 of file nodeIndexscan.c.

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

Referenced by ExecInitIndexScan().

523 {
524  IndexScanState *node = castNode(IndexScanState, pstate);
525 
526  /*
527  * If we have runtime keys and they've not already been set up, do it now.
528  */
529  if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
530  ExecReScan((PlanState *) node);
531 
532  if (node->iss_NumOrderByKeys > 0)
533  return ExecScan(&node->ss,
536  else
537  return ExecScan(&node->ss,
540 }
static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
#define castNode(_type_, nodeptr)
Definition: nodes.h:593
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:119
void ExecReScan(PlanState *node)
Definition: execAmi.c:77
int iss_NumRuntimeKeys
Definition: execnodes.h:1375
bool iss_RuntimeKeysReady
Definition: execnodes.h:1376
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:426
static TupleTableSlot * IndexNext(IndexScanState *node)
Definition: nodeIndexscan.c:81
static TupleTableSlot * IndexNextWithReorder(IndexScanState *node)
ScanState ss
Definition: execnodes.h:1367
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:425
int iss_NumOrderByKeys
Definition: execnodes.h:1373

◆ ExecIndexScanEstimate()

void ExecIndexScanEstimate ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1651 of file nodeIndexscan.c.

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

1653 {
1654  EState *estate = node->ss.ps.state;
1655 
1657  estate->es_snapshot);
1659  shm_toc_estimate_keys(&pcxt->estimator, 1);
1660 }
shm_toc_estimator estimator
Definition: parallel.h:41
Snapshot es_snapshot
Definition: execnodes.h:503
EState * state
Definition: execnodes.h:947
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:394
PlanState ps
Definition: execnodes.h:1280
ScanState ss
Definition: execnodes.h:1367
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Relation iss_RelationDesc
Definition: execnodes.h:1378

◆ ExecIndexScanInitializeDSM()

void ExecIndexScanInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1669 of file nodeIndexscan.c.

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

1671 {
1672  EState *estate = node->ss.ps.state;
1673  ParallelIndexScanDesc piscan;
1674 
1675  piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1677  node->iss_RelationDesc,
1678  estate->es_snapshot,
1679  piscan);
1680  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1681  node->iss_ScanDesc =
1683  node->iss_RelationDesc,
1684  node->iss_NumScanKeys,
1685  node->iss_NumOrderByKeys,
1686  piscan);
1687 
1688  /*
1689  * If no run-time keys to calculate or they are ready, go ahead and pass
1690  * the scankeys to the index AM.
1691  */
1692  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1693  index_rescan(node->iss_ScanDesc,
1694  node->iss_ScanKeys, node->iss_NumScanKeys,
1695  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1696 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:476
int plan_node_id
Definition: plannodes.h:139
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:289
Snapshot es_snapshot
Definition: execnodes.h:503
Relation ss_currentRelation
Definition: execnodes.h:1281
EState * state
Definition: execnodes.h:947
PlanState ps
Definition: execnodes.h:1280
int iss_NumRuntimeKeys
Definition: execnodes.h:1375
bool iss_RuntimeKeysReady
Definition: execnodes.h:1376
Plan * plan
Definition: execnodes.h:945
ScanState ss
Definition: execnodes.h:1367
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1372
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:427
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1370
int iss_NumOrderByKeys
Definition: execnodes.h:1373
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1379
shm_toc * toc
Definition: parallel.h:44
Relation iss_RelationDesc
Definition: execnodes.h:1378

◆ ExecIndexScanInitializeWorker()

void ExecIndexScanInitializeWorker ( IndexScanState node,
ParallelWorkerContext pwcxt 
)

Definition at line 1718 of file nodeIndexscan.c.

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

1720 {
1721  ParallelIndexScanDesc piscan;
1722 
1723  piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1724  node->iss_ScanDesc =
1726  node->iss_RelationDesc,
1727  node->iss_NumScanKeys,
1728  node->iss_NumOrderByKeys,
1729  piscan);
1730 
1731  /*
1732  * If no run-time keys to calculate or they are ready, go ahead and pass
1733  * the scankeys to the index AM.
1734  */
1735  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1736  index_rescan(node->iss_ScanDesc,
1737  node->iss_ScanKeys, node->iss_NumScanKeys,
1738  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1739 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:476
int plan_node_id
Definition: plannodes.h:139
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:289
Relation ss_currentRelation
Definition: execnodes.h:1281
PlanState ps
Definition: execnodes.h:1280
int iss_NumRuntimeKeys
Definition: execnodes.h:1375
bool iss_RuntimeKeysReady
Definition: execnodes.h:1376
Plan * plan
Definition: execnodes.h:945
ScanState ss
Definition: execnodes.h:1367
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1372
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1370
int iss_NumOrderByKeys
Definition: execnodes.h:1373
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1379
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232
Relation iss_RelationDesc
Definition: execnodes.h:1378

◆ ExecIndexScanReInitializeDSM()

void ExecIndexScanReInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1705 of file nodeIndexscan.c.

References index_parallelrescan(), and IndexScanState::iss_ScanDesc.

Referenced by ExecParallelReInitializeDSM().

1707 {
1709 }
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:458
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1379

◆ ExecInitIndexScan()

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

Definition at line 896 of file nodeIndexscan.c.

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, IndexScan::indexorderbyorig, IndexScan::indexqual, IndexScan::indexqualorig, lfirst, lfirst_oid, list_length(), makeNode, pairingheap_allocate(), palloc(), palloc0(), Scan::plan, PlanState::plan, PrepareSortSupportFromOrderingOp(), ScanState::ps, PlanState::ps_ExprContext, Plan::qual, 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().

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

◆ ExecReScanIndexScan()

void ExecReScanIndexScan ( IndexScanState node)

Definition at line 554 of file nodeIndexscan.c.

References ExecIndexEvalRuntimeKeys(), ExecScanReScan(), 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().

555 {
556  /*
557  * If we are doing runtime key calculations (ie, any of the index key
558  * values weren't simple Consts), compute the new key values. But first,
559  * reset the context so we don't leak memory as each outer tuple is
560  * scanned. Note this assumes that we will recalculate *all* runtime keys
561  * on each call.
562  */
563  if (node->iss_NumRuntimeKeys != 0)
564  {
565  ExprContext *econtext = node->iss_RuntimeContext;
566 
567  ResetExprContext(econtext);
568  ExecIndexEvalRuntimeKeys(econtext,
569  node->iss_RuntimeKeys,
570  node->iss_NumRuntimeKeys);
571  }
572  node->iss_RuntimeKeysReady = true;
573 
574  /* flush the reorder queue */
575  if (node->iss_ReorderQueue)
576  {
577  while (!pairingheap_is_empty(node->iss_ReorderQueue))
578  reorderqueue_pop(node);
579  }
580 
581  /* reset index scan */
582  if (node->iss_ScanDesc)
584  node->iss_ScanKeys, node->iss_NumScanKeys,
585  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
586  node->iss_ReachedEnd = false;
587 
588  ExecScanReScan(&node->ss);
589 }
IndexRuntimeKeyInfo * iss_RuntimeKeys
Definition: execnodes.h:1374
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:289
bool iss_ReachedEnd
Definition: execnodes.h:1383
int iss_NumRuntimeKeys
Definition: execnodes.h:1375
bool iss_RuntimeKeysReady
Definition: execnodes.h:1376
ScanState ss
Definition: execnodes.h:1367
static HeapTuple reorderqueue_pop(IndexScanState *node)
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1377
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1372
void ExecScanReScan(ScanState *node)
Definition: execScan.c:260
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1370
int iss_NumOrderByKeys
Definition: execnodes.h:1373
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1379
#define ResetExprContext(econtext)
Definition: executor.h:495
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1382

◆ IndexNext()

static TupleTableSlot * IndexNext ( IndexScanState node)
static

Definition at line 81 of file nodeIndexscan.c.

References BackwardScanDirection, CHECK_FOR_INTERRUPTS, ExprContext::ecxt_scantuple, EState::es_direction, EState::es_snapshot, ExecClearTuple(), 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_ReachedEnd, IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, ScanDirectionIsBackward, ScanDirectionIsForward, IndexScanState::ss, ScanState::ss_currentRelation, ScanState::ss_ScanTupleSlot, PlanState::state, and IndexScanDescData::xs_recheck.

Referenced by ExecIndexScan().

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  direction = estate->es_direction;
94  /* flip direction if this is an overall backward scan */
95  if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
96  {
97  if (ScanDirectionIsForward(direction))
98  direction = BackwardScanDirection;
99  else if (ScanDirectionIsBackward(direction))
100  direction = ForwardScanDirection;
101  }
102  scandesc = node->iss_ScanDesc;
103  econtext = node->ss.ps.ps_ExprContext;
104  slot = node->ss.ss_ScanTupleSlot;
105 
106  if (scandesc == NULL)
107  {
108  /*
109  * We reach here if the index scan is not parallel, or if we're
110  * serially executing an index scan that was planned to be parallel.
111  */
112  scandesc = index_beginscan(node->ss.ss_currentRelation,
113  node->iss_RelationDesc,
114  estate->es_snapshot,
115  node->iss_NumScanKeys,
116  node->iss_NumOrderByKeys);
117 
118  node->iss_ScanDesc = scandesc;
119 
120  /*
121  * If no run-time keys to calculate or they are ready, go ahead and
122  * pass the scankeys to the index AM.
123  */
124  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
125  index_rescan(scandesc,
126  node->iss_ScanKeys, node->iss_NumScanKeys,
127  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
128  }
129 
130  /*
131  * ok, now that we have what we need, fetch the next tuple.
132  */
133  while (index_getnext_slot(scandesc, direction, slot))
134  {
136 
137  /*
138  * If the index was lossy, we have to recheck the index quals using
139  * the fetched tuple.
140  */
141  if (scandesc->xs_recheck)
142  {
143  econtext->ecxt_scantuple = slot;
144  if (!ExecQualAndReset(node->indexqualorig, econtext))
145  {
146  /* Fails recheck, so drop it and loop back for another */
147  InstrCountFiltered2(node, 1);
148  continue;
149  }
150  }
151 
152  return slot;
153  }
154 
155  /*
156  * if we get here it means the index scan failed so we are at the end of
157  * the scan..
158  */
159  node->iss_ReachedEnd = true;
160  return ExecClearTuple(slot);
161 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
ExprContext * ps_ExprContext
Definition: execnodes.h:984
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:289
Snapshot es_snapshot
Definition: execnodes.h:503
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
Relation ss_currentRelation
Definition: execnodes.h:1281
EState * state
Definition: execnodes.h:947
ExprState * indexqualorig
Definition: execnodes.h:1368
ScanDirection es_direction
Definition: execnodes.h:502
PlanState ps
Definition: execnodes.h:1280
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
bool iss_ReachedEnd
Definition: execnodes.h:1383
int iss_NumRuntimeKeys
Definition: execnodes.h:1375
ScanDirection
Definition: sdir.h:22
bool iss_RuntimeKeysReady
Definition: execnodes.h:1376
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:392
Plan * plan
Definition: execnodes.h:945
ScanState ss
Definition: execnodes.h:1367
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:1052
bool index_getnext_slot(IndexScanDesc scan, ScanDirection direction, TupleTableSlot *slot)
Definition: indexam.c:607
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:224
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1372
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1370
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
int iss_NumOrderByKeys
Definition: execnodes.h:1373
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1379
Relation iss_RelationDesc
Definition: execnodes.h:1378
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:197

◆ IndexNextWithReorder()

static TupleTableSlot * IndexNextWithReorder ( IndexScanState node)
static

Definition at line 171 of file nodeIndexscan.c.

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

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

◆ IndexRecheck()

static bool IndexRecheck ( IndexScanState node,
TupleTableSlot slot 
)
static

Definition at line 389 of file nodeIndexscan.c.

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

Referenced by ExecIndexScan().

390 {
391  ExprContext *econtext;
392 
393  /*
394  * extract necessary information from index scan node
395  */
396  econtext = node->ss.ps.ps_ExprContext;
397 
398  /* Does the tuple meet the indexqual condition? */
399  econtext->ecxt_scantuple = slot;
400  return ExecQualAndReset(node->indexqualorig, econtext);
401 }
ExprContext * ps_ExprContext
Definition: execnodes.h:984
ExprState * indexqualorig
Definition: execnodes.h:1368
PlanState ps
Definition: execnodes.h:1280
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:392
ScanState ss
Definition: execnodes.h:1367
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:224

◆ reorderqueue_cmp()

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

Definition at line 444 of file nodeIndexscan.c.

References cmp_orderbyvals(), ReorderTuple::orderbynulls, and ReorderTuple::orderbyvals.

Referenced by ExecInitIndexScan().

446 {
447  ReorderTuple *rta = (ReorderTuple *) a;
448  ReorderTuple *rtb = (ReorderTuple *) b;
449  IndexScanState *node = (IndexScanState *) arg;
450 
451  /* exchange argument order to invert the sort order */
452  return cmp_orderbyvals(rtb->orderbyvals, rtb->orderbynulls,
453  rta->orderbyvals, rta->orderbynulls,
454  node);
455 }
bool * orderbynulls
Definition: nodeIndexscan.c:56
static int cmp_orderbyvals(const Datum *adist, const bool *anulls, const Datum *bdist, const bool *bnulls, IndexScanState *node)
Datum * orderbyvals
Definition: nodeIndexscan.c:55
void * arg

◆ reorderqueue_pop()

static HeapTuple reorderqueue_pop ( IndexScanState node)
static

Definition at line 495 of file nodeIndexscan.c.

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

496 {
497  HeapTuple result;
498  ReorderTuple *topmost;
499  int i;
500 
502 
503  result = topmost->htup;
504  for (i = 0; i < node->iss_NumOrderByKeys; i++)
505  {
506  if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
507  pfree(DatumGetPointer(topmost->orderbyvals[i]));
508  }
509  pfree(topmost->orderbyvals);
510  pfree(topmost->orderbynulls);
511  pfree(topmost);
512 
513  return result;
514 }
bool * orderbynulls
Definition: nodeIndexscan.c:56
void pfree(void *pointer)
Definition: mcxt.c:1031
Datum * orderbyvals
Definition: nodeIndexscan.c:55
bool * iss_OrderByTypByVals
Definition: execnodes.h:1387
HeapTuple htup
Definition: nodeIndexscan.c:54
#define DatumGetPointer(X)
Definition: postgres.h:549
int i
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145
int iss_NumOrderByKeys
Definition: execnodes.h:1373
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1382

◆ reorderqueue_push()

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

Definition at line 461 of file nodeIndexscan.c.

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

463 {
464  IndexScanDesc scandesc = node->iss_ScanDesc;
465  EState *estate = node->ss.ps.state;
466  MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
467  ReorderTuple *rt;
468  int i;
469 
470  rt = (ReorderTuple *) palloc(sizeof(ReorderTuple));
471  rt->htup = ExecCopySlotHeapTuple(slot);
472  rt->orderbyvals =
473  (Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys);
474  rt->orderbynulls =
475  (bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys);
476  for (i = 0; i < node->iss_NumOrderByKeys; i++)
477  {
478  if (!orderbynulls[i])
479  rt->orderbyvals[i] = datumCopy(orderbyvals[i],
480  node->iss_OrderByTypByVals[i],
481  node->iss_OrderByTypLens[i]);
482  else
483  rt->orderbyvals[i] = (Datum) 0;
484  rt->orderbynulls[i] = orderbynulls[i];
485  }
487 
488  MemoryContextSwitchTo(oldContext);
489 }
bool * orderbynulls
Definition: nodeIndexscan.c:56
int16 * iss_OrderByTypLens
Definition: execnodes.h:1388
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
EState * state
Definition: execnodes.h:947
PlanState ps
Definition: execnodes.h:1280
MemoryContext es_query_cxt
Definition: execnodes.h:550
Datum * orderbyvals
Definition: nodeIndexscan.c:55
bool * iss_OrderByTypByVals
Definition: execnodes.h:1387
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
pairingheap_node ph_node
Definition: nodeIndexscan.c:53
uintptr_t Datum
Definition: postgres.h:367
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition: tuptable.h:453
ScanState ss
Definition: execnodes.h:1367
HeapTuple htup
Definition: nodeIndexscan.c:54
void * palloc(Size size)
Definition: mcxt.c:924
int i
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
int numberOfOrderBys
Definition: relscan.h:106
int iss_NumOrderByKeys
Definition: execnodes.h:1373
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1379
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1382