PostgreSQL Source Code git master
Loading...
Searching...
No Matches
nodeIndexscan.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "access/relscan.h"
#include "access/tableam.h"
#include "catalog/pg_am.h"
#include "executor/executor.h"
#include "executor/instrument.h"
#include "executor/nodeIndexscan.h"
#include "lib/pairingheap.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "utils/array.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/sortsupport.h"
Include dependency graph for nodeIndexscan.c:

Go to the source code of this file.

Data Structures

struct  ReorderTuple
 

Functions

static TupleTableSlotIndexNext (IndexScanState *node)
 
static TupleTableSlotIndexNextWithReorder (IndexScanState *node)
 
static void EvalOrderByExpressions (IndexScanState *node, ExprContext *econtext)
 
static bool IndexRecheck (IndexScanState *node, TupleTableSlot *slot)
 
static int cmp_orderbyvals (const Datum *adist, const bool *anulls, const Datum *bdist, const bool *bnulls, IndexScanState *node)
 
static int reorderqueue_cmp (const pairingheap_node *a, const pairingheap_node *b, void *arg)
 
static void reorderqueue_push (IndexScanState *node, TupleTableSlot *slot, const Datum *orderbyvals, const bool *orderbynulls)
 
static HeapTuple reorderqueue_pop (IndexScanState *node)
 
static TupleTableSlotExecIndexScan (PlanState *pstate)
 
void ExecReScanIndexScan (IndexScanState *node)
 
