PostgreSQL Source Code  git master
nodeIndexscan.h File Reference
#include "access/parallel.h"
#include "nodes/execnodes.h"
Include dependency graph for nodeIndexscan.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

IndexScanStateExecInitIndexScan (IndexScan *node, EState *estate, int eflags)
 
void ExecEndIndexScan (IndexScanState *node)
 
void ExecIndexMarkPos (IndexScanState *node)
 
void ExecIndexRestrPos (IndexScanState *node)
 
void ExecReScanIndexScan (IndexScanState *node)
 
void ExecIndexScanEstimate (IndexScanState *node, ParallelContext *pcxt)
 
void ExecIndexScanInitializeDSM (IndexScanState *node, ParallelContext *pcxt)
 
void ExecIndexScanReInitializeDSM (IndexScanState *node, ParallelContext *pcxt)
 
void ExecIndexScanInitializeWorker (IndexScanState *node, ParallelWorkerContext *pwcxt)
 
void ExecIndexBuildScanKeys (PlanState *planstate, Relation index, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
 
void ExecIndexEvalRuntimeKeys (ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
 
bool ExecIndexEvalArrayKeys (ExprContext *econtext, IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 
bool ExecIndexAdvanceArrayKeys (IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 

Function Documentation

◆ 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:1195
Relation ss_currentRelation
Definition: execnodes.h:1193
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:566
PlanState ps
Definition: execnodes.h:1192
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:946
#define NoLock
Definition: lockdefs.h:34
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:340
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:359
ScanState ss
Definition: execnodes.h:1276
void ExecCloseScanRelation(Relation scanrel)
Definition: execUtils.c:701
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1286
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1288
Relation iss_RelationDesc
Definition: execnodes.h:1287

◆ 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:1244
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:367
int sk_flags
Definition: skey.h:66
Datum sk_argument
Definition: skey.h:72

◆ ExecIndexBuildScanKeys()

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

Definition at line 1177 of file nodeIndexscan.c.

References IndexAmRoutine::amsearcharray, arg, NullTest::arg, ScalarArrayOpExpr::args, IndexArrayKeyInfo::array_expr, Assert, BTORDER_PROC, elog, ERROR, ExecInitExpr(), get_leftop(), get_op_opfamily_properties(), get_opfamily_proc(), get_rightop(), INDEX_VAR, IndexRelationGetNumberOfKeyAttributes, ScalarArrayOpExpr::inputcollid, RowCompareExpr::inputcollids, InvalidOid, InvalidStrategy, IS_NOT_NULL, IS_NULL, IsA, IndexRuntimeKeyInfo::key_expr, IndexRuntimeKeyInfo::key_toastable, RowCompareExpr::largs, lfirst, lfirst_oid, linitial, list_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_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  int indnkeyatts;
1231 
1232  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
1233  if (IsA(clause, OpExpr))
1234  {
1235  /* indexkey op const or indexkey op expression */
1236  int flags = 0;
1237  Datum scanvalue;
1238 
1239  opno = ((OpExpr *) clause)->opno;
1240  opfuncid = ((OpExpr *) clause)->opfuncid;
1241 
1242  /*
1243  * leftop should be the index key Var, possibly relabeled
1244  */
1245  leftop = (Expr *) get_leftop(clause);
1246 
1247  if (leftop && IsA(leftop, RelabelType))
1248  leftop = ((RelabelType *) leftop)->arg;
1249 
1250  Assert(leftop != NULL);
1251 
1252  if (!(IsA(leftop, Var) &&
1253  ((Var *) leftop)->varno == INDEX_VAR))
1254  elog(ERROR, "indexqual doesn't have key on left side");
1255 
1256  varattno = ((Var *) leftop)->varattno;
1257  if (varattno < 1 || varattno > indnkeyatts)
1258  elog(ERROR, "bogus index qualification");
1259 
1260  /*
1261  * We have to look up the operator's strategy number. This
1262  * provides a cross-check that the operator does match the index.
1263  */
1264  opfamily = index->rd_opfamily[varattno - 1];
1265 
1266  get_op_opfamily_properties(opno, opfamily, isorderby,
1267  &op_strategy,
1268  &op_lefttype,
1269  &op_righttype);
1270 
1271  if (isorderby)
1272  flags |= SK_ORDER_BY;
1273 
1274  /*
1275  * rightop is the constant or variable comparison value
1276  */
1277  rightop = (Expr *) get_rightop(clause);
1278 
1279  if (rightop && IsA(rightop, RelabelType))
1280  rightop = ((RelabelType *) rightop)->arg;
1281 
1282  Assert(rightop != NULL);
1283 
1284  if (IsA(rightop, Const))
1285  {
1286  /* OK, simple constant comparison value */
1287  scanvalue = ((Const *) rightop)->constvalue;
1288  if (((Const *) rightop)->constisnull)
1289  flags |= SK_ISNULL;
1290  }
1291  else
1292  {
1293  /* Need to treat this one as a runtime key */
1294  if (n_runtime_keys >= max_runtime_keys)
1295  {
1296  if (max_runtime_keys == 0)
1297  {
1298  max_runtime_keys = 8;
1299  runtime_keys = (IndexRuntimeKeyInfo *)
1300  palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1301  }
1302  else
1303  {
1304  max_runtime_keys *= 2;
1305  runtime_keys = (IndexRuntimeKeyInfo *)
1306  repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1307  }
1308  }
1309  runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1310  runtime_keys[n_runtime_keys].key_expr =
1311  ExecInitExpr(rightop, planstate);
1312  runtime_keys[n_runtime_keys].key_toastable =
1313  TypeIsToastable(op_righttype);
1314  n_runtime_keys++;
1315  scanvalue = (Datum) 0;
1316  }
1317 
1318  /*
1319  * initialize the scan key's fields appropriately
1320  */
1321  ScanKeyEntryInitialize(this_scan_key,
1322  flags,
1323  varattno, /* attribute number to scan */
1324  op_strategy, /* op's strategy */
1325  op_righttype, /* strategy subtype */
1326  ((OpExpr *) clause)->inputcollid, /* collation */
1327  opfuncid, /* reg proc to use */
1328  scanvalue); /* constant */
1329  }
1330  else if (IsA(clause, RowCompareExpr))
1331  {
1332  /* (indexkey, indexkey, ...) op (expression, expression, ...) */
1333  RowCompareExpr *rc = (RowCompareExpr *) clause;
1334  ListCell *largs_cell = list_head(rc->largs);
1335  ListCell *rargs_cell = list_head(rc->rargs);
1336  ListCell *opnos_cell = list_head(rc->opnos);
1337  ListCell *collids_cell = list_head(rc->inputcollids);
1338  ScanKey first_sub_key;
1339  int n_sub_key;
1340 
1341  Assert(!isorderby);
1342 
1343  first_sub_key = (ScanKey)
1344  palloc(list_length(rc->opnos) * sizeof(ScanKeyData));
1345  n_sub_key = 0;
1346 
1347  /* Scan RowCompare columns and generate subsidiary ScanKey items */
1348  while (opnos_cell != NULL)
1349  {
1350  ScanKey this_sub_key = &first_sub_key[n_sub_key];
1351  int flags = SK_ROW_MEMBER;
1352  Datum scanvalue;
1353  Oid inputcollation;
1354 
1355  /*
1356  * leftop should be the index key Var, possibly relabeled
1357  */
1358  leftop = (Expr *) lfirst(largs_cell);
1359  largs_cell = lnext(largs_cell);
1360 
1361  if (leftop && IsA(leftop, RelabelType))
1362  leftop = ((RelabelType *) leftop)->arg;
1363 
1364  Assert(leftop != NULL);
1365 
1366  if (!(IsA(leftop, Var) &&
1367  ((Var *) leftop)->varno == INDEX_VAR))
1368  elog(ERROR, "indexqual doesn't have key on left side");
1369 
1370  varattno = ((Var *) leftop)->varattno;
1371 
1372  /*
1373  * We have to look up the operator's associated btree support
1374  * function
1375  */
1376  opno = lfirst_oid(opnos_cell);
1377  opnos_cell = lnext(opnos_cell);
1378 
1379  if (index->rd_rel->relam != BTREE_AM_OID ||
1380  varattno < 1 || varattno > indnkeyatts)
1381  elog(ERROR, "bogus RowCompare index qualification");
1382  opfamily = index->rd_opfamily[varattno - 1];
1383 
1384  get_op_opfamily_properties(opno, opfamily, isorderby,
1385  &op_strategy,
1386  &op_lefttype,
1387  &op_righttype);
1388 
1389  if (op_strategy != rc->rctype)
1390  elog(ERROR, "RowCompare index qualification contains wrong operator");
1391 
1392  opfuncid = get_opfamily_proc(opfamily,
1393  op_lefttype,
1394  op_righttype,
1395  BTORDER_PROC);
1396  if (!RegProcedureIsValid(opfuncid))
1397  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
1398  BTORDER_PROC, op_lefttype, op_righttype, opfamily);
1399 
1400  inputcollation = lfirst_oid(collids_cell);
1401  collids_cell = lnext(collids_cell);
1402 
1403  /*
1404  * rightop is the constant or variable comparison value
1405  */
1406  rightop = (Expr *) lfirst(rargs_cell);
1407  rargs_cell = lnext(rargs_cell);
1408 
1409  if (rightop && IsA(rightop, RelabelType))
1410  rightop = ((RelabelType *) rightop)->arg;
1411 
1412  Assert(rightop != NULL);
1413 
1414  if (IsA(rightop, Const))
1415  {
1416  /* OK, simple constant comparison value */
1417  scanvalue = ((Const *) rightop)->constvalue;
1418  if (((Const *) rightop)->constisnull)
1419  flags |= SK_ISNULL;
1420  }
1421  else
1422  {
1423  /* Need to treat this one as a runtime key */
1424  if (n_runtime_keys >= max_runtime_keys)
1425  {
1426  if (max_runtime_keys == 0)
1427  {
1428  max_runtime_keys = 8;
1429  runtime_keys = (IndexRuntimeKeyInfo *)
1430  palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1431  }
1432  else
1433  {
1434  max_runtime_keys *= 2;
1435  runtime_keys = (IndexRuntimeKeyInfo *)
1436  repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1437  }
1438  }
1439  runtime_keys[n_runtime_keys].scan_key = this_sub_key;
1440  runtime_keys[n_runtime_keys].key_expr =
1441  ExecInitExpr(rightop, planstate);
1442  runtime_keys[n_runtime_keys].key_toastable =
1443  TypeIsToastable(op_righttype);
1444  n_runtime_keys++;
1445  scanvalue = (Datum) 0;
1446  }
1447 
1448  /*
1449  * initialize the subsidiary scan key's fields appropriately
1450  */
1451  ScanKeyEntryInitialize(this_sub_key,
1452  flags,
1453  varattno, /* attribute number */
1454  op_strategy, /* op's strategy */
1455  op_righttype, /* strategy subtype */
1456  inputcollation, /* collation */
1457  opfuncid, /* reg proc to use */
1458  scanvalue); /* constant */
1459  n_sub_key++;
1460  }
1461 
1462  /* Mark the last subsidiary scankey correctly */
1463  first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END;
1464 
1465  /*
1466  * We don't use ScanKeyEntryInitialize for the header because it
1467  * isn't going to contain a valid sk_func pointer.
1468  */
1469  MemSet(this_scan_key, 0, sizeof(ScanKeyData));
1470  this_scan_key->sk_flags = SK_ROW_HEADER;
1471  this_scan_key->sk_attno = first_sub_key->sk_attno;
1472  this_scan_key->sk_strategy = rc->rctype;
1473  /* sk_subtype, sk_collation, sk_func not used in a header */
1474  this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
1475  }
1476  else if (IsA(clause, ScalarArrayOpExpr))
1477  {
1478  /* indexkey op ANY (array-expression) */
1479  ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
1480  int flags = 0;
1481  Datum scanvalue;
1482 
1483  Assert(!isorderby);
1484 
1485  Assert(saop->useOr);
1486  opno = saop->opno;
1487  opfuncid = saop->opfuncid;
1488 
1489  /*
1490  * leftop should be the index key Var, possibly relabeled
1491  */
1492  leftop = (Expr *) linitial(saop->args);
1493 
1494  if (leftop && IsA(leftop, RelabelType))
1495  leftop = ((RelabelType *) leftop)->arg;
1496 
1497  Assert(leftop != NULL);
1498 
1499  if (!(IsA(leftop, Var) &&
1500  ((Var *) leftop)->varno == INDEX_VAR))
1501  elog(ERROR, "indexqual doesn't have key on left side");
1502 
1503  varattno = ((Var *) leftop)->varattno;
1504  if (varattno < 1 || varattno > indnkeyatts)
1505  elog(ERROR, "bogus index qualification");
1506 
1507  /*
1508  * We have to look up the operator's strategy number. This
1509  * provides a cross-check that the operator does match the index.
1510  */
1511  opfamily = index->rd_opfamily[varattno - 1];
1512 
1513  get_op_opfamily_properties(opno, opfamily, isorderby,
1514  &op_strategy,
1515  &op_lefttype,
1516  &op_righttype);
1517 
1518  /*
1519  * rightop is the constant or variable array value
1520  */
1521  rightop = (Expr *) lsecond(saop->args);
1522 
1523  if (rightop && IsA(rightop, RelabelType))
1524  rightop = ((RelabelType *) rightop)->arg;
1525 
1526  Assert(rightop != NULL);
1527 
1528  if (index->rd_amroutine->amsearcharray)
1529  {
1530  /* Index AM will handle this like a simple operator */
1531  flags |= SK_SEARCHARRAY;
1532  if (IsA(rightop, Const))
1533  {
1534  /* OK, simple constant comparison value */
1535  scanvalue = ((Const *) rightop)->constvalue;
1536  if (((Const *) rightop)->constisnull)
1537  flags |= SK_ISNULL;
1538  }
1539  else
1540  {
1541  /* Need to treat this one as a runtime key */
1542  if (n_runtime_keys >= max_runtime_keys)
1543  {
1544  if (max_runtime_keys == 0)
1545  {
1546  max_runtime_keys = 8;
1547  runtime_keys = (IndexRuntimeKeyInfo *)
1548  palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1549  }
1550  else
1551  {
1552  max_runtime_keys *= 2;
1553  runtime_keys = (IndexRuntimeKeyInfo *)
1554  repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1555  }
1556  }
1557  runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1558  runtime_keys[n_runtime_keys].key_expr =
1559  ExecInitExpr(rightop, planstate);
1560 
1561  /*
1562  * Careful here: the runtime expression is not of
1563  * op_righttype, but rather is an array of same; so
1564  * TypeIsToastable() isn't helpful. However, we can
1565  * assume that all array types are toastable.
1566  */
1567  runtime_keys[n_runtime_keys].key_toastable = true;
1568  n_runtime_keys++;
1569  scanvalue = (Datum) 0;
1570  }
1571  }
1572  else
1573  {
1574  /* Executor has to expand the array value */
1575  array_keys[n_array_keys].scan_key = this_scan_key;
1576  array_keys[n_array_keys].array_expr =
1577  ExecInitExpr(rightop, planstate);
1578  /* the remaining fields were zeroed by palloc0 */
1579  n_array_keys++;
1580  scanvalue = (Datum) 0;
1581  }
1582 
1583  /*
1584  * initialize the scan key's fields appropriately
1585  */
1586  ScanKeyEntryInitialize(this_scan_key,
1587  flags,
1588  varattno, /* attribute number to scan */
1589  op_strategy, /* op's strategy */
1590  op_righttype, /* strategy subtype */
1591  saop->inputcollid, /* collation */
1592  opfuncid, /* reg proc to use */
1593  scanvalue); /* constant */
1594  }
1595  else if (IsA(clause, NullTest))
1596  {
1597  /* indexkey IS NULL or indexkey IS NOT NULL */
1598  NullTest *ntest = (NullTest *) clause;
1599  int flags;
1600 
1601  Assert(!isorderby);
1602 
1603  /*
1604  * argument should be the index key Var, possibly relabeled
1605  */
1606  leftop = ntest->arg;
1607 
1608  if (leftop && IsA(leftop, RelabelType))
1609  leftop = ((RelabelType *) leftop)->arg;
1610 
1611  Assert(leftop != NULL);
1612 
1613  if (!(IsA(leftop, Var) &&
1614  ((Var *) leftop)->varno == INDEX_VAR))
1615  elog(ERROR, "NullTest indexqual has wrong key");
1616 
1617  varattno = ((Var *) leftop)->varattno;
1618 
1619  /*
1620  * initialize the scan key's fields appropriately
1621  */
1622  switch (ntest->nulltesttype)
1623  {
1624  case IS_NULL:
1625  flags = SK_ISNULL | SK_SEARCHNULL;
1626  break;
1627  case IS_NOT_NULL:
1628  flags = SK_ISNULL | SK_SEARCHNOTNULL;
1629  break;
1630  default:
1631  elog(ERROR, "unrecognized nulltesttype: %d",
1632  (int) ntest->nulltesttype);
1633  flags = 0; /* keep compiler quiet */
1634  break;
1635  }
1636 
1637  ScanKeyEntryInitialize(this_scan_key,
1638  flags,
1639  varattno, /* attribute number to scan */
1640  InvalidStrategy, /* no strategy */
1641  InvalidOid, /* no strategy subtype */
1642  InvalidOid, /* no collation */
1643  InvalidOid, /* no reg proc for this */
1644  (Datum) 0); /* constant */
1645  }
1646  else
1647  elog(ERROR, "unsupported indexqual type: %d",
1648  (int) nodeTag(clause));
1649  }
1650 
1651  Assert(n_runtime_keys <= max_runtime_keys);
1652 
1653  /* Get rid of any unused arrays */
1654  if (n_array_keys == 0)
1655  {
1656  pfree(array_keys);
1657  array_keys = NULL;
1658  }
1659 
1660  /*
1661  * Return info to our caller.
1662  */
1663  *scanKeys = scan_keys;
1664  *numScanKeys = n_scan_keys;
1665  *runtimeKeys = runtime_keys;
1666  *numRuntimeKeys = n_runtime_keys;
1667  if (arrayKeys)
1668  {
1669  *arrayKeys = array_keys;
1670  *numArrayKeys = n_array_keys;
1671  }
1672  else if (n_array_keys != 0)
1673  elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
1674 }
#define InvalidStrategy
Definition: stratnum.h:24
#define SK_ROW_MEMBER
Definition: skey.h:118
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
#define BTORDER_PROC
Definition: nbtree.h:290
#define SK_ORDER_BY
Definition: skey.h:123
#define PointerGetDatum(X)
Definition: postgres.h:541
RowCompareType rctype
Definition: primnodes.h:1039
regproc RegProcedure
Definition: c.h:472
#define MemSet(start, val, len)
Definition: c.h:908
struct ScanKeyData ScanKeyData
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:164
#define SK_SEARCHARRAY
Definition: skey.h:120
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:153
#define lsecond(l)
Definition: pg_list.h:116
#define SK_ROW_END
Definition: skey.h:119
void pfree(void *pointer)
Definition: mcxt.c:1031
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
Node * get_leftop(const Expr *clause)
Definition: clauses.c:200
StrategyNumber sk_strategy
Definition: skey.h:68
Expr * arg
Definition: primnodes.h:1188
ExprState * key_expr
Definition: execnodes.h:1234
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:607
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:154
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:426
#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:955
uintptr_t Datum
Definition: postgres.h:367
NullTestType nulltesttype
Definition: primnodes.h:1189
bool amsearcharray
Definition: amapi.h:184
#define InvalidOid
Definition: postgres_ext.h:36
ExprState * array_expr
Definition: execnodes.h:1241
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:699
#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:1044
#define nodeTag(nodeptr)
Definition: nodes.h:522
Node * get_rightop(const Expr *clause)
Definition: clauses.c:217
void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:133
void * palloc(Size size)
Definition: mcxt.c:924
void * arg
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:119
#define elog
Definition: elog.h:219
List * inputcollids
Definition: primnodes.h:1042
#define INDEX_VAR
Definition: primnodes.h:156
#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:1244
signed short int16
Definition: c.h:312
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2025
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:226
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:281
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:367
ExprState * array_expr
Definition: execnodes.h:1241
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:541
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:226
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExprState * key_expr
Definition: execnodes.h:1234
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:281
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:367
int sk_flags
Definition: skey.h:66
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:210
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:558
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:370
EState * state
Definition: execnodes.h:914
PlanState ps
Definition: execnodes.h:1192
#define ERROR
Definition: elog.h:43
unsigned int Index
Definition: c.h:442
Plan * plan
Definition: execnodes.h:912
ScanState ss
Definition: execnodes.h:1276
#define Assert(condition)
Definition: c.h:699
bool * es_epqTupleSet
Definition: execnodes.h:559
bool * es_epqScanDone
Definition: execnodes.h:560
#define elog
Definition: elog.h:219
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1288

◆ 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:558
EState * state
Definition: execnodes.h:914
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:395
PlanState ps
Definition: execnodes.h:1192
#define ERROR
Definition: elog.h:43
unsigned int Index
Definition: c.h:442
Plan * plan
Definition: execnodes.h:912
ScanState ss
Definition: execnodes.h:1276
#define Assert(condition)
Definition: c.h:699
bool * es_epqTupleSet
Definition: execnodes.h:559
bool * es_epqScanDone
Definition: execnodes.h:560
#define elog
Definition: elog.h:219
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1288

◆ ExecIndexScanEstimate()

void ExecIndexScanEstimate ( IndexScanState node,
ParallelContext pcxt 
)

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

1691 {
1692  EState *estate = node->ss.ps.state;
1693 
1695  estate->es_snapshot);
1697  shm_toc_estimate_keys(&pcxt->estimator, 1);
1698 }
shm_toc_estimator estimator
Definition: parallel.h:41
Snapshot es_snapshot
Definition: execnodes.h:478
EState * state
Definition: execnodes.h:914
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:417
PlanState ps
Definition: execnodes.h:1192
ScanState ss
Definition: execnodes.h:1276
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Relation iss_RelationDesc
Definition: execnodes.h:1287

