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