void ExecIndexEvalRuntimeKeys (ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
 
bool ExecIndexEvalArrayKeys (ExprContext *econtext, IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 
bool ExecIndexAdvanceArrayKeys (IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 
void ExecEndIndexScan (IndexScanState *node)
 
void ExecIndexMarkPos (IndexScanState *node)
 
void ExecIndexRestrPos (IndexScanState *node)
 
IndexScanStateExecInitIndexScan (IndexScan *node, EState *estate, int eflags)
 
void ExecIndexBuildScanKeys (PlanState *planstate, Relation index, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
 
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)
 

Function Documentation

◆ cmp_orderbyvals()

static int cmp_orderbyvals ( const Datum adist,
const bool anulls,
const Datum bdist,
const bool bnulls,
IndexScanState node 
)
static

Definition at line 409 of file nodeIndexscan.c.

412{
413 int i;
414 int result;
415
416 for (i = 0; i < node->iss_NumOrderByKeys; i++)
417 {
418 SortSupport ssup = &node->iss_SortSupport[i];
419
420 /*
421 * Handle nulls. We only need to support NULLS LAST ordering, because
422 * match_pathkeys_to_index() doesn't consider indexorderby
423 * implementation otherwise.
424 */
425 if (anulls[i] && !bnulls[i])
426 return 1;
427 else if (!anulls[i] && bnulls[i])
428 return -1;
429 else if (anulls[i] && bnulls[i])
430 return 0;
431
432 result = ssup->comparator(adist[i], bdist[i], ssup);
433 if (result != 0)
434 return result;
435 }
436
437 return 0;
438}
int i
Definition isn.c:77
static int fb(int x)
SortSupport iss_SortSupport
Definition execnodes.h:1743
int(* comparator)(Datum x, Datum y, SortSupport ssup)

References SortSupportData::comparator, fb(), i, IndexScanState::iss_NumOrderByKeys, and IndexScanState::iss_SortSupport.

Referenced by IndexNextWithReorder(), and reorderqueue_cmp().

◆ EvalOrderByExpressions()

static void EvalOrderByExpressions ( IndexScanState node,
ExprContext econtext 
)
static

Definition at line 364 of file nodeIndexscan.c.

365{
366 int i;
367 ListCell *l;
369
371
372 i = 0;
373 foreach(l, node->indexorderbyorig)
374 {
376
378 econtext,
379 &node->iss_OrderByNulls[i]);
380 i++;
381 }
382
384}
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:396
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define lfirst(lc)
Definition pg_list.h:172
MemoryContext ecxt_per_tuple_memory
Definition execnodes.h:292
List * indexorderbyorig
Definition execnodes.h:1724
bool * iss_OrderByNulls
Definition execnodes.h:1742
Datum * iss_OrderByValues
Definition execnodes.h:1741

References ExprContext::ecxt_per_tuple_memory, ExecEvalExpr(), fb(), i, IndexScanState::indexorderbyorig, IndexScanState::iss_OrderByNulls, IndexScanState::iss_OrderByValues, lfirst, and MemoryContextSwitchTo().

Referenced by IndexNextWithReorder().

◆ ExecEndIndexScan()

void ExecEndIndexScan ( IndexScanState node)

Definition at line 787 of file nodeIndexscan.c.

788{
791
792 /*
793 * extract information from the node
794 */
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)
826}
int ParallelWorkerNumber
Definition parallel.c:117
#define Assert(condition)
Definition c.h:945
#define IsParallelWorker()
Definition parallel.h:62
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:177
void index_endscan(IndexScanDesc scan)
Definition indexam.c:392
#define NoLock
Definition lockdefs.h:34
struct IndexScanDescData * iss_ScanDesc
Definition execnodes.h:1734
IndexScanInstrumentation iss_Instrument
Definition execnodes.h:1735
Relation iss_RelationDesc
Definition execnodes.h:1733
SharedIndexScanInstrumentation * iss_SharedInfo
Definition execnodes.h:1736
IndexScanInstrumentation winstrument[FLEXIBLE_ARRAY_MEMBER]

References Assert, fb(), 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:78
uint64_t Datum
Definition postgres.h:70
#define SK_ISNULL
Definition skey.h:115
ScanKeyData * scan_key
Definition execnodes.h:1684
int sk_flags
Definition skey.h:66
Datum sk_argument
Definition skey.h:72

References IndexArrayKeyInfo::elem_nulls, IndexArrayKeyInfo::elem_values, fb(), 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 1159 of file nodeIndexscan.c.

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

References arg, ScalarArrayOpExpr::args, Assert, BTORDER_PROC, RowCompareExpr::cmptype, elog, ERROR, ExecInitExpr(), fb(), forfour, get_leftop(), get_op_opfamily_properties(), get_opfamily_proc(), get_rightop(), INDEX_VAR, IndexRelationGetNumberOfKeyAttributes, InvalidOid, InvalidStrategy, IS_NOT_NULL, IS_NULL, IsA, j, RowCompareExpr::largs, lfirst, lfirst_oid, linitial, list_length(), lsecond, MemSet, nodeTag, ScalarArrayOpExpr::opno, palloc(), palloc0(), pfree(), PointerGetDatum(), RowCompareExpr::rargs, RegProcedureIsValid, repalloc(), ScanKeyEntryInitialize(), SK_ISNULL, SK_ORDER_BY, SK_ROW_END, SK_ROW_HEADER, SK_ROW_MEMBER, SK_SEARCHARRAY, SK_SEARCHNOTNULL, SK_SEARCHNULL, 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;
669
670 /* We want to keep the arrays in 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;
678 bool isNull;
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 }
700 /* We could cache this data, but not clear it's worth it */
702 &elmlen, &elmbyval, &elmalign);
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
730
731 return result;
732}
#define DatumGetArrayTypeP(X)
Definition array.h:261
#define ARR_ELEMTYPE(a)
Definition array.h:292
void deconstruct_array(const ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
int16_t int16
Definition c.h:613
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition lsyscache.c:2491
ExprState * array_expr
Definition execnodes.h:1685

References ARR_ELEMTYPE, IndexArrayKeyInfo::array_expr, DatumGetArrayTypeP, deconstruct_array(), ExprContext::ecxt_per_tuple_memory, IndexArrayKeyInfo::elem_nulls, IndexArrayKeyInfo::elem_values, ExecEvalExpr(), fb(), 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;
606
607 /* We want to keep the key values in 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;
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)
646 scan_key->sk_argument = scanvalue;
647 scan_key->sk_flags &= ~SK_ISNULL;
648 }
649 }
650
652}
#define PG_DETOAST_DATUM(datum)
Definition fmgr.h:240

References ExprContext::ecxt_per_tuple_memory, ExecEvalExpr(), fb(), j, MemoryContextSwitchTo(), PG_DETOAST_DATUM, PointerGetDatum(), 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:700
void index_markpos(IndexScanDesc scan)
Definition indexam.c:422
ExecAuxRowMark ** relsubs_rowmark
Definition execnodes.h:1352
TupleTableSlot ** relsubs_slot
Definition execnodes.h:1324
bool * relsubs_done
Definition execnodes.h:1359
struct EPQState * es_epq_active
Definition execnodes.h:754
ScanState ss
Definition execnodes.h:1722
Plan * plan
Definition execnodes.h:1177
EState * state
Definition execnodes.h:1179
PlanState ps
Definition execnodes.h:1633

References Assert, elog, ERROR, EState::es_epq_active, fb(), 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:446

References Assert, elog, ERROR, EState::es_epq_active, fb(), 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().

◆ ExecIndexScan()

static TupleTableSlot * ExecIndexScan ( PlanState pstate)
static

Definition at line 521 of file nodeIndexscan.c.

522{
523 IndexScanState *node = castNode(IndexScanState, pstate);
524
525 /*
526 * If we have runtime keys and they've not already been set up, do it now.
527 */
528 if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
529 ExecReScan((PlanState *) node);
530
531 if (node->iss_NumOrderByKeys > 0)
532 return ExecScan(&node->ss,
535 else
536 return ExecScan(&node->ss,
539}
void ExecReScan(PlanState *node)
Definition execAmi.c:78
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition execScan.c:47
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition executor.h:583
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition executor.h:582
static TupleTableSlot * IndexNextWithReorder(IndexScanState *node)
static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
static TupleTableSlot * IndexNext(IndexScanState *node)
#define castNode(_type_, nodeptr)
Definition nodes.h:182
bool iss_RuntimeKeysReady
Definition execnodes.h:1731

References castNode, ExecReScan(), ExecScan(), IndexNext(), IndexNextWithReorder(), IndexRecheck(), IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_RuntimeKeysReady, and IndexScanState::ss.

Referenced by ExecInitIndexScan().

◆ ExecIndexScanEstimate()

void ExecIndexScanEstimate ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1665 of file nodeIndexscan.c.

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

References EState::es_snapshot, ParallelContext::estimator, fb(), 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 1695 of file nodeIndexscan.c.

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

References EState::es_snapshot, fb(), 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 1762 of file nodeIndexscan.c.

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

References fb(), 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, shm_toc_lookup(), IndexScanState::ss, and ScanState::ss_currentRelation.

Referenced by ExecParallelInitializeWorker().

◆ ExecIndexScanReInitializeDSM()

void ExecIndexScanReInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1748 of file nodeIndexscan.c.

1750{
1751 Assert(node->ss.ps.plan->parallel_aware);
1753}
void index_parallelrescan(IndexScanDesc scan)
Definition indexam.c:575

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

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

References fb(), 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{
913 LOCKMODE lockmode;
914
915 /*
916 * create state structure
917 */
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 */
945
946 /*
947 * Initialize result type and projection.
948 */
951
952 /*
953 * initialize child expressions
954 *
955 * Note: we don't initialize all of the indexqual expression, only the
956 * sub-parts corresponding to runtime keys (see below). Likewise for
957 * indexorderby, if any. But the indexqualorig expression is always
958 * initialized even though it will only be used in some uncommon cases ---
959 * would be nice to improve that. (Problem is that any SubPlans present
960 * in the expression must be found now...)
961 */
962 indexstate->ss.ps.qual =
963 ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
964 indexstate->indexqualorig =
966 indexstate->indexorderbyorig =
968
969 /*
970 * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
971 * here. This allows an index-advisor plugin to EXPLAIN a plan containing
972 * references to nonexistent indexes.
973 */
974 if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
975 return indexstate;
976
977 /* Open the index relation. */
978 lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
979 indexstate->iss_RelationDesc = index_open(node->indexid, lockmode);
980
981 /*
982 * Initialize index-specific scan state
983 */
984 indexstate->iss_RuntimeKeysReady = false;
985 indexstate->iss_RuntimeKeys = NULL;
986 indexstate->iss_NumRuntimeKeys = 0;
987
988 /*
989 * build the index scan keys from the index qualification
990 */
992 indexstate->iss_RelationDesc,
993 node->indexqual,
994 false,
995 &indexstate->iss_ScanKeys,
996 &indexstate->iss_NumScanKeys,
997 &indexstate->iss_RuntimeKeys,
998 &indexstate->iss_NumRuntimeKeys,
999 NULL, /* no ArrayKeys */
1000 NULL);
1001
1002 /*
1003 * any ORDER BY exprs have to be turned into scankeys in the same way
1004 */
1006 indexstate->iss_RelationDesc,
1007 node->indexorderby,
1008 true,
1009 &indexstate->iss_OrderByKeys,
1010 &indexstate->iss_NumOrderByKeys,
1011 &indexstate->iss_RuntimeKeys,
1012 &indexstate->iss_NumRuntimeKeys,
1013 NULL, /* no ArrayKeys */
1014 NULL);
1015
1016 /* Initialize sort support, if we need to re-check ORDER BY exprs */
1017 if (indexstate->iss_NumOrderByKeys > 0)
1018 {
1019 int numOrderByKeys = indexstate->iss_NumOrderByKeys;
1020 int i;
1021 ListCell *lco;
1022 ListCell *lcx;
1023
1024 /*
1025 * Prepare sort support, and look up the data type for each ORDER BY
1026 * expression.
1027 */
1030 indexstate->iss_SortSupport = (SortSupportData *)
1032 indexstate->iss_OrderByTypByVals = (bool *)
1033 palloc(numOrderByKeys * sizeof(bool));
1034 indexstate->iss_OrderByTypLens = (int16 *)
1035 palloc(numOrderByKeys * sizeof(int16));
1036 i = 0;
1038 {
1040 Node *orderbyexpr = (Node *) lfirst(lcx);
1043 SortSupport orderbysort = &indexstate->iss_SortSupport[i];
1044
1045 /* Initialize sort support */
1047 orderbysort->ssup_collation = orderbyColl;
1048 /* See cmp_orderbyvals() comments on NULLS LAST */
1049 orderbysort->ssup_nulls_first = false;
1050 /* ssup_attno is unused here and elsewhere */
1051 orderbysort->ssup_attno = 0;
1052 /* No abbreviation */
1053 orderbysort->abbreviate = false;
1055
1057 &indexstate->iss_OrderByTypLens[i],
1058 &indexstate->iss_OrderByTypByVals[i]);
1059 i++;
1060 }
1061
1062 /* allocate arrays to hold the re-calculated distances */
1063 indexstate->iss_OrderByValues = (Datum *)
1064 palloc(numOrderByKeys * sizeof(Datum));
1065 indexstate->iss_OrderByNulls = (bool *)
1066 palloc(numOrderByKeys * sizeof(bool));
1067
1068 /* and initialize the reorder queue */
1070 indexstate);
1071 }
1072
1073 /*
1074 * If we have runtime keys, we need an ExprContext to evaluate them. The
1075 * node's standard context won't do because we want to reset that context
1076 * for every tuple. So, build another context just like the other one...
1077 * -tgl 7/11/00
1078 */
1079 if (indexstate->iss_NumRuntimeKeys != 0)
1080 {
1081 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
1082
1083 ExecAssignExprContext(estate, &indexstate->ss.ps);
1084 indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
1085 indexstate->ss.ps.ps_ExprContext = stdecontext;
1086 }
1087 else
1088 {
1089 indexstate->iss_RuntimeContext = NULL;
1090 }
1091
1092 /*
1093 * all done.
1094 */
1095 return indexstate;
1096}
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition execExpr.c:250
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition execExpr.c:356
void ExecAssignScanProjectionInfo(ScanState *node)
Definition execScan.c:81
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops, uint16 flags)
void ExecInitResultTypeTL(PlanState *planstate)
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition execUtils.c:490
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition execUtils.c:747
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition executor.h:701
#define EXEC_FLAG_EXPLAIN_ONLY
Definition executor.h:67
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:133
int LOCKMODE
Definition lockdefs.h:26
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition lsyscache.c:2471
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
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:161
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:540
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
List * indexorderby
Definition plannodes.h:610
List * indexorderbyops
Definition plannodes.h:614
Scan scan
Definition plannodes.h:602
List * indexqualorig
Definition plannodes.h:608
Oid indexid
Definition plannodes.h:604
List * indexqual
Definition plannodes.h:606
List * indexorderbyorig
Definition plannodes.h:612
Definition nodes.h:135
Index scanrelid
Definition plannodes.h:540
MemoryContext ssup_cxt
Definition sortsupport.h:66
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition tableam.c:59
#define TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS
Definition tuptable.h:102

