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  * close the index relation (no-op if we didn't open it)
799  */
800  if (indexScanDesc)
801  index_endscan(indexScanDesc);
802  if (indexRelationDesc)
803  index_close(indexRelationDesc, NoLock);
804 }
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:379
#define NoLock
Definition: lockdefs.h:34
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1579
Relation iss_RelationDesc
Definition: execnodes.h:1578

References index_close(), index_endscan(), IndexScanState::iss_RelationDesc, IndexScanState::iss_ScanDesc, and NoLock.

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:1535
struct ScanKeyData * scan_key
Definition: execnodes.h:1531
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 1136 of file nodeIndexscan.c.

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

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

815 {
816  EState *estate = node->ss.ps.state;
817  EPQState *epqstate = estate->es_epq_active;
818 
819  if (epqstate != NULL)
820  {
821  /*
822  * We are inside an EvalPlanQual recheck. If a test tuple exists for
823  * this relation, then we shouldn't access the index at all. We would
824  * instead need to save, and later restore, the state of the
825  * relsubs_done flag, so that re-fetching the test tuple is possible.
826  * However, given the assumption that no caller sets a mark at the
827  * start of the scan, we can only get here with relsubs_done[i]
828  * already set, and so no state need be saved.
829  */
830  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
831 
832  Assert(scanrelid > 0);
833  if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
834  epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
835  {
836  /* Verify the claim above */
837  if (!epqstate->relsubs_done[scanrelid - 1])
838  elog(ERROR, "unexpected ExecIndexMarkPos call in EPQ recheck");
839  return;
840  }
841  }
842 
844 }
unsigned int Index
Definition: c.h:603
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:409
ExecAuxRowMark ** relsubs_rowmark
Definition: execnodes.h:1218
TupleTableSlot ** relsubs_slot
Definition: execnodes.h:1190
bool * relsubs_done
Definition: execnodes.h:1225
struct EPQState * es_epq_active
Definition: execnodes.h:697
ScanState ss
Definition: execnodes.h:1567
Plan * plan
Definition: execnodes.h:1043
EState * state
Definition: execnodes.h:1045
PlanState ps
Definition: execnodes.h:1480

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

852 {
853  EState *estate = node->ss.ps.state;
854  EPQState *epqstate = estate->es_epq_active;
855 
856  if (estate->es_epq_active != NULL)
857  {
858  /* See comments in ExecIndexMarkPos */
859  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
860 
861  Assert(scanrelid > 0);
862  if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
863  epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
864  {
865  /* Verify the claim above */
866  if (!epqstate->relsubs_done[scanrelid - 1])
867  elog(ERROR, "unexpected ExecIndexRestrPos call in EPQ recheck");
868  return;
869  }
870  }
871 
873 }
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:433

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

1644 {
1645  EState *estate = node->ss.ps.state;
1646 
1648  estate->es_snapshot);
1650  shm_toc_estimate_keys(&pcxt->estimator, 1);
1651 }
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:458
#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:622
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 1660 of file nodeIndexscan.c.

1662 {
1663  EState *estate = node->ss.ps.state;
1664  ParallelIndexScanDesc piscan;
1665 
1666  piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1668  node->iss_RelationDesc,
1669  estate->es_snapshot,
1670  piscan);
1671  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1672  node->iss_ScanDesc =
1674  node->iss_RelationDesc,
1675  node->iss_NumScanKeys,
1676  node->iss_NumOrderByKeys,
1677  piscan);
1678 
1679  /*
1680  * If no run-time keys to calculate or they are ready, go ahead and pass
1681  * the scankeys to the index AM.
1682  */
1683  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1684  index_rescan(node->iss_ScanDesc,
1685  node->iss_ScanKeys, node->iss_NumScanKeys,
1686  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1687 }
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:544
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:493
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:353
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:1575
bool iss_RuntimeKeysReady
Definition: execnodes.h:1576
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1570
int iss_NumOrderByKeys
Definition: execnodes.h:1573
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1572
shm_toc * toc
Definition: parallel.h:45
int plan_node_id
Definition: plannodes.h:151
Relation ss_currentRelation
Definition: execnodes.h:1481

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

1711 {
1712  ParallelIndexScanDesc piscan;
1713 
1714  piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1715  node->iss_ScanDesc =
1717  node->iss_RelationDesc,
1718  node->iss_NumScanKeys,
1719  node->iss_NumOrderByKeys,
1720  piscan);
1721 
1722  /*
1723  * If no run-time keys to calculate or they are ready, go ahead and pass
1724  * the scankeys to the index AM.
1725  */
1726  if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1727  index_rescan(node->iss_ScanDesc,
1728  node->iss_ScanKeys, node->iss_NumScanKeys,
1729  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1730 }
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 1696 of file nodeIndexscan.c.

1698 {
1700 }
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:526

References index_parallelrescan(), and IndexScanState::iss_ScanDesc.

Referenced by ExecParallelReInitializeDSM().

◆ ExecInitIndexScan()

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

Definition at line 887 of file nodeIndexscan.c.

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

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