PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 "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)
 
TupleTableSlotExecIndexScan (IndexScanState *node)
 
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 ExecIndexScanInitializeWorker (IndexScanState *node, shm_toc *toc)
 

Function Documentation

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

Definition at line 426 of file nodeIndexscan.c.

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

Referenced by IndexNextWithReorder(), and reorderqueue_cmp().

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

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

379 {
380  int i;
381  ListCell *l;
382  MemoryContext oldContext;
383 
384  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
385 
386  i = 0;
387  foreach(l, node->indexorderbyorig)
388  {
389  ExprState *orderby = (ExprState *) lfirst(l);
390 
391  node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
392  econtext,
393  &node->iss_OrderByNulls[i]);
394  i++;
395  }
396 
397  MemoryContextSwitchTo(oldContext);
398 }
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * indexorderbyorig
Definition: execnodes.h:1133
bool * iss_OrderByNulls
Definition: execnodes.h:1149
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:265
#define lfirst(lc)
Definition: pg_list.h:106
int i
Datum * iss_OrderByValues
Definition: execnodes.h:1148
void ExecEndIndexScan ( IndexScanState node)

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

821 {
822  Relation indexRelationDesc;
823  IndexScanDesc indexScanDesc;
824  Relation relation;
825 
826  /*
827  * extract information from the node
828  */
829  indexRelationDesc = node->iss_RelationDesc;
830  indexScanDesc = node->iss_ScanDesc;
831  relation = node->ss.ss_currentRelation;
832 
833  /*
834  * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
835  */
836 #ifdef NOT_USED
837  ExecFreeExprContext(&node->ss.ps);
838  if (node->iss_RuntimeContext)
839  FreeExprContext(node->iss_RuntimeContext, true);
840 #endif
841 
842  /*
843  * clear out tuple table slots
844  */
847 
848  /*
849  * close the index relation (no-op if we didn't open it)
850  */
851  if (indexScanDesc)
852  index_endscan(indexScanDesc);
853  if (indexRelationDesc)
854  index_close(indexRelationDesc, NoLock);
855 
856  /*
857  * close the heap relation.
858  */
859  ExecCloseScanRelation(relation);
860 }
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
Relation ss_currentRelation
Definition: execnodes.h:1048
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:516
PlanState ps
Definition: execnodes.h:1047
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:832
#define NoLock
Definition: lockdefs.h:34
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:340
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:349
ScanState ss
Definition: execnodes.h:1131
void ExecCloseScanRelation(Relation scanrel)
Definition: execUtils.c:661
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1141
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1143
Relation iss_RelationDesc
Definition: execnodes.h:1142
bool ExecIndexAdvanceArrayKeys ( IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

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

776 {
777  bool found = false;
778  int j;
779 
780  /*
781  * Note we advance the rightmost array key most quickly, since it will
782  * correspond to the lowest-order index column among the available
783  * qualifications. This is hypothesized to result in better locality of
784  * access in the index.
785  */
786  for (j = numArrayKeys - 1; j >= 0; j--)
787  {
788  ScanKey scan_key = arrayKeys[j].scan_key;
789  int next_elem = arrayKeys[j].next_elem;
790  int num_elems = arrayKeys[j].num_elems;
791  Datum *elem_values = arrayKeys[j].elem_values;
792  bool *elem_nulls = arrayKeys[j].elem_nulls;
793 
794  if (next_elem >= num_elems)
795  {
796  next_elem = 0;
797  found = false; /* need to advance next array key */
798  }
799  else
800  found = true;
801  scan_key->sk_argument = elem_values[next_elem];
802  if (elem_nulls[next_elem])
803  scan_key->sk_flags |= SK_ISNULL;
804  else
805  scan_key->sk_flags &= ~SK_ISNULL;
806  arrayKeys[j].next_elem = next_elem + 1;
807  if (found)
808  break;
809  }
810 
811  return found;
812 }
Datum * elem_values
Definition: execnodes.h:1099
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:372
int sk_flags
Definition: skey.h:66
Datum sk_argument
Definition: skey.h:72
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 1153 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, NULL, 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, 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().

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

Definition at line 696 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, result, IndexArrayKeyInfo::scan_key, ScanKeyData::sk_argument, ScanKeyData::sk_flags, and SK_ISNULL.

Referenced by ExecReScanBitmapIndexScan().

698 {
699  bool result = true;
700  int j;
701  MemoryContext oldContext;
702 
703  /* We want to keep the arrays in per-tuple memory */
704  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
705 
706  for (j = 0; j < numArrayKeys; j++)
707  {
708  ScanKey scan_key = arrayKeys[j].scan_key;
709  ExprState *array_expr = arrayKeys[j].array_expr;
710  Datum arraydatum;
711  bool isNull;
712  ArrayType *arrayval;
713  int16 elmlen;
714  bool elmbyval;
715  char elmalign;
716  int num_elems;
717  Datum *elem_values;
718  bool *elem_nulls;
719 
720  /*
721  * Compute and deconstruct the array expression. (Notes in
722  * ExecIndexEvalRuntimeKeys() apply here too.)
723  */
724  arraydatum = ExecEvalExpr(array_expr,
725  econtext,
726  &isNull);
727  if (isNull)
728  {
729  result = false;
730  break; /* no point in evaluating more */
731  }
732  arrayval = DatumGetArrayTypeP(arraydatum);
733  /* We could cache this data, but not clear it's worth it */
735  &elmlen, &elmbyval, &elmalign);
736  deconstruct_array(arrayval,
737  ARR_ELEMTYPE(arrayval),
738  elmlen, elmbyval, elmalign,
739  &elem_values, &elem_nulls, &num_elems);
740  if (num_elems <= 0)
741  {
742  result = false;
743  break; /* no point in evaluating more */
744  }
745 
746  /*
747  * Note: we expect the previous array data, if any, to be
748  * automatically freed by resetting the per-tuple context; hence no
749  * pfree's here.
750  */
751  arrayKeys[j].elem_values = elem_values;
752  arrayKeys[j].elem_nulls = elem_nulls;
753  arrayKeys[j].num_elems = num_elems;
754  scan_key->sk_argument = elem_values[0];
755  if (elem_nulls[0])
756  scan_key->sk_flags |= SK_ISNULL;
757  else
758  scan_key->sk_flags &= ~SK_ISNULL;
759  arrayKeys[j].next_elem = 1;
760  }
761 
762  MemoryContextSwitchTo(oldContext);
763 
764  return result;
765 }
Datum * elem_values
Definition: execnodes.h:1099
signed short int16
Definition: c.h:255
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2021
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
return result
Definition: formatting.c:1618
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:265
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:372
ExprState * array_expr
Definition: execnodes.h:1096
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:3475
Datum sk_argument
Definition: skey.h:72
#define ARR_ELEMTYPE(a)
Definition: array.h:273
#define DatumGetArrayTypeP(X)
Definition: array.h:242
void ExecIndexEvalRuntimeKeys ( ExprContext econtext,
IndexRuntimeKeyInfo runtimeKeys,
int  numRuntimeKeys 
)

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

