1 /*-------------------------------------------------------------------------
4 * Routines to support indexed scans of relations
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
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 "access/relscan.h"
30 #include "executor/execdebug.h"
31 #include "executor/nodeIndexscan.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 while ((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 */
122 * If the index was lossy, we have to recheck the index quals using
125 if (scandesc
->xs_recheck
)
127 econtext
->ecxt_scantuple
= slot
;
128 ResetExprContext(econtext
);
129 if (!ExecQual(node
->indexqualorig
, econtext
, false))
130 continue; /* nope, so ask index for another one */
137 * if we get here it means the index scan failed so we are at the end of
140 return ExecClearTuple(slot
);
143 /* ----------------------------------------------------------------
144 * ExecIndexScan(node)
145 * ----------------------------------------------------------------
148 ExecIndexScan(IndexScanState
*node
)
151 * If we have runtime keys and they've not already been set up, do it now.
153 if (node
->iss_NumRuntimeKeys
!= 0 && !node
->iss_RuntimeKeysReady
)
154 ExecReScan((PlanState
*) node
, NULL
);
157 * use IndexNext as access method
159 return ExecScan(&node
->ss
, (ExecScanAccessMtd
) IndexNext
);
162 /* ----------------------------------------------------------------
163 * ExecIndexReScan(node)
165 * Recalculates the value of the scan keys whose value depends on
166 * information known at runtime and rescans the indexed relation.
167 * Updating the scan key was formerly done separately in
168 * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
169 * rescans of indices and relations/general streams more uniform.
170 * ----------------------------------------------------------------
173 ExecIndexReScan(IndexScanState
*node
, ExprContext
*exprCtxt
)
176 ExprContext
*econtext
;
179 estate
= node
->ss
.ps
.state
;
180 econtext
= node
->iss_RuntimeContext
; /* context for runtime keys */
181 scanrelid
= ((IndexScan
*) node
->ss
.ps
.plan
)->scan
.scanrelid
;
183 node
->ss
.ps
.ps_TupFromTlist
= false;
188 * If we are being passed an outer tuple, save it for runtime key
189 * calc. We also need to link it into the "regular" per-tuple
190 * econtext, so it can be used during indexqualorig evaluations.
192 if (exprCtxt
!= NULL
)
194 ExprContext
*stdecontext
;
196 econtext
->ecxt_outertuple
= exprCtxt
->ecxt_outertuple
;
197 stdecontext
= node
->ss
.ps
.ps_ExprContext
;
198 stdecontext
->ecxt_outertuple
= exprCtxt
->ecxt_outertuple
;
202 * Reset the runtime-key context so we don't leak memory as each outer
203 * tuple is scanned. Note this assumes that we will recalculate *all*
204 * runtime keys on each call.
206 ResetExprContext(econtext
);
210 * If we are doing runtime key calculations (ie, the index keys depend on
211 * data from an outer scan), compute the new key values
213 if (node
->iss_NumRuntimeKeys
!= 0)
214 ExecIndexEvalRuntimeKeys(econtext
,
215 node
->iss_RuntimeKeys
,
216 node
->iss_NumRuntimeKeys
);
217 node
->iss_RuntimeKeysReady
= true;
219 /* If this is re-scanning of PlanQual ... */
220 if (estate
->es_evTuple
!= NULL
&&
221 estate
->es_evTuple
[scanrelid
- 1] != NULL
)
223 estate
->es_evTupleNull
[scanrelid
- 1] = false;
227 /* reset index scan */
228 index_rescan(node
->iss_ScanDesc
, node
->iss_ScanKeys
);
233 * ExecIndexEvalRuntimeKeys
234 * Evaluate any runtime key values, and update the scankeys.
237 ExecIndexEvalRuntimeKeys(ExprContext
*econtext
,
238 IndexRuntimeKeyInfo
*runtimeKeys
, int numRuntimeKeys
)
242 for (j
= 0; j
< numRuntimeKeys
; j
++)
244 ScanKey scan_key
= runtimeKeys
[j
].scan_key
;
245 ExprState
*key_expr
= runtimeKeys
[j
].key_expr
;
250 * For each run-time key, extract the run-time expression and evaluate
251 * it with respect to the current outer tuple. We then stick the
252 * result into the proper scan key.
254 * Note: the result of the eval could be a pass-by-ref value that's
255 * stored in the outer scan's tuple, not in
256 * econtext->ecxt_per_tuple_memory. We assume that the outer tuple
257 * will stay put throughout our scan. If this is wrong, we could copy
258 * the result into our context explicitly, but I think that's not
261 scanvalue
= ExecEvalExprSwitchContext(key_expr
,
265 scan_key
->sk_argument
= scanvalue
;
267 scan_key
->sk_flags
|= SK_ISNULL
;
269 scan_key
->sk_flags
&= ~SK_ISNULL
;
274 * ExecIndexEvalArrayKeys
275 * Evaluate any array key values, and set up to iterate through arrays.
277 * Returns TRUE if there are array elements to consider; FALSE means there
278 * is at least one null or empty array, so no match is possible. On TRUE
279 * result, the scankeys are initialized with the first elements of the arrays.
282 ExecIndexEvalArrayKeys(ExprContext
*econtext
,
283 IndexArrayKeyInfo
*arrayKeys
, int numArrayKeys
)
287 MemoryContext oldContext
;
289 /* We want to keep the arrays in per-tuple memory */
290 oldContext
= MemoryContextSwitchTo(econtext
->ecxt_per_tuple_memory
);
292 for (j
= 0; j
< numArrayKeys
; j
++)
294 ScanKey scan_key
= arrayKeys
[j
].scan_key
;
295 ExprState
*array_expr
= arrayKeys
[j
].array_expr
;
307 * Compute and deconstruct the array expression. (Notes in
308 * ExecIndexEvalRuntimeKeys() apply here too.)
310 arraydatum
= ExecEvalExpr(array_expr
,
317 break; /* no point in evaluating more */
319 arrayval
= DatumGetArrayTypeP(arraydatum
);
320 /* We could cache this data, but not clear it's worth it */
321 get_typlenbyvalalign(ARR_ELEMTYPE(arrayval
),
322 &elmlen
, &elmbyval
, &elmalign
);
323 deconstruct_array(arrayval
,
324 ARR_ELEMTYPE(arrayval
),
325 elmlen
, elmbyval
, elmalign
,
326 &elem_values
, &elem_nulls
, &num_elems
);
330 break; /* no point in evaluating more */
334 * Note: we expect the previous array data, if any, to be
335 * automatically freed by resetting the per-tuple context; hence no
338 arrayKeys
[j
].elem_values
= elem_values
;
339 arrayKeys
[j
].elem_nulls
= elem_nulls
;
340 arrayKeys
[j
].num_elems
= num_elems
;
341 scan_key
->sk_argument
= elem_values
[0];
343 scan_key
->sk_flags
|= SK_ISNULL
;
345 scan_key
->sk_flags
&= ~SK_ISNULL
;
346 arrayKeys
[j
].next_elem
= 1;
349 MemoryContextSwitchTo(oldContext
);
355 * ExecIndexAdvanceArrayKeys
356 * Advance to the next set of array key values, if any.
358 * Returns TRUE if there is another set of values to consider, FALSE if not.
359 * On TRUE result, the scankeys are initialized with the next set of values.
362 ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo
*arrayKeys
, int numArrayKeys
)
368 * Note we advance the rightmost array key most quickly, since it will
369 * correspond to the lowest-order index column among the available
370 * qualifications. This is hypothesized to result in better locality
371 * of access in the index.
373 for (j
= numArrayKeys
- 1; j
>= 0; j
--)
375 ScanKey scan_key
= arrayKeys
[j
].scan_key
;
376 int next_elem
= arrayKeys
[j
].next_elem
;
377 int num_elems
= arrayKeys
[j
].num_elems
;
378 Datum
*elem_values
= arrayKeys
[j
].elem_values
;
379 bool *elem_nulls
= arrayKeys
[j
].elem_nulls
;
381 if (next_elem
>= num_elems
)
384 found
= false; /* need to advance next array key */
388 scan_key
->sk_argument
= elem_values
[next_elem
];
389 if (elem_nulls
[next_elem
])
390 scan_key
->sk_flags
|= SK_ISNULL
;
392 scan_key
->sk_flags
&= ~SK_ISNULL
;
393 arrayKeys
[j
].next_elem
= next_elem
+ 1;
402 /* ----------------------------------------------------------------
404 * ----------------------------------------------------------------
407 ExecEndIndexScan(IndexScanState
*node
)
409 Relation indexRelationDesc
;
410 IndexScanDesc indexScanDesc
;
414 * extract information from the node
416 indexRelationDesc
= node
->iss_RelationDesc
;
417 indexScanDesc
= node
->iss_ScanDesc
;
418 relation
= node
->ss
.ss_currentRelation
;
421 * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
424 ExecFreeExprContext(&node
->ss
.ps
);
425 if (node
->iss_RuntimeContext
)
426 FreeExprContext(node
->iss_RuntimeContext
);
430 * clear out tuple table slots
432 ExecClearTuple(node
->ss
.ps
.ps_ResultTupleSlot
);
433 ExecClearTuple(node
->ss
.ss_ScanTupleSlot
);
436 * close the index relation (no-op if we didn't open it)
439 index_endscan(indexScanDesc
);
440 if (indexRelationDesc
)
441 index_close(indexRelationDesc
, NoLock
);
444 * close the heap relation.
446 ExecCloseScanRelation(relation
);
449 /* ----------------------------------------------------------------
451 * ----------------------------------------------------------------
454 ExecIndexMarkPos(IndexScanState
*node
)
456 index_markpos(node
->iss_ScanDesc
);
459 /* ----------------------------------------------------------------
461 * ----------------------------------------------------------------
464 ExecIndexRestrPos(IndexScanState
*node
)
466 index_restrpos(node
->iss_ScanDesc
);
469 /* ----------------------------------------------------------------
472 * Initializes the index scan's state information, creates
473 * scan keys, and opens the base and index relations.
475 * Note: index scans have 2 sets of state information because
476 * we have to keep track of the base relation and the
478 * ----------------------------------------------------------------
481 ExecInitIndexScan(IndexScan
*node
, EState
*estate
, int eflags
)
483 IndexScanState
*indexstate
;
484 Relation currentRelation
;
488 * create state structure
490 indexstate
= makeNode(IndexScanState
);
491 indexstate
->ss
.ps
.plan
= (Plan
*) node
;
492 indexstate
->ss
.ps
.state
= estate
;
495 * Miscellaneous initialization
497 * create expression context for node
499 ExecAssignExprContext(estate
, &indexstate
->ss
.ps
);
501 indexstate
->ss
.ps
.ps_TupFromTlist
= false;
504 * initialize child expressions
506 * Note: we don't initialize all of the indexqual expression, only the
507 * sub-parts corresponding to runtime keys (see below). The indexqualorig
508 * expression is always initialized even though it will only be used in
509 * some uncommon cases --- would be nice to improve that. (Problem is
510 * that any SubPlans present in the expression must be found now...)
512 indexstate
->ss
.ps
.targetlist
= (List
*)
513 ExecInitExpr((Expr
*) node
->scan
.plan
.targetlist
,
514 (PlanState
*) indexstate
);
515 indexstate
->ss
.ps
.qual
= (List
*)
516 ExecInitExpr((Expr
*) node
->scan
.plan
.qual
,
517 (PlanState
*) indexstate
);
518 indexstate
->indexqualorig
= (List
*)
519 ExecInitExpr((Expr
*) node
->indexqualorig
,
520 (PlanState
*) indexstate
);
522 #define INDEXSCAN_NSLOTS 2
525 * tuple table initialization
527 ExecInitResultTupleSlot(estate
, &indexstate
->ss
.ps
);
528 ExecInitScanTupleSlot(estate
, &indexstate
->ss
);
531 * open the base relation and acquire appropriate lock on it.
533 currentRelation
= ExecOpenScanRelation(estate
, node
->scan
.scanrelid
);
535 indexstate
->ss
.ss_currentRelation
= currentRelation
;
536 indexstate
->ss
.ss_currentScanDesc
= NULL
; /* no heap scan here */
539 * get the scan type from the relation descriptor.
541 ExecAssignScanType(&indexstate
->ss
, RelationGetDescr(currentRelation
));
544 * Initialize result tuple type and projection info.
546 ExecAssignResultTypeFromTL(&indexstate
->ss
.ps
);
547 ExecAssignScanProjectionInfo(&indexstate
->ss
);
550 * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
551 * here. This allows an index-advisor plugin to EXPLAIN a plan containing
552 * references to nonexistent indexes.
554 if (eflags
& EXEC_FLAG_EXPLAIN_ONLY
)
558 * Open the index relation.
560 * If the parent table is one of the target relations of the query, then
561 * InitPlan already opened and write-locked the index, so we can avoid
562 * taking another lock here. Otherwise we need a normal reader's lock.
564 relistarget
= ExecRelationIsTargetRelation(estate
, node
->scan
.scanrelid
);
565 indexstate
->iss_RelationDesc
= index_open(node
->indexid
,
566 relistarget
? NoLock
: AccessShareLock
);
569 * Initialize index-specific scan state
571 indexstate
->iss_RuntimeKeysReady
= false;
574 * build the index scan keys from the index qualification
576 ExecIndexBuildScanKeys((PlanState
*) indexstate
,
577 indexstate
->iss_RelationDesc
,
578 node
->scan
.scanrelid
,
580 &indexstate
->iss_ScanKeys
,
581 &indexstate
->iss_NumScanKeys
,
582 &indexstate
->iss_RuntimeKeys
,
583 &indexstate
->iss_NumRuntimeKeys
,
584 NULL
, /* no ArrayKeys */
588 * If we have runtime keys, we need an ExprContext to evaluate them. The
589 * node's standard context won't do because we want to reset that context
590 * for every tuple. So, build another context just like the other one...
593 if (indexstate
->iss_NumRuntimeKeys
!= 0)
595 ExprContext
*stdecontext
= indexstate
->ss
.ps
.ps_ExprContext
;
597 ExecAssignExprContext(estate
, &indexstate
->ss
.ps
);
598 indexstate
->iss_RuntimeContext
= indexstate
->ss
.ps
.ps_ExprContext
;
599 indexstate
->ss
.ps
.ps_ExprContext
= stdecontext
;
603 indexstate
->iss_RuntimeContext
= NULL
;
607 * Initialize scan descriptor.
609 indexstate
->iss_ScanDesc
= index_beginscan(currentRelation
,
610 indexstate
->iss_RelationDesc
,
612 indexstate
->iss_NumScanKeys
,
613 indexstate
->iss_ScanKeys
);
623 * ExecIndexBuildScanKeys
624 * Build the index scan keys from the index qualification expressions
626 * The index quals are passed to the index AM in the form of a ScanKey array.
627 * This routine sets up the ScanKeys, fills in all constant fields of the
628 * ScanKeys, and prepares information about the keys that have non-constant
629 * comparison values. We divide index qual expressions into five types:
631 * 1. Simple operator with constant comparison value ("indexkey op constant").
632 * For these, we just fill in a ScanKey containing the constant value.
634 * 2. Simple operator with non-constant value ("indexkey op expression").
635 * For these, we create a ScanKey with everything filled in except the
636 * expression value, and set up an IndexRuntimeKeyInfo struct to drive
637 * evaluation of the expression at the right times.
639 * 3. RowCompareExpr ("(indexkey, indexkey, ...) op (expr, expr, ...)").
640 * For these, we create a header ScanKey plus a subsidiary ScanKey array,
641 * as specified in access/skey.h. The elements of the row comparison
642 * can have either constant or non-constant comparison values.
644 * 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)"). For these,
645 * we create a ScanKey with everything filled in except the comparison value,
646 * and set up an IndexArrayKeyInfo struct to drive processing of the qual.
647 * (Note that we treat all array-expressions as requiring runtime evaluation,
648 * even if they happen to be constants.)
650 * 5. NullTest ("indexkey IS NULL"). We just fill in the ScanKey properly.
654 * planstate: executor state node we are working for
655 * index: the index we are building scan keys for
656 * scanrelid: varno of the index's relation within current query
657 * quals: indexquals expressions
661 * *scanKeys: receives ptr to array of ScanKeys
662 * *numScanKeys: receives number of scankeys
663 * *runtimeKeys: receives ptr to array of IndexRuntimeKeyInfos, or NULL if none
664 * *numRuntimeKeys: receives number of runtime keys
665 * *arrayKeys: receives ptr to array of IndexArrayKeyInfos, or NULL if none
666 * *numArrayKeys: receives number of array keys
668 * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
669 * ScalarArrayOpExpr quals are not supported.
672 ExecIndexBuildScanKeys(PlanState
*planstate
, Relation index
, Index scanrelid
,
673 List
*quals
, ScanKey
*scanKeys
, int *numScanKeys
,
674 IndexRuntimeKeyInfo
**runtimeKeys
, int *numRuntimeKeys
,
675 IndexArrayKeyInfo
**arrayKeys
, int *numArrayKeys
)
679 IndexRuntimeKeyInfo
*runtime_keys
;
680 IndexArrayKeyInfo
*array_keys
;
688 * If there are any RowCompareExpr quals, we need extra ScanKey entries
689 * for them, and possibly extra runtime-key entries. Count up what's
690 * needed. (The subsidiary ScanKey arrays for the RowCompareExprs could
691 * be allocated as separate chunks, but we have to count anyway to make
692 * runtime_keys large enough, so might as well just do one palloc.)
694 n_scan_keys
= list_length(quals
);
696 foreach(qual_cell
, quals
)
698 if (IsA(lfirst(qual_cell
), RowCompareExpr
))
700 list_length(((RowCompareExpr
*) lfirst(qual_cell
))->opnos
);
702 scan_keys
= (ScanKey
)
703 palloc((n_scan_keys
+ extra_scan_keys
) * sizeof(ScanKeyData
));
704 /* Allocate these arrays as large as they could possibly need to be */
705 runtime_keys
= (IndexRuntimeKeyInfo
*)
706 palloc((n_scan_keys
+ extra_scan_keys
) * sizeof(IndexRuntimeKeyInfo
));
707 array_keys
= (IndexArrayKeyInfo
*)
708 palloc0(n_scan_keys
* sizeof(IndexArrayKeyInfo
));
713 * Below here, extra_scan_keys is index of first cell to use for next
716 extra_scan_keys
= n_scan_keys
;
719 * for each opclause in the given qual, convert the opclause into
723 foreach(qual_cell
, quals
)
725 Expr
*clause
= (Expr
*) lfirst(qual_cell
);
726 ScanKey this_scan_key
= &scan_keys
[j
++];
727 Oid opno
; /* operator's OID */
728 RegProcedure opfuncid
; /* operator proc id used in scan */
729 Oid opfamily
; /* opfamily of index column */
730 int op_strategy
; /* operator's strategy number */
731 Oid op_lefttype
; /* operator's declared input types */
733 Expr
*leftop
; /* expr on lhs of operator */
734 Expr
*rightop
; /* expr on rhs ... */
735 AttrNumber varattno
; /* att number used in scan */
737 if (IsA(clause
, OpExpr
))
739 /* indexkey op const or indexkey op expression */
743 opno
= ((OpExpr
*) clause
)->opno
;
744 opfuncid
= ((OpExpr
*) clause
)->opfuncid
;
747 * leftop should be the index key Var, possibly relabeled
749 leftop
= (Expr
*) get_leftop(clause
);
751 if (leftop
&& IsA(leftop
, RelabelType
))
752 leftop
= ((RelabelType
*) leftop
)->arg
;
754 Assert(leftop
!= NULL
);
756 if (!(IsA(leftop
, Var
) &&
757 ((Var
*) leftop
)->varno
== scanrelid
))
758 elog(ERROR
, "indexqual doesn't have key on left side");
760 varattno
= ((Var
*) leftop
)->varattno
;
761 if (varattno
< 1 || varattno
> index
->rd_index
->indnatts
)
762 elog(ERROR
, "bogus index qualification");
765 * We have to look up the operator's strategy number. This
766 * provides a cross-check that the operator does match the index.
768 opfamily
= index
->rd_opfamily
[varattno
- 1];
770 get_op_opfamily_properties(opno
, opfamily
,
776 * rightop is the constant or variable comparison value
778 rightop
= (Expr
*) get_rightop(clause
);
780 if (rightop
&& IsA(rightop
, RelabelType
))
781 rightop
= ((RelabelType
*) rightop
)->arg
;
783 Assert(rightop
!= NULL
);
785 if (IsA(rightop
, Const
))
787 /* OK, simple constant comparison value */
788 scanvalue
= ((Const
*) rightop
)->constvalue
;
789 if (((Const
*) rightop
)->constisnull
)
794 /* Need to treat this one as a runtime key */
795 runtime_keys
[n_runtime_keys
].scan_key
= this_scan_key
;
796 runtime_keys
[n_runtime_keys
].key_expr
=
797 ExecInitExpr(rightop
, planstate
);
799 scanvalue
= (Datum
) 0;
803 * initialize the scan key's fields appropriately
805 ScanKeyEntryInitialize(this_scan_key
,
807 varattno
, /* attribute number to scan */
808 op_strategy
, /* op's strategy */
809 op_righttype
, /* strategy subtype */
810 opfuncid
, /* reg proc to use */
811 scanvalue
); /* constant */
813 else if (IsA(clause
, RowCompareExpr
))
815 /* (indexkey, indexkey, ...) op (expression, expression, ...) */
816 RowCompareExpr
*rc
= (RowCompareExpr
*) clause
;
817 ListCell
*largs_cell
= list_head(rc
->largs
);
818 ListCell
*rargs_cell
= list_head(rc
->rargs
);
819 ListCell
*opnos_cell
= list_head(rc
->opnos
);
820 ScanKey first_sub_key
= &scan_keys
[extra_scan_keys
];
822 /* Scan RowCompare columns and generate subsidiary ScanKey items */
823 while (opnos_cell
!= NULL
)
825 ScanKey this_sub_key
= &scan_keys
[extra_scan_keys
];
826 int flags
= SK_ROW_MEMBER
;
830 * leftop should be the index key Var, possibly relabeled
832 leftop
= (Expr
*) lfirst(largs_cell
);
833 largs_cell
= lnext(largs_cell
);
835 if (leftop
&& IsA(leftop
, RelabelType
))
836 leftop
= ((RelabelType
*) leftop
)->arg
;
838 Assert(leftop
!= NULL
);
840 if (!(IsA(leftop
, Var
) &&
841 ((Var
*) leftop
)->varno
== scanrelid
))
842 elog(ERROR
, "indexqual doesn't have key on left side");
844 varattno
= ((Var
*) leftop
)->varattno
;
847 * rightop is the constant or variable comparison value
849 rightop
= (Expr
*) lfirst(rargs_cell
);
850 rargs_cell
= lnext(rargs_cell
);
852 if (rightop
&& IsA(rightop
, RelabelType
))
853 rightop
= ((RelabelType
*) rightop
)->arg
;
855 Assert(rightop
!= NULL
);
857 if (IsA(rightop
, Const
))
859 /* OK, simple constant comparison value */
860 scanvalue
= ((Const
*) rightop
)->constvalue
;
861 if (((Const
*) rightop
)->constisnull
)
866 /* Need to treat this one as a runtime key */
867 runtime_keys
[n_runtime_keys
].scan_key
= this_sub_key
;
868 runtime_keys
[n_runtime_keys
].key_expr
=
869 ExecInitExpr(rightop
, planstate
);
871 scanvalue
= (Datum
) 0;
875 * We have to look up the operator's associated btree support
878 opno
= lfirst_oid(opnos_cell
);
879 opnos_cell
= lnext(opnos_cell
);
881 if (index
->rd_rel
->relam
!= BTREE_AM_OID
||
882 varattno
< 1 || varattno
> index
->rd_index
->indnatts
)
883 elog(ERROR
, "bogus RowCompare index qualification");
884 opfamily
= index
->rd_opfamily
[varattno
- 1];
886 get_op_opfamily_properties(opno
, opfamily
,
891 if (op_strategy
!= rc
->rctype
)
892 elog(ERROR
, "RowCompare index qualification contains wrong operator");
894 opfuncid
= get_opfamily_proc(opfamily
,
900 * initialize the subsidiary scan key's fields appropriately
902 ScanKeyEntryInitialize(this_sub_key
,
904 varattno
, /* attribute number */
905 op_strategy
, /* op's strategy */
906 op_righttype
, /* strategy subtype */
907 opfuncid
, /* reg proc to use */
908 scanvalue
); /* constant */
912 /* Mark the last subsidiary scankey correctly */
913 scan_keys
[extra_scan_keys
- 1].sk_flags
|= SK_ROW_END
;
916 * We don't use ScanKeyEntryInitialize for the header because it
917 * isn't going to contain a valid sk_func pointer.
919 MemSet(this_scan_key
, 0, sizeof(ScanKeyData
));
920 this_scan_key
->sk_flags
= SK_ROW_HEADER
;
921 this_scan_key
->sk_attno
= first_sub_key
->sk_attno
;
922 this_scan_key
->sk_strategy
= rc
->rctype
;
923 /* sk_subtype, sk_func not used in a header */
924 this_scan_key
->sk_argument
= PointerGetDatum(first_sub_key
);
926 else if (IsA(clause
, ScalarArrayOpExpr
))
928 /* indexkey op ANY (array-expression) */
929 ScalarArrayOpExpr
*saop
= (ScalarArrayOpExpr
*) clause
;
933 opfuncid
= saop
->opfuncid
;
936 * leftop should be the index key Var, possibly relabeled
938 leftop
= (Expr
*) linitial(saop
->args
);
940 if (leftop
&& IsA(leftop
, RelabelType
))
941 leftop
= ((RelabelType
*) leftop
)->arg
;
943 Assert(leftop
!= NULL
);
945 if (!(IsA(leftop
, Var
) &&
946 ((Var
*) leftop
)->varno
== scanrelid
))
947 elog(ERROR
, "indexqual doesn't have key on left side");
949 varattno
= ((Var
*) leftop
)->varattno
;
950 if (varattno
< 1 || varattno
> index
->rd_index
->indnatts
)
951 elog(ERROR
, "bogus index qualification");
954 * We have to look up the operator's strategy number. This
955 * provides a cross-check that the operator does match the index.
957 opfamily
= index
->rd_opfamily
[varattno
- 1];
959 get_op_opfamily_properties(opno
, opfamily
,
965 * rightop is the constant or variable array value
967 rightop
= (Expr
*) lsecond(saop
->args
);
969 if (rightop
&& IsA(rightop
, RelabelType
))
970 rightop
= ((RelabelType
*) rightop
)->arg
;
972 Assert(rightop
!= NULL
);
974 array_keys
[n_array_keys
].scan_key
= this_scan_key
;
975 array_keys
[n_array_keys
].array_expr
=
976 ExecInitExpr(rightop
, planstate
);
977 /* the remaining fields were zeroed by palloc0 */
981 * initialize the scan key's fields appropriately
983 ScanKeyEntryInitialize(this_scan_key
,
985 varattno
, /* attribute number to scan */
986 op_strategy
, /* op's strategy */
987 op_righttype
, /* strategy subtype */
988 opfuncid
, /* reg proc to use */
989 (Datum
) 0); /* constant */
991 else if (IsA(clause
, NullTest
))
993 /* indexkey IS NULL */
994 Assert(((NullTest
*) clause
)->nulltesttype
== IS_NULL
);
997 * argument should be the index key Var, possibly relabeled
999 leftop
= ((NullTest
*) clause
)->arg
;
1001 if (leftop
&& IsA(leftop
, RelabelType
))
1002 leftop
= ((RelabelType
*) leftop
)->arg
;
1004 Assert(leftop
!= NULL
);
1006 if (!(IsA(leftop
, Var
) &&
1007 ((Var
*) leftop
)->varno
== scanrelid
))
1008 elog(ERROR
, "NullTest indexqual has wrong key");
1010 varattno
= ((Var
*) leftop
)->varattno
;
1013 * initialize the scan key's fields appropriately
1015 ScanKeyEntryInitialize(this_scan_key
,
1016 SK_ISNULL
| SK_SEARCHNULL
,
1017 varattno
, /* attribute number to scan */
1018 InvalidStrategy
, /* no strategy */
1019 InvalidOid
, /* no strategy subtype */
1020 InvalidOid
, /* no reg proc for this */
1021 (Datum
) 0); /* constant */
1024 elog(ERROR
, "unsupported indexqual type: %d",
1025 (int) nodeTag(clause
));
1028 /* Get rid of any unused arrays */
1029 if (n_runtime_keys
== 0)
1031 pfree(runtime_keys
);
1032 runtime_keys
= NULL
;
1034 if (n_array_keys
== 0)
1041 * Return info to our caller.
1043 *scanKeys
= scan_keys
;
1044 *numScanKeys
= n_scan_keys
;
1045 *runtimeKeys
= runtime_keys
;
1046 *numRuntimeKeys
= n_runtime_keys
;
1049 *arrayKeys
= array_keys
;
1050 *numArrayKeys
= n_array_keys
;
1052 else if (n_array_keys
!= 0)
1053 elog(ERROR
, "ScalarArrayOpExpr index qual found where not allowed");
1057 ExecCountSlotsIndexScan(IndexScan
*node
)
1059 return ExecCountSlotsNode(outerPlan((Plan
*) node
)) +
1060 ExecCountSlotsNode(innerPlan((Plan
*) node
)) + INDEXSCAN_NSLOTS
;