References Assert, CurrentMemoryContext, EXEC_FLAG_EXPLAIN_ONLY, exec_rt_fetch(), ExecAssignExprContext(), ExecAssignScanProjectionInfo(), ExecIndexBuildScanKeys(), ExecIndexScan(), ExecInitExprList(), ExecInitQual(), ExecInitResultTypeTL(), ExecInitScanTupleSlot(), ExecOpenScanRelation(), exprCollation(), exprType(), fb(), forboth, get_typlenbyval(), i, index_open(), IndexScan::indexid, IndexScan::indexorderby, IndexScan::indexorderbyops, IndexScan::indexorderbyorig, IndexScan::indexqual, IndexScan::indexqualorig, lfirst, lfirst_oid, list_length(), makeNode, pairingheap_allocate(), palloc(), palloc0(), PrepareSortSupportFromOrderingOp(), RelationGetDescr, reorderqueue_cmp(), IndexScan::scan, Scan::scanrelid, SortSupportData::ssup_cxt, table_slot_callbacks(), and TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS.

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:654
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1384
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
static HeapTuple reorderqueue_pop(IndexScanState *node)
#define pairingheap_is_empty(h)
Definition pairingheap.h:99
pairingheap * iss_ReorderQueue
Definition execnodes.h:1739
ExprContext * iss_RuntimeContext
Definition execnodes.h:1732
IndexRuntimeKeyInfo * iss_RuntimeKeys
Definition execnodes.h:1729

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

