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