PostgreSQL Source Code  git master
nodeIndexscan.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "access/relscan.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 "optimizer/clauses.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, HeapTuple tuple, 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 429 of file nodeIndexscan.c.

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

Referenced by IndexNextWithReorder(), and reorderqueue_cmp().

432 {
433  int i;
434  int result;
435 
436  for (i = 0; i < node->iss_NumOrderByKeys; i++)
437  {
438  SortSupport ssup = &node->iss_SortSupport[i];
439 
440  /*
441  * Handle nulls. We only need to support NULLS LAST ordering, because
442  * match_pathkeys_to_index() doesn't consider indexorderby
443  * implementation otherwise.
444  */
445  if (anulls[i] && !bnulls[i])
446  return 1;
447  else if (!anulls[i] && bnulls[i])
448  return -1;
449  else if (anulls[i] && bnulls[i])
450  return 0;
451 
452  result = ssup->comparator(adist[i], bdist[i], ssup);
453  if (result != 0)
454  return result;
455  }
456 
457  return 0;
458 }
SortSupport iss_SortSupport
Definition: execnodes.h:1227
int(* comparator)(Datum x, Datum y, SortSupport ssup)
Definition: sortsupport.h:107
int i
int iss_NumOrderByKeys
Definition: execnodes.h:1214

◆ EvalOrderByExpressions()

static void EvalOrderByExpressions ( IndexScanState node,
ExprContext econtext 
)
static

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

385 {
386  int i;
387  ListCell *l;
388  MemoryContext oldContext;
389 
390  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
391 
392  i = 0;
393  foreach(l, node->indexorderbyorig)
394  {
395  ExprState *orderby = (ExprState *) lfirst(l);
396 
397  node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
398  econtext,
399  &node->iss_OrderByNulls[i]);
400  i++;
401  }
402 
403  MemoryContextSwitchTo(oldContext);
404 }
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:217
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * indexorderbyorig
Definition: execnodes.h:1210
bool * iss_OrderByNulls
Definition: execnodes.h:1226
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:282
#define lfirst(lc)
Definition: pg_list.h:106
int i
Datum * iss_OrderByValues
Definition: execnodes.h:1225

◆ ExecEndIndexScan()

void ExecEndIndexScan ( IndexScanState node)

Definition at line 803 of file nodeIndexscan.c.

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

Referenced by ExecEndNode().

804 {
805  Relation indexRelationDesc;
806  IndexScanDesc indexScanDesc;
807  Relation relation;
808 
809  /*
810  * extract information from the node
811  */
812  indexRelationDesc = node->iss_RelationDesc;
813  indexScanDesc = node->iss_ScanDesc;
814  relation = node->ss.ss_currentRelation;
815 
816  /*
817  * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
818  */
819 #ifdef NOT_USED
820  ExecFreeExprContext(&node->ss.ps);
821  if (node->iss_RuntimeContext)
822  FreeExprContext(node->iss_RuntimeContext, true);
823 #endif
824 
825  /*
826  * clear out tuple table slots
827  */
830 
831  /*
832  * close the index relation (no-op if we didn't open it)
833  */
834  if (indexScanDesc)
835  index_endscan(indexScanDesc);
836  if (indexRelationDesc)
837  index_close(indexRelationDesc, NoLock);
838 
839  /*
840  * close the heap relation.
841  */
842  ExecCloseScanRelation(relation);
843 }
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1127
Relation ss_currentRelation
Definition: execnodes.h:1125
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:561
PlanState ps
Definition: execnodes.h:1124
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:901
#define NoLock
Definition: lockdefs.h:34
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:341
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:356
ScanState ss
Definition: execnodes.h:1208
void ExecCloseScanRelation(Relation scanrel)
Definition: execUtils.c:696
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1218
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220
Relation iss_RelationDesc
Definition: execnodes.h:1219

◆ ExecIndexAdvanceArrayKeys()

bool ExecIndexAdvanceArrayKeys ( IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

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

759 {
760  bool found = false;
761  int j;
762 
763  /*
764  * Note we advance the rightmost array key most quickly, since it will
765  * correspond to the lowest-order index column among the available
766  * qualifications. This is hypothesized to result in better locality of
767  * access in the index.
768  */
769  for (j = numArrayKeys - 1; j >= 0; j--)
770  {
771  ScanKey scan_key = arrayKeys[j].scan_key;
772  int next_elem = arrayKeys[j].next_elem;
773  int num_elems = arrayKeys[j].num_elems;
774  Datum *elem_values = arrayKeys[j].elem_values;
775  bool *elem_nulls = arrayKeys[j].elem_nulls;
776 
777  if (next_elem >= num_elems)
778  {
779  next_elem = 0;
780  found = false; /* need to advance next array key */
781  }
782  else
783  found = true;
784  scan_key->sk_argument = elem_values[next_elem];
785  if (elem_nulls[next_elem])
786  scan_key->sk_flags |= SK_ISNULL;
787  else
788  scan_key->sk_flags &= ~SK_ISNULL;
789  arrayKeys[j].next_elem = next_elem + 1;
790  if (found)
791  break;
792  }
793 
794  return found;
795 }
Datum * elem_values
Definition: execnodes.h:1176
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:365
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 1177 of file nodeIndexscan.c.

References IndexAmRoutine::amsearcharray, arg, NullTest::arg, ScalarArrayOpExpr::args, IndexArrayKeyInfo::array_expr, Assert, BTORDER_PROC, BTREE_AM_OID, elog, ERROR, ExecInitExpr(), get_leftop(), get_op_opfamily_properties(), get_opfamily_proc(), get_rightop(), INDEX_VAR, 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_head(), list_length(), lnext, lsecond, MemSet, nodeTag, NullTest::nulltesttype, ScalarArrayOpExpr::opfuncid, ScalarArrayOpExpr::opno, RowCompareExpr::opnos, palloc(), palloc0(), pfree(), PointerGetDatum, RowCompareExpr::rargs, RowCompareExpr::rctype, RelationData::rd_amroutine, RelationData::rd_index, 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().

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

◆ ExecIndexEvalArrayKeys()

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

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

681 {
682  bool result = true;
683  int j;
684  MemoryContext oldContext;
685 
686  /* We want to keep the arrays in per-tuple memory */
687  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
688 
689  for (j = 0; j < numArrayKeys; j++)
690  {
691  ScanKey scan_key = arrayKeys[j].scan_key;
692  ExprState *array_expr = arrayKeys[j].array_expr;
693  Datum arraydatum;
694  bool isNull;
695  ArrayType *arrayval;
696  int16 elmlen;
697  bool elmbyval;
698  char elmalign;
699  int num_elems;
700  Datum *elem_values;
701  bool *elem_nulls;
702 
703  /*
704  * Compute and deconstruct the array expression. (Notes in
705  * ExecIndexEvalRuntimeKeys() apply here too.)
706  */
707  arraydatum = ExecEvalExpr(array_expr,
708  econtext,
709  &isNull);
710  if (isNull)
711  {
712  result = false;
713  break; /* no point in evaluating more */
714  }
715  arrayval = DatumGetArrayTypeP(arraydatum);
716  /* We could cache this data, but not clear it's worth it */
718  &elmlen, &elmbyval, &elmalign);
719  deconstruct_array(arrayval,
720  ARR_ELEMTYPE(arrayval),
721  elmlen, elmbyval, elmalign,
722  &elem_values, &elem_nulls, &num_elems);
723  if (num_elems <= 0)
724  {
725  result = false;
726  break; /* no point in evaluating more */
727  }
728 
729  /*
730  * Note: we expect the previous array data, if any, to be
731  * automatically freed by resetting the per-tuple context; hence no
732  * pfree's here.
733  */
734  arrayKeys[j].elem_values = elem_values;
735  arrayKeys[j].elem_nulls = elem_nulls;
736  arrayKeys[j].num_elems = num_elems;
737  scan_key->sk_argument = elem_values[0];
738  if (elem_nulls[0])
739  scan_key->sk_flags |= SK_ISNULL;
740  else
741  scan_key->sk_flags &= ~SK_ISNULL;
742  arrayKeys[j].next_elem = 1;
743  }
744 
745  MemoryContextSwitchTo(oldContext);
746 
747  return result;
748 }
Datum * elem_values
Definition: execnodes.h:1176
signed short int16
Definition: c.h:301
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2025
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:217
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:282
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:365
ExprState * array_expr
Definition: execnodes.h:1173
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:3449
Datum sk_argument
Definition: skey.h:72
#define ARR_ELEMTYPE(a)
Definition: array.h:277
#define DatumGetArrayTypeP(X)
Definition: array.h:246

