PostgreSQL Source Code git master
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/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 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 407 of file nodeIndexscan.c.

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

References SortSupportData::comparator, 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 362 of file nodeIndexscan.c.

363{
364 int i;
365 ListCell *l;
366 MemoryContext oldContext;
367
368 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
369
370 i = 0;
371 foreach(l, node->indexorderbyorig)
372 {
373 ExprState *orderby = (ExprState *) lfirst(l);
374
375 node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
376 econtext,
377 &node->iss_OrderByNulls[i]);
378 i++;
379 }
380
381 MemoryContextSwitchTo(oldContext);
382}
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:393
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:281
List * indexorderbyorig
Definition: execnodes.h:1712
bool * iss_OrderByNulls
Definition: execnodes.h:1730
Datum * iss_OrderByValues
Definition: execnodes.h:1729

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

Referenced by IndexNextWithReorder().

◆ ExecEndIndexScan()

void ExecEndIndexScan ( IndexScanState node)

Definition at line 785 of file nodeIndexscan.c.

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

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

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

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

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

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

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

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

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

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

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

◆ ExecIndexScan()

static TupleTableSlot * ExecIndexScan ( PlanState pstate)
static

Definition at line 519 of file nodeIndexscan.c.

520{
521 IndexScanState *node = castNode(IndexScanState, pstate);
522
523 /*
524 * If we have runtime keys and they've not already been set up, do it now.
525 */
526 if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
527 ExecReScan((PlanState *) node);
528
529 if (node->iss_NumOrderByKeys > 0)
530 return ExecScan(&node->ss,
533 else
534 return ExecScan(&node->ss,
537}
void ExecReScan(PlanState *node)
Definition: execAmi.c:77
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:47
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:580
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:579
static TupleTableSlot * IndexNextWithReorder(IndexScanState *node)
static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
static TupleTableSlot * IndexNext(IndexScanState *node)
Definition: nodeIndexscan.c:80
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
int iss_NumRuntimeKeys
Definition: execnodes.h:1718
bool iss_RuntimeKeysReady
Definition: execnodes.h:1719

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

1664{
1665 EState *estate = node->ss.ps.state;
1666 bool instrument = node->ss.ps.instrument != NULL;
1667 bool parallel_aware = node->ss.ps.plan->parallel_aware;
1668
1669 if (!instrument && !parallel_aware)
1670 {
1671 /* No DSM required by the scan */
1672 return;
1673 }
1674
1676 node->iss_NumScanKeys,
1677 node->iss_NumOrderByKeys,
1678 estate->es_snapshot,
1679 instrument, parallel_aware,
1680 pcxt->nworkers);
1683}
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:660
shm_toc_estimator estimator
Definition: parallel.h:41
Instrumentation * instrument
Definition: execnodes.h:1175
bool parallel_aware
Definition: plannodes.h:213

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

1694{
1695 EState *estate = node->ss.ps.state;
1696 ParallelIndexScanDesc piscan;
1697 bool instrument = node->ss.ps.instrument != NULL;
1698 bool parallel_aware = node->ss.ps.plan->parallel_aware;
1699
1700 if (!instrument && !parallel_aware)
1701 {
1702 /* No DSM required by the scan */
1703 return;
1704 }
1705
1706 piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1708 node->iss_RelationDesc,
1709 estate->es_snapshot,
1710 instrument, parallel_aware, pcxt->nworkers,
1711 &node->iss_SharedInfo, piscan);
1712 shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1713
1714 if (!parallel_aware)
1715 {
1716 /* Only here to initialize SharedInfo in DSM */
1717 return;
1718 }
1719
1720 node->iss_ScanDesc =
1722 node->iss_RelationDesc,
1723 &node->iss_Instrument,
1724 node->iss_NumScanKeys,
1725 node->iss_NumOrderByKeys,
1726 piscan);
1727
1728 /*
1729 * If no run-time keys to calculate or they are ready, go ahead and pass
1730 * the scankeys to the index AM.
1731 */
1732 if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1734 node->iss_ScanKeys, node->iss_NumScanKeys,
1735 node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1736}
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:1713
ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1715
shm_toc * toc
Definition: parallel.h:44
int plan_node_id
Definition: plannodes.h:227
Relation ss_currentRelation
Definition: execnodes.h:1622

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

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