636 {
637  int j;
638  MemoryContext oldContext;
639 
640  /* We want to keep the key values in per-tuple memory */
641  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
642 
643  for (j = 0; j < numRuntimeKeys; j++)
644  {
645  ScanKey scan_key = runtimeKeys[j].scan_key;
646  ExprState *key_expr = runtimeKeys[j].key_expr;
647  Datum scanvalue;
648  bool isNull;
649 
650  /*
651  * For each run-time key, extract the run-time expression and evaluate
652  * it with respect to the current context. We then stick the result
653  * into the proper scan key.
654  *
655  * Note: the result of the eval could be a pass-by-ref value that's
656  * stored in some outer scan's tuple, not in
657  * econtext->ecxt_per_tuple_memory. We assume that the outer tuple
658  * will stay put throughout our scan. If this is wrong, we could copy
659  * the result into our context explicitly, but I think that's not
660  * necessary.
661  *
662  * It's also entirely possible that the result of the eval is a
663  * toasted value. In this case we should forcibly detoast it, to
664  * avoid repeat detoastings each time the value is examined by an
665  * index support function.
666  */
667  scanvalue = ExecEvalExpr(key_expr,
668  econtext,
669  &isNull);
670  if (isNull)
671  {
672  scan_key->sk_argument = scanvalue;
673  scan_key->sk_flags |= SK_ISNULL;
674  }
675  else
676  {
677  if (runtimeKeys[j].key_toastable)
678  scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
679  scan_key->sk_argument = scanvalue;
680  scan_key->sk_flags &= ~SK_ISNULL;
681  }
682  }
683 
684  MemoryContextSwitchTo(oldContext);
685 }
#define PointerGetDatum(X)
Definition: postgres.h:562
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExprState * key_expr
Definition: execnodes.h:1089
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:265
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:372
int sk_flags
Definition: skey.h:66
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:205
Datum sk_argument
Definition: skey.h:72
void ExecIndexMarkPos ( IndexScanState node)

