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 ExecIndexScanRetrieveInstrumentation (IndexScanState *node)
 
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 787 of file nodeIndexscan.c.

788{
789 Relation indexRelationDesc;
790 IndexScanDesc indexScanDesc;
791
792 /*
793 * extract information from the node
794 */
795 indexRelationDesc = node->iss_RelationDesc;
796 indexScanDesc = node->iss_ScanDesc;
797
798 /*
799 * When ending a parallel worker, copy the statistics gathered by the
800 * worker back into shared memory so that it can be picked up by the main
801 * process to report in EXPLAIN ANALYZE
802 */
803 if (node->iss_SharedInfo != NULL && IsParallelWorker())
804 {
805 IndexScanInstrumentation *winstrument;
806
807 Assert(ParallelWorkerNumber <= node->iss_SharedInfo->num_workers);
808 winstrument = &node->iss_SharedInfo->winstrument[ParallelWorkerNumber];
809
810 /*
811 * We have to accumulate the stats rather than performing a memcpy.
812 * When a Gather/GatherMerge node finishes it will perform planner
813 * shutdown on the workers. On rescan it will spin up new workers
814 * which will have a new IndexOnlyScanState and zeroed stats.
815 */
816 winstrument->nsearches += node->iss_Instrument.nsearches;
817 }
818
819 /*
820 * close the index relation (no-op if we didn't open it)
821 */
822 if (indexScanDesc)
823 index_endscan(indexScanDesc);
824 if (indexRelationDesc)
825 index_close(indexRelationDesc, NoLock);
826}
int ParallelWorkerNumber
Definition: parallel.c:115
Assert(PointerIsAligned(start, uint64))
#define IsParallelWorker()
Definition: parallel.h:60
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:382
#define NoLock
Definition: lockdefs.h:34
struct IndexScanDescData * iss_ScanDesc
Definition: execnodes.h:1710
IndexScanInstrumentation iss_Instrument
Definition: execnodes.h:1711
Relation iss_RelationDesc
Definition: execnodes.h:1709
SharedIndexScanInstrumentation * iss_SharedInfo
Definition: execnodes.h:1712
IndexScanInstrumentation winstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: genam.h:47

References Assert(), index_close(), index_endscan(), IsParallelWorker, IndexScanState::iss_Instrument, IndexScanState::iss_RelationDesc, IndexScanState::iss_ScanDesc, IndexScanState::iss_SharedInfo, NoLock, IndexScanInstrumentation::nsearches, ParallelWorkerNumber, and SharedIndexScanInstrumentation::winstrument.

Referenced by ExecEndNode().

◆ ExecIndexAdvanceArrayKeys()

bool ExecIndexAdvanceArrayKeys ( IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 742 of file nodeIndexscan.c.

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

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

References arg, NullTest::arg, ScalarArrayOpExpr::args, IndexArrayKeyInfo::array_expr, Assert(), BTORDER_PROC, RowCompareExpr::cmptype, 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, 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 663 of file nodeIndexscan.c.

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

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

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

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

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

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

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

1666{
1667 EState *estate = node->ss.ps.state;
1668 bool instrument = node->ss.ps.instrument != NULL;
1669 bool parallel_aware = node->ss.ps.plan->parallel_aware;
1670
1671 if (!instrument && !parallel_aware)
1672 {
1673 /* No DSM required by the scan */
1674 return;
1675 }
1676
1678 node->iss_NumScanKeys,
1679 node->iss_NumOrderByKeys,
1680 estate->es_snapshot,
1681 instrument, parallel_aware,
1682 pcxt->nworkers);
1685}
Size index_parallelscan_estimate(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot, bool instrument, bool parallel_aware, int nworkers)
Definition: indexam.c:461
#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:651
int iss_NumOrderByKeys
Definition: execnodes.h:1704
shm_toc_estimator estimator
Definition: parallel.h:41
Instrumentation * instrument
Definition: execnodes.h:1163
bool parallel_aware
Definition: plannodes.h:190

References EState::es_snapshot, ParallelContext::estimator, index_parallelscan_estimate(), PlanState::instrument, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_PscanLen, IndexScanState::iss_RelationDesc, ParallelContext::nworkers, Plan::parallel_aware, PlanState::plan, 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 1694 of file nodeIndexscan.c.