◆ IndexNext()

static TupleTableSlot * IndexNext ( IndexScanState node)
static

Definition at line 82 of file nodeIndexscan.c.

83{
84 EState *estate;
85 ExprContext *econtext;
86 ScanDirection direction;
87 IndexScanDesc scandesc;
88 TupleTableSlot *slot;
89
90 /*
91 * extract necessary information from index scan node
92 */
93 estate = node->ss.ps.state;
94
95 /*
96 * Determine which direction to scan the index in based on the plan's scan
97 * direction and the current direction of execution.
98 */
99 direction = ScanDirectionCombine(estate->es_direction,
100 ((IndexScan *) node->ss.ps.plan)->indexorderdir);
101 scandesc = node->iss_ScanDesc;
102 econtext = node->ss.ps.ps_ExprContext;
103 slot = node->ss.ss_ScanTupleSlot;
104
105 if (scandesc == NULL)
106 {
107 /*
108 * We reach here if the index scan is not parallel, or if we're
109 * serially executing an index scan that was planned to be parallel.
110 */
111 scandesc = index_beginscan(node->ss.ss_currentRelation,
112 node->iss_RelationDesc,
113 estate->es_snapshot,
114 &node->iss_Instrument,
115 node->iss_NumScanKeys,
116 node->iss_NumOrderByKeys);
117
118 node->iss_ScanDesc = scandesc;
119
120 /*
121 * If no run-time keys to calculate or they are ready, go ahead and
122 * pass the scankeys to the index AM.
123 */
124 if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
125 index_rescan(scandesc,
126 node->iss_ScanKeys, node->iss_NumScanKeys,
128 }
129
130 /*
131 * ok, now that we have what we need, fetch the next tuple.
132 */
133 while (index_getnext_slot(scandesc, direction, slot))
134 {
136
137 /*
138 * If the index was lossy, we have to recheck the index quals using
139 * the fetched tuple.
140 */
141 if (scandesc->xs_recheck)
142 {
143 econtext->ecxt_scantuple = slot;
144 if (!ExecQualAndReset(node->indexqualorig, econtext))
145 {
146 /* Fails recheck, so drop it and loop back for another */
147 InstrCountFiltered2(node, 1);
148 continue;
149 }
150 }
151
152 return slot;
153 }
154
155 /*
156 * if we get here it means the index scan failed so we are at the end of
157 * the scan..
158 */
159 node->iss_ReachedEnd = true;
160 return ExecClearTuple(slot);
161}
#define InstrCountFiltered2(node, delta)
Definition execnodes.h:1286
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition executor.h:549
bool index_getnext_slot(IndexScanDesc scan, ScanDirection direction, TupleTableSlot *slot)
Definition indexam.c:730
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, IndexScanInstrumentation *instrument, int nkeys, int norderbys)
Definition indexam.c:256
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
#define ScanDirectionCombine(a, b)
Definition sdir.h:36
ScanDirection
Definition sdir.h:25
ScanDirection es_direction
Definition execnodes.h:671
TupleTableSlot * ecxt_scantuple
Definition execnodes.h:284
ExprState * indexqualorig
Definition execnodes.h:1723
ExprContext * ps_ExprContext
Definition execnodes.h:1216
TupleTableSlot * ss_ScanTupleSlot
Definition execnodes.h:1636
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476