Definition at line 867 of file nodeIndexscan.c.

References index_markpos(), and IndexScanState::iss_ScanDesc.

Referenced by ExecMarkPos().

868 {
870 }
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:370
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1143
void ExecIndexRestrPos ( IndexScanState node)

Definition at line 877 of file nodeIndexscan.c.

References index_restrpos(), and IndexScanState::iss_ScanDesc.

Referenced by ExecRestrPos().

878 {
880 }
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:395
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1143
TupleTableSlot* ExecIndexScan ( IndexScanState node)

Definition at line 539 of file nodeIndexscan.c.

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

Referenced by ExecProcNode().

540 {
541  /*
542  * If we have runtime keys and they've not already been set up, do it now.
543  */
544  if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
545  ExecReScan((PlanState *) node);
546 
547  if (node->iss_NumOrderByKeys > 0)
548  return ExecScan(&node->ss,
551  else
552  return ExecScan(&node->ss,
555 }
static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:121
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:388
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:389
int iss_NumRuntimeKeys
Definition: execnodes.h:1139
bool iss_RuntimeKeysReady
Definition: execnodes.h:1140
static TupleTableSlot * IndexNext(IndexScanState *node)
Definition: nodeIndexscan.c:79
static TupleTableSlot * IndexNextWithReorder(IndexScanState *node)
ScanState ss
Definition: execnodes.h:1131
int iss_NumOrderByKeys
Definition: execnodes.h:1137
void ExecIndexScanEstimate ( IndexScanState node,
ParallelContext pcxt 
)

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

1661 {
1662  EState *estate = node->ss.ps.state;
1663 
1665  estate->es_snapshot);
1667  shm_toc_estimate_keys(&pcxt->estimator, 1);
1668 }
shm_toc_estimator estimator
Definition: parallel.h:41
Snapshot es_snapshot
Definition: execnodes.h:409
EState * state
Definition: execnodes.h:805
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:49
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:417
PlanState ps
Definition: execnodes.h:1047
ScanState ss
Definition: execnodes.h:1131
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:52
Relation iss_RelationDesc
Definition: execnodes.h:1142
void ExecIndexScanInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

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

1679 {
1680  EState *estate = node->ss.ps.state;
1681  ParallelIndexScanDesc piscan;
1682 
1683  piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1685  node->iss_RelationDesc,
1686  estate->es_snapshot,
1687  piscan);
1688  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1689  node->iss_ScanDesc =
1691  node->iss_RelationDesc,
1692  node->iss_NumScanKeys,
1693  node->iss_NumOrderByKeys,
1694  piscan);
1695 
1696  /*
1697  * If no run-time keys to calculate or they are ready, go ahead and pass
1698  * the scankeys to the index AM.
1699  */
1700  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1701  index_rescan(node->iss_ScanDesc,
1702  node->iss_ScanKeys, node->iss_NumScanKeys,
1703  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1704 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:496
int plan_node_id
Definition: plannodes.h:133
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:310
Snapshot es_snapshot
Definition: execnodes.h:409
Relation ss_currentRelation
Definition: execnodes.h:1048
EState * state
Definition: execnodes.h:805
ScanKey iss_ScanKeys
Definition: execnodes.h:1134
PlanState ps
Definition: execnodes.h:1047
int iss_NumRuntimeKeys
Definition: execnodes.h:1139
bool iss_RuntimeKeysReady
Definition: execnodes.h:1140
Plan * plan
Definition: execnodes.h:803
ScanState ss
Definition: execnodes.h:1131
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:83
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:161
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:450
int iss_NumOrderByKeys
Definition: execnodes.h:1137
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1143
shm_toc * toc
Definition: parallel.h:44
Relation iss_RelationDesc
Definition: execnodes.h:1142
ScanKey iss_OrderByKeys
Definition: execnodes.h:1136
void ExecIndexScanInitializeWorker ( IndexScanState node,
shm_toc toc 
)

Definition at line 1713 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, and ScanState::ss_currentRelation.

Referenced by ExecParallelInitializeWorker().

1714 {
1715  ParallelIndexScanDesc piscan;
1716 
1717  piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
1718  node->iss_ScanDesc =
1720  node->iss_RelationDesc,
1721  node->iss_NumScanKeys,
1722  node->iss_NumOrderByKeys,
1723  piscan);
1724 
1725  /*
1726  * If no run-time keys to calculate or they are ready, go ahead and pass
1727  * the scankeys to the index AM.
1728  */
1729  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1730  index_rescan(node->iss_ScanDesc,
1731  node->iss_ScanKeys, node->iss_NumScanKeys,
1732  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1733 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:496
int plan_node_id
Definition: plannodes.h:133
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:310
Relation ss_currentRelation
Definition: execnodes.h:1048
ScanKey iss_ScanKeys
Definition: execnodes.h:1134
PlanState ps
Definition: execnodes.h:1047
void * shm_toc_lookup(shm_toc *toc, uint64 key)
Definition: shm_toc.c:218
int iss_NumRuntimeKeys
Definition: execnodes.h:1139
bool iss_RuntimeKeysReady
Definition: execnodes.h:1140
Plan * plan
Definition: execnodes.h:803
ScanState ss
Definition: execnodes.h:1131
int iss_NumOrderByKeys
Definition: execnodes.h:1137
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1143
Relation iss_RelationDesc
Definition: execnodes.h:1142
ScanKey iss_OrderByKeys
Definition: execnodes.h:1136
IndexScanState* ExecInitIndexScan ( IndexScan node,
EState estate,
int  eflags 
)

Definition at line 894 of file nodeIndexscan.c.

References SortSupportData::abbreviate, AccessShareLock, Assert, CurrentMemoryContext, EXEC_FLAG_EXPLAIN_ONLY, ExecAssignExprContext(), ExecAssignResultTypeFromTL(), ExecAssignScanProjectionInfo(), ExecAssignScanType(), ExecIndexBuildScanKeys(), ExecInitExprList(), ExecInitQual(), ExecInitResultTupleSlot(), ExecInitScanTupleSlot(), ExecOpenScanRelation(), ExecRelationIsTargetRelation(), exprCollation(), exprType(), forboth, get_typlenbyval(), i, index_open(), IndexScan::indexid, IndexScan::indexorderby, IndexScan::indexorderbyops, IndexScan::indexorderbyorig, IndexScanState::indexorderbyorig, IndexScan::indexqual, IndexScan::indexqualorig, IndexScanState::indexqualorig, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_OrderByNulls, IndexScanState::iss_OrderByTypByVals, IndexScanState::iss_OrderByTypLens, IndexScanState::iss_OrderByValues, IndexScanState::iss_RelationDesc, IndexScanState::iss_ReorderQueue, IndexScanState::iss_RuntimeContext, IndexScanState::iss_RuntimeKeys, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanKeys, IndexScanState::iss_SortSupport, lfirst, lfirst_oid, list_length(), makeNode, NoLock, NULL, 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().

895 {
896  IndexScanState *indexstate;
897  Relation currentRelation;
898  bool relistarget;
899 
900  /*
901  * create state structure
902  */
903  indexstate = makeNode(IndexScanState);
904  indexstate->ss.ps.plan = (Plan *) node;
905  indexstate->ss.ps.state = estate;
906 
907  /*
908  * Miscellaneous initialization
909  *
910  * create expression context for node
911  */
912  ExecAssignExprContext(estate, &indexstate->ss.ps);
913 
914  /*
915  * initialize child expressions
916  *
917  * Note: we don't initialize all of the indexqual expression, only the
918  * sub-parts corresponding to runtime keys (see below). Likewise for
919  * indexorderby, if any. But the indexqualorig expression is always
920  * initialized even though it will only be used in some uncommon cases ---
921  * would be nice to improve that. (Problem is that any SubPlans present
922  * in the expression must be found now...)
923  */
924  indexstate->ss.ps.qual =
925  ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
926  indexstate->indexqualorig =
927  ExecInitQual(node->indexqualorig, (PlanState *) indexstate);
928  indexstate->indexorderbyorig =
929  ExecInitExprList(node->indexorderbyorig, (PlanState *) indexstate);
930 
931  /*
932  * tuple table initialization
933  */
934  ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
935  ExecInitScanTupleSlot(estate, &indexstate->ss);
936 
937  /*
938  * open the base relation and acquire appropriate lock on it.
939  */
940  currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
941 
942  indexstate->ss.ss_currentRelation = currentRelation;
943  indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
944 
945  /*
946  * get the scan type from the relation descriptor.
947  */
948  ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation));
949 
950  /*
951  * Initialize result tuple type and projection info.
952  */
953  ExecAssignResultTypeFromTL(&indexstate->ss.ps);
954  ExecAssignScanProjectionInfo(&indexstate->ss);
955 
956  /*
957  * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
958  * here. This allows an index-advisor plugin to EXPLAIN a plan containing
959  * references to nonexistent indexes.
960  */
961  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
962  return indexstate;
963 
964  /*
965  * Open the index relation.
966  *
967  * If the parent table is one of the target relations of the query, then
968  * InitPlan already opened and write-locked the index, so we can avoid
969  * taking another lock here. Otherwise we need a normal reader's lock.
970  */
971  relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
972  indexstate->iss_RelationDesc = index_open(node->indexid,
973  relistarget ? NoLock : AccessShareLock);
974 
975  /*
976  * Initialize index-specific scan state
977  */
978  indexstate->iss_RuntimeKeysReady = false;
979  indexstate->iss_RuntimeKeys = NULL;
980  indexstate->iss_NumRuntimeKeys = 0;
981 
982  /*
983  * build the index scan keys from the index qualification
984  */
985  ExecIndexBuildScanKeys((PlanState *) indexstate,
986  indexstate->iss_RelationDesc,
987  node->indexqual,
988  false,
989  &indexstate->iss_ScanKeys,
990  &indexstate->iss_NumScanKeys,
991  &indexstate->iss_RuntimeKeys,
992  &indexstate->iss_NumRuntimeKeys,
993  NULL, /* no ArrayKeys */
994  NULL);
995 
996  /*
997  * any ORDER BY exprs have to be turned into scankeys in the same way
998  */
999  ExecIndexBuildScanKeys((PlanState *) indexstate,
1000  indexstate->iss_RelationDesc,
1001  node->indexorderby,
1002  true,
1003  &indexstate->iss_OrderByKeys,
1004  &indexstate->iss_NumOrderByKeys,
1005  &indexstate->iss_RuntimeKeys,
1006  &indexstate->iss_NumRuntimeKeys,
1007  NULL, /* no ArrayKeys */
1008  NULL);
1009 
1010  /* Initialize sort support, if we need to re-check ORDER BY exprs */
1011  if (indexstate->iss_NumOrderByKeys > 0)
1012  {
1013  int numOrderByKeys = indexstate->iss_NumOrderByKeys;
1014  int i;
1015  ListCell *lco;
1016  ListCell *lcx;
1017 
1018  /*
1019  * Prepare sort support, and look up the data type for each ORDER BY
1020  * expression.
1021  */
1022  Assert(numOrderByKeys == list_length(node->indexorderbyops));
1023  Assert(numOrderByKeys == list_length(node->indexorderbyorig));
1024  indexstate->iss_SortSupport = (SortSupportData *)
1025  palloc0(numOrderByKeys * sizeof(SortSupportData));
1026  indexstate->iss_OrderByTypByVals = (bool *)
1027  palloc(numOrderByKeys * sizeof(bool));
1028  indexstate->iss_OrderByTypLens = (int16 *)
1029  palloc(numOrderByKeys * sizeof(int16));
1030  i = 0;
1031  forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
1032  {
1033  Oid orderbyop = lfirst_oid(lco);
1034  Node *orderbyexpr = (Node *) lfirst(lcx);
1035  Oid orderbyType = exprType(orderbyexpr);
1036  Oid orderbyColl = exprCollation(orderbyexpr);
1037  SortSupport orderbysort = &indexstate->iss_SortSupport[i];
1038 
1039  /* Initialize sort support */
1040  orderbysort->ssup_cxt = CurrentMemoryContext;
1041  orderbysort->ssup_collation = orderbyColl;
1042  /* See cmp_orderbyvals() comments on NULLS LAST */
1043  orderbysort->ssup_nulls_first = false;
1044  /* ssup_attno is unused here and elsewhere */
1045  orderbysort->ssup_attno = 0;
1046  /* No abbreviation */
1047  orderbysort->abbreviate = false;
1048  PrepareSortSupportFromOrderingOp(orderbyop, orderbysort);
1049 
1050  get_typlenbyval(orderbyType,
1051  &indexstate->iss_OrderByTypLens[i],
1052  &indexstate->iss_OrderByTypByVals[i]);
1053  i++;
1054  }
1055 
1056  /* allocate arrays to hold the re-calculated distances */
1057  indexstate->iss_OrderByValues = (Datum *)
1058  palloc(numOrderByKeys * sizeof(Datum));
1059  indexstate->iss_OrderByNulls = (bool *)
1060  palloc(numOrderByKeys * sizeof(bool));
1061 
1062  /* and initialize the reorder queue */
1064  indexstate);
1065  }
1066 
1067  /*
1068  * If we have runtime keys, we need an ExprContext to evaluate them. The
1069  * node's standard context won't do because we want to reset that context
1070  * for every tuple. So, build another context just like the other one...
1071  * -tgl 7/11/00
1072  */
1073  if (indexstate->iss_NumRuntimeKeys != 0)
1074  {
1075  ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
1076 
1077  ExecAssignExprContext(estate, &indexstate->ss.ps);
1078  indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
1079  indexstate->ss.ps.ps_ExprContext = stdecontext;
1080  }
1081  else
1082  {
1083  indexstate->iss_RuntimeContext = NULL;
1084  }
1085 
1086  /*
1087  * all done.
1088  */
1089  return indexstate;
1090 }
signed short int16
Definition: c.h:255
bool ssup_nulls_first
Definition: sortsupport.h:75
List * qual
Definition: plannodes.h:135
Plan plan
Definition: plannodes.h:317
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
Definition: execTuples.c:842
Index scanrelid
Definition: plannodes.h:318
#define RelationGetDescr(relation)
Definition: rel.h:429
IndexRuntimeKeyInfo * iss_RuntimeKeys
Definition: execnodes.h:1138
int16 * iss_OrderByTypLens
Definition: execnodes.h:1152
ExprContext * ps_ExprContext
Definition: execnodes.h:833
SortSupport iss_SortSupport
Definition: execnodes.h:1150
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:133
List * indexqualorig
Definition: plannodes.h:380
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:509
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:42
Relation ss_currentRelation
Definition: execnodes.h:1048
EState * state
Definition: execnodes.h:805
unsigned int Oid
Definition: postgres_ext.h:31
ExprState * indexqualorig
Definition: execnodes.h:1132
ScanKey iss_ScanKeys
Definition: execnodes.h:1134
Oid indexid
Definition: plannodes.h:378
List * indexorderbyorig
Definition: execnodes.h:1133
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:160
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:440
bool * iss_OrderByNulls
Definition: execnodes.h:1149
PlanState ps
Definition: execnodes.h:1047
List * indexorderbyorig
Definition: plannodes.h:382
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:235
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition: execUtils.c:603
MemoryContext ssup_cxt
Definition: sortsupport.h:66
Scan scan
Definition: plannodes.h:377
#define NoLock
Definition: lockdefs.h:34
int iss_NumRuntimeKeys
Definition: execnodes.h:1139
bool * iss_OrderByTypByVals
Definition: execnodes.h:1151
static int reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:266
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
bool iss_RuntimeKeysReady
Definition: execnodes.h:1140
List * indexqual
Definition: plannodes.h:379
void * palloc0(Size size)
Definition: mcxt.c:878
uintptr_t Datum
Definition: postgres.h:372
AttrNumber ssup_attno
Definition: sortsupport.h:81
Plan * plan
Definition: execnodes.h:803
ScanState ss
Definition: execnodes.h:1131
#define makeNode(_type_)
Definition: nodes.h:557
List * indexorderby
Definition: plannodes.h:381
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:418
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:748
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2001
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1141
List * indexorderbyops
Definition: plannodes.h:383
ExprState * qual
Definition: execnodes.h:817
HeapScanDesc ss_currentScanDesc
Definition: execnodes.h:1049
void * palloc(Size size)
Definition: mcxt.c:849
int i
void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
Definition: execUtils.c:540
Datum * iss_OrderByValues
Definition: execnodes.h:1148
int iss_NumOrderByKeys
Definition: execnodes.h:1137
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:58
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
Definition: execUtils.c:577
#define lfirst_oid(lc)
Definition: pg_list.h:108
Relation iss_RelationDesc
Definition: execnodes.h:1142
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1146
ScanKey iss_OrderByKeys
Definition: execnodes.h:1136
void ExecReScanIndexScan ( IndexScanState node)

