Coverage Report

Created: 2025-07-03 06:49

/src/postgres/src/backend/nodes/multibitmapset.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * multibitmapset.c
4
 *    Lists of Bitmapsets
5
 *
6
 * A multibitmapset is useful in situations where members of a set can
7
 * be identified by two small integers; for example, varno and varattno
8
 * of a group of Vars within a query.  The implementation is a List of
9
 * Bitmapsets, so that the empty set can be represented by NIL.  (But,
10
 * as with Bitmapsets, that's not the only allowed representation.)
11
 * The zero-based index of a List element is the first identifying value,
12
 * and the (also zero-based) index of a bit within that Bitmapset is
13
 * the second identifying value.  There is no expectation that the
14
 * Bitmapsets should all be the same size.
15
 *
16
 * The available operations on multibitmapsets are intended to parallel
17
 * those on bitmapsets, for example union and intersection.  So far only
18
 * a small fraction of that has been built out; we'll add more as needed.
19
 *
20
 *
21
 * Copyright (c) 2022-2025, PostgreSQL Global Development Group
22
 *
23
 * IDENTIFICATION
24
 *    src/backend/nodes/multibitmapset.c
25
 *
26
 *-------------------------------------------------------------------------
27
 */
28
#include "postgres.h"
29
30
#include "nodes/multibitmapset.h"
31
32
33
/*
34
 * mbms_add_member
35
 *    Add a new member to a multibitmapset.
36
 *
37
 * The new member is identified by "listidx", the zero-based index of the
38
 * List element it should go into, and "bitidx", which specifies the bit
39
 * number to be set therein.
40
 *
41
 * This is like bms_add_member, but for multibitmapsets.
42
 */
43
List *
44
mbms_add_member(List *a, int listidx, int bitidx)
45
0
{
46
0
  Bitmapset  *bms;
47
0
  ListCell   *lc;
48
49
0
  if (listidx < 0 || bitidx < 0)
50
0
    elog(ERROR, "negative multibitmapset member index not allowed");
51
  /* Add empty elements as needed */
52
0
  while (list_length(a) <= listidx)
53
0
    a = lappend(a, NULL);
54
  /* Update the target element */
55
0
  lc = list_nth_cell(a, listidx);
56
0
  bms = lfirst_node(Bitmapset, lc);
57
0
  bms = bms_add_member(bms, bitidx);
58
0
  lfirst(lc) = bms;
59
0
  return a;
60
0
}
61
62
/*
63
 * mbms_add_members
64
 *    Add all members of set b to set a.
65
 *
66
 * This is a UNION operation, but the left input is modified in-place.
67
 *
68
 * This is like bms_add_members, but for multibitmapsets.
69
 */
70
List *
71
mbms_add_members(List *a, const List *b)
72
0
{
73
0
  ListCell   *lca,
74
0
         *lcb;
75
76
  /* Add empty elements to a, as needed */
77
0
  while (list_length(a) < list_length(b))
78
0
    a = lappend(a, NULL);
79
  /* forboth will stop at the end of the shorter list, which is fine */
80
0
  forboth(lca, a, lcb, b)
81
0
  {
82
0
    Bitmapset  *bmsa = lfirst_node(Bitmapset, lca);
83
0
    const Bitmapset *bmsb = lfirst_node(Bitmapset, lcb);
84
85
0
    bmsa = bms_add_members(bmsa, bmsb);
86
0
    lfirst(lca) = bmsa;
87
0
  }
88
0
  return a;
89
0
}
90
91
/*
92
 * mbms_int_members
93
 *    Reduce set a to its intersection with set b.
94
 *
95
 * This is an INTERSECT operation, but the left input is modified in-place.
96
 *
97
 * This is like bms_int_members, but for multibitmapsets.
98
 */
99
List *
100
mbms_int_members(List *a, const List *b)
101
0
{
102
0
  ListCell   *lca,
103
0
         *lcb;
104
105
  /* Remove any elements of a that are no longer of use */
106
0
  a = list_truncate(a, list_length(b));
107
  /* forboth will stop at the end of the shorter list, which is fine */
108
0
  forboth(lca, a, lcb, b)
109
0
  {
110
0
    Bitmapset  *bmsa = lfirst_node(Bitmapset, lca);
111
0
    const Bitmapset *bmsb = lfirst_node(Bitmapset, lcb);
112
113
0
    bmsa = bms_int_members(bmsa, bmsb);
114
0
    lfirst(lca) = bmsa;
115
0
  }
116
0
  return a;
117
0
}
118
119
/*
120
 * mbms_is_member
121
 *    Is listidx/bitidx a member of A?
122
 *
123
 * This is like bms_is_member, but for multibitmapsets.
124
 */
125
bool
126
mbms_is_member(int listidx, int bitidx, const List *a)
127
0
{
128
0
  const Bitmapset *bms;
129
130
  /* XXX better to just return false for negative indexes? */
131
0
  if (listidx < 0 || bitidx < 0)
132
0
    elog(ERROR, "negative multibitmapset member index not allowed");
133
0
  if (listidx >= list_length(a))
134
0
    return false;
135
0
  bms = list_nth_node(Bitmapset, a, listidx);
136
0
  return bms_is_member(bitidx, bms);
137
0
}
138
139
/*
140
 * mbms_overlap_sets
141
 *    Identify the bitmapsets having common members in a and b.
142
 *
143
 * The result is a bitmapset of the list indexes of bitmapsets that overlap.
144
 */
145
Bitmapset *
146
mbms_overlap_sets(const List *a, const List *b)
147
0
{
148
0
  Bitmapset  *result = NULL;
149
0
  ListCell   *lca,
150
0
         *lcb;
151
152
  /* forboth will stop at the end of the shorter list, which is fine */
153
0
  forboth(lca, a, lcb, b)
154
0
  {
155
0
    const Bitmapset *bmsa = lfirst_node(Bitmapset, lca);
156
0
    const Bitmapset *bmsb = lfirst_node(Bitmapset, lcb);
157
158
0
    if (bms_overlap(bmsa, bmsb))
159
0
      result = bms_add_member(result, foreach_current_index(lca));
160
0
  }
161
0
  return result;
162
0
}