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