Definition at line 569 of file nodeIndexscan.c.

References ExecIndexEvalRuntimeKeys(), ExecScanReScan(), index_parallelrescan(), 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, IndexScanDescData::parallel_scan, reorderqueue_pop(), ResetExprContext, and IndexScanState::ss.

Referenced by ExecReScan().

570 {
571  bool reset_parallel_scan = true;
572 
573  /*
574  * If we are here to just update the scan keys, then don't reset parallel
575  * scan. We don't want each of the participating process in the parallel
576  * scan to update the shared parallel scan state at the start of the scan.
577  * It is quite possible that one of the participants has already begun
578  * scanning the index when another has yet to start it.
579  */
580  if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
581  reset_parallel_scan = false;
582 
583  /*
584  * If we are doing runtime key calculations (ie, any of the index key
585  * values weren't simple Consts), compute the new key values. But first,
586  * reset the context so we don't leak memory as each outer tuple is
587  * scanned. Note this assumes that we will recalculate *all* runtime keys
588  * on each call.
589  */
590  if (node->iss_NumRuntimeKeys != 0)
591  {
592  ExprContext *econtext = node->iss_RuntimeContext;
593 
594  ResetExprContext(econtext);
595  ExecIndexEvalRuntimeKeys(econtext,
596  node->iss_RuntimeKeys,
597  node->iss_NumRuntimeKeys);
598  }
599  node->iss_RuntimeKeysReady = true;
600 
601  /* flush the reorder queue */
602  if (node->iss_ReorderQueue)
603  {
604  while (!pairingheap_is_empty(node->iss_ReorderQueue))
605  reorderqueue_pop(node);
606  }
607 
608  /*
609  * Reset (parallel) index scan. For parallel-aware nodes, the scan
610  * descriptor is initialized during actual execution of node and we can
611  * reach here before that (ex. during execution of nest loop join). So,
612  * avoid updating the scan descriptor at that time.
613  */
614  if (node->iss_ScanDesc)
615  {
617  node->iss_ScanKeys, node->iss_NumScanKeys,
618  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
619 
620  if (reset_parallel_scan && node->iss_ScanDesc->parallel_scan)
622  }
623  node->iss_ReachedEnd = false;
624 
625  ExecScanReScan(&node->ss);
626 }
ParallelIndexScanDesc parallel_scan
Definition: relscan.h:139
IndexRuntimeKeyInfo * iss_RuntimeKeys
Definition: execnodes.h:1138
#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:310
ScanKey iss_ScanKeys
Definition: execnodes.h:1134
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:481
bool iss_ReachedEnd
Definition: execnodes.h:1147
int iss_NumRuntimeKeys
Definition: execnodes.h:1139
bool iss_RuntimeKeysReady
Definition: execnodes.h:1140
ScanState ss
Definition: execnodes.h:1131
static HeapTuple reorderqueue_pop(IndexScanState *node)
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1141
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
void ExecScanReScan(ScanState *node)
Definition: execScan.c:327
int iss_NumOrderByKeys
Definition: execnodes.h:1137
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1143
#define ResetExprContext(econtext)
Definition: executor.h:449
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1146
ScanKey iss_OrderByKeys
Definition: execnodes.h:1136
static TupleTableSlot * IndexNext ( IndexScanState node)
static

