]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeBitmapOr.c
Faster expression evaluation and targetlist projection.
[postgresql] / src / backend / executor / nodeBitmapOr.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeBitmapOr.c
4  *        routines to handle BitmapOr nodes.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/executor/nodeBitmapOr.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /* INTERFACE ROUTINES
16  *              ExecInitBitmapOr        - initialize the BitmapOr node
17  *              MultiExecBitmapOr       - retrieve the result bitmap from the node
18  *              ExecEndBitmapOr         - shut down the BitmapOr node
19  *              ExecReScanBitmapOr      - rescan the BitmapOr node
20  *
21  *       NOTES
22  *              BitmapOr nodes don't make use of their left and right
23  *              subtrees, rather they maintain a list of subplans,
24  *              much like Append nodes.  The logic is much simpler than
25  *              Append, however, since we needn't cope with forward/backward
26  *              execution.
27  */
28
29 #include "postgres.h"
30
31 #include "executor/execdebug.h"
32 #include "executor/nodeBitmapOr.h"
33 #include "miscadmin.h"
34
35
36 /* ----------------------------------------------------------------
37  *              ExecInitBitmapOr
38  *
39  *              Begin all of the subscans of the BitmapOr node.
40  * ----------------------------------------------------------------
41  */
42 BitmapOrState *
43 ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags)
44 {
45         BitmapOrState *bitmaporstate = makeNode(BitmapOrState);
46         PlanState **bitmapplanstates;
47         int                     nplans;
48         int                     i;
49         ListCell   *l;
50         Plan       *initNode;
51
52         /* check for unsupported flags */
53         Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
54
55         /*
56          * Set up empty vector of subplan states
57          */
58         nplans = list_length(node->bitmapplans);
59
60         bitmapplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
61
62         /*
63          * create new BitmapOrState for our BitmapOr node
64          */
65         bitmaporstate->ps.plan = (Plan *) node;
66         bitmaporstate->ps.state = estate;
67         bitmaporstate->bitmapplans = bitmapplanstates;
68         bitmaporstate->nplans = nplans;
69
70         /*
71          * Miscellaneous initialization
72          *
73          * BitmapOr plans don't have expression contexts because they never call
74          * ExecQual or ExecProject.  They don't need any tuple slots either.
75          */
76
77         /*
78          * call ExecInitNode on each of the plans to be executed and save the
79          * results into the array "bitmapplanstates".
80          */
81         i = 0;
82         foreach(l, node->bitmapplans)
83         {
84                 initNode = (Plan *) lfirst(l);
85                 bitmapplanstates[i] = ExecInitNode(initNode, estate, eflags);
86                 i++;
87         }
88
89         return bitmaporstate;
90 }
91
92 /* ----------------------------------------------------------------
93  *         MultiExecBitmapOr
94  * ----------------------------------------------------------------
95  */
96 Node *
97 MultiExecBitmapOr(BitmapOrState *node)
98 {
99         PlanState **bitmapplans;
100         int                     nplans;
101         int                     i;
102         TIDBitmap  *result = NULL;
103
104         /* must provide our own instrumentation support */
105         if (node->ps.instrument)
106                 InstrStartNode(node->ps.instrument);
107
108         /*
109          * get information from the node
110          */
111         bitmapplans = node->bitmapplans;
112         nplans = node->nplans;
113
114         /*
115          * Scan all the subplans and OR their result bitmaps
116          */
117         for (i = 0; i < nplans; i++)
118         {
119                 PlanState  *subnode = bitmapplans[i];
120                 TIDBitmap  *subresult;
121
122                 /*
123                  * We can special-case BitmapIndexScan children to avoid an explicit
124                  * tbm_union step for each child: just pass down the current result
125                  * bitmap and let the child OR directly into it.
126                  */
127                 if (IsA(subnode, BitmapIndexScanState))
128                 {
129                         if (result == NULL) /* first subplan */
130                         {
131                                 /* XXX should we use less than work_mem for this? */
132                                 result = tbm_create(work_mem * 1024L,
133                                                                         ((BitmapOr *) node->ps.plan)->isshared ?
134                                                                         node->ps.state->es_query_dsa : NULL);
135                         }
136
137                         ((BitmapIndexScanState *) subnode)->biss_result = result;
138
139                         subresult = (TIDBitmap *) MultiExecProcNode(subnode);
140
141                         if (subresult != result)
142                                 elog(ERROR, "unrecognized result from subplan");
143                 }
144                 else
145                 {
146                         /* standard implementation */
147                         subresult = (TIDBitmap *) MultiExecProcNode(subnode);
148
149                         if (!subresult || !IsA(subresult, TIDBitmap))
150                                 elog(ERROR, "unrecognized result from subplan");
151
152                         if (result == NULL)
153                                 result = subresult;             /* first subplan */
154                         else
155                         {
156                                 tbm_union(result, subresult);
157                                 tbm_free(subresult);
158                         }
159                 }
160         }
161
162         /* We could return an empty result set here? */
163         if (result == NULL)
164                 elog(ERROR, "BitmapOr doesn't support zero inputs");
165
166         /* must provide our own instrumentation support */
167         if (node->ps.instrument)
168                 InstrStopNode(node->ps.instrument, 0 /* XXX */ );
169
170         return (Node *) result;
171 }
172
173 /* ----------------------------------------------------------------
174  *              ExecEndBitmapOr
175  *
176  *              Shuts down the subscans of the BitmapOr node.
177  *
178  *              Returns nothing of interest.
179  * ----------------------------------------------------------------
180  */
181 void
182 ExecEndBitmapOr(BitmapOrState *node)
183 {
184         PlanState **bitmapplans;
185         int                     nplans;
186         int                     i;
187
188         /*
189          * get information from the node
190          */
191         bitmapplans = node->bitmapplans;
192         nplans = node->nplans;
193
194         /*
195          * shut down each of the subscans (that we've initialized)
196          */
197         for (i = 0; i < nplans; i++)
198         {
199                 if (bitmapplans[i])
200                         ExecEndNode(bitmapplans[i]);
201         }
202 }
203
204 void
205 ExecReScanBitmapOr(BitmapOrState *node)
206 {
207         int                     i;
208
209         for (i = 0; i < node->nplans; i++)
210         {
211                 PlanState  *subnode = node->bitmapplans[i];
212
213                 /*
214                  * ExecReScan doesn't know about my subplans, so I have to do
215                  * changed-parameter signaling myself.
216                  */
217                 if (node->ps.chgParam != NULL)
218                         UpdateChangedParamSet(subnode, node->ps.chgParam);
219
220                 /*
221                  * If chgParam of subnode is not null then plan will be re-scanned by
222                  * first ExecProcNode.
223                  */
224                 if (subnode->chgParam == NULL)
225                         ExecReScan(subnode);
226         }
227 }