]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeIndexscan.c
D'Arcy's recent cleanups
[postgresql] / src / backend / executor / nodeIndexscan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeIndexscan.c--
4  *    Routines to support indexes and indexed scans of relations
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *    $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.5 1996/11/08 00:45:57 scrappy Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  * INTERFACE ROUTINES
16  *      ExecInsertIndexTuples   inserts tuples into indices on result relation
17  *
18  *      ExecIndexScan           scans a relation using indices
19  *      ExecIndexNext           using index to retrieve next tuple
20  *      ExecInitIndexScan       creates and initializes state info. 
21  *      ExecIndexReScan         rescans the indexed relation.
22  *      ExecEndIndexScan        releases all storage.
23  *      ExecIndexMarkPos        marks scan position.
24  *      ExecIndexRestrPos       restores scan position.
25  *
26  *   NOTES
27  *      the code supporting ExecInsertIndexTuples should be
28  *      collected and merged with the genam stuff.
29  *
30  */
31 #include "postgres.h"
32
33 #include "executor/executor.h"
34 #include "executor/execdebug.h"
35 #include "executor/nodeIndexscan.h"
36
37 #include "optimizer/clauses.h"  /* for get_op, get_leftop, get_rightop */
38 #include "parser/parsetree.h"   /* for rt_fetch() */
39
40 #include "access/skey.h"
41 #include "access/heapam.h"
42 #include "access/genam.h"
43 #include "utils/palloc.h"
44 #include "utils/mcxt.h"
45 #include "catalog/index.h"
46 #include "storage/bufmgr.h"
47 #include "storage/lmgr.h"
48 #include "nodes/nodeFuncs.h"
49
50 /* ----------------
51  *      Misc stuff to move to executor.h soon -cim 6/5/90
52  * ----------------
53  */
54 #define NO_OP           0
55 #define LEFT_OP         1
56 #define RIGHT_OP        2
57
58 static TupleTableSlot *IndexNext(IndexScan *node);
59
60 /* ----------------------------------------------------------------
61  *      IndexNext
62  *
63  *      Retrieve a tuple from the IndexScan node's currentRelation
64  *      using the indices in the IndexScanState information.
65  *
66  *      note: the old code mentions 'Primary indices'.  to my knowledge
67  *      we only support a single secondary index. -cim 9/11/89
68  *
69  * old comments:
70  *      retrieve a tuple from relation using the indices given.
71  *      The indices are used in the order they appear in 'indices'.
72  *      The indices may be primary or secondary indices:
73  *        * primary index --    scan the relation 'relID' using keys supplied.
74  *        * secondary index --  scan the index relation to get the 'tid' for
75  *                              a tuple in the relation 'relID'.
76  *      If the current index(pointed by 'indexPtr') fails to return a
77  *      tuple, the next index in the indices is used.
78  *   
79  *        bug fix so that it should retrieve on a null scan key.
80  * ----------------------------------------------------------------
81  */
82 static TupleTableSlot *
83 IndexNext(IndexScan *node)
84 {
85     EState                      *estate;
86     CommonScanState             *scanstate;
87     IndexScanState              *indexstate;
88     ScanDirection               direction;
89     int                         indexPtr;
90     IndexScanDescPtr            scanDescs;
91     IndexScanDesc               scandesc;
92     Relation                    heapRelation;
93     RetrieveIndexResult         result;
94     ItemPointer                 iptr;
95     HeapTuple                   tuple;
96     TupleTableSlot              *slot;
97     Buffer                      buffer = InvalidBuffer;
98
99     /* ----------------
100      *  extract necessary information from index scan node
101      * ----------------
102      */
103     estate =            node->scan.plan.state;
104     direction =         estate->es_direction;
105     scanstate =         node->scan.scanstate;
106     indexstate =        node->indxstate;
107     indexPtr =          indexstate->iss_IndexPtr;
108     scanDescs =         indexstate->iss_ScanDescs;
109     scandesc =          scanDescs[ indexPtr ];
110     heapRelation =      scanstate->css_currentRelation;
111
112     slot = scanstate->css_ScanTupleSlot;
113
114     /* ----------------
115      *  ok, now that we have what we need, fetch an index tuple.
116      * ----------------
117      */
118
119     for(;;) {
120         result = index_getnext(scandesc, direction);
121         /* ----------------
122          *  if scanning this index succeeded then return the
123          *  appropriate heap tuple.. else return NULL.
124          * ----------------
125          */
126         if (result) {
127             iptr =  &result->heap_iptr;
128             tuple = heap_fetch(heapRelation,
129                                NowTimeQual,
130                                iptr,
131                                &buffer);
132             /* be tidy */
133             pfree(result);
134             
135             if (tuple == NULL) {
136                 /* ----------------
137                  *   we found a deleted tuple, so keep on scanning..
138                  * ----------------
139                  */
140                 if (BufferIsValid(buffer))
141                     ReleaseBuffer(buffer);
142                 continue;
143             }
144             
145             /* ----------------
146              *  store the scanned tuple in the scan tuple slot of
147              *  the scan state.  Eventually we will only do this and not
148              *  return a tuple.  Note: we pass 'false' because tuples
149              *  returned by amgetnext are pointers onto disk pages and
150              *  were not created with palloc() and so should not be pfree()'d.
151              * ----------------
152              */
153             ExecStoreTuple(tuple,         /* tuple to store */
154                            slot,          /* slot to store in */
155                            buffer,        /* buffer associated with tuple  */
156                            false);        /* don't pfree */
157             
158             return slot;
159         }
160         
161         /* ----------------
162          *  if we get here it means the index scan failed so we
163          *  are at the end of the scan..
164          * ----------------
165          */
166         return ExecClearTuple(slot);
167     }
168 }
169
170 /* ----------------------------------------------------------------
171  *      ExecIndexScan(node)
172  *
173  * old comments:
174  *      Scans the relation using primary or secondary indices and returns 
175  *         the next qualifying tuple in the direction specified.
176  *      It calls ExecScan() and passes it the access methods which returns
177  *      the next tuple using the indices.
178  *      
179  *      Conditions:
180  *        -- the "cursor" maintained by the AMI is positioned at the tuple
181  *           returned previously.
182  *   
183  *      Initial States:
184  *        -- the relation indicated is opened for scanning so that the 
185  *           "cursor" is positioned before the first qualifying tuple.
186  *        -- all index realtions are opened for scanning.
187  *        -- indexPtr points to the first index.
188  *        -- state variable ruleFlag = nil.
189  * ----------------------------------------------------------------
190  */
191 TupleTableSlot *
192 ExecIndexScan(IndexScan *node)
193 {
194     TupleTableSlot *returnTuple;
195
196     /* ----------------
197      *  use IndexNext as access method
198      * ----------------
199      */
200     returnTuple = ExecScan(&node->scan, IndexNext);
201     return returnTuple;
202 }       
203
204 /* ----------------------------------------------------------------
205  *      ExecIndexReScan(node)
206  *
207  *      Recalculates the value of the scan keys whose value depends on 
208  *      information known at runtime and rescans the indexed relation.
209  *      Updating the scan key was formerly done separately in 
210  *      ExecUpdateIndexScanKeys. Integrating it into ReScan
211  *      makes rescans of indices and
212  *      relations/general streams more uniform.
213  *
214  * ----------------------------------------------------------------
215  */
216 void
217 ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan* parent)
218 {
219     EState          *estate;
220     IndexScanState  *indexstate;
221     ScanDirection   direction;
222     IndexScanDescPtr scanDescs;
223     ScanKey         *scanKeys;
224     IndexScanDesc   sdesc;
225     ScanKey         skey;
226     int             numIndices;
227     int             i;
228
229     Pointer             *runtimeKeyInfo;
230     int                 indexPtr;
231     int                 *numScanKeys;
232     List                *indxqual;
233     List                *qual;
234     int                 n_keys;
235     ScanKey             scan_keys;
236     int                 *run_keys;
237     int                 j;
238     Expr                *clause;
239     Node                *scanexpr;
240     Datum               scanvalue;
241     bool                isNull;
242     bool                isDone;
243
244     indexstate = node->indxstate;
245     estate = node->scan.plan.state;
246     direction = estate->es_direction;
247     indexstate = node->indxstate;
248     numIndices = indexstate->iss_NumIndices;
249     scanDescs = indexstate->iss_ScanDescs;
250     scanKeys = indexstate->iss_ScanKeys;
251
252     runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
253
254     if (runtimeKeyInfo != NULL) {
255         /* 
256          * get the index qualifications and
257          * recalculate the appropriate values
258          */
259         indexPtr = indexstate->iss_IndexPtr;
260         indxqual = node->indxqual;
261         qual = nth(indexPtr, indxqual);
262         numScanKeys = indexstate->iss_NumScanKeys;
263         n_keys = numScanKeys[indexPtr];
264         run_keys = (int *) runtimeKeyInfo[indexPtr];
265         scan_keys = (ScanKey) scanKeys[indexPtr];
266
267         for (j=0; j < n_keys; j++) {
268             /* 
269              * If we have a run-time key, then extract the run-time
270              * expression and evaluate it with respect to the current
271              * outer tuple.  We then stick the result into the scan
272              * key.
273              */
274             if (run_keys[j] != NO_OP) {
275                 clause =    nth(j, qual);
276                 scanexpr =  (run_keys[j] == RIGHT_OP) ?
277                     (Node*) get_rightop(clause) : (Node*) get_leftop(clause) ;
278                 /* pass in isDone but ignore it.  We don't iterate in quals */
279                 scanvalue = (Datum)
280                     ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone);
281                 scan_keys[j].sk_argument = scanvalue;
282                 if (isNull) {
283                     scan_keys[j].sk_flags |= SK_ISNULL;
284                 } else {
285                     scan_keys[j].sk_flags &= ~SK_ISNULL;
286                 }
287             }
288         }
289     } 
290
291     /* 
292      * rescans all indices
293      *
294      * note: AMrescan assumes only one scan key.  This may have
295      *       to change if we ever decide to support multiple keys.
296      */
297     for (i = 0; i < numIndices; i++) {
298         sdesc = scanDescs[ i ];
299         skey =  scanKeys[ i ];
300         index_rescan(sdesc, direction, skey);
301     }
302
303     /* ----------------
304      *  perhaps return something meaningful
305      * ----------------
306      */
307     return;
308 }
309
310 /* ----------------------------------------------------------------
311  *      ExecEndIndexScan
312  *
313  * old comments
314  *      Releases any storage allocated through C routines.
315  *      Returns nothing.
316  * ----------------------------------------------------------------
317  */
318 void
319 ExecEndIndexScan(IndexScan *node)
320 {
321     CommonScanState     *scanstate;
322     IndexScanState      *indexstate;
323     ScanKey             *scanKeys;
324     int                 numIndices;
325     int                 i;
326
327     scanstate =  node->scan.scanstate;
328     indexstate = node->indxstate;
329
330     /* ----------------
331      *  extract information from the node
332      * ----------------
333      */
334     numIndices = indexstate->iss_NumIndices;
335     scanKeys =   indexstate->iss_ScanKeys;
336
337     /* ----------------
338      *  Free the projection info and the scan attribute info
339      *
340      *  Note: we don't ExecFreeResultType(scanstate) 
341      *        because the rule manager depends on the tupType
342      *        returned by ExecMain().  So for now, this
343      *        is freed at end-transaction time.  -cim 6/2/91     
344      * ----------------
345      */    
346     ExecFreeProjectionInfo(&scanstate->cstate);
347
348     /* ----------------
349      *  close the heap and index relations
350      * ----------------
351      */
352     ExecCloseR((Plan *) node);
353
354     /* ----------------
355      *  free the scan keys used in scanning the indices
356      * ----------------
357      */
358     for (i=0; i<numIndices; i++) { 
359         if (scanKeys[i]!=NULL)
360             pfree(scanKeys[i]);
361             
362     }
363
364     /* ----------------
365      *  clear out tuple table slots
366      * ----------------
367      */
368     ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
369     ExecClearTuple(scanstate->css_ScanTupleSlot);
370 /*    ExecClearTuple(scanstate->css_RawTupleSlot); */
371 }
372
373 /* ----------------------------------------------------------------
374  *      ExecIndexMarkPos
375  *
376  * old comments
377  *      Marks scan position by marking the current index.
378  *      Returns nothing.
379  * ----------------------------------------------------------------
380  */
381 void
382 ExecIndexMarkPos(IndexScan *node)
383 {
384     IndexScanState      *indexstate;
385     IndexScanDescPtr    indexScanDescs;
386     IndexScanDesc       scanDesc;
387     int                 indexPtr;
388
389     indexstate =     node->indxstate;
390     indexPtr =       indexstate->iss_IndexPtr;
391     indexScanDescs = indexstate->iss_ScanDescs;
392     scanDesc = indexScanDescs[ indexPtr ];
393
394     /* ----------------
395      *  XXX access methods don't return marked positions so
396      * ----------------
397      */
398     IndexScanMarkPosition( scanDesc );
399     return;
400 }
401
402 /* ----------------------------------------------------------------
403  *      ExecIndexRestrPos
404  *
405  * old comments
406  *      Restores scan position by restoring the current index.
407  *      Returns nothing.
408  *    
409  *      XXX Assumes previously marked scan position belongs to current index
410  * ----------------------------------------------------------------
411  */
412 void
413 ExecIndexRestrPos(IndexScan *node)
414 {
415     IndexScanState      *indexstate;
416     IndexScanDescPtr    indexScanDescs;
417     IndexScanDesc       scanDesc;
418     int                 indexPtr;
419
420     indexstate =     node->indxstate;
421     indexPtr =       indexstate->iss_IndexPtr;
422     indexScanDescs = indexstate->iss_ScanDescs;
423     scanDesc = indexScanDescs[ indexPtr ];
424
425     IndexScanRestorePosition( scanDesc );
426 }
427
428 /* ----------------------------------------------------------------
429  *      ExecInitIndexScan
430  *
431  *      Initializes the index scan's state information, creates
432  *      scan keys, and opens the base and index relations.
433  *
434  *      Note: index scans have 2 sets of state information because
435  *            we have to keep track of the base relation and the
436  *            index relations.
437  *            
438  * old comments
439  *      Creates the run-time state information for the node and 
440  *      sets the relation id to contain relevant decriptors.
441  *    
442  *      Parameters: 
443  *        node: IndexNode node produced by the planner.
444  *        estate: the execution state initialized in InitPlan.
445  * ----------------------------------------------------------------
446  */
447 bool
448 ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
449 {
450     IndexScanState      *indexstate;
451     CommonScanState     *scanstate;
452     List                *indxqual;
453     List                *indxid;
454     int                 i;
455     int                 numIndices;
456     int                 indexPtr;
457     ScanKey             *scanKeys;
458     int                 *numScanKeys;
459     RelationPtr         relationDescs;
460     IndexScanDescPtr    scanDescs;
461     Pointer             *runtimeKeyInfo;
462     bool                have_runtime_keys;
463     List                *rangeTable;
464     RangeTblEntry       *rtentry;
465     Index               relid;
466     Oid                 reloid;
467     TimeQual            timeQual;
468
469     Relation            currentRelation;
470     HeapScanDesc        currentScanDesc;
471     ScanDirection       direction;
472     int                 baseid;
473
474     /* ----------------
475      *  assign execution state to node
476      * ----------------
477      */
478     node->scan.plan.state = estate;
479
480     /* --------------------------------
481      *  Part 1)  initialize scan state
482      *
483      *  create new CommonScanState for node
484      * --------------------------------
485      */
486     scanstate = makeNode(CommonScanState);
487 /*
488     scanstate->ss_ProcOuterFlag = false;
489     scanstate->ss_OldRelId = 0;
490 */
491
492     node->scan.scanstate = scanstate;
493
494     /* ----------------
495      *  assign node's base_id .. we don't use AssignNodeBaseid() because
496      *  the increment is done later on after we assign the index scan's
497      *  scanstate.  see below. 
498      * ----------------
499      */
500     baseid = estate->es_BaseId;
501 /*    scanstate->csstate.cstate.bnode.base_id = baseid; */
502     scanstate->cstate.cs_base_id = baseid;
503
504     /* ----------------
505      *  create expression context for node
506      * ----------------
507      */
508     ExecAssignExprContext(estate, &scanstate->cstate);
509
510 #define INDEXSCAN_NSLOTS 3
511     /* ----------------
512      *  tuple table initialization
513      * ----------------
514      */
515     ExecInitResultTupleSlot(estate, &scanstate->cstate); 
516     ExecInitScanTupleSlot(estate, scanstate);
517 /*    ExecInitRawTupleSlot(estate, scanstate); */
518
519     /* ----------------
520      *  initialize projection info.  result type comes from scan desc
521      *  below..
522      * ----------------
523      */
524     ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
525
526    /* --------------------------------
527      *  Part 2)  initialize index scan state
528      *
529      *  create new IndexScanState for node
530      * --------------------------------
531      */
532     indexstate = makeNode(IndexScanState);
533     indexstate->iss_NumIndices = 0;
534     indexstate->iss_IndexPtr = 0;
535     indexstate->iss_ScanKeys = NULL;
536     indexstate->iss_NumScanKeys = NULL;
537     indexstate->iss_RuntimeKeyInfo = NULL;
538     indexstate->iss_RelationDescs = NULL;
539     indexstate->iss_ScanDescs = NULL;
540     
541     node->indxstate = indexstate;
542
543     /* ----------------
544      *  assign base id to index scan state also
545      * ----------------
546      */
547     indexstate->cstate.cs_base_id = baseid;
548     baseid++;
549     estate->es_BaseId = baseid;
550
551     /* ----------------
552      *  get the index node information
553      * ----------------
554      */
555     indxid =    node->indxid;
556     indxqual =  node->indxqual;
557     numIndices = length(indxid);
558     indexPtr =   0;
559
560     CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
561
562     /* ----------------
563      *  scanKeys is used to keep track of the ScanKey's. This is needed
564      *  because a single scan may use several indices and each index has
565      *  its own ScanKey.
566      * ----------------
567      */
568     numScanKeys = (int *) palloc(numIndices * sizeof(int));
569     scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
570     relationDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
571     scanDescs =  (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
572
573     /* ----------------
574      *  initialize runtime key info.
575      * ----------------
576      */
577     have_runtime_keys = false;
578     runtimeKeyInfo = (Pointer *)
579         palloc(numIndices * sizeof(Pointer));
580
581     /* ----------------
582      *  build the index scan keys from the index qualification
583      * ----------------
584      */
585     for (i=0; i < numIndices; i++) {
586         int             j;
587         List            *qual;
588         int             n_keys;
589         ScanKey         scan_keys;
590         int             *run_keys;
591         
592         qual =          nth(i, indxqual);
593         n_keys =        length(qual);
594         scan_keys = (n_keys <= 0) ? NULL :
595             (ScanKey)palloc(n_keys * sizeof(ScanKeyData));
596         run_keys = (n_keys <= 0) ? NULL :
597                 (int *)palloc(n_keys * sizeof(int));
598         
599         CXT1_printf("ExecInitIndexScan: context is %d\n",
600                     CurrentMemoryContext);
601         
602         /* ----------------
603          *  for each opclause in the given qual,
604          *  convert each qual's opclause into a single scan key
605          * ----------------
606          */
607         for (j=0; j < n_keys; j++) {
608             Expr        *clause;                /* one part of index qual */
609             Oper        *op;            /* operator used in scan.. */
610             Node        *leftop;                /* expr on lhs of operator */
611             Node        *rightop;       /* expr on rhs ... */
612             
613             int         scanvar;        /* which var identifies varattno */
614             AttrNumber  varattno = 0;   /* att number used in scan */
615             Oid         opid;           /* operator id used in scan */
616             Datum       scanvalue = 0;  /* value used in scan (if const) */
617             
618             /* ----------------
619              *  extract clause information from the qualification
620              * ----------------
621              */
622             clause =    nth(j, qual);
623             
624             op = (Oper*)clause->oper;
625             if (!IsA(op,Oper))
626                 elog(WARN, "ExecInitIndexScan: op not an Oper!");
627             
628             opid = op->opid;
629             
630             /* ----------------
631              *  Here we figure out the contents of the index qual.
632              *  The usual case is (op var const) or (op const var)
633              *  which means we form a scan key for the attribute
634              *  listed in the var node and use the value of the const.
635              *
636              *  If we don't have a const node, then it means that
637              *  one of the var nodes refers to the "scan" tuple and
638              *  is used to determine which attribute to scan, and the
639              *  other expression is used to calculate the value used in
640              *  scanning the index.
641              *
642              *  This means our index scan's scan key is a function of
643              *  information obtained during the execution of the plan
644              *  in which case we need to recalculate the index scan key
645              *  at run time.
646              *  
647              *  Hence, we set have_runtime_keys to true and then set
648              *  the appropriate flag in run_keys to LEFT_OP or RIGHT_OP.
649              *  The corresponding scan keys are recomputed at run time.
650              * ----------------
651              */
652             
653             scanvar = NO_OP;
654             
655             /* ----------------
656              *  determine information in leftop
657              * ----------------
658              */
659             leftop =    (Node*) get_leftop(clause);
660             
661             if (IsA(leftop,Var) && var_is_rel((Var*)leftop)) {
662                 /* ----------------
663                  *  if the leftop is a "rel-var", then it means
664                  *  that it is a var node which tells us which
665                  *  attribute to use for our scan key.
666                  * ----------------
667                  */
668                 varattno =      ((Var*) leftop)->varattno;
669                 scanvar =       LEFT_OP;
670             } else if (IsA(leftop,Const)) {
671                 /* ----------------
672                  *  if the leftop is a const node then it means
673                  *  it identifies the value to place in our scan key.
674                  * ----------------
675                  */
676                 run_keys[ j ] = NO_OP;
677                 scanvalue = ((Const*) leftop)->constvalue;
678             } else if (leftop != NULL &&
679                        is_funcclause(leftop) &&
680                        var_is_rel(lfirst(((Expr*)leftop)->args))) {
681                 /* ----------------
682                  *  if the leftop is a func node then it means
683                  *  it identifies the value to place in our scan key.
684                  *  Since functional indices have only one attribute
685                  *  the attno must always be set to 1.
686                  * ----------------
687                  */
688                 varattno =      1;
689                 scanvar =       LEFT_OP;
690                 
691             } else {
692                 /* ----------------
693                  *  otherwise, the leftop contains information usable
694                  *  at runtime to figure out the value to place in our
695                  *  scan key.
696                  * ----------------
697                  */
698                 have_runtime_keys = true;
699                 run_keys[ j ] = LEFT_OP;
700                 scanvalue = Int32GetDatum((int32) true);
701             }
702             
703             /* ----------------
704              *  now determine information in rightop
705              * ----------------
706              */
707             rightop =   (Node*) get_rightop(clause);
708             
709             if (IsA(rightop,Var) && var_is_rel((Var*)rightop)) {
710                 /* ----------------
711                  *  here we make sure only one op identifies the
712                  *  scan-attribute...
713                  * ----------------
714                  */
715                 if (scanvar == LEFT_OP)
716                     elog(WARN, "ExecInitIndexScan: %s",
717                          "both left and right op's are rel-vars");
718                 
719                 /* ----------------
720                  *  if the rightop is a "rel-var", then it means
721                  *  that it is a var node which tells us which
722                  *  attribute to use for our scan key.
723                  * ----------------
724                  */
725                 varattno =      ((Var*) rightop)->varattno;
726                 scanvar =       RIGHT_OP;
727                 
728             } else if (IsA(rightop,Const)) {
729                 /* ----------------
730                  *  if the leftop is a const node then it means
731                  *  it identifies the value to place in our scan key.
732                  * ----------------
733                  */
734                 run_keys[ j ] = NO_OP;
735                 scanvalue = ((Const*) rightop)->constvalue;
736                 
737             } else if (rightop!=NULL &&
738                        is_funcclause(rightop) &&
739                        var_is_rel(lfirst(((Expr*)rightop)->args))) {
740                 /* ----------------
741                  *  if the rightop is a func node then it means
742                  *  it identifies the value to place in our scan key.
743                  *  Since functional indices have only one attribute
744                  *  the attno must always be set to 1.
745                  * ----------------
746                  */
747                 if (scanvar == LEFT_OP)
748                     elog(WARN, "ExecInitIndexScan: %s",
749                          "both left and right ops are rel-vars");
750                 
751                 varattno =      1;
752                 scanvar =       RIGHT_OP;
753                 
754             } else {
755                 /* ----------------
756                  *  otherwise, the leftop contains information usable
757                  *  at runtime to figure out the value to place in our
758                  *  scan key.
759                  * ----------------
760                  */
761                 have_runtime_keys = true;
762                 run_keys[ j ] = RIGHT_OP;
763                 scanvalue = Int32GetDatum((int32) true);
764             }
765             
766             /* ----------------
767              *  now check that at least one op tells us the scan
768              *  attribute...
769              * ----------------
770              */
771             if (scanvar == NO_OP) 
772                 elog(WARN, "ExecInitIndexScan: %s",
773                      "neither leftop nor rightop refer to scan relation");
774             
775             /* ----------------
776              *  initialize the scan key's fields appropriately
777              * ----------------
778              */
779             ScanKeyEntryInitialize(&scan_keys[j],
780                                    0,
781                                    varattno, /* attribute number to scan */
782                                    (RegProcedure) opid, /* reg proc to use */
783                                    (Datum) scanvalue);  /* constant */
784         }
785         
786         /* ----------------
787          *  store the key information into our array.
788          * ----------------
789          */
790         numScanKeys[ i ] =      n_keys;
791         scanKeys[ i ] =         scan_keys;
792         runtimeKeyInfo[ i ] =   (Pointer) run_keys;
793     }
794
795     indexstate->iss_NumIndices = numIndices;
796     indexstate->iss_IndexPtr = indexPtr;
797     indexstate->iss_ScanKeys = scanKeys;
798     indexstate->iss_NumScanKeys = numScanKeys;
799
800     /* ----------------
801      *  If all of our keys have the form (op var const) , then we have no
802      *  runtime keys so we store NULL in the runtime key info.
803      *  Otherwise runtime key info contains an array of pointers
804      *  (one for each index) to arrays of flags (one for each key)
805      *  which indicate that the qual needs to be evaluated at runtime.
806      *  -cim 10/24/89
807      * ----------------
808      */
809     if (have_runtime_keys)
810         {
811             indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
812         }
813     else {
814         indexstate->iss_RuntimeKeyInfo = NULL;
815         for (i=0; i < numIndices; i++) {
816             List *qual;
817             int n_keys;
818             qual = nth(i, indxqual);
819             n_keys = length(qual);
820             if (n_keys > 0)
821                 pfree(runtimeKeyInfo[i]);
822         }
823         pfree(runtimeKeyInfo);
824     }
825
826     /* ----------------
827      *  get the range table and direction information
828      *  from the execution state (these are needed to
829      *  open the relations).
830      * ----------------
831      */
832     rangeTable = estate->es_range_table;
833     direction =  estate->es_direction;
834
835     /* ----------------
836      *  open the base relation
837      * ----------------
838      */
839     relid =   node->scan.scanrelid;
840     rtentry = rt_fetch(relid, rangeTable);
841     reloid =  rtentry->relid;
842     timeQual = rtentry->timeQual;
843
844     ExecOpenScanR(reloid,             /* relation */
845                   0,                  /* nkeys */
846                   (ScanKey) NULL,     /* scan key */
847                   0,                  /* is index */
848                   direction,          /* scan direction */
849                   timeQual,           /* time qual */
850                   &currentRelation,   /* return: rel desc */
851                   (Pointer *) &currentScanDesc);  /* return: scan desc */
852
853     scanstate->css_currentRelation = currentRelation;
854     scanstate->css_currentScanDesc = currentScanDesc;
855
856
857     /* ----------------
858      *  get the scan type from the relation descriptor.
859      * ----------------
860      */
861     ExecAssignScanType(scanstate, RelationGetTupleDescriptor(currentRelation));
862     ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
863
864     /* ----------------
865      *  index scans don't have subtrees..
866      * ----------------
867      */
868 /*    scanstate->ss_ProcOuterFlag = false; */
869
870     /* ----------------
871      *  open the index relations and initialize
872      *  relation and scan descriptors.
873      * ----------------
874      */
875     for (i=0; i < numIndices; i++) {
876         Oid     indexOid;
877         
878         indexOid =  (Oid)nth(i, indxid);
879         
880         if (indexOid != 0) {
881             ExecOpenScanR(indexOid,               /* relation */
882                           numScanKeys[ i ],       /* nkeys */
883                           scanKeys[ i ],          /* scan key */
884                           true,                   /* is index */
885                           direction,              /* scan direction */
886                           timeQual,               /* time qual */
887                           &(relationDescs[ i ]),  /* return: rel desc */
888                           (Pointer *) &(scanDescs[ i ]));
889             /* return: scan desc */
890         }
891     }
892
893     indexstate->iss_RelationDescs = relationDescs;
894     indexstate->iss_ScanDescs = scanDescs;
895
896     indexstate->cstate.cs_TupFromTlist = false;
897
898     /* ----------------
899      *  all done.
900      * ----------------
901      */
902     return TRUE;
903 }
904
905 int
906 ExecCountSlotsIndexScan(IndexScan *node)
907 {
908     return ExecCountSlotsNode(outerPlan((Plan *)node)) +
909         ExecCountSlotsNode(innerPlan((Plan *)node)) +
910             INDEXSCAN_NSLOTS;
911 }