References CHECK_FOR_INTERRUPTS, ExprContext::ecxt_scantuple, EState::es_direction, EState::es_snapshot, ExecClearTuple(), ExecQualAndReset(), fb(), index_beginscan(), index_getnext_slot(), index_rescan(), IndexScanState::indexqualorig, InstrCountFiltered2, IndexScanState::iss_Instrument, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_ReachedEnd, IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, ScanDirectionCombine, IndexScanState::ss, ScanState::ss_currentRelation, ScanState::ss_ScanTupleSlot, PlanState::state, and IndexScanDescData::xs_recheck.

Referenced by ExecIndexScan().

◆ IndexNextWithReorder()

static TupleTableSlot * IndexNextWithReorder ( IndexScanState node)
static

Definition at line 171 of file nodeIndexscan.c.

172{
173 EState *estate;
174 ExprContext *econtext;
175 IndexScanDesc scandesc;
176 TupleTableSlot *slot;
178 bool was_exact;
180 bool *lastfetched_nulls;
181 int cmp;
182
183 estate = node->ss.ps.state;
184
185 /*
186 * Only forward scan is supported with reordering. Note: we can get away
187 * with just Asserting here because the system will not try to run the
188 * plan backwards if ExecSupportsBackwardScan() says it won't work.
189 * Currently, that is guaranteed because no index AMs support both
190 * amcanorderbyop and amcanbackward; if any ever do,
191 * ExecSupportsBackwardScan() will need to consider indexorderbys
192 * explicitly.
193 */
194 Assert(!ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir));
196
197 scandesc = node->iss_ScanDesc;
198 econtext = node->ss.ps.ps_ExprContext;
199 slot = node->ss.ss_ScanTupleSlot;
200
201 if (scandesc == NULL)
202 {
203 /*
204 * We reach here if the index scan is not parallel, or if we're
205 * serially executing an index scan that was planned to be parallel.
206 */
207 scandesc = index_beginscan(node->ss.ss_currentRelation,
208 node->iss_RelationDesc,
209 estate->es_snapshot,
210 &node->iss_Instrument,
211 node->iss_NumScanKeys,
212 node->iss_NumOrderByKeys);
213
214 node->iss_ScanDesc = scandesc;
215
216 /*
217 * If no run-time keys to calculate or they are ready, go ahead and
218 * pass the scankeys to the index AM.
219 */
220 if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
221 index_rescan(scandesc,
222 node->iss_ScanKeys, node->iss_NumScanKeys,
224 }
225
226 for (;;)
227 {
229
230 /*
231 * Check the reorder queue first. If the topmost tuple in the queue
232 * has an ORDER BY value smaller than (or equal to) the value last
233 * returned by the index, we can return it now.
234 */
236 {
238
239 if (node->iss_ReachedEnd ||
240 cmp_orderbyvals(topmost->orderbyvals,
241 topmost->orderbynulls,
242 scandesc->xs_orderbyvals,
243 scandesc->xs_orderbynulls,
244 node) <= 0)
245 {
246 HeapTuple tuple;
247
248 tuple = reorderqueue_pop(node);
249
250 /* Pass 'true', as the tuple in the queue is a palloc'd copy */
251 ExecForceStoreHeapTuple(tuple, slot, true);
252 return slot;
253 }
254 }
255 else if (node->iss_ReachedEnd)
256 {
257 /* Queue is empty, and no more tuples from index. We're done. */
258 return ExecClearTuple(slot);
259 }
260
261 /*
262 * Fetch next tuple from the index.
263 */
265 if (!index_getnext_slot(scandesc, ForwardScanDirection, slot))
266 {
267 /*
268 * No more tuples from the index. But we still need to drain any
269 * remaining tuples from the queue before we're done.
270 */
271 node->iss_ReachedEnd = true;
272 continue;
273 }
274
275 /*
276 * If the index was lossy, we have to recheck the index quals and
277 * ORDER BY expressions using the fetched tuple.
278 */
279 if (scandesc->xs_recheck)
280 {
281 econtext->ecxt_scantuple = slot;
282 if (!ExecQualAndReset(node->indexqualorig, econtext))
283 {
284 /* Fails recheck, so drop it and loop back for another */
285 InstrCountFiltered2(node, 1);
286 /* allow this loop to be cancellable */
288 goto next_indextuple;
289 }
290 }
291
292 if (scandesc->xs_recheckorderby)
293 {
294 econtext->ecxt_scantuple = slot;
295 ResetExprContext(econtext);
296 EvalOrderByExpressions(node, econtext);
297
298 /*
299 * Was the ORDER BY value returned by the index accurate? The
300 * recheck flag means that the index can return inaccurate values,
301 * but then again, the value returned for any particular tuple
302 * could also be exactly correct. Compare the value returned by
303 * the index with the recalculated value. (If the value returned
304 * by the index happened to be exact right, we can often avoid
305 * pushing the tuple to the queue, just to pop it back out again.)
306 */
308 node->iss_OrderByNulls,
309 scandesc->xs_orderbyvals,
310 scandesc->xs_orderbynulls,
311 node);
312 if (cmp < 0)
313 elog(ERROR, "index returned tuples in wrong order");
314 else if (cmp == 0)
315 was_exact = true;
316 else
317 was_exact = false;
320 }
321 else
322 {
323 was_exact = true;
326 }
327
328 /*
329 * Can we return this tuple immediately, or does it need to be pushed
330 * to the reorder queue? If the ORDER BY expression values returned
331 * by the index were inaccurate, we can't return it yet, because the
332 * next tuple from the index might need to come before this one. Also,
333 * we can't return it yet if there are any smaller tuples in the queue
334 * already.
335 */
338 topmost->orderbyvals,
339 topmost->orderbynulls,
340 node) > 0))
341 {
342 /* Put this tuple to the queue */
344 continue;
345 }
346 else
347 {
348 /* Can return this tuple immediately. */
349 return slot;
350 }
351 }
352
353 /*
354 * if we get here it means the index scan failed so we are at the end of
355 * the scan..
356 */
357 return ExecClearTuple(slot);
358}
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
static void reorderqueue_push(IndexScanState *node, TupleTableSlot *slot, const Datum *orderbyvals, const bool *orderbynulls)
static void EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
static int cmp_orderbyvals(const Datum *adist, const bool *anulls, const Datum *bdist, const bool *bnulls, IndexScanState *node)
pairingheap_node * pairingheap_first(pairingheap *heap)
static int cmp(const chr *x, const chr *y, size_t len)
#define ScanDirectionIsForward(direction)
Definition sdir.h:64
#define ScanDirectionIsBackward(direction)
Definition sdir.h:50
@ ForwardScanDirection
Definition sdir.h:28
bool * xs_orderbynulls
Definition relscan.h:188
bool xs_recheckorderby
Definition relscan.h:189
Datum * xs_orderbyvals
Definition relscan.h:187