◆ ExecIndexScanInitializeDSM()

void ExecIndexScanInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

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

1709 {
1710  EState *estate = node->ss.ps.state;
1711  ParallelIndexScanDesc piscan;
1712 
1713  piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1715  node->iss_RelationDesc,
1716  estate->es_snapshot,
1717  piscan);
1718  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1719  node->iss_ScanDesc =
1721  node->iss_RelationDesc,
1722  node->iss_NumScanKeys,
1723  node->iss_NumOrderByKeys,
1724  piscan);
1725 
1726  /*
1727  * If no run-time keys to calculate or they are ready, go ahead and pass
1728  * the scankeys to the index AM.
1729  */
1730  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1731  index_rescan(node->iss_ScanDesc,
1732  node->iss_ScanKeys, node->iss_NumScanKeys,
1733  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1734 }
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:145
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:310
Snapshot es_snapshot
Definition: execnodes.h:478
Relation ss_currentRelation
Definition: execnodes.h:1193
EState * state
Definition: execnodes.h:914
ScanKey iss_ScanKeys
Definition: execnodes.h:1279
PlanState ps
Definition: execnodes.h:1192
int iss_NumRuntimeKeys
Definition: execnodes.h:1284
bool iss_RuntimeKeysReady
Definition: execnodes.h:1285
Plan * plan
Definition: execnodes.h:912
ScanState ss
Definition: execnodes.h:1276
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:450
int iss_NumOrderByKeys
Definition: execnodes.h:1282
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1288
shm_toc * toc
Definition: parallel.h:44
Relation iss_RelationDesc
Definition: execnodes.h:1287
ScanKey iss_OrderByKeys
Definition: execnodes.h:1281

