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

789 {
790  Relation indexRelationDesc;
791  IndexScanDesc indexScanDesc;
792 
793  /*
794  * extract information from the node
795  */
796  indexRelationDesc = node->iss_RelationDesc;
797  indexScanDesc = node->iss_ScanDesc;
798 
799  /*
800  * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
801  */
802 #ifdef NOT_USED
803  ExecFreeExprContext(&node->ss.ps);
804  if (node->iss_RuntimeContext)
805  FreeExprContext(node->iss_RuntimeContext, true);
806 #endif
807 
808  /*
809  * clear out tuple table slots
810  */
811  if (node->ss.ps.ps_ResultTupleSlot)
814 
815  /*
816  * close the index relation (no-op if we didn't open it)
817  */
818  if (indexScanDesc)
819  index_endscan(indexScanDesc);
820  if (indexRelationDesc)
821  index_close(indexRelationDesc, NoLock);
822 }
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:411
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:323
#define NoLock
Definition: lockdefs.h:34
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1522
Relation iss_RelationDesc
Definition: execnodes.h:1521
ScanState ss
Definition: execnodes.h:1510
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1520
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1036
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1426
PlanState ps
Definition: execnodes.h:1423
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425

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

◆ ExecIndexAdvanceArrayKeys()

bool ExecIndexAdvanceArrayKeys ( IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 743 of file nodeIndexscan.c.

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

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

Referenced by MultiExecBitmapIndexScan().

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

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

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

◆ ExecIndexEvalArrayKeys()

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

Definition at line 664 of file nodeIndexscan.c.

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

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

Referenced by ExecReScanBitmapIndexScan().

◆ ExecIndexEvalRuntimeKeys()

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

Definition at line 602 of file nodeIndexscan.c.

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

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

◆ ExecIndexMarkPos()

void ExecIndexMarkPos ( IndexScanState node)

Definition at line 832 of file nodeIndexscan.c.

833 {
834  EState *estate = node->ss.ps.state;
835  EPQState *epqstate = estate->es_epq_active;
836 
837  if (epqstate != NULL)
838  {
839  /*
840  * We are inside an EvalPlanQual recheck. If a test tuple exists for
841  * this relation, then we shouldn't access the index at all. We would
842  * instead need to save, and later restore, the state of the
843  * relsubs_done flag, so that re-fetching the test tuple is possible.
844  * However, given the assumption that no caller sets a mark at the
845  * start of the scan, we can only get here with relsubs_done[i]
846  * already set, and so no state need be saved.
847  */
848  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
849 
850  Assert(scanrelid > 0);
851  if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
852  epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
853  {
854  /* Verify the claim above */
855  if (!epqstate->relsubs_done[scanrelid - 1])
856  elog(ERROR, "unexpected ExecIndexMarkPos call in EPQ recheck");
857  return;
858  }
859  }
860 
862 }
unsigned int Index
Definition: c.h:560
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:353
ExecAuxRowMark ** relsubs_rowmark
Definition: execnodes.h:1172
TupleTableSlot ** relsubs_slot
Definition: execnodes.h:1144
bool * relsubs_done
Definition: execnodes.h:1178
struct EPQState * es_epq_active
Definition: execnodes.h:661
Plan * plan
Definition: execnodes.h:998
EState * state
Definition: execnodes.h:1000

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

◆ ExecIndexRestrPos()

void ExecIndexRestrPos ( IndexScanState node)

Definition at line 869 of file nodeIndexscan.c.

870 {
871  EState *estate = node->ss.ps.state;
872  EPQState *epqstate = estate->es_epq_active;
873 
874  if (estate->es_epq_active != NULL)
875  {
876  /* See comments in ExecIndexMarkPos */
877  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
878 
879  Assert(scanrelid > 0);
880  if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
881  epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
882  {
883  /* Verify the claim above */
884  if (!epqstate->relsubs_done[scanrelid - 1])
885  elog(ERROR, "unexpected ExecIndexRestrPos call in EPQ recheck");
886  return;
887  }
888  }
889 
891 }
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:377

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

◆ ExecIndexScanEstimate()

void ExecIndexScanEstimate ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1660 of file nodeIndexscan.c.

1662 {
1663  EState *estate = node->ss.ps.state;
1664 
1666  estate->es_snapshot);
1668  shm_toc_estimate_keys(&pcxt->estimator, 1);
1669 }
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:402
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Snapshot es_snapshot
Definition: execnodes.h:590
shm_toc_estimator estimator
Definition: parallel.h:42

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

