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-2025, 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 *
2973 andres@anarazel.de 43 :UBC 0 : ExecBitmapOr(PlanState *pstate)
44 : : {
45 [ # # ]: 0 : elog(ERROR, "BitmapOr node does not support ExecProcNode call convention");
46 : : return NULL;
47 : : }
48 : :
49 : : /* ----------------------------------------------------------------
50 : : * ExecInitBitmapOr
51 : : *
52 : : * Begin all of the subscans of the BitmapOr node.
53 : : * ----------------------------------------------------------------
54 : : */
55 : : BitmapOrState *
7130 tgl@sss.pgh.pa.us 56 :CBC 209 : ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags)
57 : : {
7445 58 : 209 : BitmapOrState *bitmaporstate = makeNode(BitmapOrState);
59 : : PlanState **bitmapplanstates;
60 : : int nplans;
61 : : int i;
62 : : ListCell *l;
63 : : Plan *initNode;
64 : :
65 : : /* check for unsupported flags */
7130 66 [ - + ]: 209 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
67 : :
68 : : /*
69 : : * Set up empty vector of subplan states
70 : : */
7445 71 : 209 : nplans = list_length(node->bitmapplans);
72 : :
73 : 209 : bitmapplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
74 : :
75 : : /*
76 : : * create new BitmapOrState for our BitmapOr node
77 : : */
78 : 209 : bitmaporstate->ps.plan = (Plan *) node;
79 : 209 : bitmaporstate->ps.state = estate;
2973 andres@anarazel.de 80 : 209 : bitmaporstate->ps.ExecProcNode = ExecBitmapOr;
7445 tgl@sss.pgh.pa.us 81 : 209 : bitmaporstate->bitmapplans = bitmapplanstates;
82 : 209 : 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 : : */
7444 88 : 209 : i = 0;
89 [ + - + + : 630 : foreach(l, node->bitmapplans)
+ + ]
90 : : {
91 : 421 : initNode = (Plan *) lfirst(l);
7130 92 : 421 : bitmapplanstates[i] = ExecInitNode(initNode, estate, eflags);
7444 93 : 421 : i++;
94 : : }
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 : :
7445 103 : 209 : return bitmaporstate;
104 : : }
105 : :
106 : : /* ----------------------------------------------------------------
107 : : * MultiExecBitmapOr
108 : : * ----------------------------------------------------------------
109 : : */
110 : : Node *
111 : 152 : MultiExecBitmapOr(BitmapOrState *node)
112 : : {
113 : : PlanState **bitmapplans;
114 : : int nplans;
115 : : int i;
116 : 152 : TIDBitmap *result = NULL;
117 : :
118 : : /* must provide our own instrumentation support */
119 [ + + ]: 152 : if (node->ps.instrument)
120 : 3 : InstrStartNode(node->ps.instrument);
121 : :
122 : : /*
123 : : * get information from the node
124 : : */
125 : 152 : bitmapplans = node->bitmapplans;
126 : 152 : nplans = node->nplans;
127 : :
128 : : /*
129 : : * Scan all the subplans and OR their result bitmaps
130 : : */
131 [ + + ]: 456 : for (i = 0; i < nplans; i++)
132 : : {
133 : 304 : PlanState *subnode = bitmapplans[i];
134 : : 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 : : */
7444 141 [ + + ]: 304 : if (IsA(subnode, BitmapIndexScanState))
142 : : {
7266 bruce@momjian.us 143 [ + + ]: 301 : if (result == NULL) /* first subplan */
144 : : {
145 : : /* XXX should we use less than work_mem for this? */
218 tgl@sss.pgh.pa.us 146 : 149 : result = tbm_create(work_mem * (Size) 1024,
3104 rhaas@postgresql.org 147 [ - + ]: 149 : ((BitmapOr *) node->ps.plan)->isshared ?
3104 rhaas@postgresql.org 148 :UBC 0 : node->ps.state->es_query_dsa : NULL);
149 : : }
150 : :
7444 tgl@sss.pgh.pa.us 151 :CBC 301 : ((BitmapIndexScanState *) subnode)->biss_result = result;
152 : :
153 : 301 : subresult = (TIDBitmap *) MultiExecProcNode(subnode);
154 : :
155 [ - + ]: 301 : if (subresult != result)
7444 tgl@sss.pgh.pa.us 156 [ # # ]:UBC 0 : elog(ERROR, "unrecognized result from subplan");
157 : : }
158 : : else
159 : : {
160 : : /* standard implementation */
7444 tgl@sss.pgh.pa.us 161 :CBC 3 : subresult = (TIDBitmap *) MultiExecProcNode(subnode);
162 : :
163 [ + - - + ]: 3 : if (!subresult || !IsA(subresult, TIDBitmap))
7444 tgl@sss.pgh.pa.us 164 [ # # ]:UBC 0 : elog(ERROR, "unrecognized result from subplan");
165 : :
7444 tgl@sss.pgh.pa.us 166 [ + - ]:CBC 3 : if (result == NULL)
2999 167 : 3 : result = subresult; /* first subplan */
168 : : else
169 : : {
7444 tgl@sss.pgh.pa.us 170 :UBC 0 : tbm_union(result, subresult);
171 : 0 : tbm_free(subresult);
172 : : }
173 : : }
174 : : }
175 : :
176 : : /* We could return an empty result set here? */
7445 tgl@sss.pgh.pa.us 177 [ - + ]:CBC 152 : if (result == NULL)
7445 tgl@sss.pgh.pa.us 178 [ # # ]:UBC 0 : elog(ERROR, "BitmapOr doesn't support zero inputs");
179 : :
180 : : /* must provide our own instrumentation support */
7445 tgl@sss.pgh.pa.us 181 [ + + ]:CBC 152 : if (node->ps.instrument)
7039 bruce@momjian.us 182 : 3 : InstrStopNode(node->ps.instrument, 0 /* XXX */ );
183 : :
7445 tgl@sss.pgh.pa.us 184 : 152 : return (Node *) result;
185 : : }
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 : 209 : ExecEndBitmapOr(BitmapOrState *node)
197 : : {
198 : : PlanState **bitmapplans;
199 : : int nplans;
200 : : int i;
201 : :
202 : : /*
203 : : * get information from the node
204 : : */
205 : 209 : bitmapplans = node->bitmapplans;
206 : 209 : nplans = node->nplans;
207 : :
208 : : /*
209 : : * shut down each of the subscans (that we've initialized)
210 : : */
211 [ + + ]: 630 : for (i = 0; i < nplans; i++)
212 : : {
213 [ + - ]: 421 : if (bitmapplans[i])
214 : 421 : ExecEndNode(bitmapplans[i]);
215 : : }
216 : 209 : }
217 : :
218 : : void
5535 219 : 20 : ExecReScanBitmapOr(BitmapOrState *node)
220 : : {
221 : : int i;
222 : :
7445 223 [ + + ]: 60 : for (i = 0; i < node->nplans; i++)
224 : : {
225 : 40 : 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 [ + + ]: 40 : if (node->ps.chgParam != NULL)
232 : 6 : 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 : : */
5535 238 [ + + ]: 40 : if (subnode->chgParam == NULL)
239 : 37 : ExecReScan(subnode);
240 : : }
7445 241 : 20 : }
|