◆ ExecIndexEvalRuntimeKeys()

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

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

619 {
620  int j;
621  MemoryContext oldContext;
622 
623  /* We want to keep the key values in per-tuple memory */
624  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
625 
626  for (j = 0; j < numRuntimeKeys; j++)
627  {
628  ScanKey scan_key = runtimeKeys[j].scan_key;
629  ExprState *key_expr = runtimeKeys[j].key_expr;
630  Datum scanvalue;
631  bool isNull;
632 
633  /*
634  * For each run-time key, extract the run-time expression and evaluate
635  * it with respect to the current context. We then stick the result
636  * into the proper scan key.
637  *
638  * Note: the result of the eval could be a pass-by-ref value that's
639  * stored in some outer scan's tuple, not in
640  * econtext->ecxt_per_tuple_memory. We assume that the outer tuple
641  * will stay put throughout our scan. If this is wrong, we could copy
642  * the result into our context explicitly, but I think that's not
643  * necessary.
644  *
645  * It's also entirely possible that the result of the eval is a
646  * toasted value. In this case we should forcibly detoast it, to
647  * avoid repeat detoastings each time the value is examined by an
648  * index support function.
649  */
650  scanvalue = ExecEvalExpr(key_expr,
651  econtext,
652  &isNull);
653  if (isNull)
654  {
655  scan_key->sk_argument = scanvalue;
656  scan_key->sk_flags |= SK_ISNULL;
657  }
658  else
659  {
660  if (runtimeKeys[j].key_toastable)
661  scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
662  scan_key->sk_argument = scanvalue;
663  scan_key->sk_flags &= ~SK_ISNULL;
664  }
665  }
666 
667  MemoryContextSwitchTo(oldContext);
668 }
#define PointerGetDatum(X)
Definition: postgres.h:539
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:217
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExprState * key_expr
Definition: execnodes.h:1166
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:282
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:365
int sk_flags
Definition: skey.h:66
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:205
Datum sk_argument
Definition: skey.h:72

◆ ExecIndexMarkPos()

void ExecIndexMarkPos ( IndexScanState node)

Definition at line 853 of file nodeIndexscan.c.

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

Referenced by ExecMarkPos().

854 {
855  EState *estate = node->ss.ps.state;
856 
857  if (estate->es_epqTuple != NULL)
858  {
859  /*
860  * We are inside an EvalPlanQual recheck. If a test tuple exists for
861  * this relation, then we shouldn't access the index at all. We would
862  * instead need to save, and later restore, the state of the
863  * es_epqScanDone flag, so that re-fetching the test tuple is
864  * possible. However, given the assumption that no caller sets a mark
865  * at the start of the scan, we can only get here with es_epqScanDone
866  * already set, and so no state need be saved.
867  */
868  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
869 
870  Assert(scanrelid > 0);
871  if (estate->es_epqTupleSet[scanrelid - 1])
872  {
873  /* Verify the claim above */
874  if (!estate->es_epqScanDone[scanrelid - 1])
875  elog(ERROR, "unexpected ExecIndexMarkPos call in EPQ recheck");
876  return;
877  }
878  }
879 
881 }
HeapTuple * es_epqTuple
Definition: execnodes.h:523
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:371
EState * state
Definition: execnodes.h:870
PlanState ps
Definition: execnodes.h:1124
#define ERROR
Definition: elog.h:43
unsigned int Index
Definition: c.h:431
Plan * plan
Definition: execnodes.h:868
ScanState ss
Definition: execnodes.h:1208
#define Assert(condition)
Definition: c.h:688
bool * es_epqTupleSet
Definition: execnodes.h:524
bool * es_epqScanDone
Definition: execnodes.h:525
#define elog
Definition: elog.h:219
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220

◆ ExecIndexRestrPos()

void ExecIndexRestrPos ( IndexScanState node)

Definition at line 888 of file nodeIndexscan.c.

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

Referenced by ExecRestrPos().