◆ ExecIndexScanInitializeDSM()

void ExecIndexScanInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1678 of file nodeIndexscan.c.

1680 {
1681  EState *estate = node->ss.ps.state;
1682  ParallelIndexScanDesc piscan;
1683 
1684  piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1686  node->iss_RelationDesc,
1687  estate->es_snapshot,
1688  piscan);
1689  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1690  node->iss_ScanDesc =
1692  node->iss_RelationDesc,
1693  node->iss_NumScanKeys,
1694  node->iss_NumOrderByKeys,
1695  piscan);
1696 
1697  /*
1698  * If no run-time keys to calculate or they are ready, go ahead and pass
1699  * the scankeys to the index AM.
1700  */
1701  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1702  index_rescan(node->iss_ScanDesc,
1703  node->iss_ScanKeys, node->iss_NumScanKeys,
1704  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1705 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:484
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:435
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:297
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
int iss_NumRuntimeKeys
Definition: execnodes.h:1518
bool iss_RuntimeKeysReady
Definition: execnodes.h:1519
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1513
int iss_NumOrderByKeys
Definition: execnodes.h:1516
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1515
shm_toc * toc
Definition: parallel.h:45
int plan_node_id
Definition: plannodes.h:141
Relation ss_currentRelation
Definition: execnodes.h:1424

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

◆ ExecIndexScanInitializeWorker()

void ExecIndexScanInitializeWorker ( IndexScanState node,
ParallelWorkerContext pwcxt 
)

Definition at line 1727 of file nodeIndexscan.c.

1729 {
1730  ParallelIndexScanDesc piscan;
1731 
1732  piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1733  node->iss_ScanDesc =
1735  node->iss_RelationDesc,
1736  node->iss_NumScanKeys,
1737  node->iss_NumOrderByKeys,
1738  piscan);
1739 
1740  /*
1741  * If no run-time keys to calculate or they are ready, go ahead and pass
1742  * the scankeys to the index AM.
1743  */
1744  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1745  index_rescan(node->iss_ScanDesc,
1746  node->iss_ScanKeys, node->iss_NumScanKeys,
1747  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1748 }
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

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

◆ ExecIndexScanReInitializeDSM()

void ExecIndexScanReInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1714 of file nodeIndexscan.c.

1716 {
1718 }
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:466

References index_parallelrescan(), and IndexScanState::iss_ScanDesc.

Referenced by ExecParallelReInitializeDSM().

◆ ExecInitIndexScan()

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

Definition at line 905 of file nodeIndexscan.c.

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

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, IndexScanState::indexorderbyorig, IndexScan::indexorderbyorig, IndexScan::indexqual, IndexScanState::indexqualorig, IndexScan::indexqualorig, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_OrderByNulls, IndexScanState::iss_OrderByTypByVals, IndexScanState::iss_OrderByTypLens, IndexScanState::iss_OrderByValues, IndexScanState::iss_RelationDesc, IndexScanState::iss_ReorderQueue, IndexScanState::iss_RuntimeContext, IndexScanState::iss_RuntimeKeys, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanKeys, IndexScanState::iss_SortSupport, lfirst, lfirst_oid, list_length(), makeNode, pairingheap_allocate(), palloc(), palloc0(), PlanState::plan, Scan::plan, PrepareSortSupportFromOrderingOp(), ScanState::ps, PlanState::ps_ExprContext, PlanState::qual, Plan::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().

◆ ExecReScanIndexScan()

void ExecReScanIndexScan ( IndexScanState node)

Definition at line 554 of file nodeIndexscan.c.

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  HeapTuple tuple;
578 
579  while (!pairingheap_is_empty(node->iss_ReorderQueue))
580  {
581  tuple = reorderqueue_pop(node);
582  heap_freetuple(tuple);
583  }
584  }
585 
586  /* reset index scan */
587  if (node->iss_ScanDesc)
589  node->iss_ScanKeys, node->iss_NumScanKeys,
590  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
591  node->iss_ReachedEnd = false;
592 
593  ExecScanReScan(&node->ss);
594 }
void ExecScanReScan(ScanState *node)
Definition: execScan.c:299
#define ResetExprContext(econtext)
Definition: executor.h:531
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
static HeapTuple reorderqueue_pop(IndexScanState *node)
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
bool iss_ReachedEnd
Definition: execnodes.h:1526

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