]> granicus.if.org Git - postgresql/blob - src/backend/executor/execAmi.c
Re-implement LIMIT/OFFSET as a plan node type, instead of a hack in
[postgresql] / src / backend / executor / execAmi.c
1 /*-------------------------------------------------------------------------
2  *
3  * execAmi.c
4  *        miscellaneous executor access method routines
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *      $Id: execAmi.c,v 1.54 2000/10/26 21:35:15 tgl Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 /*
14  *       INTERFACE ROUTINES
15  *
16  *              ExecOpenScanR   \                                                         / amopen
17  *              ExecBeginScan    \                                                       /      ambeginscan
18  *              ExecCloseR                \                                                     /       amclose
19  *              ExecInsert                 \  executor interface   /    aminsert
20  *              ExecReScanR                /  to access methods    \    amrescan
21  *              ExecMarkPos               /                                                     \       ammarkpos
22  *              ExecRestrPos     /                                                       \  amrestpos
23  */
24
25 #include "postgres.h"
26
27
28 #include "access/genam.h"
29 #include "access/heapam.h"
30 #include "catalog/heap.h"
31 #include "executor/execdebug.h"
32 #include "executor/nodeAgg.h"
33 #include "executor/nodeAppend.h"
34 #include "executor/nodeGroup.h"
35 #include "executor/nodeGroup.h"
36 #include "executor/nodeHash.h"
37 #include "executor/nodeHashjoin.h"
38 #include "executor/nodeIndexscan.h"
39 #include "executor/nodeTidscan.h"
40 #include "executor/nodeLimit.h"
41 #include "executor/nodeMaterial.h"
42 #include "executor/nodeMergejoin.h"
43 #include "executor/nodeNestloop.h"
44 #include "executor/nodeResult.h"
45 #include "executor/nodeSeqscan.h"
46 #include "executor/nodeSetOp.h"
47 #include "executor/nodeSort.h"
48 #include "executor/nodeSubplan.h"
49 #include "executor/nodeSubqueryscan.h"
50 #include "executor/nodeUnique.h"
51
52 static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
53                           bool isindex, ScanDirection dir, Snapshot snapshot);
54
55 /* ----------------------------------------------------------------
56  *              ExecOpenScanR
57  *
58  * old comments:
59  *              Parameters:
60  *                relation -- relation to be opened and scanned.
61  *                nkeys    -- number of keys
62  *                skeys    -- keys to restrict scanning
63  *                       isindex  -- if this is true, the relation is the relid of
64  *                                               an index relation, else it is an index into the
65  *                                               range table.
66  *              Returns the relation as(relDesc scanDesc)
67  *                 If this structure is changed, need to modify the access macros
68  *              defined in execInt.h.
69  * ----------------------------------------------------------------
70  */
71 void
72 ExecOpenScanR(Oid relOid,
73                           int nkeys,
74                           ScanKey skeys,
75                           bool isindex,
76                           ScanDirection dir,
77                           Snapshot snapshot,
78                           Relation *returnRelation, /* return */
79                           Pointer *returnScanDesc)      /* return */
80 {
81         Relation        relation;
82         Pointer         scanDesc;
83
84         /* ----------------
85          *      note: scanDesc returned by ExecBeginScan can be either
86          *                a HeapScanDesc or an IndexScanDesc so for now we
87          *                make it a Pointer.  There should be a better scan
88          *                abstraction someday -cim 9/9/89
89          * ----------------
90          */
91
92         /* ----------------
93          *      open the relation with the correct call depending
94          *      on whether this is a heap relation or an index relation.
95          *
96          *      Do not lock the rel here; beginscan will acquire AccessShareLock.
97          * ----------------
98          */
99         if (isindex)
100                 relation = index_open(relOid);
101         else
102                 relation = heap_open(relOid, NoLock);
103
104         scanDesc = ExecBeginScan(relation,
105                                                          nkeys,
106                                                          skeys,
107                                                          isindex,
108                                                          dir,
109                                                          snapshot);
110
111         if (returnRelation != NULL)
112                 *returnRelation = relation;
113         if (scanDesc != NULL)
114                 *returnScanDesc = scanDesc;
115 }
116
117 /* ----------------------------------------------------------------
118  *              ExecBeginScan
119  *
120  *              beginscans a relation in current direction.
121  *
122  *              XXX fix parameters to AMbeginscan (and btbeginscan)
123  *                              currently we need to pass a flag stating whether
124  *                              or not the scan should begin at an endpoint of
125  *                              the relation.. Right now we always pass false
126  *                              -cim 9/14/89
127  * ----------------------------------------------------------------
128  */
129 static Pointer
130 ExecBeginScan(Relation relation,
131                           int nkeys,
132                           ScanKey skeys,
133                           bool isindex,
134                           ScanDirection dir,
135                           Snapshot snapshot)
136 {
137         Pointer         scanDesc;
138
139         scanDesc = NULL;
140
141         /* ----------------
142          *      open the appropriate type of scan.
143          *
144          *      Note: ambeginscan()'s second arg is a boolean indicating
145          *                that the scan should be done in reverse..  That is,
146          *                if you pass it true, then the scan is backward.
147          * ----------------
148          */
149         if (isindex)
150         {
151                 scanDesc = (Pointer) index_beginscan(relation,
152                                                                                          false,         /* see above comment */
153                                                                                          nkeys,
154                                                                                          skeys);
155         }
156         else
157         {
158                 scanDesc = (Pointer) heap_beginscan(relation,
159                                                                                         ScanDirectionIsBackward(dir),
160                                                                                         snapshot,
161                                                                                         nkeys,
162                                                                                         skeys);
163         }
164
165         if (scanDesc == NULL)
166                 elog(DEBUG, "ExecBeginScan: scanDesc = NULL, heap_beginscan failed.");
167
168         return scanDesc;
169 }
170
171 /* ----------------------------------------------------------------
172  *              ExecCloseR
173  *
174  *              closes the relation and scan descriptor for a scan node.
175  *              Also closes index relations and scans for index scans.
176  * ----------------------------------------------------------------
177  */
178 void
179 ExecCloseR(Plan *node)
180 {
181         CommonScanState *state;
182         Relation        relation;
183         HeapScanDesc scanDesc;
184
185         /* ----------------
186          *      shut down the heap scan and close the heap relation
187          * ----------------
188          */
189         switch (nodeTag(node))
190         {
191
192                 case T_SeqScan:
193                         state = ((SeqScan *) node)->scanstate;
194                         break;
195
196                 case T_IndexScan:
197                         state = ((IndexScan *) node)->scan.scanstate;
198                         break;
199
200                 case T_TidScan:
201                         state = ((TidScan *) node)->scan.scanstate;
202                         break;
203
204                 default:
205                         elog(DEBUG, "ExecCloseR: not a scan node!");
206                         return;
207         }
208
209         relation = state->css_currentRelation;
210         scanDesc = state->css_currentScanDesc;
211
212         if (scanDesc != NULL)
213                 heap_endscan(scanDesc);
214
215         /*
216          * endscan released AccessShareLock acquired by beginscan.      If we are
217          * holding any stronger locks on the rel, they should be held till end
218          * of xact.  Therefore, we need only close the rel and not release
219          * locks.
220          */
221         if (relation != NULL)
222                 heap_close(relation, NoLock);
223
224         /* ----------------
225          *      if this is an index scan then we have to take care
226          *      of the index relations as well..
227          * ----------------
228          */
229         if (IsA(node, IndexScan))
230         {
231                 IndexScan  *iscan = (IndexScan *) node;
232                 IndexScanState *indexstate = iscan->indxstate;
233                 int                     numIndices;
234                 RelationPtr indexRelationDescs;
235                 IndexScanDescPtr indexScanDescs;
236                 int                     i;
237
238                 numIndices = indexstate->iss_NumIndices;
239                 indexRelationDescs = indexstate->iss_RelationDescs;
240                 indexScanDescs = indexstate->iss_ScanDescs;
241
242                 for (i = 0; i < numIndices; i++)
243                 {
244                         /* ----------------
245                          *      shut down each of the scans and
246                          *      close each of the index relations
247                          * ----------------
248                          */
249                         if (indexScanDescs[i] != NULL)
250                                 index_endscan(indexScanDescs[i]);
251
252                         if (indexRelationDescs[i] != NULL)
253                                 index_close(indexRelationDescs[i]);
254                 }
255         }
256 }
257
258 /* ----------------------------------------------------------------
259  *              ExecReScan
260  *
261  *              XXX this should be extended to cope with all the node types..
262  *
263  *              takes the new expression context as an argument, so that
264  *              index scans needn't have their scan keys updated separately
265  *              - marcel 09/20/94
266  * ----------------------------------------------------------------
267  */
268 void
269 ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
270 {
271
272         if (node->chgParam != NULL) /* Wow! */
273         {
274                 List       *lst;
275
276                 foreach(lst, node->initPlan)
277                 {
278                         Plan       *splan = ((SubPlan *) lfirst(lst))->plan;
279
280                         if (splan->extParam != NULL)            /* don't care about child
281                                                                                                  * locParam */
282                                 SetChangedParamList(splan, node->chgParam);
283                         if (splan->chgParam != NULL)
284                                 ExecReScanSetParamPlan((SubPlan *) lfirst(lst), node);
285                 }
286                 foreach(lst, node->subPlan)
287                 {
288                         Plan       *splan = ((SubPlan *) lfirst(lst))->plan;
289
290                         if (splan->extParam != NULL)
291                                 SetChangedParamList(splan, node->chgParam);
292                 }
293                 /* Well. Now set chgParam for left/right trees. */
294                 if (node->lefttree != NULL)
295                         SetChangedParamList(node->lefttree, node->chgParam);
296                 if (node->righttree != NULL)
297                         SetChangedParamList(node->righttree, node->chgParam);
298         }
299
300         switch (nodeTag(node))
301         {
302                 case T_SeqScan:
303                         ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
304                         break;
305
306                 case T_IndexScan:
307                         ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
308                         break;
309
310                 case T_TidScan:
311                         ExecTidReScan((TidScan *) node, exprCtxt, parent);
312                         break;
313
314                 case T_SubqueryScan:
315                         ExecSubqueryReScan((SubqueryScan *) node, exprCtxt, parent);
316                         break;
317
318                 case T_Material:
319                         ExecMaterialReScan((Material *) node, exprCtxt, parent);
320                         break;
321
322                 case T_NestLoop:
323                         ExecReScanNestLoop((NestLoop *) node, exprCtxt, parent);
324                         break;
325
326                 case T_HashJoin:
327                         ExecReScanHashJoin((HashJoin *) node, exprCtxt, parent);
328                         break;
329
330                 case T_Hash:
331                         ExecReScanHash((Hash *) node, exprCtxt, parent);
332                         break;
333
334                 case T_Agg:
335                         ExecReScanAgg((Agg *) node, exprCtxt, parent);
336                         break;
337
338                 case T_Group:
339                         ExecReScanGroup((Group *) node, exprCtxt, parent);
340                         break;
341
342                 case T_Result:
343                         ExecReScanResult((Result *) node, exprCtxt, parent);
344                         break;
345
346                 case T_Unique:
347                         ExecReScanUnique((Unique *) node, exprCtxt, parent);
348                         break;
349
350                 case T_SetOp:
351                         ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
352                         break;
353
354                 case T_Limit:
355                         ExecReScanLimit((Limit *) node, exprCtxt, parent);
356                         break;
357
358                 case T_Sort:
359                         ExecReScanSort((Sort *) node, exprCtxt, parent);
360                         break;
361
362                 case T_MergeJoin:
363                         ExecReScanMergeJoin((MergeJoin *) node, exprCtxt, parent);
364                         break;
365
366                 case T_Append:
367                         ExecReScanAppend((Append *) node, exprCtxt, parent);
368                         break;
369
370                 default:
371                         elog(ERROR, "ExecReScan: node type %d not supported",
372                                  nodeTag(node));
373                         return;
374         }
375
376         if (node->chgParam != NULL)
377         {
378                 freeList(node->chgParam);
379                 node->chgParam = NULL;
380         }
381 }
382
383 /* ----------------------------------------------------------------
384  *              ExecReScanR
385  *
386  *              XXX this does not do the right thing with indices yet.
387  * ----------------------------------------------------------------
388  */
389 HeapScanDesc
390 ExecReScanR(Relation relDesc,   /* LLL relDesc unused  */
391                         HeapScanDesc scanDesc,
392                         ScanDirection direction,
393                         int nkeys,                      /* LLL nkeys unused  */
394                         ScanKey skeys)
395 {
396         if (scanDesc != NULL)
397                 heap_rescan(scanDesc,   /* scan desc */
398                                         ScanDirectionIsBackward(direction), /* backward flag */
399                                         skeys);         /* scan keys */
400
401         return scanDesc;
402 }
403
404 /* ----------------------------------------------------------------
405  *              ExecMarkPos
406  *
407  *              Marks the current scan position.
408  *
409  *              XXX Needs to be extended to include all the node types,
410  *              or at least all the ones that can be directly below a mergejoin.
411  * ----------------------------------------------------------------
412  */
413 void
414 ExecMarkPos(Plan *node)
415 {
416         switch (nodeTag(node))
417         {
418                 case T_SeqScan:
419                         ExecSeqMarkPos((SeqScan *) node);
420                         break;
421
422                 case T_IndexScan:
423                         ExecIndexMarkPos((IndexScan *) node);
424                         break;
425
426                 case T_Material:
427                         ExecMaterialMarkPos((Material *) node);
428                         break;
429
430                 case T_Sort:
431                         ExecSortMarkPos((Sort *) node);
432                         break;
433
434                 case T_TidScan:
435                         ExecTidMarkPos((TidScan *) node);
436                         break;
437
438                 default:
439                         /* don't make hard error unless caller asks to restore... */
440                         elog(DEBUG, "ExecMarkPos: node type %d not supported",
441                                  nodeTag(node));
442                         break;
443         }
444 }
445
446 /* ----------------------------------------------------------------
447  *              ExecRestrPos
448  *
449  *              restores the scan position previously saved with ExecMarkPos()
450  *
451  *              XXX Needs to be extended to include all the node types,
452  *              or at least all the ones that can be directly below a mergejoin.
453  * ----------------------------------------------------------------
454  */
455 void
456 ExecRestrPos(Plan *node)
457 {
458         switch (nodeTag(node))
459         {
460                 case T_SeqScan:
461                         ExecSeqRestrPos((SeqScan *) node);
462                         break;
463
464                 case T_IndexScan:
465                         ExecIndexRestrPos((IndexScan *) node);
466                         break;
467
468                 case T_Material:
469                         ExecMaterialRestrPos((Material *) node);
470                         break;
471
472                 case T_Sort:
473                         ExecSortRestrPos((Sort *) node);
474                         break;
475
476                 default:
477                         elog(ERROR, "ExecRestrPos: node type %d not supported",
478                                  nodeTag(node));
479                         break;
480         }
481 }