Age Owner Branch data TLA 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 *
3214 andres@anarazel.de 45 :UBC 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 *
7371 tgl@sss.pgh.pa.us 58 :CBC 254 : ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags)
59 : : {
7686 60 : 254 : 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 */
7371 68 [ - + ]: 254 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
69 : :
70 : : /*
71 : : * Set up empty vector of subplan states
72 : : */
7686 73 : 254 : nplans = list_length(node->bitmapplans);
74 : :
75 : 254 : bitmapplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
76 : :
77 : : /*
78 : : * create new BitmapOrState for our BitmapOr node
79 : : */
80 : 254 : bitmaporstate->ps.plan = (Plan *) node;
81 : 254 : bitmaporstate->ps.state = estate;
3214 andres@anarazel.de 82 : 254 : bitmaporstate->ps.ExecProcNode = ExecBitmapOr;
7686 tgl@sss.pgh.pa.us 83 : 254 : bitmaporstate->bitmapplans = bitmapplanstates;
84 : 254 : 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 : : */
7685 90 : 254 : i = 0;
91 [ + - + + : 766 : foreach(l, node->bitmapplans)
+ + ]
92 : : {
93 : 512 : initNode = (Plan *) lfirst(l);
7371 94 : 512 : bitmapplanstates[i] = ExecInitNode(initNode, estate, eflags);
7685 95 : 512 : 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 : :
7686 105 : 254 : return bitmaporstate;
106 : : }
107 : :
108 : : /* ----------------------------------------------------------------
109 : : * MultiExecBitmapOr
110 : : * ----------------------------------------------------------------
111 : : */
112 : : Node *
113 : 177 : MultiExecBitmapOr(BitmapOrState *node)
114 : : {
115 : : PlanState **bitmapplans;
116 : : int nplans;
117 : : int i;
118 : 177 : TIDBitmap *result = NULL;
119 : :
120 : : /* must provide our own instrumentation support */
121 [ + + ]: 177 : if (node->ps.instrument)
122 : 4 : InstrStartNode(node->ps.instrument);
123 : :
124 : : /*
125 : : * get information from the node
126 : : */
127 : 177 : bitmapplans = node->bitmapplans;
128 : 177 : nplans = node->nplans;
129 : :
130 : : /*
131 : : * Scan all the subplans and OR their result bitmaps
132 : : */
133 [ + + ]: 531 : for (i = 0; i < nplans; i++)
134 : : {
135 : 354 : 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 : : */
7685 143 [ + + ]: 354 : if (IsA(subnode, BitmapIndexScanState))
144 : : {
7507 bruce@momjian.us 145 [ + + ]: 350 : if (result == NULL) /* first subplan */
146 : : {
147 : : /* XXX should we use less than work_mem for this? */
459 tgl@sss.pgh.pa.us 148 : 173 : result = tbm_create(work_mem * (Size) 1024,
3345 rhaas@postgresql.org 149 [ - + ]: 173 : ((BitmapOr *) node->ps.plan)->isshared ?
3345 rhaas@postgresql.org 150 :UBC 0 : node->ps.state->es_query_dsa : NULL);
151 : : }
152 : :
7685 tgl@sss.pgh.pa.us 153 :CBC 350 : ((BitmapIndexScanState *) subnode)->biss_result = result;
154 : :
155 : 350 : subresult = (TIDBitmap *) MultiExecProcNode(subnode);
156 : :
157 [ - + ]: 350 : if (subresult != result)
7685 tgl@sss.pgh.pa.us 158 [ # # ]:UBC 0 : elog(ERROR, "unrecognized result from subplan");
159 : : }
160 : : else
161 : : {
162 : : /* standard implementation */
7685 tgl@sss.pgh.pa.us 163 :CBC 4 : subresult = (TIDBitmap *) MultiExecProcNode(subnode);
164 : :
165 [ + - - + ]: 4 : if (!subresult || !IsA(subresult, TIDBitmap))
7685 tgl@sss.pgh.pa.us 166 [ # # ]:UBC 0 : elog(ERROR, "unrecognized result from subplan");
167 : :
7685 tgl@sss.pgh.pa.us 168 [ + - ]:CBC 4 : if (result == NULL)
3240 169 : 4 : result = subresult; /* first subplan */
170 : : else
171 : : {
7685 tgl@sss.pgh.pa.us 172 :UBC 0 : tbm_union(result, subresult);
173 : 0 : tbm_free(subresult);
174 : : }
175 : : }
176 : : }
177 : :
178 : : /* We could return an empty result set here? */
7686 tgl@sss.pgh.pa.us 179 [ - + ]:CBC 177 : if (result == NULL)
7686 tgl@sss.pgh.pa.us 180 [ # # ]:UBC 0 : elog(ERROR, "BitmapOr doesn't support zero inputs");
181 : :
182 : : /* must provide our own instrumentation support */
7686 tgl@sss.pgh.pa.us 183 [ + + ]:CBC 177 : if (node->ps.instrument)
7280 bruce@momjian.us 184 : 4 : InstrStopNode(node->ps.instrument, 0 /* XXX */ );
185 : :
7686 tgl@sss.pgh.pa.us 186 : 177 : 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 : 254 : ExecEndBitmapOr(BitmapOrState *node)
199 : : {
200 : : PlanState **bitmapplans;
201 : : int nplans;
202 : : int i;
203 : :
204 : : /*
205 : : * get information from the node
206 : : */
207 : 254 : bitmapplans = node->bitmapplans;
208 : 254 : nplans = node->nplans;
209 : :
210 : : /*
211 : : * shut down each of the subscans (that we've initialized)
212 : : */
213 [ + + ]: 766 : for (i = 0; i < nplans; i++)
214 : : {
215 [ + - ]: 512 : if (bitmapplans[i])
216 : 512 : ExecEndNode(bitmapplans[i]);
217 : : }
218 : 254 : }
219 : :
220 : : void
5776 221 : 25 : ExecReScanBitmapOr(BitmapOrState *node)
222 : : {
223 : : int i;
224 : :
7686 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 : : */
5776 240 [ + + ]: 50 : if (subnode->chgParam == NULL)
241 : 46 : ExecReScan(subnode);
242 : : }
7686 243 : 25 : }
|