889 {
890  EState *estate = node->ss.ps.state;
891 
892  if (estate->es_epqTuple != NULL)
893  {
894  /* See comments in ExecIndexMarkPos */
895  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
896 
897  Assert(scanrelid > 0);
898  if (estate->es_epqTupleSet[scanrelid - 1])
899  {
900  /* Verify the claim above */
901  if (!estate->es_epqScanDone[scanrelid - 1])
902  elog(ERROR, "unexpected ExecIndexRestrPos call in EPQ recheck");
903  return;
904  }
905  }
906 
908 }
HeapTuple * es_epqTuple
Definition: execnodes.h:523
EState * state
Definition: execnodes.h:870
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:396
PlanState ps
Definition: execnodes.h:1124
#define ERROR
Definition: elog.h:43
unsigned int Index
Definition: c.h:431
Plan * plan
Definition: execnodes.h:868
ScanState ss
Definition: execnodes.h:1208
#define Assert(condition)
Definition: c.h:688
bool * es_epqTupleSet
Definition: execnodes.h:524
bool * es_epqScanDone
Definition: execnodes.h:525
#define elog
Definition: elog.h:219
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220

◆ ExecIndexScan()

static TupleTableSlot* ExecIndexScan ( PlanState pstate)
static

Definition at line 542 of file nodeIndexscan.c.

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

Referenced by ExecInitIndexScan().

