1 /*-------------------------------------------------------------------------
4 * Routines to support indexed scans of relations
6 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.121 2007/04/06 22:33:42 tgl Exp $
13 *-------------------------------------------------------------------------
17 * ExecIndexScan scans a relation using indices
18 * ExecIndexNext using index to retrieve next tuple
19 * ExecInitIndexScan creates and initializes state info.
20 * ExecIndexReScan rescans the indexed relation.
21 * ExecEndIndexScan releases all storage.
22 * ExecIndexMarkPos marks scan position.
23 * ExecIndexRestrPos restores scan position.
27 #include "access/genam.h"
28 #include "access/nbtree.h"
29 #include "executor/execdebug.h"
30 #include "executor/nodeIndexscan.h"
31 #include "nodes/nodeFuncs.h"
32 #include "optimizer/clauses.h"
33 #include "utils/array.h"
34 #include "utils/lsyscache.h"
35 #include "utils/memutils.h"
38 static TupleTableSlot *IndexNext(IndexScanState *node);
41 /* ----------------------------------------------------------------
44 * Retrieve a tuple from the IndexScan node's currentRelation
45 * using the index specified in the IndexScanState information.
46 * ----------------------------------------------------------------
48 static TupleTableSlot *
49 IndexNext(IndexScanState *node)
52 ExprContext *econtext;
53 ScanDirection direction;
54 IndexScanDesc scandesc;
60 * extract necessary information from index scan node
62 estate = node->ss.ps.state;
63 direction = estate->es_direction;
64 /* flip direction if this is an overall backward scan */
65 if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
67 if (ScanDirectionIsForward(direction))
68 direction = BackwardScanDirection;
69 else if (ScanDirectionIsBackward(direction))
70 direction = ForwardScanDirection;
72 scandesc = node->iss_ScanDesc;
73 econtext = node->ss.ps.ps_ExprContext;
74 slot = node->ss.ss_ScanTupleSlot;
75 scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
78 * Check if we are evaluating PlanQual for tuple of this relation.
79 * Additional checking is not good, but no other way for now. We could
80 * introduce new nodes for this case and handle IndexScan --> NewNode
81 * switching in Init/ReScan plan...
83 if (estate->es_evTuple != NULL &&
84 estate->es_evTuple[scanrelid - 1] != NULL)
86 if (estate->es_evTupleNull[scanrelid - 1])
87 return ExecClearTuple(slot);
89 ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
90 slot, InvalidBuffer, false);
92 /* Does the tuple meet the indexqual condition? */
93 econtext->ecxt_scantuple = slot;
95 ResetExprContext(econtext);
97 if (!ExecQual(node->indexqualorig, econtext, false))
98 ExecClearTuple(slot); /* would not be returned by scan */
100 /* Flag for the next call that no more tuples */
101 estate->es_evTupleNull[scanrelid - 1] = true;
107 * ok, now that we have what we need, fetch the next tuple.
109 if ((tuple = index_getnext(scandesc, direction)) != NULL)
112 * Store the scanned tuple in the scan tuple slot of the scan state.
113 * Note: we pass 'false' because tuples returned by amgetnext are
114 * pointers onto disk pages and must not be pfree()'d.
116 ExecStoreTuple(tuple, /* tuple to store */
117 slot, /* slot to store in */
118 scandesc->xs_cbuf, /* buffer containing tuple */
119 false); /* don't pfree */
125 * if we get here it means the index scan failed so we are at the end of
128 return ExecClearTuple(slot);
131 /* ----------------------------------------------------------------
132 * ExecIndexScan(node)
133 * ----------------------------------------------------------------
136 ExecIndexScan(IndexScanState *node)
139 * If we have runtime keys and they've not already been set up, do it now.
141 if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
142 ExecReScan((PlanState *) node, NULL);
145 * use IndexNext as access method
147 return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
150 /* ----------------------------------------------------------------
151 * ExecIndexReScan(node)
153 * Recalculates the value of the scan keys whose value depends on
154 * information known at runtime and rescans the indexed relation.
155 * Updating the scan key was formerly done separately in
156 * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
157 * rescans of indices and relations/general streams more uniform.
158 * ----------------------------------------------------------------
161 ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
164 ExprContext *econtext;
167 estate = node->ss.ps.state;
168 econtext = node->iss_RuntimeContext; /* context for runtime keys */
169 scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
171 node->ss.ps.ps_TupFromTlist = false;
176 * If we are being passed an outer tuple, save it for runtime key
177 * calc. We also need to link it into the "regular" per-tuple
178 * econtext, so it can be used during indexqualorig evaluations.
180 if (exprCtxt != NULL)
182 ExprContext *stdecontext;
184 econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
185 stdecontext = node->ss.ps.ps_ExprContext;
186 stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
190 * Reset the runtime-key context so we don't leak memory as each outer
191 * tuple is scanned. Note this assumes that we will recalculate *all*
192 * runtime keys on each call.
194 ResetExprContext(econtext);
198 * If we are doing runtime key calculations (ie, the index keys depend on
199 * data from an outer scan), compute the new key values
201 if (node->iss_NumRuntimeKeys != 0)
202 ExecIndexEvalRuntimeKeys(econtext,
203 node->iss_RuntimeKeys,
204 node->iss_NumRuntimeKeys);
205 node->iss_RuntimeKeysReady = true;
207 /* If this is re-scanning of PlanQual ... */
208 if (estate->es_evTuple != NULL &&
209 estate->es_evTuple[scanrelid - 1] != NULL)
211 estate->es_evTupleNull[scanrelid - 1] = false;
215 /* reset index scan */
216 index_rescan(node->iss_ScanDesc, node->iss_ScanKeys);
221 * ExecIndexEvalRuntimeKeys
222 * Evaluate any runtime key values, and update the scankeys.
225 ExecIndexEvalRuntimeKeys(ExprContext *econtext,
226 IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
230 for (j = 0; j < numRuntimeKeys; j++)
232 ScanKey scan_key = runtimeKeys[j].scan_key;
233 ExprState *key_expr = runtimeKeys[j].key_expr;
238 * For each run-time key, extract the run-time expression and evaluate
239 * it with respect to the current outer tuple. We then stick the
240 * result into the proper scan key.
242 * Note: the result of the eval could be a pass-by-ref value that's
243 * stored in the outer scan's tuple, not in
244 * econtext->ecxt_per_tuple_memory. We assume that the outer tuple
245 * will stay put throughout our scan. If this is wrong, we could copy
246 * the result into our context explicitly, but I think that's not
249 scanvalue = ExecEvalExprSwitchContext(key_expr,
253 scan_key->sk_argument = scanvalue;
255 scan_key->sk_flags |= SK_ISNULL;
257 scan_key->sk_flags &= ~SK_ISNULL;
262 * ExecIndexEvalArrayKeys
263 * Evaluate any array key values, and set up to iterate through arrays.
265 * Returns TRUE if there are array elements to consider; FALSE means there
266 * is at least one null or empty array, so no match is possible. On TRUE
267 * result, the scankeys are initialized with the first elements of the arrays.
270 ExecIndexEvalArrayKeys(ExprContext *econtext,
271 IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
275 MemoryContext oldContext;
277 /* We want to keep the arrays in per-tuple memory */
278 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
280 for (j = 0; j < numArrayKeys; j++)
282 ScanKey scan_key = arrayKeys[j].scan_key;
283 ExprState *array_expr = arrayKeys[j].array_expr;
295 * Compute and deconstruct the array expression. (Notes in
296 * ExecIndexEvalRuntimeKeys() apply here too.)
298 arraydatum = ExecEvalExpr(array_expr,
305 break; /* no point in evaluating more */
307 arrayval = DatumGetArrayTypeP(arraydatum);
308 /* We could cache this data, but not clear it's worth it */
309 get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
310 &elmlen, &elmbyval, &elmalign);
311 deconstruct_array(arrayval,
312 ARR_ELEMTYPE(arrayval),
313 elmlen, elmbyval, elmalign,
314 &elem_values, &elem_nulls, &num_elems);
318 break; /* no point in evaluating more */
322 * Note: we expect the previous array data, if any, to be
323 * automatically freed by resetting the per-tuple context; hence no
326 arrayKeys[j].elem_values = elem_values;
327 arrayKeys[j].elem_nulls = elem_nulls;
328 arrayKeys[j].num_elems = num_elems;
329 scan_key->sk_argument = elem_values[0];
331 scan_key->sk_flags |= SK_ISNULL;
333 scan_key->sk_flags &= ~SK_ISNULL;
334 arrayKeys[j].next_elem = 1;
337 MemoryContextSwitchTo(oldContext);
343 * ExecIndexAdvanceArrayKeys
344 * Advance to the next set of array key values, if any.
346 * Returns TRUE if there is another set of values to consider, FALSE if not.
347 * On TRUE result, the scankeys are initialized with the next set of values.
350 ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
355 for (j = 0; j < numArrayKeys; j++)
357 ScanKey scan_key = arrayKeys[j].scan_key;
358 int next_elem = arrayKeys[j].next_elem;
359 int num_elems = arrayKeys[j].num_elems;
360 Datum *elem_values = arrayKeys[j].elem_values;
361 bool *elem_nulls = arrayKeys[j].elem_nulls;
363 if (next_elem >= num_elems)
366 found = false; /* need to advance next array key */
370 scan_key->sk_argument = elem_values[next_elem];
371 if (elem_nulls[next_elem])
372 scan_key->sk_flags |= SK_ISNULL;
374 scan_key->sk_flags &= ~SK_ISNULL;
375 arrayKeys[j].next_elem = next_elem + 1;
384 /* ----------------------------------------------------------------
386 * ----------------------------------------------------------------
389 ExecEndIndexScan(IndexScanState *node)
391 Relation indexRelationDesc;
392 IndexScanDesc indexScanDesc;
396 * extract information from the node
398 indexRelationDesc = node->iss_RelationDesc;
399 indexScanDesc = node->iss_ScanDesc;
400 relation = node->ss.ss_currentRelation;
403 * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
406 ExecFreeExprContext(&node->ss.ps);
407 if (node->iss_RuntimeContext)
408 FreeExprContext(node->iss_RuntimeContext);
412 * clear out tuple table slots
414 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
415 ExecClearTuple(node->ss.ss_ScanTupleSlot);
418 * close the index relation
420 index_endscan(indexScanDesc);
421 index_close(indexRelationDesc, NoLock);
424 * close the heap relation.
426 ExecCloseScanRelation(relation);
429 /* ----------------------------------------------------------------
431 * ----------------------------------------------------------------
434 ExecIndexMarkPos(IndexScanState *node)
436 index_markpos(node->iss_ScanDesc);
439 /* ----------------------------------------------------------------
441 * ----------------------------------------------------------------
444 ExecIndexRestrPos(IndexScanState *node)
446 index_restrpos(node->iss_ScanDesc);
449 /* ----------------------------------------------------------------
452 * Initializes the index scan's state information, creates
453 * scan keys, and opens the base and index relations.
455 * Note: index scans have 2 sets of state information because
456 * we have to keep track of the base relation and the
458 * ----------------------------------------------------------------
461 ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
463 IndexScanState *indexstate;
464 Relation currentRelation;
468 * create state structure
470 indexstate = makeNode(IndexScanState);
471 indexstate->ss.ps.plan = (Plan *) node;
472 indexstate->ss.ps.state = estate;
475 * Miscellaneous initialization
477 * create expression context for node
479 ExecAssignExprContext(estate, &indexstate->ss.ps);
481 indexstate->ss.ps.ps_TupFromTlist = false;
484 * initialize child expressions
486 * Note: we don't initialize all of the indexqual expression, only the
487 * sub-parts corresponding to runtime keys (see below). The indexqualorig
488 * expression is always initialized even though it will only be used in
489 * some uncommon cases --- would be nice to improve that. (Problem is
490 * that any SubPlans present in the expression must be found now...)
492 indexstate->ss.ps.targetlist = (List *)
493 ExecInitExpr((Expr *) node->scan.plan.targetlist,
494 (PlanState *) indexstate);
495 indexstate->ss.ps.qual = (List *)
496 ExecInitExpr((Expr *) node->scan.plan.qual,
497 (PlanState *) indexstate);
498 indexstate->indexqualorig = (List *)
499 ExecInitExpr((Expr *) node->indexqualorig,
500 (PlanState *) indexstate);
502 #define INDEXSCAN_NSLOTS 2
505 * tuple table initialization
507 ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
508 ExecInitScanTupleSlot(estate, &indexstate->ss);
511 * open the base relation and acquire appropriate lock on it.
513 currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
515 indexstate->ss.ss_currentRelation = currentRelation;
516 indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
519 * get the scan type from the relation descriptor.
521 ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation));
524 * Open the index relation.
526 * If the parent table is one of the target relations of the query, then
527 * InitPlan already opened and write-locked the index, so we can avoid
528 * taking another lock here. Otherwise we need a normal reader's lock.
530 relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
531 indexstate->iss_RelationDesc = index_open(node->indexid,
532 relistarget ? NoLock : AccessShareLock);
535 * Initialize index-specific scan state
537 indexstate->iss_RuntimeKeysReady = false;
540 * build the index scan keys from the index qualification
542 ExecIndexBuildScanKeys((PlanState *) indexstate,
543 indexstate->iss_RelationDesc,
547 &indexstate->iss_ScanKeys,
548 &indexstate->iss_NumScanKeys,
549 &indexstate->iss_RuntimeKeys,
550 &indexstate->iss_NumRuntimeKeys,
551 NULL, /* no ArrayKeys */
555 * If we have runtime keys, we need an ExprContext to evaluate them. The
556 * node's standard context won't do because we want to reset that context
557 * for every tuple. So, build another context just like the other one...
560 if (indexstate->iss_NumRuntimeKeys != 0)
562 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
564 ExecAssignExprContext(estate, &indexstate->ss.ps);
565 indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
566 indexstate->ss.ps.ps_ExprContext = stdecontext;
570 indexstate->iss_RuntimeContext = NULL;
574 * Initialize scan descriptor.
576 indexstate->iss_ScanDesc = index_beginscan(currentRelation,
577 indexstate->iss_RelationDesc,
579 indexstate->iss_NumScanKeys,
580 indexstate->iss_ScanKeys);
583 * Initialize result tuple type and projection info.
585 ExecAssignResultTypeFromTL(&indexstate->ss.ps);
586 ExecAssignScanProjectionInfo(&indexstate->ss);
596 * ExecIndexBuildScanKeys
597 * Build the index scan keys from the index qualification expressions
599 * The index quals are passed to the index AM in the form of a ScanKey array.
600 * This routine sets up the ScanKeys, fills in all constant fields of the
601 * ScanKeys, and prepares information about the keys that have non-constant
602 * comparison values. We divide index qual expressions into five types:
604 * 1. Simple operator with constant comparison value ("indexkey op constant").
605 * For these, we just fill in a ScanKey containing the constant value.
607 * 2. Simple operator with non-constant value ("indexkey op expression").
608 * For these, we create a ScanKey with everything filled in except the
609 * expression value, and set up an IndexRuntimeKeyInfo struct to drive
610 * evaluation of the expression at the right times.
612 * 3. RowCompareExpr ("(indexkey, indexkey, ...) op (expr, expr, ...)").
613 * For these, we create a header ScanKey plus a subsidiary ScanKey array,
614 * as specified in access/skey.h. The elements of the row comparison
615 * can have either constant or non-constant comparison values.
617 * 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)"). For these,
618 * we create a ScanKey with everything filled in except the comparison value,
619 * and set up an IndexArrayKeyInfo struct to drive processing of the qual.
620 * (Note that we treat all array-expressions as requiring runtime evaluation,
621 * even if they happen to be constants.)
623 * 5. NullTest ("indexkey IS NULL"). We just fill in the ScanKey properly.
627 * planstate: executor state node we are working for
628 * index: the index we are building scan keys for
629 * quals: indexquals expressions
630 * strategies: associated operator strategy numbers
631 * subtypes: associated operator subtype OIDs
633 * (Any elements of the strategies and subtypes lists that correspond to
634 * RowCompareExpr quals are not used here; instead we look up the info
639 * *scanKeys: receives ptr to array of ScanKeys
640 * *numScanKeys: receives number of scankeys
641 * *runtimeKeys: receives ptr to array of IndexRuntimeKeyInfos, or NULL if none
642 * *numRuntimeKeys: receives number of runtime keys
643 * *arrayKeys: receives ptr to array of IndexArrayKeyInfos, or NULL if none
644 * *numArrayKeys: receives number of array keys
646 * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
647 * ScalarArrayOpExpr quals are not supported.
650 ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
651 List *quals, List *strategies, List *subtypes,
652 ScanKey *scanKeys, int *numScanKeys,
653 IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys,
654 IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
657 ListCell *strategy_cell;
658 ListCell *subtype_cell;
660 IndexRuntimeKeyInfo *runtime_keys;
661 IndexArrayKeyInfo *array_keys;
669 * If there are any RowCompareExpr quals, we need extra ScanKey entries
670 * for them, and possibly extra runtime-key entries. Count up what's
671 * needed. (The subsidiary ScanKey arrays for the RowCompareExprs could
672 * be allocated as separate chunks, but we have to count anyway to make
673 * runtime_keys large enough, so might as well just do one palloc.)
675 n_scan_keys = list_length(quals);
677 foreach(qual_cell, quals)
679 if (IsA(lfirst(qual_cell), RowCompareExpr))
681 list_length(((RowCompareExpr *) lfirst(qual_cell))->opnos);
683 scan_keys = (ScanKey)
684 palloc((n_scan_keys + extra_scan_keys) * sizeof(ScanKeyData));
685 /* Allocate these arrays as large as they could possibly need to be */
686 runtime_keys = (IndexRuntimeKeyInfo *)
687 palloc((n_scan_keys + extra_scan_keys) * sizeof(IndexRuntimeKeyInfo));
688 array_keys = (IndexArrayKeyInfo *)
689 palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo));
694 * Below here, extra_scan_keys is index of first cell to use for next
697 extra_scan_keys = n_scan_keys;
700 * for each opclause in the given qual, convert each qual's opclause into
703 qual_cell = list_head(quals);
704 strategy_cell = list_head(strategies);
705 subtype_cell = list_head(subtypes);
707 for (j = 0; j < n_scan_keys; j++)
709 ScanKey this_scan_key = &scan_keys[j];
710 Expr *clause; /* one clause of index qual */
711 RegProcedure opfuncid; /* operator proc id used in scan */
712 StrategyNumber strategy; /* op's strategy number */
713 Oid subtype; /* op's strategy subtype */
714 Expr *leftop; /* expr on lhs of operator */
715 Expr *rightop; /* expr on rhs ... */
716 AttrNumber varattno; /* att number used in scan */
719 * extract clause information from the qualification
721 clause = (Expr *) lfirst(qual_cell);
722 qual_cell = lnext(qual_cell);
723 strategy = lfirst_int(strategy_cell);
724 strategy_cell = lnext(strategy_cell);
725 subtype = lfirst_oid(subtype_cell);
726 subtype_cell = lnext(subtype_cell);
728 if (IsA(clause, OpExpr))
730 /* indexkey op const or indexkey op expression */
734 opfuncid = ((OpExpr *) clause)->opfuncid;
737 * leftop should be the index key Var, possibly relabeled
739 leftop = (Expr *) get_leftop(clause);
741 if (leftop && IsA(leftop, RelabelType))
742 leftop = ((RelabelType *) leftop)->arg;
744 Assert(leftop != NULL);
746 if (!(IsA(leftop, Var) &&
747 var_is_rel((Var *) leftop)))
748 elog(ERROR, "indexqual doesn't have key on left side");
750 varattno = ((Var *) leftop)->varattno;
753 * rightop is the constant or variable comparison value
755 rightop = (Expr *) get_rightop(clause);
757 if (rightop && IsA(rightop, RelabelType))
758 rightop = ((RelabelType *) rightop)->arg;
760 Assert(rightop != NULL);
762 if (IsA(rightop, Const))
764 /* OK, simple constant comparison value */
765 scanvalue = ((Const *) rightop)->constvalue;
766 if (((Const *) rightop)->constisnull)
771 /* Need to treat this one as a runtime key */
772 runtime_keys[n_runtime_keys].scan_key = this_scan_key;
773 runtime_keys[n_runtime_keys].key_expr =
774 ExecInitExpr(rightop, planstate);
776 scanvalue = (Datum) 0;
780 * initialize the scan key's fields appropriately
782 ScanKeyEntryInitialize(this_scan_key,
784 varattno, /* attribute number to scan */
785 strategy, /* op's strategy */
786 subtype, /* strategy subtype */
787 opfuncid, /* reg proc to use */
788 scanvalue); /* constant */
790 else if (IsA(clause, RowCompareExpr))
792 /* (indexkey, indexkey, ...) op (expression, expression, ...) */
793 RowCompareExpr *rc = (RowCompareExpr *) clause;
794 ListCell *largs_cell = list_head(rc->largs);
795 ListCell *rargs_cell = list_head(rc->rargs);
796 ListCell *opnos_cell = list_head(rc->opnos);
797 ScanKey first_sub_key = &scan_keys[extra_scan_keys];
799 /* Scan RowCompare columns and generate subsidiary ScanKey items */
800 while (opnos_cell != NULL)
802 ScanKey this_sub_key = &scan_keys[extra_scan_keys];
803 int flags = SK_ROW_MEMBER;
813 * leftop should be the index key Var, possibly relabeled
815 leftop = (Expr *) lfirst(largs_cell);
816 largs_cell = lnext(largs_cell);
818 if (leftop && IsA(leftop, RelabelType))
819 leftop = ((RelabelType *) leftop)->arg;
821 Assert(leftop != NULL);
823 if (!(IsA(leftop, Var) &&
824 var_is_rel((Var *) leftop)))
825 elog(ERROR, "indexqual doesn't have key on left side");
827 varattno = ((Var *) leftop)->varattno;
830 * rightop is the constant or variable comparison value
832 rightop = (Expr *) lfirst(rargs_cell);
833 rargs_cell = lnext(rargs_cell);
835 if (rightop && IsA(rightop, RelabelType))
836 rightop = ((RelabelType *) rightop)->arg;
838 Assert(rightop != NULL);
840 if (IsA(rightop, Const))
842 /* OK, simple constant comparison value */
843 scanvalue = ((Const *) rightop)->constvalue;
844 if (((Const *) rightop)->constisnull)
849 /* Need to treat this one as a runtime key */
850 runtime_keys[n_runtime_keys].scan_key = this_sub_key;
851 runtime_keys[n_runtime_keys].key_expr =
852 ExecInitExpr(rightop, planstate);
854 scanvalue = (Datum) 0;
858 * We have to look up the operator's associated btree support
861 opno = lfirst_oid(opnos_cell);
862 opnos_cell = lnext(opnos_cell);
864 if (index->rd_rel->relam != BTREE_AM_OID ||
865 varattno < 1 || varattno > index->rd_index->indnatts)
866 elog(ERROR, "bogus RowCompare index qualification");
867 opfamily = index->rd_opfamily[varattno - 1];
869 get_op_opfamily_properties(opno, opfamily,
875 if (op_strategy != rc->rctype)
876 elog(ERROR, "RowCompare index qualification contains wrong operator");
878 opfuncid = get_opfamily_proc(opfamily,
884 * initialize the subsidiary scan key's fields appropriately
886 ScanKeyEntryInitialize(this_sub_key,
888 varattno, /* attribute number */
889 op_strategy, /* op's strategy */
890 op_righttype, /* strategy subtype */
891 opfuncid, /* reg proc to use */
892 scanvalue); /* constant */
896 /* Mark the last subsidiary scankey correctly */
897 scan_keys[extra_scan_keys - 1].sk_flags |= SK_ROW_END;
900 * We don't use ScanKeyEntryInitialize for the header because it
901 * isn't going to contain a valid sk_func pointer.
903 MemSet(this_scan_key, 0, sizeof(ScanKeyData));
904 this_scan_key->sk_flags = SK_ROW_HEADER;
905 this_scan_key->sk_attno = first_sub_key->sk_attno;
906 this_scan_key->sk_strategy = rc->rctype;
907 /* sk_subtype, sk_func not used in a header */
908 this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
910 else if (IsA(clause, ScalarArrayOpExpr))
912 /* indexkey op ANY (array-expression) */
913 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
916 opfuncid = saop->opfuncid;
919 * leftop should be the index key Var, possibly relabeled
921 leftop = (Expr *) linitial(saop->args);
923 if (leftop && IsA(leftop, RelabelType))
924 leftop = ((RelabelType *) leftop)->arg;
926 Assert(leftop != NULL);
928 if (!(IsA(leftop, Var) &&
929 var_is_rel((Var *) leftop)))
930 elog(ERROR, "indexqual doesn't have key on left side");
932 varattno = ((Var *) leftop)->varattno;
935 * rightop is the constant or variable array value
937 rightop = (Expr *) lsecond(saop->args);
939 if (rightop && IsA(rightop, RelabelType))
940 rightop = ((RelabelType *) rightop)->arg;
942 Assert(rightop != NULL);
944 array_keys[n_array_keys].scan_key = this_scan_key;
945 array_keys[n_array_keys].array_expr =
946 ExecInitExpr(rightop, planstate);
947 /* the remaining fields were zeroed by palloc0 */
951 * initialize the scan key's fields appropriately
953 ScanKeyEntryInitialize(this_scan_key,
955 varattno, /* attribute number to scan */
956 strategy, /* op's strategy */
957 subtype, /* strategy subtype */
958 opfuncid, /* reg proc to use */
959 (Datum) 0); /* constant */
961 else if (IsA(clause, NullTest))
963 /* indexkey IS NULL */
964 Assert(((NullTest *) clause)->nulltesttype == IS_NULL);
967 * argument should be the index key Var, possibly relabeled
969 leftop = ((NullTest *) clause)->arg;
971 if (leftop && IsA(leftop, RelabelType))
972 leftop = ((RelabelType *) leftop)->arg;
974 Assert(leftop != NULL);
976 if (!(IsA(leftop, Var) &&
977 var_is_rel((Var *) leftop)))
978 elog(ERROR, "NullTest indexqual has wrong key");
980 varattno = ((Var *) leftop)->varattno;
983 * initialize the scan key's fields appropriately
985 ScanKeyEntryInitialize(this_scan_key,
986 SK_ISNULL | SK_SEARCHNULL,
987 varattno, /* attribute number to scan */
988 strategy, /* op's strategy */
989 subtype, /* strategy subtype */
990 InvalidOid, /* no reg proc for this */
991 (Datum) 0); /* constant */
994 elog(ERROR, "unsupported indexqual type: %d",
995 (int) nodeTag(clause));
998 /* Get rid of any unused arrays */
999 if (n_runtime_keys == 0)
1001 pfree(runtime_keys);
1002 runtime_keys = NULL;
1004 if (n_array_keys == 0)
1011 * Return info to our caller.
1013 *scanKeys = scan_keys;
1014 *numScanKeys = n_scan_keys;
1015 *runtimeKeys = runtime_keys;
1016 *numRuntimeKeys = n_runtime_keys;
1019 *arrayKeys = array_keys;
1020 *numArrayKeys = n_array_keys;
1022 else if (n_array_keys != 0)
1023 elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
1027 ExecCountSlotsIndexScan(IndexScan *node)
1029 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
1030 ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;