1696{
1697 EState *estate = node->ss.ps.state;
1698 ParallelIndexScanDesc piscan;
1699 bool instrument = node->ss.ps.instrument != NULL;
1700 bool parallel_aware = node->ss.ps.plan->parallel_aware;
1701
1702 if (!instrument && !parallel_aware)
1703 {
1704 /* No DSM required by the scan */
1705 return;
1706 }
1707
1708 piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1710 node->iss_RelationDesc,
1711 estate->es_snapshot,
1712 instrument, parallel_aware, pcxt->nworkers,
1713 &node->iss_SharedInfo, piscan);
1714 shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1715
1716 if (!parallel_aware)
1717 {
1718 /* Only here to initialize SharedInfo in DSM */
1719 return;
1720 }
1721
1722 node->iss_ScanDesc =
1724 node->iss_RelationDesc,
1725 &node->iss_Instrument,
1726 node->iss_NumScanKeys,
1727 node->iss_NumOrderByKeys,
1728 piscan);
1729
1730 /*
1731 * If no run-time keys to calculate or they are ready, go ahead and pass
1732 * the scankeys to the index AM.
1733 */
1734 if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1736 node->iss_ScanKeys, node->iss_NumScanKeys,
1737 node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1738}
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, bool instrument, bool parallel_aware, int nworkers, SharedIndexScanInstrumentation **sharedinfo, ParallelIndexScanDesc target)
Definition: indexam.c:509
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, IndexScanInstrumentation *instrument, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:582
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:356
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
int iss_NumRuntimeKeys
Definition: execnodes.h:1706
bool iss_RuntimeKeysReady
Definition: execnodes.h:1707
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1701
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1703
shm_toc * toc
Definition: parallel.h:44
int plan_node_id
Definition: plannodes.h:204
Relation ss_currentRelation
Definition: execnodes.h:1610

References EState::es_snapshot, index_beginscan_parallel(), index_parallelscan_initialize(), index_rescan(), PlanState::instrument, IndexScanState::iss_Instrument, 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, IndexScanState::iss_SharedInfo, ParallelContext::nworkers, Plan::parallel_aware, 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 1761 of file nodeIndexscan.c.

1763{
1764 ParallelIndexScanDesc piscan;
1765 bool instrument = node->ss.ps.instrument != NULL;
1766 bool parallel_aware = node->ss.ps.plan->parallel_aware;
1767
1768 if (!instrument && !parallel_aware)
1769 {
1770 /* No DSM required by the scan */
1771 return;
1772 }
1773
1774 piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1775
1776 if (instrument)
1778 OffsetToPointer(piscan, piscan->ps_offset_ins);
1779
1780 if (!parallel_aware)
1781 {
1782 /* Only here to set up worker node's SharedInfo */
1783 return;
1784 }
1785
1786 node->iss_ScanDesc =
1788 node->iss_RelationDesc,
1789 &node->iss_Instrument,
1790 node->iss_NumScanKeys,
1791 node->iss_NumOrderByKeys,
1792 piscan);
1793
1794 /*
1795 * If no run-time keys to calculate or they are ready, go ahead and pass
1796 * the scankeys to the index AM.
1797 */
1798 if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1800 node->iss_ScanKeys, node->iss_NumScanKeys,
1801 node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1802}
#define OffsetToPointer(base, offset)
Definition: c.h:743
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

References index_beginscan_parallel(), index_rescan(), PlanState::instrument, IndexScanState::iss_Instrument, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, IndexScanState::iss_SharedInfo, OffsetToPointer, Plan::parallel_aware, PlanState::plan, Plan::plan_node_id, ScanState::ps, ParallelIndexScanDescData::ps_offset_ins, shm_toc_lookup(), IndexScanState::ss, ScanState::ss_currentRelation, and ParallelWorkerContext::toc.

Referenced by ExecParallelInitializeWorker().

◆ ExecIndexScanReInitializeDSM()

void ExecIndexScanReInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1747 of file nodeIndexscan.c.

1749{
1750 Assert(node->ss.ps.plan->parallel_aware);
1752}
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:564

References Assert(), index_parallelrescan(), IndexScanState::iss_ScanDesc, Plan::parallel_aware, PlanState::plan, ScanState::ps, and IndexScanState::ss.

Referenced by ExecParallelReInitializeDSM().

◆ ExecIndexScanRetrieveInstrumentation()

void ExecIndexScanRetrieveInstrumentation ( IndexScanState node)

Definition at line 1811 of file nodeIndexscan.c.

1812{
1814 size_t size;
1815
1816 if (SharedInfo == NULL)
1817 return;
1818
1819 /* Create a copy of SharedInfo in backend-local memory */
1820 size = offsetof(SharedIndexScanInstrumentation, winstrument) +
1821 SharedInfo->num_workers * sizeof(IndexScanInstrumentation);
1822 node->iss_SharedInfo = palloc(size);
1823 memcpy(node->iss_SharedInfo, SharedInfo, size);
1824}
struct IndexScanInstrumentation IndexScanInstrumentation

References IndexScanState::iss_SharedInfo, SharedIndexScanInstrumentation::num_workers, and palloc().

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecInitIndexScan()

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

Definition at line 909 of file nodeIndexscan.c.

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

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

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

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