543 {
544  IndexScanState *node = castNode(IndexScanState, pstate);
545 
546  /*
547  * If we have runtime keys and they've not already been set up, do it now.
548  */
549  if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
550  ExecReScan((PlanState *) node);
551 
552  if (node->iss_NumOrderByKeys > 0)
553  return ExecScan(&node->ss,
556  else
557  return ExecScan(&node->ss,
560 }
static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:121
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
int iss_NumRuntimeKeys
Definition: execnodes.h:1216
bool iss_RuntimeKeysReady
Definition: execnodes.h:1217
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:423
static TupleTableSlot * IndexNext(IndexScanState *node)
Definition: nodeIndexscan.c:81
static TupleTableSlot * IndexNextWithReorder(IndexScanState *node)
ScanState ss
Definition: execnodes.h:1208
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:422
int iss_NumOrderByKeys
Definition: execnodes.h:1214

◆ ExecIndexScanEstimate()

void ExecIndexScanEstimate ( IndexScanState node,
ParallelContext pcxt 
)

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

1689 {
1690  EState *estate = node->ss.ps.state;
1691 
1693  estate->es_snapshot);
1695  shm_toc_estimate_keys(&pcxt->estimator, 1);
1696 }
shm_toc_estimator estimator
Definition: parallel.h:41
Snapshot es_snapshot
Definition: execnodes.h:443
EState * state
Definition: execnodes.h:870
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:418
PlanState ps
Definition: execnodes.h:1124
ScanState ss
Definition: execnodes.h:1208
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Relation iss_RelationDesc
Definition: execnodes.h:1219

◆ ExecIndexScanInitializeDSM()

void ExecIndexScanInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

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

1707 {
1708  EState *estate = node->ss.ps.state;
1709  ParallelIndexScanDesc piscan;
1710 
1711  piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1713  node->iss_RelationDesc,
1714  estate->es_snapshot,
1715  piscan);
1716  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1717  node->iss_ScanDesc =
1719  node->iss_RelationDesc,
1720  node->iss_NumScanKeys,
1721  node->iss_NumOrderByKeys,
1722  piscan);
1723 
1724  /*
1725  * If no run-time keys to calculate or they are ready, go ahead and pass
1726  * the scankeys to the index AM.
1727  */
1728  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1729  index_rescan(node->iss_ScanDesc,
1730  node->iss_ScanKeys, node->iss_NumScanKeys,
1731  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1732 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:497
int plan_node_id
Definition: plannodes.h:143
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:311
Snapshot es_snapshot
Definition: execnodes.h:443
Relation ss_currentRelation
Definition: execnodes.h:1125
EState * state
Definition: execnodes.h:870
ScanKey iss_ScanKeys
Definition: execnodes.h:1211
PlanState ps
Definition: execnodes.h:1124
int iss_NumRuntimeKeys
Definition: execnodes.h:1216
bool iss_RuntimeKeysReady
Definition: execnodes.h:1217
Plan * plan
Definition: execnodes.h:868
ScanState ss
Definition: execnodes.h:1208
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
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:451
int iss_NumOrderByKeys
Definition: execnodes.h:1214
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220
shm_toc * toc
Definition: parallel.h:44
Relation iss_RelationDesc
Definition: execnodes.h:1219
ScanKey iss_OrderByKeys
Definition: execnodes.h:1213

◆ ExecIndexScanInitializeWorker()

void ExecIndexScanInitializeWorker ( IndexScanState node,
ParallelWorkerContext pwcxt 
)

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

1756 {
1757  ParallelIndexScanDesc piscan;
1758 
1759  piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1760  node->iss_ScanDesc =
1762  node->iss_RelationDesc,
1763  node->iss_NumScanKeys,
1764  node->iss_NumOrderByKeys,
1765  piscan);
1766 
1767  /*
1768  * If no run-time keys to calculate or they are ready, go ahead and pass
1769  * the scankeys to the index AM.
1770  */
1771  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1772  index_rescan(node->iss_ScanDesc,
1773  node->iss_ScanKeys, node->iss_NumScanKeys,
1774  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1775 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:497
int plan_node_id
Definition: plannodes.h:143
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:311
Relation ss_currentRelation
Definition: execnodes.h:1125
ScanKey iss_ScanKeys
Definition: execnodes.h:1211
PlanState ps
Definition: execnodes.h:1124
int iss_NumRuntimeKeys
Definition: execnodes.h:1216
bool iss_RuntimeKeysReady
Definition: execnodes.h:1217
Plan * plan
Definition: execnodes.h:868
ScanState ss
Definition: execnodes.h:1208
int iss_NumOrderByKeys
Definition: execnodes.h:1214
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232
Relation iss_RelationDesc
Definition: execnodes.h:1219
ScanKey iss_OrderByKeys
Definition: execnodes.h:1213

◆ ExecIndexScanReInitializeDSM()

void ExecIndexScanReInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1741 of file nodeIndexscan.c.

References index_parallelrescan(), and IndexScanState::iss_ScanDesc.

Referenced by ExecParallelReInitializeDSM().

1743 {
1745 }
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:482
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220

◆ ExecInitIndexScan()

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

Definition at line 922 of file nodeIndexscan.c.

References SortSupportData::abbreviate, AccessShareLock, Assert, CurrentMemoryContext, EXEC_FLAG_EXPLAIN_ONLY, ExecAssignExprContext(), ExecAssignScanProjectionInfo(), ExecIndexBuildScanKeys(), ExecIndexScan(), ExecInitExprList(), ExecInitQual(), ExecInitResultTupleSlotTL(), ExecInitScanTupleSlot(), ExecOpenScanRelation(), PlanState::ExecProcNode, ExecRelationIsTargetRelation(), 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, NoLock, pairingheap_allocate(), palloc(), palloc0(), Scan::plan, PlanState::plan, PrepareSortSupportFromOrderingOp(), ScanState::ps, PlanState::ps_ExprContext, Plan::qual, PlanState::qual, RelationGetDescr, 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, and PlanState::state.

Referenced by ExecInitNode().

923 {
924  IndexScanState *indexstate;
925  Relation currentRelation;
926  bool relistarget;
927 
928  /*
929  * create state structure
930  */
931  indexstate = makeNode(IndexScanState);
932  indexstate->ss.ps.plan = (Plan *) node;
933  indexstate->ss.ps.state = estate;
934  indexstate->ss.ps.ExecProcNode = ExecIndexScan;
935 
936  /*
937  * Miscellaneous initialization
938  *
939  * create expression context for node
940  */
941  ExecAssignExprContext(estate, &indexstate->ss.ps);
942 
943  /*
944  * open the base relation and acquire appropriate lock on it.
945  */
946  currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
947 
948  indexstate->ss.ss_currentRelation = currentRelation;
949  indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
950 
951  /*
952  * get the scan type from the relation descriptor.
953  */
954  ExecInitScanTupleSlot(estate, &indexstate->ss,
955  RelationGetDescr(currentRelation));
956 
957  /*
958  * Initialize result slot, type and projection.
959  */
960  ExecInitResultTupleSlotTL(estate, &indexstate->ss.ps);
961  ExecAssignScanProjectionInfo(&indexstate->ss);
962 
963  /*
964  * initialize child expressions
965  *
966  * Note: we don't initialize all of the indexqual expression, only the
967  * sub-parts corresponding to runtime keys (see below). Likewise for
968  * indexorderby, if any. But the indexqualorig expression is always
969  * initialized even though it will only be used in some uncommon cases ---
970  * would be nice to improve that. (Problem is that any SubPlans present
971  * in the expression must be found now...)
972  */
973  indexstate->ss.ps.qual =
974  ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
975  indexstate->indexqualorig =
976  ExecInitQual(node->indexqualorig, (PlanState *) indexstate);
977  indexstate->indexorderbyorig =
978  ExecInitExprList(node->indexorderbyorig, (PlanState *) indexstate);
979 
980  /*
981  * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
982  * here. This allows an index-advisor plugin to EXPLAIN a plan containing
983  * references to nonexistent indexes.
984  */
985  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
986  return indexstate;
987 
988  /*
989  * Open the index relation.
990  *
991  * If the parent table is one of the target relations of the query, then
992  * InitPlan already opened and write-locked the index, so we can avoid
993  * taking another lock here. Otherwise we need a normal reader's lock.
994  */
995  relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
996  indexstate->iss_RelationDesc = index_open(node->indexid,
997  relistarget ? NoLock : AccessShareLock);
998 
999  /*
1000  * Initialize index-specific scan state
1001  */
1002  indexstate->iss_RuntimeKeysReady = false;
1003  indexstate->iss_RuntimeKeys = NULL;
1004  indexstate->iss_NumRuntimeKeys = 0;
1005 
1006  /*
1007  * build the index scan keys from the index qualification
1008  */
1009  ExecIndexBuildScanKeys((PlanState *) indexstate,
1010  indexstate->iss_RelationDesc,
1011  node->indexqual,
1012  false,
1013  &indexstate->iss_ScanKeys,
1014  &indexstate->iss_NumScanKeys,
1015  &indexstate->iss_RuntimeKeys,
1016  &indexstate->iss_NumRuntimeKeys,
1017  NULL, /* no ArrayKeys */
1018  NULL);
1019 
1020  /*
1021  * any ORDER BY exprs have to be turned into scankeys in the same way
1022  */
1023  ExecIndexBuildScanKeys((PlanState *) indexstate,
1024  indexstate->iss_RelationDesc,
1025  node->indexorderby,
1026  true,
1027  &indexstate->iss_OrderByKeys,
1028  &indexstate->iss_NumOrderByKeys,
1029  &indexstate->iss_RuntimeKeys,
1030  &indexstate->iss_NumRuntimeKeys,
1031  NULL, /* no ArrayKeys */
1032  NULL);
1033 
1034  /* Initialize sort support, if we need to re-check ORDER BY exprs */
1035  if (indexstate->iss_NumOrderByKeys > 0)
1036  {
1037  int numOrderByKeys = indexstate->iss_NumOrderByKeys;
1038  int i;
1039  ListCell *lco;
1040  ListCell *lcx;
1041 
1042  /*
1043  * Prepare sort support, and look up the data type for each ORDER BY
1044  * expression.
1045  */
1046  Assert(numOrderByKeys == list_length(node->indexorderbyops));
1047  Assert(numOrderByKeys == list_length(node->indexorderbyorig));
1048  indexstate->iss_SortSupport = (SortSupportData *)
1049  palloc0(numOrderByKeys * sizeof(SortSupportData));
1050  indexstate->iss_OrderByTypByVals = (bool *)
1051  palloc(numOrderByKeys * sizeof(bool));
1052  indexstate->iss_OrderByTypLens = (int16 *)
1053  palloc(numOrderByKeys * sizeof(int16));
1054  i = 0;
1055  forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
1056  {
1057  Oid orderbyop = lfirst_oid(lco);
1058  Node *orderbyexpr = (Node *) lfirst(lcx);
1059  Oid orderbyType = exprType(orderbyexpr);
1060  Oid orderbyColl = exprCollation(orderbyexpr);
1061  SortSupport orderbysort = &indexstate->iss_SortSupport[i];
1062 
1063  /* Initialize sort support */
1064  orderbysort->ssup_cxt = CurrentMemoryContext;
1065  orderbysort->ssup_collation = orderbyColl;
1066  /* See cmp_orderbyvals() comments on NULLS LAST */
1067  orderbysort->ssup_nulls_first = false;
1068  /* ssup_attno is unused here and elsewhere */
1069  orderbysort->ssup_attno = 0;
1070  /* No abbreviation */
1071  orderbysort->abbreviate = false;
1072  PrepareSortSupportFromOrderingOp(orderbyop, orderbysort);
1073 
1074  get_typlenbyval(orderbyType,
1075  &indexstate->iss_OrderByTypLens[i],
1076  &indexstate->iss_OrderByTypByVals[i]);
1077  i++;
1078  }
1079 
1080  /* allocate arrays to hold the re-calculated distances */
1081  indexstate->iss_OrderByValues = (Datum *)
1082  palloc(numOrderByKeys * sizeof(Datum));
1083  indexstate->iss_OrderByNulls = (bool *)
1084  palloc(numOrderByKeys * sizeof(bool));
1085 
1086  /* and initialize the reorder queue */
1088  indexstate);
1089  }
1090 
1091  /*
1092  * If we have runtime keys, we need an ExprContext to evaluate them. The
1093  * node's standard context won't do because we want to reset that context
1094  * for every tuple. So, build another context just like the other one...
1095  * -tgl 7/11/00
1096  */
1097  if (indexstate->iss_NumRuntimeKeys != 0)
1098  {
1099  ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
1100 
1101  ExecAssignExprContext(estate, &indexstate->ss.ps);
1102  indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
1103  indexstate->ss.ps.ps_ExprContext = stdecontext;
1104  }
1105  else
1106  {
1107  indexstate->iss_RuntimeContext = NULL;
1108  }
1109 
1110  /*
1111  * all done.
1112  */
1113  return indexstate;
1114 }
signed short int16
Definition: c.h:301
bool ssup_nulls_first
Definition: sortsupport.h:75
List * qual
Definition: plannodes.h:145
Plan plan
Definition: plannodes.h:330
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
Index scanrelid
Definition: plannodes.h:331
#define RelationGetDescr(relation)
Definition: rel.h:437
IndexRuntimeKeyInfo * iss_RuntimeKeys
Definition: execnodes.h:1215
int16 * iss_OrderByTypLens
Definition: execnodes.h:1229
ExprContext * ps_ExprContext
Definition: execnodes.h:902
SortSupport iss_SortSupport
Definition: execnodes.h:1227
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:133
List * indexqualorig
Definition: plannodes.h:393
#define AccessShareLock
Definition: lockdefs.h:36
static TupleTableSlot * ExecIndexScan(PlanState *pstate)
Definition: nodes.h:513
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:42
Relation ss_currentRelation
Definition: execnodes.h:1125
EState * state
Definition: execnodes.h:870
unsigned int Oid
Definition: postgres_ext.h:31
ExprState * indexqualorig
Definition: execnodes.h:1209
Oid indexid
Definition: plannodes.h:391
List * indexorderbyorig
Definition: execnodes.h:1210
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:204
bool * iss_OrderByNulls
Definition: execnodes.h:1226
PlanState ps
Definition: execnodes.h:1124
List * indexorderbyorig
Definition: plannodes.h:395
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:235
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition: execUtils.c:638
MemoryContext ssup_cxt
Definition: sortsupport.h:66
Scan scan
Definition: plannodes.h:390
#define NoLock
Definition: lockdefs.h:34
int iss_NumRuntimeKeys
Definition: execnodes.h:1216
bool * iss_OrderByTypByVals
Definition: execnodes.h:1228
static int reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:313
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
bool iss_RuntimeKeysReady
Definition: execnodes.h:1217
List * indexqual
Definition: plannodes.h:392
void * palloc0(Size size)
Definition: mcxt.c:864
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:874
uintptr_t Datum
Definition: postgres.h:365
AttrNumber ssup_attno
Definition: sortsupport.h:81
void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate)
Definition: execTuples.c:870
Plan * plan
Definition: execnodes.h:868
ScanState ss
Definition: execnodes.h:1208
#define makeNode(_type_)
Definition: nodes.h:561
List * indexorderby
Definition: plannodes.h:394
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:425
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:89
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:720
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2005
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1218
List * indexorderbyops
Definition: plannodes.h:396
ExprState * qual
Definition: execnodes.h:886
HeapScanDesc ss_currentScanDesc
Definition: execnodes.h:1126
void * palloc(Size size)
Definition: mcxt.c:835
int i
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc)
Definition: execTuples.c:895
Datum * iss_OrderByValues
Definition: execnodes.h:1225
int iss_NumOrderByKeys
Definition: execnodes.h:1214
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:59
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
Definition: execUtils.c:612
#define lfirst_oid(lc)
Definition: pg_list.h:108
Relation iss_RelationDesc
Definition: execnodes.h:1219
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1223