References Assert, CHECK_FOR_INTERRUPTS, cmp(), cmp_orderbyvals(), ExprContext::ecxt_scantuple, elog, ERROR, EState::es_direction, EState::es_snapshot, EvalOrderByExpressions(), ExecClearTuple(), ExecForceStoreHeapTuple(), ExecQualAndReset(), fb(), ForwardScanDirection, index_beginscan(), index_getnext_slot(), index_rescan(), IndexScanState::indexqualorig, InstrCountFiltered2, IndexScanState::iss_Instrument, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_OrderByNulls, IndexScanState::iss_OrderByValues, IndexScanState::iss_ReachedEnd, IndexScanState::iss_RelationDesc, IndexScanState::iss_ReorderQueue, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, pairingheap_first(), pairingheap_is_empty, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, reorderqueue_pop(), reorderqueue_push(), ResetExprContext, ScanDirectionIsBackward, ScanDirectionIsForward, IndexScanState::ss, ScanState::ss_currentRelation, ScanState::ss_ScanTupleSlot, PlanState::state, IndexScanDescData::xs_orderbynulls, IndexScanDescData::xs_orderbyvals, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_recheckorderby.

Referenced by ExecIndexScan().

◆ IndexRecheck()

static bool IndexRecheck ( IndexScanState node,
TupleTableSlot slot 
)
static