1747{
1748 Assert(node->ss.ps.plan->parallel_aware);
1750}
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 1809 of file nodeIndexscan.c.

1810{
1812 size_t size;
1813
1814 if (SharedInfo == NULL)
1815 return;
1816
1817 /* Create a copy of SharedInfo in backend-local memory */
1818 size = offsetof(SharedIndexScanInstrumentation, winstrument) +
1819 SharedInfo->num_workers * sizeof(IndexScanInstrumentation);
1820 node->iss_SharedInfo = palloc(size);
1821 memcpy(node->iss_SharedInfo, SharedInfo, size);
1822}
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 907 of file nodeIndexscan.c.

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

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

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

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

References CHECK_FOR_INTERRUPTS, ExprContext::ecxt_scantuple, EState::es_direction, EState::es_snapshot, ExecClearTuple(), ExecQualAndReset(), 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 169 of file nodeIndexscan.c.

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

References Assert(), CHECK_FOR_INTERRUPTS, cmp(), cmp_orderbyvals(), ExprContext::ecxt_scantuple, elog, ERROR, EState::es_direction, EState::es_snapshot, EvalOrderByExpressions(), ExecClearTuple(), ExecForceStoreHeapTuple(), ExecQualAndReset(), 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, ReorderTuple::orderbynulls, ReorderTuple::orderbyvals, 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 388 of file nodeIndexscan.c.

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

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

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

References a, arg, b, cmp_orderbyvals(), ReorderTuple::orderbynulls, and ReorderTuple::orderbyvals.

Referenced by ExecInitIndexScan().

◆ reorderqueue_pop()

static HeapTuple reorderqueue_pop ( IndexScanState node)
static

Definition at line 492 of file nodeIndexscan.c.

493{
494 HeapTuple result;
495 ReorderTuple *topmost;
496 int i;
497
499
500 result = topmost->htup;
501 for (i = 0; i < node->iss_NumOrderByKeys; i++)
502 {
503 if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
505 }
506 pfree(topmost->orderbyvals);
507 pfree(topmost->orderbynulls);
508 pfree(topmost);
509
510 return result;
511}
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:159
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
HeapTuple htup
Definition: nodeIndexscan.c:53

References DatumGetPointer(), ReorderTuple::htup, i, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_OrderByTypByVals, IndexScanState::iss_ReorderQueue, ReorderTuple::orderbynulls, ReorderTuple::orderbyvals, 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 460 of file nodeIndexscan.c.

462{
463 IndexScanDesc scandesc = node->iss_ScanDesc;
464 EState *estate = node->ss.ps.state;
466 ReorderTuple *rt;
467 int i;
468
470 rt->htup = ExecCopySlotHeapTuple(slot);
472 rt->orderbynulls = palloc_array(bool, scandesc->numberOfOrderBys);
473 for (i = 0; i < node->iss_NumOrderByKeys; i++)
474 {
475 if (!orderbynulls[i])
476 rt->orderbyvals[i] = datumCopy(orderbyvals[i],
477 node->iss_OrderByTypByVals[i],
478 node->iss_OrderByTypLens[i]);
479 else
480 rt->orderbyvals[i] = (Datum) 0;
481 rt->orderbynulls[i] = orderbynulls[i];
482 }
484
485 MemoryContextSwitchTo(oldContext);
486}
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)
Definition: pairingheap.c:126
MemoryContext es_query_cxt
Definition: execnodes.h:710
int numberOfOrderBys
Definition: relscan.h:142
pairingheap_node ph_node
Definition: nodeIndexscan.c:52
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition: tuptable.h:484

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

Referenced by IndexNextWithReorder().