◆ ExecReScanIndexScan()

void ExecReScanIndexScan ( IndexScanState node)

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

575 {
576  /*
577  * If we are doing runtime key calculations (ie, any of the index key
578  * values weren't simple Consts), compute the new key values. But first,
579  * reset the context so we don't leak memory as each outer tuple is
580  * scanned. Note this assumes that we will recalculate *all* runtime keys
581  * on each call.
582  */
583  if (node->iss_NumRuntimeKeys != 0)
584  {
585  ExprContext *econtext = node->iss_RuntimeContext;
586 
587  ResetExprContext(econtext);
588  ExecIndexEvalRuntimeKeys(econtext,
589  node->iss_RuntimeKeys,
590  node->iss_NumRuntimeKeys);
591  }
592  node->iss_RuntimeKeysReady = true;
593 
594  /* flush the reorder queue */
595  if (node->iss_ReorderQueue)
596  {
597  while (!pairingheap_is_empty(node->iss_ReorderQueue))
598  reorderqueue_pop(node);
599  }
600 
601  /* reset index scan */
602  if (node->iss_ScanDesc)
604  node->iss_ScanKeys, node->iss_NumScanKeys,
605  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
606  node->iss_ReachedEnd = false;
607 
608  ExecScanReScan(&node->ss);
609 }
IndexRuntimeKeyInfo * iss_RuntimeKeys
Definition: execnodes.h:1215
#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:311
ScanKey iss_ScanKeys
Definition: execnodes.h:1211
bool iss_ReachedEnd
Definition: execnodes.h:1224
int iss_NumRuntimeKeys
Definition: execnodes.h:1216
bool iss_RuntimeKeysReady
Definition: execnodes.h:1217
ScanState ss
Definition: execnodes.h:1208
static HeapTuple reorderqueue_pop(IndexScanState *node)
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1218
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
void ExecScanReScan(ScanState *node)
Definition: execScan.c:262
int iss_NumOrderByKeys
Definition: execnodes.h:1214
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220
#define ResetExprContext(econtext)
Definition: executor.h:484
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1223
ScanKey iss_OrderByKeys
Definition: execnodes.h:1213

