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