Add support for user-defined I/O conversion casts.
[PostgreSQL.git] / src / backend / executor / nodeIndexscan.c
blob4d106ec9819633ed9a5203ecb7eaf50d423418fa
1 /*-------------------------------------------------------------------------
3 * nodeIndexscan.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
16 * INTERFACE ROUTINES
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.
25 #include "postgres.h"
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 /* ----------------------------------------------------------------
42 * IndexNext
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)
51 EState *estate;
52 ExprContext *econtext;
53 ScanDirection direction;
54 IndexScanDesc scandesc;
55 Index scanrelid;
56 HeapTuple tuple;
57 TupleTableSlot *slot;
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;
103 return slot;
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
123 * the real tuple.
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 */
133 return slot;
137 * if we get here it means the index scan failed so we are at the end of
138 * the scan..
140 return ExecClearTuple(slot);
143 /* ----------------------------------------------------------------
144 * ExecIndexScan(node)
145 * ----------------------------------------------------------------
147 TupleTableSlot *
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 * ----------------------------------------------------------------
172 void
173 ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
175 EState *estate;
176 ExprContext *econtext;
177 Index scanrelid;
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;
185 if (econtext)
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;
224 return;
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.
236 void
237 ExecIndexEvalRuntimeKeys(ExprContext *econtext,
238 IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
240 int j;
242 for (j = 0; j < numRuntimeKeys; j++)
244 ScanKey scan_key = runtimeKeys[j].scan_key;
245 ExprState *key_expr = runtimeKeys[j].key_expr;
246 Datum scanvalue;
247 bool isNull;
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
259 * necessary...
261 scanvalue = ExecEvalExprSwitchContext(key_expr,
262 econtext,
263 &isNull,
264 NULL);
265 scan_key->sk_argument = scanvalue;
266 if (isNull)
267 scan_key->sk_flags |= SK_ISNULL;
268 else
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.
281 bool
282 ExecIndexEvalArrayKeys(ExprContext *econtext,
283 IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
285 bool result = true;
286 int j;
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;
296 Datum arraydatum;
297 bool isNull;
298 ArrayType *arrayval;
299 int16 elmlen;
300 bool elmbyval;
301 char elmalign;
302 int num_elems;
303 Datum *elem_values;
304 bool *elem_nulls;
307 * Compute and deconstruct the array expression. (Notes in
308 * ExecIndexEvalRuntimeKeys() apply here too.)
310 arraydatum = ExecEvalExpr(array_expr,
311 econtext,
312 &isNull,
313 NULL);
314 if (isNull)
316 result = false;
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);
327 if (num_elems <= 0)
329 result = false;
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
336 * pfree's here.
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];
342 if (elem_nulls[0])
343 scan_key->sk_flags |= SK_ISNULL;
344 else
345 scan_key->sk_flags &= ~SK_ISNULL;
346 arrayKeys[j].next_elem = 1;
349 MemoryContextSwitchTo(oldContext);
351 return result;
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.
361 bool
362 ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
364 bool found = false;
365 int j;
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)
383 next_elem = 0;
384 found = false; /* need to advance next array key */
386 else
387 found = true;
388 scan_key->sk_argument = elem_values[next_elem];
389 if (elem_nulls[next_elem])
390 scan_key->sk_flags |= SK_ISNULL;
391 else
392 scan_key->sk_flags &= ~SK_ISNULL;
393 arrayKeys[j].next_elem = next_elem + 1;
394 if (found)
395 break;
398 return found;
402 /* ----------------------------------------------------------------
403 * ExecEndIndexScan
404 * ----------------------------------------------------------------
406 void
407 ExecEndIndexScan(IndexScanState *node)
409 Relation indexRelationDesc;
410 IndexScanDesc indexScanDesc;
411 Relation relation;
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
423 #ifdef NOT_USED
424 ExecFreeExprContext(&node->ss.ps);
425 if (node->iss_RuntimeContext)
426 FreeExprContext(node->iss_RuntimeContext);
427 #endif
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)
438 if (indexScanDesc)
439 index_endscan(indexScanDesc);
440 if (indexRelationDesc)
441 index_close(indexRelationDesc, NoLock);
444 * close the heap relation.
446 ExecCloseScanRelation(relation);
449 /* ----------------------------------------------------------------
450 * ExecIndexMarkPos
451 * ----------------------------------------------------------------
453 void
454 ExecIndexMarkPos(IndexScanState *node)
456 index_markpos(node->iss_ScanDesc);
459 /* ----------------------------------------------------------------
460 * ExecIndexRestrPos
461 * ----------------------------------------------------------------
463 void
464 ExecIndexRestrPos(IndexScanState *node)
466 index_restrpos(node->iss_ScanDesc);
469 /* ----------------------------------------------------------------
470 * ExecInitIndexScan
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
477 * index relation.
478 * ----------------------------------------------------------------
480 IndexScanState *
481 ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
483 IndexScanState *indexstate;
484 Relation currentRelation;
485 bool relistarget;
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)
555 return indexstate;
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,
579 node->indexqual,
580 &indexstate->iss_ScanKeys,
581 &indexstate->iss_NumScanKeys,
582 &indexstate->iss_RuntimeKeys,
583 &indexstate->iss_NumRuntimeKeys,
584 NULL, /* no ArrayKeys */
585 NULL);
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...
591 * -tgl 7/11/00
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;
601 else
603 indexstate->iss_RuntimeContext = NULL;
607 * Initialize scan descriptor.
609 indexstate->iss_ScanDesc = index_beginscan(currentRelation,
610 indexstate->iss_RelationDesc,
611 estate->es_snapshot,
612 indexstate->iss_NumScanKeys,
613 indexstate->iss_ScanKeys);
616 * all done.
618 return indexstate;
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.
652 * Input params are:
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
659 * Output params are:
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.
671 void
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)
677 ListCell *qual_cell;
678 ScanKey scan_keys;
679 IndexRuntimeKeyInfo *runtime_keys;
680 IndexArrayKeyInfo *array_keys;
681 int n_scan_keys;
682 int extra_scan_keys;
683 int n_runtime_keys;
684 int n_array_keys;
685 int j;
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);
695 extra_scan_keys = 0;
696 foreach(qual_cell, quals)
698 if (IsA(lfirst(qual_cell), RowCompareExpr))
699 extra_scan_keys +=
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));
709 n_runtime_keys = 0;
710 n_array_keys = 0;
713 * Below here, extra_scan_keys is index of first cell to use for next
714 * RowCompareExpr
716 extra_scan_keys = n_scan_keys;
719 * for each opclause in the given qual, convert the opclause into
720 * a single scan key
722 j = 0;
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 */
732 Oid op_righttype;
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 */
740 int flags = 0;
741 Datum scanvalue;
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,
771 &op_strategy,
772 &op_lefttype,
773 &op_righttype);
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)
790 flags |= SK_ISNULL;
792 else
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);
798 n_runtime_keys++;
799 scanvalue = (Datum) 0;
803 * initialize the scan key's fields appropriately
805 ScanKeyEntryInitialize(this_scan_key,
806 flags,
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;
827 Datum scanvalue;
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)
862 flags |= SK_ISNULL;
864 else
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);
870 n_runtime_keys++;
871 scanvalue = (Datum) 0;
875 * We have to look up the operator's associated btree support
876 * function
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,
887 &op_strategy,
888 &op_lefttype,
889 &op_righttype);
891 if (op_strategy != rc->rctype)
892 elog(ERROR, "RowCompare index qualification contains wrong operator");
894 opfuncid = get_opfamily_proc(opfamily,
895 op_lefttype,
896 op_righttype,
897 BTORDER_PROC);
900 * initialize the subsidiary scan key's fields appropriately
902 ScanKeyEntryInitialize(this_sub_key,
903 flags,
904 varattno, /* attribute number */
905 op_strategy, /* op's strategy */
906 op_righttype, /* strategy subtype */
907 opfuncid, /* reg proc to use */
908 scanvalue); /* constant */
909 extra_scan_keys++;
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;
931 Assert(saop->useOr);
932 opno = saop->opno;
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,
960 &op_strategy,
961 &op_lefttype,
962 &op_righttype);
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 */
978 n_array_keys++;
981 * initialize the scan key's fields appropriately
983 ScanKeyEntryInitialize(this_scan_key,
984 0, /* flags */
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 */
1023 else
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)
1036 pfree(array_keys);
1037 array_keys = NULL;
1041 * Return info to our caller.
1043 *scanKeys = scan_keys;
1044 *numScanKeys = n_scan_keys;
1045 *runtimeKeys = runtime_keys;
1046 *numRuntimeKeys = n_runtime_keys;
1047 if (arrayKeys)
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;