◆ ExecIndexScanInitializeWorker()

void ExecIndexScanInitializeWorker ( IndexScanState node,
ParallelWorkerContext pwcxt 
)

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

1758 {
1759  ParallelIndexScanDesc piscan;
1760 
1761  piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1762  node->iss_ScanDesc =
1764  node->iss_RelationDesc,
1765  node->iss_NumScanKeys,
1766  node->iss_NumOrderByKeys,
1767  piscan);
1768 
1769  /*
1770  * If no run-time keys to calculate or they are ready, go ahead and pass
1771  * the scankeys to the index AM.
1772  */
1773  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1774  index_rescan(node->iss_ScanDesc,
1775  node->iss_ScanKeys, node->iss_NumScanKeys,
1776  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1777 }
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:145
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:310
Relation ss_currentRelation
Definition: execnodes.h:1193
ScanKey iss_ScanKeys
Definition: execnodes.h:1279
PlanState ps
Definition: execnodes.h:1192
int iss_NumRuntimeKeys
Definition: execnodes.h:1284
bool iss_RuntimeKeysReady
Definition: execnodes.h:1285
Plan * plan
Definition: execnodes.h:912
ScanState ss
Definition: execnodes.h:1276
int iss_NumOrderByKeys
Definition: execnodes.h:1282
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1288
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232
Relation iss_RelationDesc
Definition: execnodes.h:1287
ScanKey iss_OrderByKeys
Definition: execnodes.h:1281