Definition at line 79 of file nodeIndexscan.c.

References BackwardScanDirection, ExprContext::ecxt_scantuple, EState::es_direction, EState::es_snapshot, ExecClearTuple(), ExecQual(), 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, NULL, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, ResetExprContext, ScanDirectionIsBackward, ScanDirectionIsForward, IndexScanState::ss, ScanState::ss_currentRelation, ScanState::ss_ScanTupleSlot, PlanState::state, IndexScanDescData::xs_cbuf, and IndexScanDescData::xs_recheck.

Referenced by ExecIndexScan().

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

Definition at line 179 of file nodeIndexscan.c.

References Assert, cmp(), cmp_orderbyvals(), ExprContext::ecxt_scantuple, elog, ERROR, EState::es_direction, EState::es_snapshot, EvalOrderByExpressions(), ExecClearTuple(), ExecQual(), 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, NULL, 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().

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

Definition at line 404 of file nodeIndexscan.c.

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

Referenced by ExecIndexScan().

405 {
406  ExprContext *econtext;
407 
408  /*
409  * extract necessary information from index scan node
410  */
411  econtext = node->ss.ps.ps_ExprContext;
412 
413  /* Does the tuple meet the indexqual condition? */
414  econtext->ecxt_scantuple = slot;
415 
416  ResetExprContext(econtext);
417 
418  return ExecQual(node->indexqualorig, econtext);
419 }
ExprContext * ps_ExprContext
Definition: execnodes.h:833
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:345
ExprState * indexqualorig
Definition: execnodes.h:1132
PlanState ps
Definition: execnodes.h:1047
ScanState ss
Definition: execnodes.h:1131
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:197
#define ResetExprContext(econtext)
Definition: executor.h:449
static int reorderqueue_cmp ( const pairingheap_node a,
const pairingheap_node b,
void *  arg 
)
static

