PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
nodeIndexscan.h File Reference
#include "access/genam.h"
#include "access/parallel.h"
#include "nodes/execnodes.h"
Include dependency graph for nodeIndexscan.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

IndexScanStateExecInitIndexScan (IndexScan *node, EState *estate, int eflags)
 
void ExecEndIndexScan (IndexScanState *node)
 
void ExecIndexMarkPos (IndexScanState *node)
 
void ExecIndexRestrPos (IndexScanState *node)
 
void ExecReScanIndexScan (IndexScanState *node)
 
void ExecIndexScanEstimate (IndexScanState *node, ParallelContext *pcxt)
 
void ExecIndexScanInitializeDSM (IndexScanState *node, ParallelContext *pcxt)
 
void ExecIndexScanReInitializeDSM (IndexScanState *node, ParallelContext *pcxt)
 
void ExecIndexScanInitializeWorker (IndexScanState *node, ParallelWorkerContext *pwcxt)
 
void ExecIndexBuildScanKeys (PlanState *planstate, Relation index, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
 
void ExecIndexEvalRuntimeKeys (ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
 
bool ExecIndexEvalArrayKeys (ExprContext *econtext, IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 
bool ExecIndexAdvanceArrayKeys (IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 

Function Documentation

◆ ExecEndIndexScan()

void ExecEndIndexScan ( IndexScanState node)

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

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

Referenced by ExecEndNode().

◆ ExecIndexAdvanceArrayKeys()

bool ExecIndexAdvanceArrayKeys ( IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 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:73
uintptr_t Datum
Definition: postgres.h:64
#define SK_ISNULL
Definition: skey.h:115
Datum * elem_values
Definition: execnodes.h:1627
struct ScanKeyData * scan_key
Definition: execnodes.h:1623
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 1135 of file nodeIndexscan.c.

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

References arg, NullTest::arg, ScalarArrayOpExpr::args, IndexArrayKeyInfo::array_expr, Assert, BTORDER_PROC, elog, ERROR, ExecInitExpr(), forfour, get_leftop(), get_op_opfamily_properties(), get_opfamily_proc(), get_rightop(), INDEX_VAR, IndexRelationGetNumberOfKeyAttributes, InvalidOid, InvalidStrategy, IS_NOT_NULL, IS_NULL, IsA, j, IndexRuntimeKeyInfo::key_expr, IndexRuntimeKeyInfo::key_toastable, RowCompareExpr::largs, lfirst, lfirst_oid, linitial, list_length(), lsecond, MemSet, nodeTag, NullTest::nulltesttype, ScalarArrayOpExpr::opno, palloc(), palloc0(), pfree(), PointerGetDatum(), RowCompareExpr::rargs, RowCompareExpr::rctype, RegProcedureIsValid, repalloc(), IndexRuntimeKeyInfo::scan_key, IndexArrayKeyInfo::scan_key, ScanKeyEntryInitialize(), ScanKeyData::sk_argument, ScanKeyData::sk_attno, ScanKeyData::sk_flags, SK_ISNULL, SK_ORDER_BY, SK_ROW_END, SK_ROW_HEADER, SK_ROW_MEMBER, SK_SEARCHARRAY, SK_SEARCHNOTNULL, SK_SEARCHNULL, ScanKeyData::sk_strategy, TypeIsToastable, and ScalarArrayOpExpr::useOr.

Referenced by ExecInitBitmapIndexScan(), ExecInitIndexOnlyScan(), and ExecInitIndexScan().

◆ ExecIndexEvalArrayKeys()

bool ExecIndexEvalArrayKeys ( ExprContext econtext,
IndexArrayKeyInfo arrayKeys,
int  numArrayKeys 
)

Definition at line 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(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3631
int16_t int16
Definition: c.h:480
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:346
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2271
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:266

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

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

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

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

References Assert, elog, ERROR, EState::es_epq_active, index_restrpos(), IndexScanState::iss_ScanDesc, PlanState::plan, ScanState::ps, EPQState::relsubs_done, EPQState::relsubs_rowmark, EPQState::relsubs_slot, IndexScanState::ss, and PlanState::state.

Referenced by ExecRestrPos().

◆ ExecIndexScanEstimate()

void ExecIndexScanEstimate ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1641 of file nodeIndexscan.c.

1643{
1644 EState *estate = node->ss.ps.state;
1645
1647 node->iss_NumScanKeys,
1648 node->iss_NumOrderByKeys,
1649 estate->es_snapshot);
1652}
Size index_parallelscan_estimate(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot)
Definition: indexam.c:453
#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:632
int iss_NumOrderByKeys
Definition: execnodes.h:1665
shm_toc_estimator estimator
Definition: parallel.h:41

References EState::es_snapshot, ParallelContext::estimator, index_parallelscan_estimate(), IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_PscanLen, IndexScanState::iss_RelationDesc, ScanState::ps, shm_toc_estimate_chunk, shm_toc_estimate_keys, IndexScanState::ss, and PlanState::state.

Referenced by ExecParallelEstimate().

◆ ExecIndexScanInitializeDSM()

void ExecIndexScanInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1661 of file nodeIndexscan.c.

1663{
1664 EState *estate = node->ss.ps.state;
1665 ParallelIndexScanDesc piscan;
1666
1667 piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1669 node->iss_RelationDesc,
1670 estate->es_snapshot,
1671 piscan);
1672 shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
1673 node->iss_ScanDesc =
1675 node->iss_RelationDesc,
1676 node->iss_NumScanKeys,
1677 node->iss_NumOrderByKeys,
1678 piscan);
1679
1680 /*
1681 * If no run-time keys to calculate or they are ready, go ahead and pass
1682 * the scankeys to the index AM.
1683 */
1684 if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1686 node->iss_ScanKeys, node->iss_NumScanKeys,
1687 node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1688}
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:541
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:490
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:352
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
int iss_NumRuntimeKeys
Definition: execnodes.h:1667
bool iss_RuntimeKeysReady
Definition: execnodes.h:1668
struct ScanKeyData * iss_ScanKeys
Definition: execnodes.h:1662
struct ScanKeyData * iss_OrderByKeys
Definition: execnodes.h:1664
shm_toc * toc
Definition: parallel.h:44
int plan_node_id
Definition: plannodes.h:152
Relation ss_currentRelation
Definition: execnodes.h:1573

References EState::es_snapshot, index_beginscan_parallel(), index_parallelscan_initialize(), index_rescan(), IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_PscanLen, IndexScanState::iss_RelationDesc, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanDesc, IndexScanState::iss_ScanKeys, PlanState::plan, Plan::plan_node_id, ScanState::ps, shm_toc_allocate(), shm_toc_insert(), IndexScanState::ss, ScanState::ss_currentRelation, PlanState::state, and ParallelContext::toc.

Referenced by ExecParallelInitializeDSM().

◆ ExecIndexScanInitializeWorker()

void ExecIndexScanInitializeWorker ( IndexScanState node,
ParallelWorkerContext pwcxt 
)

Definition at line 1710 of file nodeIndexscan.c.

1712{
1713 ParallelIndexScanDesc piscan;
1714
1715 piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
1716 node->iss_ScanDesc =
1718 node->iss_RelationDesc,
1719 node->iss_NumScanKeys,
1720 node->iss_NumOrderByKeys,
1721 piscan);
1722
1723 /*
1724 * If no run-time keys to calculate or they are ready, go ahead and pass
1725 * the scankeys to the index AM.
1726 */
1727 if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
1729 node->iss_ScanKeys, node->iss_NumScanKeys,
1730 node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1731}
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

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

Referenced by ExecParallelInitializeWorker().

◆ ExecIndexScanReInitializeDSM()

void ExecIndexScanReInitializeDSM ( IndexScanState node,
ParallelContext pcxt 
)

Definition at line 1697 of file nodeIndexscan.c.

1699{
1701}
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:523

References index_parallelrescan(), and IndexScanState::iss_ScanDesc.

Referenced by ExecParallelReInitializeDSM().

◆ ExecInitIndexScan()

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

Definition at line 886 of file nodeIndexscan.c.

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

References SortSupportData::abbreviate, Assert, CurrentMemoryContext, EXEC_FLAG_EXPLAIN_ONLY, exec_rt_fetch(), ExecAssignExprContext(), ExecAssignScanProjectionInfo(), ExecIndexBuildScanKeys(), ExecIndexScan(), ExecInitExprList(), ExecInitQual(), ExecInitResultTypeTL(), ExecInitScanTupleSlot(), ExecOpenScanRelation(), PlanState::ExecProcNode, exprCollation(), exprType(), forboth, get_typlenbyval(), i, index_open(), IndexScan::indexid, IndexScan::indexorderby, IndexScan::indexorderbyops, IndexScanState::indexorderbyorig, IndexScan::indexorderbyorig, IndexScan::indexqual, IndexScanState::indexqualorig, IndexScan::indexqualorig, IndexScanState::iss_NumOrderByKeys, IndexScanState::iss_NumRuntimeKeys, IndexScanState::iss_NumScanKeys, IndexScanState::iss_OrderByKeys, IndexScanState::iss_OrderByNulls, IndexScanState::iss_OrderByTypByVals, IndexScanState::iss_OrderByTypLens, IndexScanState::iss_OrderByValues, IndexScanState::iss_RelationDesc, IndexScanState::iss_ReorderQueue, IndexScanState::iss_RuntimeContext, IndexScanState::iss_RuntimeKeys, IndexScanState::iss_RuntimeKeysReady, IndexScanState::iss_ScanKeys, IndexScanState::iss_SortSupport, lfirst, lfirst_oid, list_length(), makeNode, pairingheap_allocate(), palloc(), palloc0(), PlanState::plan, PrepareSortSupportFromOrderingOp(), ScanState::ps, PlanState::ps_ExprContext, PlanState::qual, RelationGetDescr, 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:297
#define ResetExprContext(econtext)
Definition: executor.h:557
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
static HeapTuple reorderqueue_pop(IndexScanState *node)
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
bool iss_ReachedEnd
Definition: execnodes.h:1675

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