◆ 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(), ExecStoreTuple(), ForwardScanDirection, index_beginscan(), index_getnext(), 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, IndexScanDescData::xs_cbuf, and IndexScanDescData::xs_recheck.

Referenced by ExecIndexScan().

82 {
83  EState *estate;
84  ExprContext *econtext;
85  ScanDirection direction;
86  IndexScanDesc scandesc;
87  HeapTuple tuple;
88  TupleTableSlot *slot;
89 
90  /*
91  * extract necessary information from index scan node
92  */
93  estate = node->ss.ps.state;
94  direction = estate->es_direction;
95  /* flip direction if this is an overall backward scan */
96  if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
97  {
98  if (ScanDirectionIsForward(direction))
99  direction = BackwardScanDirection;
100  else if (ScanDirectionIsBackward(direction))
101  direction = ForwardScanDirection;
102  }
103  scandesc = node->iss_ScanDesc;
104  econtext = node->ss.ps.ps_ExprContext;
105  slot = node->ss.ss_ScanTupleSlot;
106 
107  if (scandesc == NULL)
108  {
109  /*
110  * We reach here if the index scan is not parallel, or if we're
111  * executing a index scan that was intended to be parallel serially.
112  */
113  scandesc = index_beginscan(node->ss.ss_currentRelation,
114  node->iss_RelationDesc,
115  estate->es_snapshot,
116  node->iss_NumScanKeys,
117  node->iss_NumOrderByKeys);
118 
119  node->iss_ScanDesc = scandesc;
120 
121  /*
122  * If no run-time keys to calculate or they are ready, go ahead and
123  * pass the scankeys to the index AM.
124  */
125  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
126  index_rescan(scandesc,
127  node->iss_ScanKeys, node->iss_NumScanKeys,
128  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
129  }
130 
131  /*
132  * ok, now that we have what we need, fetch the next tuple.
133  */
134  while ((tuple = index_getnext(scandesc, direction)) != NULL)
135  {
137 
138  /*
139  * Store the scanned tuple in the scan tuple slot of the scan state.
140  * Note: we pass 'false' because tuples returned by amgetnext are
141  * pointers onto disk pages and must not be pfree()'d.
142  */
143  ExecStoreTuple(tuple, /* tuple to store */
144  slot, /* slot to store in */
145  scandesc->xs_cbuf, /* buffer containing tuple */
146  false); /* don't pfree */
147 
148  /*
149  * If the index was lossy, we have to recheck the index quals using
150  * the fetched tuple.
151  */
152  if (scandesc->xs_recheck)
153  {
154  econtext->ecxt_scantuple = slot;
155  if (!ExecQualAndReset(node->indexqualorig, econtext))
156  {
157  /* Fails recheck, so drop it and loop back for another */
158  InstrCountFiltered2(node, 1);
159  continue;
160  }
161  }
162 
163  return slot;
164  }
165 
166  /*
167  * if we get here it means the index scan failed so we are at the end of
168  * the scan..
169  */
170  node->iss_ReachedEnd = true;
171  return ExecClearTuple(slot);
172 }
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:356
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
ExprContext * ps_ExprContext
Definition: execnodes.h:902
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:311
Snapshot es_snapshot
Definition: execnodes.h:443
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1127
Relation ss_currentRelation
Definition: execnodes.h:1125
EState * state
Definition: execnodes.h:870
ExprState * indexqualorig
Definition: execnodes.h:1209
ScanKey iss_ScanKeys
Definition: execnodes.h:1211
ScanDirection es_direction
Definition: execnodes.h:442
PlanState ps
Definition: execnodes.h:1124
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
Buffer xs_cbuf
Definition: relscan.h:122
bool iss_ReachedEnd
Definition: execnodes.h:1224
int iss_NumRuntimeKeys
Definition: execnodes.h:1216
ScanDirection
Definition: sdir.h:22
bool iss_RuntimeKeysReady
Definition: execnodes.h:1217
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:389
Plan * plan
Definition: execnodes.h:868
ScanState ss
Definition: execnodes.h:1208
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:922
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:211
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
int iss_NumOrderByKeys
Definition: execnodes.h:1214
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220
HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:660
Relation iss_RelationDesc
Definition: execnodes.h:1219
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:222
ScanKey iss_OrderByKeys
Definition: execnodes.h:1213

◆ IndexNextWithReorder()

static TupleTableSlot * IndexNextWithReorder ( IndexScanState node)
static

Definition at line 182 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(), ExecQualAndReset(), ExecStoreTuple(), ForwardScanDirection, index_beginscan(), index_getnext(), index_rescan(), IndexScanState::indexqualorig, InstrCountFiltered2, InvalidBuffer, 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_cbuf, IndexScanDescData::xs_orderbynulls, IndexScanDescData::xs_orderbyvals, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_recheckorderby.

Referenced by ExecIndexScan().

183 {
184  EState *estate;
185  ExprContext *econtext;
186  IndexScanDesc scandesc;
187  HeapTuple tuple;
188  TupleTableSlot *slot;
189  ReorderTuple *topmost = NULL;
190  bool was_exact;
191  Datum *lastfetched_vals;
192  bool *lastfetched_nulls;
193  int cmp;
194 
195  estate = node->ss.ps.state;
196 
197  /*
198  * Only forward scan is supported with reordering. Note: we can get away
199  * with just Asserting here because the system will not try to run the
200  * plan backwards if ExecSupportsBackwardScan() says it won't work.
201  * Currently, that is guaranteed because no index AMs support both
202  * amcanorderbyop and amcanbackward; if any ever do,
203  * ExecSupportsBackwardScan() will need to consider indexorderbys
204  * explicitly.
205  */
206  Assert(!ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir));
208 
209  scandesc = node->iss_ScanDesc;
210  econtext = node->ss.ps.ps_ExprContext;
211  slot = node->ss.ss_ScanTupleSlot;
212 
213  if (scandesc == NULL)
214  {
215  /*
216  * We reach here if the index scan is not parallel, or if we're
217  * executing a index scan that was intended to be parallel serially.
218  */
219  scandesc = index_beginscan(node->ss.ss_currentRelation,
220  node->iss_RelationDesc,
221  estate->es_snapshot,
222  node->iss_NumScanKeys,
223  node->iss_NumOrderByKeys);
224 
225  node->iss_ScanDesc = scandesc;
226 
227  /*
228  * If no run-time keys to calculate or they are ready, go ahead and
229  * pass the scankeys to the index AM.
230  */
231  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
232  index_rescan(scandesc,
233  node->iss_ScanKeys, node->iss_NumScanKeys,
234  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
235  }
236 
237  for (;;)
238  {
240 
241  /*
242  * Check the reorder queue first. If the topmost tuple in the queue
243  * has an ORDER BY value smaller than (or equal to) the value last
244  * returned by the index, we can return it now.
245  */
247  {
248  topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
249 
250  if (node->iss_ReachedEnd ||
251  cmp_orderbyvals(topmost->orderbyvals,
252  topmost->orderbynulls,
253  scandesc->xs_orderbyvals,
254  scandesc->xs_orderbynulls,
255  node) <= 0)
256  {
257  tuple = reorderqueue_pop(node);
258 
259  /* Pass 'true', as the tuple in the queue is a palloc'd copy */
260  ExecStoreTuple(tuple, slot, InvalidBuffer, true);
261  return slot;
262  }
263  }
264  else if (node->iss_ReachedEnd)
265  {
266  /* Queue is empty, and no more tuples from index. We're done. */
267  return ExecClearTuple(slot);
268  }
269 
270  /*
271  * Fetch next tuple from the index.
272  */
273 next_indextuple:
274  tuple = index_getnext(scandesc, ForwardScanDirection);
275  if (!tuple)
276  {
277  /*
278  * No more tuples from the index. But we still need to drain any
279  * remaining tuples from the queue before we're done.
280  */
281  node->iss_ReachedEnd = true;
282  continue;
283  }
284 
285  /*
286  * Store the scanned tuple in the scan tuple slot of the scan state.
287  * Note: we pass 'false' because tuples returned by amgetnext are
288  * pointers onto disk pages and must not be pfree()'d.
289  */
290  ExecStoreTuple(tuple, /* tuple to store */
291  slot, /* slot to store in */
292  scandesc->xs_cbuf, /* buffer containing tuple */
293  false); /* don't pfree */
294 
295  /*
296  * If the index was lossy, we have to recheck the index quals and
297  * ORDER BY expressions using the fetched tuple.
298  */
299  if (scandesc->xs_recheck)
300  {
301  econtext->ecxt_scantuple = slot;
302  if (!ExecQualAndReset(node->indexqualorig, econtext))
303  {
304  /* Fails recheck, so drop it and loop back for another */
305  InstrCountFiltered2(node, 1);
306  /* allow this loop to be cancellable */
308  goto next_indextuple;
309  }
310  }
311 
312  if (scandesc->xs_recheckorderby)
313  {
314  econtext->ecxt_scantuple = slot;
315  ResetExprContext(econtext);
316  EvalOrderByExpressions(node, econtext);
317 
318  /*
319  * Was the ORDER BY value returned by the index accurate? The
320  * recheck flag means that the index can return inaccurate values,
321  * but then again, the value returned for any particular tuple
322  * could also be exactly correct. Compare the value returned by
323  * the index with the recalculated value. (If the value returned
324  * by the index happened to be exact right, we can often avoid
325  * pushing the tuple to the queue, just to pop it back out again.)
326  */
328  node->iss_OrderByNulls,
329  scandesc->xs_orderbyvals,
330  scandesc->xs_orderbynulls,
331  node);
332  if (cmp < 0)
333  elog(ERROR, "index returned tuples in wrong order");
334  else if (cmp == 0)
335  was_exact = true;
336  else
337  was_exact = false;
338  lastfetched_vals = node->iss_OrderByValues;
339  lastfetched_nulls = node->iss_OrderByNulls;
340  }
341  else
342  {
343  was_exact = true;
344  lastfetched_vals = scandesc->xs_orderbyvals;
345  lastfetched_nulls = scandesc->xs_orderbynulls;
346  }
347 
348  /*
349  * Can we return this tuple immediately, or does it need to be pushed
350  * to the reorder queue? If the ORDER BY expression values returned
351  * by the index were inaccurate, we can't return it yet, because the
352  * next tuple from the index might need to come before this one. Also,
353  * we can't return it yet if there are any smaller tuples in the queue
354  * already.
355  */
356  if (!was_exact || (topmost && cmp_orderbyvals(lastfetched_vals,
357  lastfetched_nulls,
358  topmost->orderbyvals,
359  topmost->orderbynulls,
360  node) > 0))
361  {
362  /* Put this tuple to the queue */
363  reorderqueue_push(node, tuple, lastfetched_vals, lastfetched_nulls);
364  continue;
365  }
366  else
367  {
368  /* Can return this tuple immediately. */
369  return slot;
370  }
371  }
372 
373  /*
374  * if we get here it means the index scan failed so we are at the end of
375  * the scan..
376  */
377  return ExecClearTuple(slot);
378 }
bool * orderbynulls
Definition: nodeIndexscan.c:56
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:356
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)
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
ExprContext * ps_ExprContext
Definition: execnodes.h:902
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
static void reorderqueue_push(IndexScanState *node, HeapTuple tuple, Datum *orderbyvals, bool *orderbynulls)
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
#define InvalidBuffer
Definition: buf.h:25
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:311
Datum * xs_orderbyvals
Definition: relscan.h:133
bool xs_recheckorderby
Definition: relscan.h:135
Snapshot es_snapshot
Definition: execnodes.h:443
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1127
Relation ss_currentRelation
Definition: execnodes.h:1125
EState * state
Definition: execnodes.h:870
ExprState * indexqualorig
Definition: execnodes.h:1209
ScanKey iss_ScanKeys
Definition: execnodes.h:1211
ScanDirection es_direction
Definition: execnodes.h:442
bool * iss_OrderByNulls
Definition: execnodes.h:1226
PlanState ps
Definition: execnodes.h:1124
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
bool * xs_orderbynulls
Definition: relscan.h:134
Buffer xs_cbuf
Definition: relscan.h:122
#define ERROR
Definition: elog.h:43
bool iss_ReachedEnd
Definition: execnodes.h:1224
Datum * orderbyvals
Definition: nodeIndexscan.c:55
int iss_NumRuntimeKeys
Definition: execnodes.h:1216
bool iss_RuntimeKeysReady
Definition: execnodes.h:1217
static void EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:389
uintptr_t Datum
Definition: postgres.h:365
Plan * plan
Definition: execnodes.h:868
ScanState ss
Definition: execnodes.h:1208
#define Assert(condition)
Definition: c.h:688
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:922
static HeapTuple reorderqueue_pop(IndexScanState *node)
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:211
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define elog
Definition: elog.h:219
Datum * iss_OrderByValues
Definition: execnodes.h:1225
int iss_NumOrderByKeys
Definition: execnodes.h:1214
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220
HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:660
#define ResetExprContext(econtext)
Definition: executor.h:484
Relation iss_RelationDesc
Definition: execnodes.h:1219
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:222
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1223
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742
ScanKey iss_OrderByKeys
Definition: execnodes.h:1213

