Coverage Report

Created: 2025-08-28 07:58

/src/duckdb/src/execution/index/art/base_node.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "duckdb/execution/index/art/base_node.hpp"
2
3
#include "duckdb/execution/index/art/leaf.hpp"
4
#include "duckdb/execution/index/art/node48.hpp"
5
#include "duckdb/execution/index/art/prefix.hpp"
6
7
namespace duckdb {
8
9
//===--------------------------------------------------------------------===//
10
// BaseNode
11
//===--------------------------------------------------------------------===//
12
13
template <uint8_t CAPACITY, NType TYPE>
14
0
void BaseNode<CAPACITY, TYPE>::InsertChildInternal(BaseNode &n, const uint8_t byte, const Node child) {
15
  // Still space. Insert the child.
16
0
  uint8_t child_pos = 0;
17
0
  while (child_pos < n.count && n.key[child_pos] < byte) {
18
0
    child_pos++;
19
0
  }
20
21
  // Move children backwards to make space.
22
0
  for (uint8_t i = n.count; i > child_pos; i--) {
23
0
    n.key[i] = n.key[i - 1];
24
0
    n.children[i] = n.children[i - 1];
25
0
  }
26
27
0
  n.key[child_pos] = byte;
28
0
  n.children[child_pos] = child;
29
0
  n.count++;
30
0
}
Unexecuted instantiation: duckdb::BaseNode<(unsigned char)4, (duckdb::NType)3>::InsertChildInternal(duckdb::BaseNode<(unsigned char)4, (duckdb::NType)3>&, unsigned char, duckdb::Node)
Unexecuted instantiation: duckdb::BaseNode<(unsigned char)16, (duckdb::NType)4>::InsertChildInternal(duckdb::BaseNode<(unsigned char)16, (duckdb::NType)4>&, unsigned char, duckdb::Node)
31
32
template <uint8_t CAPACITY, NType TYPE>
33
NodeHandle<BaseNode<CAPACITY, TYPE>> BaseNode<CAPACITY, TYPE>::DeleteChildInternal(ART &art, Node &node,
34
0
                                                                                   const uint8_t byte) {
35
0
  NodeHandle<BaseNode<CAPACITY, TYPE>> handle(art, node);
36
0
  auto &n = handle.Get();
37
38
0
  uint8_t child_pos = 0;
39
0
  for (; child_pos < n.count; child_pos++) {
40
0
    if (n.key[child_pos] == byte) {
41
0
      break;
42
0
    }
43
0
  }
44
45
  // Free the child and decrease the count.
46
0
  Node::FreeTree(art, n.children[child_pos]);
47
0
  n.count--;
48
49
  // Possibly move children backwards.
50
0
  for (uint8_t i = child_pos; i < n.count; i++) {
51
0
    n.key[i] = n.key[i + 1];
52
0
    n.children[i] = n.children[i + 1];
53
0
  }
54
55
0
  return handle;
56
0
}
Unexecuted instantiation: duckdb::BaseNode<(unsigned char)4, (duckdb::NType)3>::DeleteChildInternal(duckdb::ART&, duckdb::Node&, unsigned char)
Unexecuted instantiation: duckdb::BaseNode<(unsigned char)16, (duckdb::NType)4>::DeleteChildInternal(duckdb::ART&, duckdb::Node&, unsigned char)
57
58
//===--------------------------------------------------------------------===//
59
// Node4
60
//===--------------------------------------------------------------------===//
61
62
0
void Node4::InsertChild(ART &art, Node &node, const uint8_t byte, const Node child) {
63
0
  {
64
0
    NodeHandle<Node4> handle(art, node);
65
0
    auto &n = handle.Get();
66
67
0
    if (n.count != CAPACITY) {
68
0
      InsertChildInternal(n, byte, child);
69
0
      return;
70
0
    }
71
0
  }
72
  // The node is full.
73
  // Grow to Node16.
74
0
  auto node4 = node;
75
0
  Node16::GrowNode4(art, node, node4);
76
0
  Node16::InsertChild(art, node, byte, child);
77
0
}
78
79
0
void Node4::DeleteChild(ART &art, Node &node, Node &parent, const uint8_t byte, const GateStatus status) {
80
0
  Node child;
81
0
  uint8_t remaining_byte;
82
83
0
  {
84
0
    auto handle = DeleteChildInternal(art, node, byte);
85
0
    auto &n = handle.Get();
86
87
0
    if (n.count != 1) {
88
0
      return;
89
0
    }
90
91
    // Compress one-way nodes.
92
0
    child = n.children[0];
93
0
    remaining_byte = n.key[0];
94
0
  }
95
96
0
  auto prev_node4_status = node.GetGateStatus();
97
0
  Node::FreeNode(art, node);
98
0
  Prefix::Concat(art, parent, node, child, remaining_byte, prev_node4_status);
99
0
}
100
101
0
void Node4::ShrinkNode16(ART &art, Node &node4, Node &node16) {
102
0
  {
103
0
    auto n4_handle = New(art, node4);
104
0
    auto &n4 = n4_handle.Get();
105
0
    node4.SetGateStatus(node16.GetGateStatus());
106
107
0
    NodeHandle<Node16> n16_handle(art, node16);
108
0
    auto &n16 = n16_handle.Get();
109
110
0
    n4.count = n16.count;
111
0
    for (uint8_t i = 0; i < n16.count; i++) {
112
0
      n4.key[i] = n16.key[i];
113
0
      n4.children[i] = n16.children[i];
114
0
    }
115
0
  }
116
0
  Node::FreeNode(art, node16);
117
0
}
118
119
//===--------------------------------------------------------------------===//
120
// Node16
121
//===--------------------------------------------------------------------===//
122
123
0
void Node16::InsertChild(ART &art, Node &node, const uint8_t byte, const Node child) {
124
0
  {
125
0
    NodeHandle<Node16> handle(art, node);
126
0
    auto &n = handle.Get();
127
0
    if (n.count != CAPACITY) {
128
0
      InsertChildInternal(n, byte, child);
129
0
      return;
130
0
    }
131
0
  }
132
  // The node is full.
133
  // Grow to Node48.
134
0
  auto node16 = node;
135
0
  Node48::GrowNode16(art, node, node16);
136
0
  Node48::InsertChild(art, node, byte, child);
137
0
}
138
139
0
void Node16::DeleteChild(ART &art, Node &node, const uint8_t byte) {
140
0
  {
141
0
    auto handle = DeleteChildInternal(art, node, byte);
142
0
    auto &n = handle.Get();
143
0
    if (n.count >= Node4::CAPACITY) {
144
0
      return;
145
0
    }
146
0
  }
147
  // Shrink node to Node4.
148
0
  auto node16 = node;
149
0
  Node4::ShrinkNode16(art, node, node16);
150
0
}
151
152
0
void Node16::GrowNode4(ART &art, Node &node16, Node &node4) {
153
0
  {
154
0
    NodeHandle<Node4> n4_handle(art, node4);
155
0
    auto &n4 = n4_handle.Get();
156
157
0
    auto n16_handle = New(art, node16);
158
0
    auto &n16 = n16_handle.Get();
159
0
    node16.SetGateStatus(node4.GetGateStatus());
160
161
0
    n16.count = n4.count;
162
0
    for (uint8_t i = 0; i < n4.count; i++) {
163
0
      n16.key[i] = n4.key[i];
164
0
      n16.children[i] = n4.children[i];
165
0
    }
166
0
  }
167
0
  Node::FreeNode(art, node4);
168
0
}
169
170
0
void Node16::ShrinkNode48(ART &art, Node &node16, Node &node48) {
171
0
  {
172
0
    auto n16_handle = New(art, node16);
173
0
    auto &n16 = n16_handle.Get();
174
0
    node16.SetGateStatus(node48.GetGateStatus());
175
176
0
    NodeHandle<Node48> n48_handle(art, node48);
177
0
    auto &n48 = n48_handle.Get();
178
179
0
    n16.count = 0;
180
0
    for (uint16_t i = 0; i < Node256::CAPACITY; i++) {
181
0
      if (n48.child_index[i] != Node48::EMPTY_MARKER) {
182
0
        n16.key[n16.count] = UnsafeNumericCast<uint8_t>(i);
183
0
        n16.children[n16.count] = n48.children[n48.child_index[i]];
184
0
        n16.count++;
185
0
      }
186
0
    }
187
0
  }
188
0
  Node::FreeNode(art, node48);
189
0
}
190
191
} // namespace duckdb