/src/postgres/src/backend/executor/nodeBitmapOr.c
Line | Count | Source |
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 | | ExecBitmapOr(PlanState *pstate) |
47 | 0 | { |
48 | 0 | elog(ERROR, "BitmapOr node does not support ExecProcNode call convention"); |
49 | 0 | return NULL; |
50 | 0 | } |
51 | | |
52 | | /* ---------------------------------------------------------------- |
53 | | * ExecInitBitmapOr |
54 | | * |
55 | | * Begin all of the subscans of the BitmapOr node. |
56 | | * ---------------------------------------------------------------- |
57 | | */ |
58 | | BitmapOrState * |
59 | | ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags) |
60 | 0 | { |
61 | 0 | BitmapOrState *bitmaporstate = makeNode(BitmapOrState); |
62 | 0 | PlanState **bitmapplanstates; |
63 | 0 | int nplans; |
64 | 0 | int i; |
65 | 0 | ListCell *l; |
66 | 0 | Plan *initNode; |
67 | | |
68 | | /* check for unsupported flags */ |
69 | 0 | Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); |
70 | | |
71 | | /* |
72 | | * Set up empty vector of subplan states |
73 | | */ |
74 | 0 | nplans = list_length(node->bitmapplans); |
75 | |
|
76 | 0 | bitmapplanstates = palloc0_array(PlanState *, nplans); |
77 | | |
78 | | /* |
79 | | * create new BitmapOrState for our BitmapOr node |
80 | | */ |
81 | 0 | bitmaporstate->ps.plan = (Plan *) node; |
82 | 0 | bitmaporstate->ps.state = estate; |
83 | 0 | bitmaporstate->ps.ExecProcNode = ExecBitmapOr; |
84 | 0 | bitmaporstate->bitmapplans = bitmapplanstates; |
85 | 0 | 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 | 0 | i = 0; |
92 | 0 | foreach(l, node->bitmapplans) |
93 | 0 | { |
94 | 0 | initNode = (Plan *) lfirst(l); |
95 | 0 | bitmapplanstates[i] = ExecInitNode(initNode, estate, eflags); |
96 | 0 | i++; |
97 | 0 | } |
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 | 0 | return bitmaporstate; |
107 | 0 | } |
108 | | |
109 | | /* ---------------------------------------------------------------- |
110 | | * MultiExecBitmapOr |
111 | | * ---------------------------------------------------------------- |
112 | | */ |
113 | | Node * |
114 | | MultiExecBitmapOr(BitmapOrState *node) |
115 | 0 | { |
116 | 0 | PlanState **bitmapplans; |
117 | 0 | int nplans; |
118 | 0 | int i; |
119 | 0 | TIDBitmap *result = NULL; |
120 | | |
121 | | /* must provide our own instrumentation support */ |
122 | 0 | if (node->ps.instrument) |
123 | 0 | InstrStartNode(node->ps.instrument); |
124 | | |
125 | | /* |
126 | | * get information from the node |
127 | | */ |
128 | 0 | bitmapplans = node->bitmapplans; |
129 | 0 | nplans = node->nplans; |
130 | | |
131 | | /* |
132 | | * Scan all the subplans and OR their result bitmaps |
133 | | */ |
134 | 0 | for (i = 0; i < nplans; i++) |
135 | 0 | { |
136 | 0 | PlanState *subnode = bitmapplans[i]; |
137 | 0 | 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 | 0 | if (IsA(subnode, BitmapIndexScanState)) |
145 | 0 | { |
146 | 0 | if (result == NULL) /* first subplan */ |
147 | 0 | { |
148 | | /* XXX should we use less than work_mem for this? */ |
149 | 0 | result = tbm_create(work_mem * (Size) 1024, |
150 | 0 | ((BitmapOr *) node->ps.plan)->isshared ? |
151 | 0 | node->ps.state->es_query_dsa : NULL); |
152 | 0 | } |
153 | |
|
154 | 0 | ((BitmapIndexScanState *) subnode)->biss_result = result; |
155 | |
|
156 | 0 | subresult = (TIDBitmap *) MultiExecProcNode(subnode); |
157 | |
|
158 | 0 | if (subresult != result) |
159 | 0 | elog(ERROR, "unrecognized result from subplan"); |
160 | 0 | } |
161 | 0 | else |
162 | 0 | { |
163 | | /* standard implementation */ |
164 | 0 | subresult = (TIDBitmap *) MultiExecProcNode(subnode); |
165 | |
|
166 | 0 | if (!subresult || !IsA(subresult, TIDBitmap)) |
167 | 0 | elog(ERROR, "unrecognized result from subplan"); |
168 | | |
169 | 0 | if (result == NULL) |
170 | 0 | result = subresult; /* first subplan */ |
171 | 0 | else |
172 | 0 | { |
173 | 0 | tbm_union(result, subresult); |
174 | 0 | tbm_free(subresult); |
175 | 0 | } |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | | /* We could return an empty result set here? */ |
180 | 0 | if (result == NULL) |
181 | 0 | elog(ERROR, "BitmapOr doesn't support zero inputs"); |
182 | | |
183 | | /* must provide our own instrumentation support */ |
184 | 0 | if (node->ps.instrument) |
185 | 0 | InstrStopNode(node->ps.instrument, 0 /* XXX */ ); |
186 | |
|
187 | 0 | return (Node *) result; |
188 | 0 | } |
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 | | ExecEndBitmapOr(BitmapOrState *node) |
200 | 0 | { |
201 | 0 | PlanState **bitmapplans; |
202 | 0 | int nplans; |
203 | 0 | int i; |
204 | | |
205 | | /* |
206 | | * get information from the node |
207 | | */ |
208 | 0 | bitmapplans = node->bitmapplans; |
209 | 0 | nplans = node->nplans; |
210 | | |
211 | | /* |
212 | | * shut down each of the subscans (that we've initialized) |
213 | | */ |
214 | 0 | for (i = 0; i < nplans; i++) |
215 | 0 | { |
216 | 0 | if (bitmapplans[i]) |
217 | 0 | ExecEndNode(bitmapplans[i]); |
218 | 0 | } |
219 | 0 | } |
220 | | |
221 | | void |
222 | | ExecReScanBitmapOr(BitmapOrState *node) |
223 | 0 | { |
224 | 0 | int i; |
225 | |
|
226 | 0 | for (i = 0; i < node->nplans; i++) |
227 | 0 | { |
228 | 0 | 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 | 0 | if (node->ps.chgParam != NULL) |
235 | 0 | 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 | 0 | if (subnode->chgParam == NULL) |
242 | 0 | ExecReScan(subnode); |
243 | 0 | } |
244 | 0 | } |