◆ IndexRecheck()

static bool IndexRecheck ( IndexScanState node,
TupleTableSlot slot 
)
static

Definition at line 410 of file nodeIndexscan.c.

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

Referenced by ExecIndexScan().

411 {
412  ExprContext *econtext;
413 
414  /*
415  * extract necessary information from index scan node
416  */
417  econtext = node->ss.ps.ps_ExprContext;
418 
419  /* Does the tuple meet the indexqual condition? */
420  econtext->ecxt_scantuple = slot;
421  return ExecQualAndReset(node->indexqualorig, econtext);
422 }
ExprContext * ps_ExprContext
Definition: execnodes.h:902
ExprState * indexqualorig
Definition: execnodes.h:1209
PlanState ps
Definition: execnodes.h:1124
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:389
ScanState ss
Definition: execnodes.h:1208
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:211

◆ reorderqueue_cmp()

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

Definition at line 465 of file nodeIndexscan.c.

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

Referenced by ExecInitIndexScan().

467 {
468  ReorderTuple *rta = (ReorderTuple *) a;
469  ReorderTuple *rtb = (ReorderTuple *) b;
470  IndexScanState *node = (IndexScanState *) arg;
471 
472  return -cmp_orderbyvals(rta->orderbyvals, rta->orderbynulls,
473  rtb->orderbyvals, rtb->orderbynulls,
474  node);
475 }
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 515 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().