Definition at line 462 of file nodeIndexscan.c.

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

Referenced by ExecInitIndexScan().

464 {
465  ReorderTuple *rta = (ReorderTuple *) a;
466  ReorderTuple *rtb = (ReorderTuple *) b;
467  IndexScanState *node = (IndexScanState *) arg;
468 
469  return -cmp_orderbyvals(rta->orderbyvals, rta->orderbynulls,
470  rtb->orderbyvals, rtb->orderbynulls,
471  node);
472 }
bool * orderbynulls
Definition: nodeIndexscan.c:54
static int cmp_orderbyvals(const Datum *adist, const bool *anulls, const Datum *bdist, const bool *bnulls, IndexScanState *node)
Datum * orderbyvals
Definition: nodeIndexscan.c:53
void * arg
static HeapTuple reorderqueue_pop ( IndexScanState node)
static

Definition at line 512 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(), pfree(), and result.

Referenced by ExecReScanIndexScan(), and IndexNextWithReorder().

513 {
515  ReorderTuple *topmost;
516  int i;
517 
519 
520  result = topmost->htup;
521  for (i = 0; i < node->iss_NumOrderByKeys; i++)
522  {
523  if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
524  pfree(DatumGetPointer(topmost->orderbyvals[i]));
525  }
526  pfree(topmost->orderbyvals);
527  pfree(topmost->orderbynulls);
528  pfree(topmost);
529 
530  return result;
531 }
bool * orderbynulls
Definition: nodeIndexscan.c:54
return result
Definition: formatting.c:1618
void pfree(void *pointer)
Definition: mcxt.c:950
Datum * orderbyvals
Definition: nodeIndexscan.c:53
bool * iss_OrderByTypByVals
Definition: execnodes.h:1151
HeapTuple htup
Definition: nodeIndexscan.c:52
#define DatumGetPointer(X)
Definition: postgres.h:555
int i
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145
int iss_NumOrderByKeys
Definition: execnodes.h:1137
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1146
static void reorderqueue_push ( IndexScanState node,
HeapTuple  tuple,
Datum orderbyvals,
bool orderbynulls 
)
static

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