Definition at line 390 of file nodeIndexscan.c.

391{
392 ExprContext *econtext;
393
394 /*
395 * extract necessary information from index scan node
396 */
397 econtext = node->ss.ps.ps_ExprContext;
398
399 /* Does the tuple meet the indexqual condition? */
400 econtext->ecxt_scantuple = slot;
401 return ExecQualAndReset(node->indexqualorig, econtext);
402}

References ExprContext::ecxt_scantuple, ExecQualAndReset(), IndexScanState::indexqualorig, ScanState::ps, PlanState::ps_ExprContext, and IndexScanState::ss.

Referenced by ExecIndexScan().

◆ reorderqueue_cmp()

static int reorderqueue_cmp ( const pairingheap_node a,
const pairingheap_node b,
void arg 
)
static

Definition at line 445 of file nodeIndexscan.c.

447{
448 const ReorderTuple *rta = (const ReorderTuple *) a;
449 const ReorderTuple *rtb = (const ReorderTuple *) b;
451
452 /* exchange argument order to invert the sort order */
453 return cmp_orderbyvals(rtb->orderbyvals, rtb->orderbynulls,
454 rta->orderbyvals, rta->orderbynulls,
455 node);
456}
int b
Definition isn.c:74
int a
Definition isn.c:73

References a, arg, b, cmp_orderbyvals(), and fb().