516 {
517  HeapTuple result;
518  ReorderTuple *topmost;
519  int i;
520 
522 
523  result = topmost->htup;
524  for (i = 0; i < node->iss_NumOrderByKeys; i++)
525  {
526  if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
527  pfree(DatumGetPointer(topmost->orderbyvals[i]));
528  }
529  pfree(topmost->orderbyvals);
530  pfree(topmost->orderbynulls);
531  pfree(topmost);
532 
533  return result;
534 }
bool * orderbynulls
Definition: nodeIndexscan.c:56
void pfree(void *pointer)
Definition: mcxt.c:936
Datum * orderbyvals
Definition: nodeIndexscan.c:55
bool * iss_OrderByTypByVals
Definition: execnodes.h:1228
HeapTuple htup
Definition: nodeIndexscan.c:54
#define DatumGetPointer(X)
Definition: postgres.h:532
int i
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145
int iss_NumOrderByKeys
Definition: execnodes.h:1214
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1223

◆ reorderqueue_push()

static void reorderqueue_push ( IndexScanState node,
HeapTuple  tuple,
Datum orderbyvals,
bool orderbynulls 
)
static

Definition at line 481 of file nodeIndexscan.c.

References datumCopy(), EState::es_query_cxt, heap_copytuple(), 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().

483 {
484  IndexScanDesc scandesc = node->iss_ScanDesc;
485  EState *estate = node->ss.ps.state;
486  MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
487  ReorderTuple *rt;
488  int i;
489 
490  rt = (ReorderTuple *) palloc(sizeof(ReorderTuple));
491  rt->htup = heap_copytuple(tuple);
492  rt->orderbyvals =
493  (Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys);
494  rt->orderbynulls =
495  (bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys);
496  for (i = 0; i < node->iss_NumOrderByKeys; i++)
497  {
498  if (!orderbynulls[i])
499  rt->orderbyvals[i] = datumCopy(orderbyvals[i],
500  node->iss_OrderByTypByVals[i],
501  node->iss_OrderByTypLens[i]);
502  else
503  rt->orderbyvals[i] = (Datum) 0;
504  rt->orderbynulls[i] = orderbynulls[i];
505  }
507 
508  MemoryContextSwitchTo(oldContext);
509 }
bool * orderbynulls
Definition: nodeIndexscan.c:56
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:611
int16 * iss_OrderByTypLens
Definition: execnodes.h:1229
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
EState * state
Definition: execnodes.h:870
PlanState ps
Definition: execnodes.h:1124
MemoryContext es_query_cxt
Definition: execnodes.h:488
Datum * orderbyvals
Definition: nodeIndexscan.c:55
bool * iss_OrderByTypByVals
Definition: execnodes.h:1228
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
pairingheap_node ph_node
Definition: nodeIndexscan.c:53
uintptr_t Datum
Definition: postgres.h:365
ScanState ss
Definition: execnodes.h:1208
HeapTuple htup
Definition: nodeIndexscan.c:54
void * palloc(Size size)
Definition: mcxt.c:835
int i
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
int numberOfOrderBys
Definition: relscan.h:94
int iss_NumOrderByKeys
Definition: execnodes.h:1214
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1220
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1223