480 {
481  IndexScanDesc scandesc = node->iss_ScanDesc;
482  EState *estate = node->ss.ps.state;
483  MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
484  ReorderTuple *rt;
485  int i;
486 
487  rt = (ReorderTuple *) palloc(sizeof(ReorderTuple));
488  rt->htup = heap_copytuple(tuple);
489  rt->orderbyvals =
490  (Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys);
491  rt->orderbynulls =
492  (bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys);
493  for (i = 0; i < node->iss_NumOrderByKeys; i++)
494  {
495  if (!orderbynulls[i])
496  rt->orderbyvals[i] = datumCopy(orderbyvals[i],
497  node->iss_OrderByTypByVals[i],
498  node->iss_OrderByTypLens[i]);
499  else
500  rt->orderbyvals[i] = (Datum) 0;
501  rt->orderbynulls[i] = orderbynulls[i];
502  }
504 
505  MemoryContextSwitchTo(oldContext);
506 }
bool * orderbynulls
Definition: nodeIndexscan.c:54
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
int16 * iss_OrderByTypLens
Definition: execnodes.h:1152
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
EState * state
Definition: execnodes.h:805
PlanState ps
Definition: execnodes.h:1047
MemoryContext es_query_cxt
Definition: execnodes.h:438
Datum * orderbyvals
Definition: nodeIndexscan.c:53
bool * iss_OrderByTypByVals
Definition: execnodes.h:1151
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
pairingheap_node ph_node
Definition: nodeIndexscan.c:51
uintptr_t Datum
Definition: postgres.h:372
ScanState ss
Definition: execnodes.h:1131
HeapTuple htup
Definition: nodeIndexscan.c:52
void * palloc(Size size)
Definition: mcxt.c:849
int i
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
int numberOfOrderBys
Definition: relscan.h:92
int iss_NumOrderByKeys
Definition: execnodes.h:1137
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1143
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1146