PostgreSQL Source Code  git master
nodeIndexscan.h File Reference
#include "access/genam.h"
#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 783 of file nodeIndexscan.c.

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

Referenced by ExecEndNode().

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

◆ ExecIndexAdvanceArrayKeys()

bool ExecIndexAdvanceArrayKeys ( IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 738 of file nodeIndexscan.c.

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

Referenced by MultiExecBitmapIndexScan().

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

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

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

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

◆ ExecIndexEvalArrayKeys()

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

Definition at line 659 of file nodeIndexscan.c.

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

Referenced by ExecReScanBitmapIndexScan().

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

◆ ExecIndexEvalRuntimeKeys()

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

Definition at line 597 of file nodeIndexscan.c.

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

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

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

◆ ExecIndexMarkPos()

void ExecIndexMarkPos ( IndexScanState node)

Definition at line 827 of file nodeIndexscan.c.

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

Referenced by ExecMarkPos().

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

◆ ExecIndexRestrPos()

void ExecIndexRestrPos ( IndexScanState node)

Definition at line 864 of file nodeIndexscan.c.

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

Referenced by ExecRestrPos().

865 {
866  EState *estate = node->ss.ps.state;
867  EPQState *epqstate = estate->es_epq_active;
868 
869  if (estate->es_epq_active != NULL)
870  {
871  /* See comments in ExecIndexMarkPos */
872  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
873 
874  Assert(scanrelid > 0);
875  if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
876  epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
877  {
878  /* Verify the claim above */
879  if (!epqstate->relsubs_done[scanrelid - 1])
880  elog(ERROR, "unexpected ExecIndexRestrPos call in EPQ recheck");
881  return;
882  }
883  }
884 
886 }
TupleTableSlot ** relsubs_slot
Definition: execnodes.h:1084
EState * state
Definition: execnodes.h:941
struct EPQState * es_epq_active
Definition: execnodes.h:578
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:369
PlanState ps
Definition: execnodes.h:1330
#define ERROR
Definition: elog.h:43
bool * relsubs_done
Definition: execnodes.h:1118
unsigned int Index
Definition: c.h:476
Plan * plan
Definition: execnodes.h:939
ScanState ss
Definition: execnodes.h:1417
#define Assert(condition)
Definition: c.h:739
#define elog(elevel,...)
Definition: elog.h:228
ExecAuxRowMark ** relsubs_rowmark
Definition: execnodes.h:1112
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1429

◆ ExecIndexScanEstimate()

void ExecIndexScanEstimate ( IndexScanState node,
ParallelContext pcxt 
)

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

1657 {
1658  EState *estate = node->ss.ps.state;
1659 
1661  estate->es_snapshot);
1663  shm_toc_estimate_keys(&pcxt->estimator, 1);
1664 }
shm_toc_estimator estimator
Definition: parallel.h:41
Snapshot es_snapshot
Definition: execnodes.h:502
EState * state
Definition: execnodes.h:941
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:394
PlanState ps
Definition: execnodes.h:1330
ScanState ss
Definition: execnodes.h:1417
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Relation iss_RelationDesc
Definition: execnodes.h:1428

◆ ExecIndexScanInitializeDSM()

void ExecIndexScanInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

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

1675 {
1676  EState *estate = node->ss.ps.state;
1677  ParallelIndexScanDesc piscan;
1678 
1679  piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1681  node->iss_RelationDesc,
1682  estate->es_snapshot,
1683  piscan);
1684  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1685  node->iss_ScanDesc =
1687  node->iss_RelationDesc,
1688  node->iss_NumScanKeys,
1689  node->iss_NumOrderByKeys,
1690  piscan);
1691 
1692  /*
1693  * If no run-time keys to calculate or they are ready, go ahead and pass
1694  * the scankeys to the index AM.
1695  */
1696  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1697  index_rescan(node->iss_ScanDesc,
1698  node->iss_ScanKeys, node->iss_NumScanKeys,
1699  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1700 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:476
int plan_node_id
Definition: plannodes.h:139
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:289
Snapshot es_snapshot
Definition: execnodes.h:502
Relation ss_currentRelation
Definition: execnodes.h:1331
EState * state
Definition: execnodes.h:941
PlanState ps
Definition: execnodes.h:1330
int iss_NumRuntimeKeys
Definition: execnodes.h:1425
bool iss_RuntimeKeysReady
Definition: execnodes.h:1426
Plan * plan
Definition: execnodes.h:939
ScanState ss
Definition: execnodes.h:1417
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1422
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:427
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1420
int iss_NumOrderByKeys
Definition: execnodes.h:1423
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1429
shm_toc * toc
Definition: parallel.h:44
Relation iss_RelationDesc
Definition: execnodes.h:1428

◆ ExecIndexScanInitializeWorker()

void ExecIndexScanInitializeWorker ( IndexScanState node,
ParallelWorkerContext pwcxt 
)

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

1724 {
1725  ParallelIndexScanDesc piscan;
1726 
1727  piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1728  node->iss_ScanDesc =
1730  node->iss_RelationDesc,
1731  node->iss_NumScanKeys,
1732  node->iss_NumOrderByKeys,
1733  piscan);
1734 
1735  /*
1736  * If no run-time keys to calculate or they are ready, go ahead and pass
1737  * the scankeys to the index AM.
1738  */
1739  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1740  index_rescan(node->iss_ScanDesc,
1741  node->iss_ScanKeys, node->iss_NumScanKeys,
1742  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1743 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:476
int plan_node_id
Definition: plannodes.h:139
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:289
Relation ss_currentRelation
Definition: execnodes.h:1331
PlanState ps
Definition: execnodes.h:1330
int iss_NumRuntimeKeys
Definition: execnodes.h:1425
bool iss_RuntimeKeysReady
Definition: execnodes.h:1426
Plan * plan
Definition: execnodes.h:939
ScanState ss
Definition: execnodes.h:1417
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1422
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1420
int iss_NumOrderByKeys
Definition: execnodes.h:1423
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1429
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232
Relation iss_RelationDesc
Definition: execnodes.h:1428

◆ ExecIndexScanReInitializeDSM()

void ExecIndexScanReInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1709 of file nodeIndexscan.c.

References index_parallelrescan(), and IndexScanState::iss_ScanDesc.

Referenced by ExecParallelReInitializeDSM().

1711 {
1713 }
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:458
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1429

◆ ExecInitIndexScan()

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

Definition at line 900 of file nodeIndexscan.c.

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

Referenced by ExecInitNode().

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

◆ ExecReScanIndexScan()

void ExecReScanIndexScan ( IndexScanState node)

Definition at line 554 of file nodeIndexscan.c.

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

Referenced by ExecReScan().

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