◆ ExecIndexScanReInitializeDSM()

void ExecIndexScanReInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1743 of file nodeIndexscan.c.

References index_parallelrescan(), and IndexScanState::iss_ScanDesc.

Referenced by ExecParallelReInitializeDSM().

1745 {
1747 }
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:481
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1288

◆ 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:312
bool ssup_nulls_first
Definition: sortsupport.h:75
List * qual
Definition: plannodes.h:147
Plan plan
Definition: plannodes.h:342
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
Index scanrelid
Definition: plannodes.h:343
#define RelationGetDescr(relation)
Definition: rel.h:433
IndexRuntimeKeyInfo * iss_RuntimeKeys
Definition: execnodes.h:1283
int16 * iss_OrderByTypLens
Definition: execnodes.h:1297
ExprContext * ps_ExprContext
Definition: execnodes.h:947
SortSupport iss_SortSupport
Definition: execnodes.h:1295
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:133
List * indexqualorig
Definition: plannodes.h:405
#define AccessShareLock
Definition: lockdefs.h:36
static TupleTableSlot * ExecIndexScan(PlanState *pstate)
Definition: nodes.h:517
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:42
Relation ss_currentRelation
Definition: execnodes.h:1193
EState * state
Definition: execnodes.h:914
unsigned int Oid
Definition: postgres_ext.h:31
ExprState * indexqualorig
Definition: execnodes.h:1277
Oid indexid
Definition: plannodes.h:403
List * indexorderbyorig
Definition: execnodes.h:1278
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:205
bool * iss_OrderByNulls
Definition: execnodes.h:1294
PlanState ps
Definition: execnodes.h:1192
List * indexorderbyorig
Definition: plannodes.h:407
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:235
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition: execUtils.c:643
MemoryContext ssup_cxt
Definition: sortsupport.h:66
Scan scan
Definition: plannodes.h:402
#define NoLock
Definition: lockdefs.h:34
int iss_NumRuntimeKeys
Definition: execnodes.h:1284
bool * iss_OrderByTypByVals
Definition: execnodes.h:1296
static int reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:314
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
bool iss_RuntimeKeysReady
Definition: execnodes.h:1285
List * indexqual
Definition: plannodes.h:404
void * palloc0(Size size)
Definition: mcxt.c:955
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:918
uintptr_t Datum
Definition: postgres.h:367
AttrNumber ssup_attno
Definition: sortsupport.h:81
void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate)
Definition: execTuples.c:890
Plan * plan
Definition: execnodes.h:912
ScanState ss
Definition: execnodes.h:1276
#define makeNode(_type_)
Definition: nodes.h:565
List * indexorderby
Definition: plannodes.h:406
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:428
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:1286
List * indexorderbyops
Definition: plannodes.h:408
ExprState * qual
Definition: execnodes.h:930
HeapScanDesc ss_currentScanDesc
Definition: execnodes.h:1194
void * palloc(Size size)
Definition: mcxt.c:924
int i
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc)
Definition: execTuples.c:915
Datum * iss_OrderByValues
Definition: execnodes.h:1293
int iss_NumOrderByKeys
Definition: execnodes.h:1282
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:58
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
Definition: execUtils.c:617
#define lfirst_oid(lc)
Definition: pg_list.h:108
Relation iss_RelationDesc
Definition: execnodes.h:1287
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1291

◆ 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:1283
#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:1279
bool iss_ReachedEnd
Definition: execnodes.h:1292
int iss_NumRuntimeKeys
Definition: execnodes.h:1284
bool iss_RuntimeKeysReady
Definition: execnodes.h:1285
ScanState ss
Definition: execnodes.h:1276
static HeapTuple reorderqueue_pop(IndexScanState *node)
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1286
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
void ExecScanReScan(ScanState *node)
Definition: execScan.c:262
int iss_NumOrderByKeys
Definition: execnodes.h:1282
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1288
#define ResetExprContext(econtext)
Definition: executor.h:483
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1291
ScanKey iss_OrderByKeys
Definition: execnodes.h:1281