Coverage Report

Created: 2026-10-16 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}