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

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

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

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

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

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, 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::opno, 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 662 of file nodeIndexscan.c.

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

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

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

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

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

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

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

1660 {
1661  EState *estate = node->ss.ps.state;
1662 
1664  estate->es_snapshot);
1666  shm_toc_estimate_keys(&pcxt->estimator, 1);
1667 }
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:406
#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:616
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 1676 of file nodeIndexscan.c.

1678 {
1679  EState *estate = node->ss.ps.state;
1680  ParallelIndexScanDesc piscan;
1681 
1682  piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1684  node->iss_RelationDesc,
1685  estate->es_snapshot,
1686  piscan);
1687  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1688  node->iss_ScanDesc =
1690  node->iss_RelationDesc,
1691  node->iss_NumScanKeys,
1692  node->iss_NumOrderByKeys,
1693  piscan);
1694 
1695  /*
1696  * If no run-time keys to calculate or they are ready, go ahead and pass
1697  * the scankeys to the index AM.
1698  */
1699  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1700  index_rescan(node->iss_ScanDesc,
1701  node->iss_ScanKeys, node->iss_NumScanKeys,
1702  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1703 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:492
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:441
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:301
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:1569
bool iss_RuntimeKeysReady
Definition: execnodes.h:1570
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1564
int iss_NumOrderByKeys
Definition: execnodes.h:1567
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1566
shm_toc * toc
Definition: parallel.h:45
int plan_node_id
Definition: plannodes.h:152
Relation ss_currentRelation
Definition: execnodes.h:1475

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

1727 {
1728  ParallelIndexScanDesc piscan;
1729 
1730  piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1731  node->iss_ScanDesc =
1733  node->iss_RelationDesc,
1734  node->iss_NumScanKeys,
1735  node->iss_NumOrderByKeys,
1736  piscan);
1737 
1738  /*
1739  * If no run-time keys to calculate or they are ready, go ahead and pass
1740  * the scankeys to the index AM.
1741  */
1742  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1743  index_rescan(node->iss_ScanDesc,
1744  node->iss_ScanKeys, node->iss_NumScanKeys,
1745  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1746 }
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 1712 of file nodeIndexscan.c.

1714 {
1716 }
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:474

References index_parallelrescan(), and IndexScanState::iss_ScanDesc.

Referenced by ExecParallelReInitializeDSM().

◆ ExecInitIndexScan()

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

Definition at line 903 of file nodeIndexscan.c.

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

◆ ExecReScanIndexScan()

void ExecReScanIndexScan ( IndexScanState node)

Definition at line 552 of file nodeIndexscan.c.

553 {
554  /*
555  * If we are doing runtime key calculations (ie, any of the index key
556  * values weren't simple Consts), compute the new key values. But first,
557  * reset the context so we don't leak memory as each outer tuple is
558  * scanned. Note this assumes that we will recalculate *all* runtime keys
559  * on each call.
560  */
561  if (node->iss_NumRuntimeKeys != 0)
562  {
563  ExprContext *econtext = node->iss_RuntimeContext;
564 
565  ResetExprContext(econtext);
566  ExecIndexEvalRuntimeKeys(econtext,
567  node->iss_RuntimeKeys,
568  node->iss_NumRuntimeKeys);
569  }
570  node->iss_RuntimeKeysReady = true;
571 
572  /* flush the reorder queue */
573  if (node->iss_ReorderQueue)
574  {
575  HeapTuple tuple;
576 
577  while (!pairingheap_is_empty(node->iss_ReorderQueue))
578  {
579  tuple = reorderqueue_pop(node);
580  heap_freetuple(tuple);
581  }
582  }
583 
584  /* reset index scan */
585  if (node->iss_ScanDesc)
587  node->iss_ScanKeys, node->iss_NumScanKeys,
588  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
589  node->iss_ReachedEnd = false;
590 
591  ExecScanReScan(&node->ss);
592 }
void ExecScanReScan(ScanState *node)
Definition: execScan.c:298
#define ResetExprContext(econtext)
Definition: executor.h:543
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1426
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:1577

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