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