Referenced by ExecInitIndexScan().

◆ reorderqueue_pop()

static HeapTuple reorderqueue_pop ( IndexScanState node)
static

Definition at line 494 of file nodeIndexscan.c.

495{
496 HeapTuple result;
498 int i;
499
501
502 result = topmost->htup;
503 for (i = 0; i < node->iss_NumOrderByKeys; i++)
504 {
505 if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
506 pfree(DatumGetPointer(topmost->orderbyvals[i]));
507 }
508 pfree(topmost->orderbyvals);
509 pfree(topmost->orderbynulls);
510 pfree(topmost);
511
512 return result;
513}
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
bool * iss_OrderByTypByVals
Definition execnodes.h:1744

References DatumGetPointer(), fb(), i, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_OrderByTypByVals, IndexScanState::iss_ReorderQueue, pairingheap_remove_first(), and pfree().

Referenced by ExecReScanIndexScan(), and IndexNextWithReorder().

◆ reorderqueue_push()

static void reorderqueue_push ( IndexScanState node,
TupleTableSlot slot,
const Datum orderbyvals,
const bool orderbynulls 
)
static

Definition at line 462 of file nodeIndexscan.c.

464{
465 IndexScanDesc scandesc = node->iss_ScanDesc;
466 EState *estate = node->ss.ps.state;
469 int i;
470
472 rt->htup = ExecCopySlotHeapTuple(slot);
473 rt->orderbyvals = palloc_array(Datum, scandesc->numberOfOrderBys);
474 rt->orderbynulls = palloc_array(bool, scandesc->numberOfOrderBys);
475 for (i = 0; i < node->iss_NumOrderByKeys; i++)
476 {
477 if (!orderbynulls[i])
478 rt->orderbyvals[i] = datumCopy(orderbyvals[i],
479 node->iss_OrderByTypByVals[i],
480 node->iss_OrderByTypLens[i]);
481 else
482 rt->orderbyvals[i] = (Datum) 0;
483 rt->orderbynulls[i] = orderbynulls[i];
484 }
485 pairingheap_add(node->iss_ReorderQueue, &rt->ph_node);
486
488}
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
MemoryContext es_query_cxt
Definition execnodes.h:722
int16 * iss_OrderByTypLens
Definition execnodes.h:1745
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition tuptable.h:503

References datumCopy(), EState::es_query_cxt, ExecCopySlotHeapTuple(), fb(), i, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_OrderByTypByVals, IndexScanState::iss_OrderByTypLens, IndexScanState::iss_ReorderQueue, IndexScanState::iss_ScanDesc, MemoryContextSwitchTo(), IndexScanDescData::numberOfOrderBys, pairingheap_add(), palloc_array, palloc_object, ScanState::ps, IndexScanState::ss, and PlanState::state.

Referenced by IndexNextWithReorder().