duckdb 0.6.2-dev1070.0 → 0.6.2-dev1092.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/duckdb/src/execution/index/art/art.cpp +18 -54
- package/src/duckdb/src/execution/index/art/leaf.cpp +10 -3
- package/src/duckdb/src/execution/index/art/node.cpp +41 -36
- package/src/duckdb/src/execution/index/art/node16.cpp +13 -14
- package/src/duckdb/src/execution/index/art/node256.cpp +10 -15
- package/src/duckdb/src/execution/index/art/node4.cpp +13 -14
- package/src/duckdb/src/execution/index/art/node48.cpp +10 -17
- package/src/duckdb/src/execution/index/art/prefix.cpp +0 -4
- package/src/duckdb/src/execution/operator/schema/physical_create_index.cpp +27 -72
- package/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +60 -10
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +3 -3
- package/src/duckdb/src/include/duckdb/execution/index/art/node.hpp +5 -3
- package/src/duckdb/src/include/duckdb/execution/index/art/node16.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/index/art/node256.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/index/art/node4.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/index/art/node48.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +4 -2
- package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_index.hpp +7 -9
- package/src/duckdb/src/include/duckdb/main/prepared_statement.hpp +2 -0
- package/src/duckdb/src/include/duckdb/storage/index.hpp +2 -4
- package/src/duckdb/src/main/prepared_statement.cpp +13 -0
- package/src/duckdb/src/storage/index.cpp +2 -0
package/package.json
CHANGED
|
@@ -15,16 +15,20 @@ namespace duckdb {
|
|
|
15
15
|
ART::ART(const vector<column_t> &column_ids, TableIOManager &table_io_manager,
|
|
16
16
|
const vector<unique_ptr<Expression>> &unbound_expressions, IndexConstraintType constraint_type,
|
|
17
17
|
AttachedDatabase &db, idx_t block_id, idx_t block_offset)
|
|
18
|
+
|
|
18
19
|
: Index(IndexType::ART, table_io_manager, column_ids, unbound_expressions, constraint_type), db(db),
|
|
19
20
|
estimated_art_size(0), estimated_key_size(16) {
|
|
21
|
+
|
|
20
22
|
if (!Radix::IsLittleEndian()) {
|
|
21
23
|
throw NotImplementedException("ART indexes are not supported on big endian architectures");
|
|
22
24
|
}
|
|
25
|
+
|
|
23
26
|
if (block_id != DConstants::INVALID_INDEX) {
|
|
24
27
|
tree = Node::Deserialize(*this, block_id, block_offset);
|
|
25
28
|
} else {
|
|
26
29
|
tree = nullptr;
|
|
27
30
|
}
|
|
31
|
+
|
|
28
32
|
serialized_data_pointer = BlockPointer(block_id, block_offset);
|
|
29
33
|
for (idx_t i = 0; i < types.size(); i++) {
|
|
30
34
|
switch (types[i]) {
|
|
@@ -272,11 +276,17 @@ void Construct(vector<Key> &keys, row_t *row_ids, Node *&node, KeySection &key_s
|
|
|
272
276
|
auto num_row_ids = key_section.end - key_section.start + 1;
|
|
273
277
|
|
|
274
278
|
// check for possible constraint violation
|
|
275
|
-
|
|
279
|
+
auto single_row_id = num_row_ids == 1;
|
|
280
|
+
if (has_constraint && !single_row_id) {
|
|
276
281
|
throw ConstraintException("New data contains duplicates on indexed column(s)");
|
|
277
282
|
}
|
|
278
283
|
|
|
284
|
+
if (single_row_id) {
|
|
285
|
+
node = Leaf::New(start_key, prefix_start, row_ids[key_section.start]);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
279
288
|
node = Leaf::New(start_key, prefix_start, row_ids + key_section.start, num_row_ids);
|
|
289
|
+
|
|
280
290
|
} else { // create a new node and recurse
|
|
281
291
|
|
|
282
292
|
// we will find at least two child entries of this node, otherwise we'd have reached a leaf
|
|
@@ -298,61 +308,15 @@ void Construct(vector<Key> &keys, row_t *row_ids, Node *&node, KeySection &key_s
|
|
|
298
308
|
}
|
|
299
309
|
}
|
|
300
310
|
|
|
301
|
-
void ART::
|
|
302
|
-
|
|
303
|
-
auto payload_types = logical_types;
|
|
304
|
-
payload_types.emplace_back(LogicalType::ROW_TYPE);
|
|
305
|
-
|
|
306
|
-
ArenaAllocator arena_allocator(BufferAllocator::Get(db));
|
|
307
|
-
vector<Key> keys(STANDARD_VECTOR_SIZE);
|
|
308
|
-
|
|
309
|
-
auto temp_art = make_unique<ART>(this->column_ids, this->table_io_manager, this->unbound_expressions,
|
|
310
|
-
this->constraint_type, this->db);
|
|
311
|
+
void ART::ConstructFromSorted(idx_t count, vector<Key> &keys, Vector &row_identifiers) {
|
|
311
312
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
ordered_chunk.SetCardinality(0);
|
|
316
|
-
scanner.Scan(ordered_chunk);
|
|
317
|
-
if (ordered_chunk.size() == 0) {
|
|
318
|
-
break;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// get the key chunk and the row_identifiers vector
|
|
322
|
-
DataChunk row_id_chunk;
|
|
323
|
-
ordered_chunk.Split(row_id_chunk, ordered_chunk.ColumnCount() - 1);
|
|
324
|
-
auto &row_identifiers = row_id_chunk.data[0];
|
|
325
|
-
|
|
326
|
-
D_ASSERT(row_identifiers.GetType().InternalType() == ROW_TYPE);
|
|
327
|
-
D_ASSERT(logical_types[0] == ordered_chunk.data[0].GetType());
|
|
328
|
-
|
|
329
|
-
// generate the keys for the given input
|
|
330
|
-
arena_allocator.Reset();
|
|
331
|
-
GenerateKeys(arena_allocator, ordered_chunk, keys);
|
|
332
|
-
|
|
333
|
-
// prepare the row_identifiers
|
|
334
|
-
row_identifiers.Flatten(ordered_chunk.size());
|
|
335
|
-
auto row_ids = FlatVector::GetData<row_t>(row_identifiers);
|
|
313
|
+
// prepare the row_identifiers
|
|
314
|
+
row_identifiers.Flatten(count);
|
|
315
|
+
auto row_ids = FlatVector::GetData<row_t>(row_identifiers);
|
|
336
316
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
auto key_section = KeySection(0, ordered_chunk.size() - 1, 0, 0);
|
|
341
|
-
auto has_constraint = IsUnique();
|
|
342
|
-
Construct(keys, row_ids, art->tree, key_section, has_constraint);
|
|
343
|
-
|
|
344
|
-
// merge art into temp_art
|
|
345
|
-
if (!temp_art->MergeIndexes(lock, art.get())) {
|
|
346
|
-
throw ConstraintException("Data contains duplicates on indexed column(s)");
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// NOTE: currently this code is only used for index creation, so we can assume that there are no
|
|
351
|
-
// duplicate violations between the existing index and the new data,
|
|
352
|
-
// so we do not need to revert any changes
|
|
353
|
-
if (!this->MergeIndexes(lock, temp_art.get())) {
|
|
354
|
-
throw ConstraintException("Data contains duplicates on indexed column(s)");
|
|
355
|
-
}
|
|
317
|
+
auto key_section = KeySection(0, count - 1, 0, 0);
|
|
318
|
+
auto has_constraint = IsUnique();
|
|
319
|
+
Construct(keys, row_ids, this->tree, key_section, has_constraint);
|
|
356
320
|
}
|
|
357
321
|
|
|
358
322
|
bool ART::Insert(IndexLock &lock, DataChunk &input, Vector &row_ids) {
|
|
@@ -158,10 +158,17 @@ void Leaf::Merge(Node *&l_node, Node *&r_node) {
|
|
|
158
158
|
Leaf *l_n = (Leaf *)l_node;
|
|
159
159
|
Leaf *r_n = (Leaf *)r_node;
|
|
160
160
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
auto l_capacity = l_n->GetCapacity();
|
|
162
|
+
auto l_row_ids = l_n->GetRowIds();
|
|
163
|
+
auto r_row_ids = r_n->GetRowIds();
|
|
164
|
+
|
|
165
|
+
if (l_n->count + r_n->count > l_capacity) {
|
|
166
|
+
auto new_capacity = NextPowerOfTwo(l_n->count + r_n->count);
|
|
167
|
+
l_row_ids = l_n->Resize(l_row_ids, l_n->count, new_capacity);
|
|
164
168
|
}
|
|
169
|
+
|
|
170
|
+
memcpy(l_row_ids + l_n->count, r_row_ids, r_n->count * sizeof(row_t));
|
|
171
|
+
l_n->count += r_n->count;
|
|
165
172
|
}
|
|
166
173
|
|
|
167
174
|
BlockPointer Leaf::Serialize(duckdb::MetaBlockWriter &writer) {
|
|
@@ -314,6 +314,9 @@ void UpdateParentsOfNodes(Node *&l_node, Node *&r_node, ParentsOfNodes &parents)
|
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
+
// forward declaration
|
|
318
|
+
bool ResolvePrefixesAndMerge(MergeInfo &info, idx_t depth, ParentsOfNodes &parents);
|
|
319
|
+
|
|
317
320
|
bool Merge(MergeInfo &info, idx_t depth, ParentsOfNodes &parents) {
|
|
318
321
|
|
|
319
322
|
// always try to merge the smaller node into the bigger node
|
|
@@ -327,16 +330,7 @@ bool Merge(MergeInfo &info, idx_t depth, ParentsOfNodes &parents) {
|
|
|
327
330
|
UpdateParentsOfNodes(info.l_node, info.r_node, parents);
|
|
328
331
|
}
|
|
329
332
|
|
|
330
|
-
|
|
331
|
-
case NodeType::N256:
|
|
332
|
-
return Node256::Merge(info, depth, parents.l_parent, parents.l_pos);
|
|
333
|
-
case NodeType::N48:
|
|
334
|
-
return Node48::Merge(info, depth, parents.l_parent, parents.l_pos);
|
|
335
|
-
case NodeType::N16:
|
|
336
|
-
return Node16::Merge(info, depth, parents.l_parent, parents.l_pos);
|
|
337
|
-
case NodeType::N4:
|
|
338
|
-
return Node4::Merge(info, depth, parents.l_parent, parents.l_pos);
|
|
339
|
-
case NodeType::NLeaf:
|
|
333
|
+
if (info.r_node->type == NodeType::NLeaf) {
|
|
340
334
|
D_ASSERT(info.l_node->type == NodeType::NLeaf);
|
|
341
335
|
D_ASSERT(info.r_node->type == NodeType::NLeaf);
|
|
342
336
|
if (info.l_art->IsUnique()) {
|
|
@@ -345,7 +339,37 @@ bool Merge(MergeInfo &info, idx_t depth, ParentsOfNodes &parents) {
|
|
|
345
339
|
Leaf::Merge(info.l_node, info.r_node);
|
|
346
340
|
return true;
|
|
347
341
|
}
|
|
348
|
-
|
|
342
|
+
|
|
343
|
+
uint8_t key_byte;
|
|
344
|
+
idx_t r_child_pos = DConstants::INVALID_INDEX;
|
|
345
|
+
|
|
346
|
+
while (true) {
|
|
347
|
+
r_child_pos = info.r_node->GetNextPosAndByte(r_child_pos, key_byte);
|
|
348
|
+
if (r_child_pos == DConstants::INVALID_INDEX) {
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
auto r_child = info.r_node->GetChild(*info.r_art, r_child_pos);
|
|
352
|
+
auto l_child_pos = info.l_node->GetChildPos(key_byte);
|
|
353
|
+
|
|
354
|
+
if (l_child_pos == DConstants::INVALID_INDEX) {
|
|
355
|
+
// insert child at empty position
|
|
356
|
+
Node::InsertChild(info.l_node, key_byte, r_child);
|
|
357
|
+
if (parents.l_parent) {
|
|
358
|
+
parents.l_parent->ReplaceChildPointer(parents.l_pos, info.l_node);
|
|
359
|
+
}
|
|
360
|
+
info.r_node->ReplaceChildPointer(r_child_pos, nullptr);
|
|
361
|
+
|
|
362
|
+
} else {
|
|
363
|
+
// recurse
|
|
364
|
+
auto l_child = info.l_node->GetChild(*info.l_art, l_child_pos);
|
|
365
|
+
MergeInfo child_info(info.l_art, info.r_art, l_child, r_child);
|
|
366
|
+
ParentsOfNodes child_parents(info.l_node, l_child_pos, info.r_node, r_child_pos);
|
|
367
|
+
if (!ResolvePrefixesAndMerge(child_info, depth + 1, child_parents)) {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return true;
|
|
349
373
|
}
|
|
350
374
|
|
|
351
375
|
bool ResolvePrefixesAndMerge(MergeInfo &info, idx_t depth, ParentsOfNodes &parents) {
|
|
@@ -355,22 +379,25 @@ bool ResolvePrefixesAndMerge(MergeInfo &info, idx_t depth, ParentsOfNodes &paren
|
|
|
355
379
|
|
|
356
380
|
// NOTE: we always merge into the left ART
|
|
357
381
|
D_ASSERT(l_node);
|
|
382
|
+
auto l_prefix_size = l_node->prefix.Size();
|
|
383
|
+
auto r_prefix_size = r_node->prefix.Size();
|
|
358
384
|
|
|
359
385
|
// make sure that r_node has the longer (or equally long) prefix
|
|
360
|
-
if (
|
|
386
|
+
if (l_prefix_size > r_prefix_size) {
|
|
361
387
|
swap(info.l_art, info.r_art);
|
|
362
388
|
swap(l_node, r_node);
|
|
389
|
+
swap(l_prefix_size, r_prefix_size);
|
|
363
390
|
UpdateParentsOfNodes(l_node, r_node, parents);
|
|
364
391
|
}
|
|
365
392
|
|
|
366
393
|
auto mismatch_pos = l_node->prefix.MismatchPosition(r_node->prefix);
|
|
367
394
|
|
|
368
395
|
// both nodes have no prefix or the same prefix
|
|
369
|
-
if (mismatch_pos ==
|
|
396
|
+
if (mismatch_pos == l_prefix_size && l_prefix_size == r_prefix_size) {
|
|
370
397
|
return Merge(info, depth + mismatch_pos, parents);
|
|
371
398
|
}
|
|
372
399
|
|
|
373
|
-
if (mismatch_pos ==
|
|
400
|
+
if (mismatch_pos == l_prefix_size) {
|
|
374
401
|
// r_node's prefix contains l_node's prefix
|
|
375
402
|
// l_node cannot be a leaf, otherwise the key represented by l_node would be a subset of another key
|
|
376
403
|
// which is not possible by our construction
|
|
@@ -418,28 +445,6 @@ bool ResolvePrefixesAndMerge(MergeInfo &info, idx_t depth, ParentsOfNodes &paren
|
|
|
418
445
|
return true;
|
|
419
446
|
}
|
|
420
447
|
|
|
421
|
-
bool Node::MergeAtByte(MergeInfo &info, idx_t depth, idx_t &l_child_pos, idx_t &r_pos, uint8_t &key_byte,
|
|
422
|
-
Node *&l_parent, idx_t l_pos) {
|
|
423
|
-
|
|
424
|
-
auto r_child = info.r_node->GetChild(*info.r_art, r_pos);
|
|
425
|
-
|
|
426
|
-
// insert child at empty position
|
|
427
|
-
if (l_child_pos == DConstants::INVALID_INDEX) {
|
|
428
|
-
Node::InsertChild(info.l_node, key_byte, r_child);
|
|
429
|
-
if (l_parent) {
|
|
430
|
-
l_parent->ReplaceChildPointer(l_pos, info.l_node);
|
|
431
|
-
}
|
|
432
|
-
info.r_node->ReplaceChildPointer(r_pos, nullptr);
|
|
433
|
-
return true;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// recurse
|
|
437
|
-
auto l_child = info.l_node->GetChild(*info.l_art, l_child_pos);
|
|
438
|
-
MergeInfo child_info(info.l_art, info.r_art, l_child, r_child);
|
|
439
|
-
ParentsOfNodes child_parents(info.l_node, l_child_pos, info.r_node, r_pos);
|
|
440
|
-
return ResolvePrefixesAndMerge(child_info, depth + 1, child_parents);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
448
|
bool Node::MergeARTs(ART *l_art, ART *r_art) {
|
|
444
449
|
|
|
445
450
|
Node *null_parent = nullptr;
|
|
@@ -47,6 +47,19 @@ idx_t Node16::GetNextPos(idx_t pos) {
|
|
|
47
47
|
return pos < count ? pos : DConstants::INVALID_INDEX;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
idx_t Node16::GetNextPosAndByte(idx_t pos, uint8_t &byte) {
|
|
51
|
+
if (pos == DConstants::INVALID_INDEX) {
|
|
52
|
+
byte = key[0];
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
pos++;
|
|
56
|
+
if (pos < count) {
|
|
57
|
+
byte = key[pos];
|
|
58
|
+
return pos;
|
|
59
|
+
}
|
|
60
|
+
return DConstants::INVALID_INDEX;
|
|
61
|
+
}
|
|
62
|
+
|
|
50
63
|
Node *Node16::GetChild(ART &art, idx_t pos) {
|
|
51
64
|
D_ASSERT(pos < count);
|
|
52
65
|
return children[pos].Unswizzle(art);
|
|
@@ -124,20 +137,6 @@ void Node16::EraseChild(Node *&node, int pos, ART &art) {
|
|
|
124
137
|
}
|
|
125
138
|
}
|
|
126
139
|
|
|
127
|
-
bool Node16::Merge(MergeInfo &info, idx_t depth, Node *&l_parent, idx_t l_pos) {
|
|
128
|
-
|
|
129
|
-
Node16 *r_n = (Node16 *)info.r_node;
|
|
130
|
-
|
|
131
|
-
for (idx_t i = 0; i < info.r_node->count; i++) {
|
|
132
|
-
|
|
133
|
-
auto l_child_pos = info.l_node->GetChildPos(r_n->key[i]);
|
|
134
|
-
if (!Node::MergeAtByte(info, depth, l_child_pos, i, r_n->key[i], l_parent, l_pos)) {
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
140
|
idx_t Node16::GetSize() {
|
|
142
141
|
return 16;
|
|
143
142
|
}
|
|
@@ -47,6 +47,16 @@ idx_t Node256::GetNextPos(idx_t pos) {
|
|
|
47
47
|
return Node::GetNextPos(pos);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
idx_t Node256::GetNextPosAndByte(idx_t pos, uint8_t &byte) {
|
|
51
|
+
for (pos == DConstants::INVALID_INDEX ? pos = 0 : pos++; pos < 256; pos++) {
|
|
52
|
+
if (children[pos]) {
|
|
53
|
+
byte = uint8_t(pos);
|
|
54
|
+
return pos;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return Node::GetNextPos(pos);
|
|
58
|
+
}
|
|
59
|
+
|
|
50
60
|
Node *Node256::GetChild(ART &art, idx_t pos) {
|
|
51
61
|
return children[pos].Unswizzle(art);
|
|
52
62
|
}
|
|
@@ -82,21 +92,6 @@ void Node256::EraseChild(Node *&node, int pos, ART &art) {
|
|
|
82
92
|
}
|
|
83
93
|
}
|
|
84
94
|
|
|
85
|
-
bool Node256::Merge(MergeInfo &info, idx_t depth, Node *&l_parent, idx_t l_pos) {
|
|
86
|
-
|
|
87
|
-
for (idx_t i = 0; i < 256; i++) {
|
|
88
|
-
if (info.r_node->GetChildPos(i) != DConstants::INVALID_INDEX) {
|
|
89
|
-
|
|
90
|
-
auto l_child_pos = info.l_node->GetChildPos(i);
|
|
91
|
-
auto key_byte = (uint8_t)i;
|
|
92
|
-
if (!Node::MergeAtByte(info, depth, l_child_pos, i, key_byte, l_parent, l_pos)) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
95
|
idx_t Node256::GetSize() {
|
|
101
96
|
return 256;
|
|
102
97
|
}
|
|
@@ -45,6 +45,19 @@ idx_t Node4::GetNextPos(idx_t pos) {
|
|
|
45
45
|
return pos < count ? pos : DConstants::INVALID_INDEX;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
idx_t Node4::GetNextPosAndByte(idx_t pos, uint8_t &byte) {
|
|
49
|
+
if (pos == DConstants::INVALID_INDEX) {
|
|
50
|
+
byte = key[0];
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
pos++;
|
|
54
|
+
if (pos < count) {
|
|
55
|
+
byte = key[pos];
|
|
56
|
+
return pos;
|
|
57
|
+
}
|
|
58
|
+
return DConstants::INVALID_INDEX;
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
Node *Node4::GetChild(ART &art, idx_t pos) {
|
|
49
62
|
D_ASSERT(pos < count);
|
|
50
63
|
return children[pos].Unswizzle(art);
|
|
@@ -117,20 +130,6 @@ void Node4::EraseChild(Node *&node, int pos, ART &art) {
|
|
|
117
130
|
}
|
|
118
131
|
}
|
|
119
132
|
|
|
120
|
-
bool Node4::Merge(MergeInfo &info, idx_t depth, Node *&l_parent, idx_t l_pos) {
|
|
121
|
-
|
|
122
|
-
Node4 *r_n = (Node4 *)info.r_node;
|
|
123
|
-
|
|
124
|
-
for (idx_t i = 0; i < info.r_node->count; i++) {
|
|
125
|
-
|
|
126
|
-
auto l_child_pos = info.l_node->GetChildPos(r_n->key[i]);
|
|
127
|
-
if (!Node::MergeAtByte(info, depth, l_child_pos, i, r_n->key[i], l_parent, l_pos)) {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
133
|
idx_t Node4::GetSize() {
|
|
135
134
|
return 4;
|
|
136
135
|
}
|
|
@@ -51,6 +51,16 @@ idx_t Node48::GetNextPos(idx_t pos) {
|
|
|
51
51
|
return Node::GetNextPos(pos);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
idx_t Node48::GetNextPosAndByte(idx_t pos, uint8_t &byte) {
|
|
55
|
+
for (pos == DConstants::INVALID_INDEX ? pos = 0 : pos++; pos < 256; pos++) {
|
|
56
|
+
if (child_index[pos] != Node::EMPTY_MARKER) {
|
|
57
|
+
byte = uint8_t(pos);
|
|
58
|
+
return pos;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return Node::GetNextPos(pos);
|
|
62
|
+
}
|
|
63
|
+
|
|
54
64
|
Node *Node48::GetChild(ART &art, idx_t pos) {
|
|
55
65
|
D_ASSERT(child_index[pos] != Node::EMPTY_MARKER);
|
|
56
66
|
return children[child_index[pos]].Unswizzle(art);
|
|
@@ -114,23 +124,6 @@ void Node48::EraseChild(Node *&node, int pos, ART &art) {
|
|
|
114
124
|
}
|
|
115
125
|
}
|
|
116
126
|
|
|
117
|
-
bool Node48::Merge(MergeInfo &info, idx_t depth, Node *&l_parent, idx_t l_pos) {
|
|
118
|
-
|
|
119
|
-
Node48 *r_n = (Node48 *)info.r_node;
|
|
120
|
-
|
|
121
|
-
for (idx_t i = 0; i < 256; i++) {
|
|
122
|
-
if (r_n->child_index[i] != Node::EMPTY_MARKER) {
|
|
123
|
-
|
|
124
|
-
auto l_child_pos = info.l_node->GetChildPos(i);
|
|
125
|
-
auto key_byte = (uint8_t)i;
|
|
126
|
-
if (!Node::MergeAtByte(info, depth, l_child_pos, i, key_byte, l_parent, l_pos)) {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
127
|
idx_t Node48::GetSize() {
|
|
135
128
|
return 48;
|
|
136
129
|
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
#include "duckdb/execution/operator/schema/physical_create_index.hpp"
|
|
2
2
|
|
|
3
3
|
#include "duckdb/catalog/catalog_entry/index_catalog_entry.hpp"
|
|
4
|
-
#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp"
|
|
5
|
-
#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
|
|
6
|
-
#include "duckdb/execution/expression_executor.hpp"
|
|
7
4
|
#include "duckdb/main/client_context.hpp"
|
|
8
5
|
#include "duckdb/storage/storage_manager.hpp"
|
|
9
6
|
#include "duckdb/main/database_manager.hpp"
|
|
@@ -22,20 +19,13 @@ public:
|
|
|
22
19
|
|
|
23
20
|
class CreateIndexLocalSinkState : public LocalSinkState {
|
|
24
21
|
public:
|
|
25
|
-
explicit CreateIndexLocalSinkState(
|
|
26
|
-
}
|
|
22
|
+
explicit CreateIndexLocalSinkState(ClientContext &context) : arena_allocator(Allocator::Get(context)) {};
|
|
27
23
|
|
|
28
|
-
//! Local indexes build from chunks of the scanned data
|
|
29
24
|
unique_ptr<Index> local_index;
|
|
30
|
-
|
|
25
|
+
ArenaAllocator arena_allocator;
|
|
26
|
+
vector<Key> keys;
|
|
31
27
|
DataChunk key_chunk;
|
|
32
|
-
|
|
33
|
-
LocalSortState local_sort_state;
|
|
34
|
-
|
|
35
|
-
RowLayout payload_layout;
|
|
36
|
-
vector<LogicalType> payload_types;
|
|
37
|
-
|
|
38
|
-
ExpressionExecutor executor;
|
|
28
|
+
vector<column_t> key_column_ids;
|
|
39
29
|
};
|
|
40
30
|
|
|
41
31
|
unique_ptr<GlobalSinkState> PhysicalCreateIndex::GetGlobalSinkState(ClientContext &context) const {
|
|
@@ -51,14 +41,12 @@ unique_ptr<GlobalSinkState> PhysicalCreateIndex::GetGlobalSinkState(ClientContex
|
|
|
51
41
|
default:
|
|
52
42
|
throw InternalException("Unimplemented index type");
|
|
53
43
|
}
|
|
54
|
-
|
|
55
44
|
return (std::move(state));
|
|
56
45
|
}
|
|
57
46
|
|
|
58
47
|
unique_ptr<LocalSinkState> PhysicalCreateIndex::GetLocalSinkState(ExecutionContext &context) const {
|
|
59
|
-
auto &allocator = Allocator::Get(table.storage->db);
|
|
60
48
|
|
|
61
|
-
auto state = make_unique<CreateIndexLocalSinkState>(
|
|
49
|
+
auto state = make_unique<CreateIndexLocalSinkState>(context.client);
|
|
62
50
|
|
|
63
51
|
// create the local index
|
|
64
52
|
switch (info->index_type) {
|
|
@@ -70,82 +58,49 @@ unique_ptr<LocalSinkState> PhysicalCreateIndex::GetLocalSinkState(ExecutionConte
|
|
|
70
58
|
default:
|
|
71
59
|
throw InternalException("Unimplemented index type");
|
|
72
60
|
}
|
|
61
|
+
state->keys = vector<Key>(STANDARD_VECTOR_SIZE);
|
|
62
|
+
state->key_chunk.Initialize(Allocator::Get(context.client), state->local_index->logical_types);
|
|
73
63
|
|
|
74
|
-
state->key_chunk.
|
|
75
|
-
|
|
76
|
-
// ordering of the entries of the index
|
|
77
|
-
vector<BoundOrderByNode> orders;
|
|
78
|
-
for (idx_t i = 0; i < state->local_index->logical_types.size(); i++) {
|
|
79
|
-
auto col_expr = make_unique_base<Expression, BoundReferenceExpression>(state->local_index->logical_types[i], i);
|
|
80
|
-
orders.emplace_back(OrderType::ASCENDING, OrderByNullType::NULLS_FIRST, std::move(col_expr));
|
|
64
|
+
for (idx_t i = 0; i < state->key_chunk.ColumnCount(); i++) {
|
|
65
|
+
state->key_column_ids.push_back(i);
|
|
81
66
|
}
|
|
82
|
-
|
|
83
|
-
// row layout of the global sort state
|
|
84
|
-
state->payload_types = state->local_index->logical_types;
|
|
85
|
-
state->payload_types.emplace_back(LogicalType::ROW_TYPE);
|
|
86
|
-
state->payload_layout.Initialize(state->payload_types);
|
|
87
|
-
|
|
88
|
-
// initialize global and local sort state
|
|
89
|
-
auto &buffer_manager = BufferManager::GetBufferManager(table.storage->db);
|
|
90
|
-
state->global_sort_state = make_unique<GlobalSortState>(buffer_manager, orders, state->payload_layout);
|
|
91
|
-
state->local_sort_state.Initialize(*state->global_sort_state, buffer_manager);
|
|
92
|
-
|
|
93
67
|
return std::move(state);
|
|
94
68
|
}
|
|
95
69
|
|
|
96
70
|
SinkResultType PhysicalCreateIndex::Sink(ExecutionContext &context, GlobalSinkState &gstate_p, LocalSinkState &lstate_p,
|
|
97
71
|
DataChunk &input) const {
|
|
98
72
|
|
|
99
|
-
|
|
73
|
+
D_ASSERT(input.ColumnCount() >= 2);
|
|
100
74
|
auto &lstate = (CreateIndexLocalSinkState &)lstate_p;
|
|
75
|
+
auto &row_identifiers = input.data[input.ColumnCount() - 1];
|
|
101
76
|
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
lstate.
|
|
105
|
-
lstate.
|
|
106
|
-
|
|
107
|
-
// create the payload chunk
|
|
108
|
-
DataChunk payload_chunk;
|
|
109
|
-
payload_chunk.InitializeEmpty(lstate.payload_types);
|
|
110
|
-
for (idx_t i = 0; i < lstate.local_index->logical_types.size(); i++) {
|
|
111
|
-
payload_chunk.data[i].Reference(lstate.key_chunk.data[i]);
|
|
112
|
-
}
|
|
113
|
-
payload_chunk.data[lstate.payload_types.size() - 1].Reference(input.data[input.ColumnCount() - 1]);
|
|
114
|
-
payload_chunk.SetCardinality(input.size());
|
|
77
|
+
// generate the keys for the given input
|
|
78
|
+
lstate.key_chunk.ReferenceColumns(input, lstate.key_column_ids);
|
|
79
|
+
lstate.arena_allocator.Reset();
|
|
80
|
+
ART::GenerateKeys(lstate.arena_allocator, lstate.key_chunk, lstate.keys);
|
|
115
81
|
|
|
116
|
-
|
|
117
|
-
|
|
82
|
+
auto art = make_unique<ART>(lstate.local_index->column_ids, lstate.local_index->table_io_manager,
|
|
83
|
+
lstate.local_index->unbound_expressions, lstate.local_index->constraint_type,
|
|
84
|
+
table.storage->db);
|
|
85
|
+
art->ConstructFromSorted(lstate.key_chunk.size(), lstate.keys, row_identifiers);
|
|
118
86
|
|
|
87
|
+
// merge into the local ART
|
|
88
|
+
{
|
|
89
|
+
IndexLock local_lock;
|
|
90
|
+
lstate.local_index->InitializeLock(local_lock);
|
|
91
|
+
if (!lstate.local_index->MergeIndexes(local_lock, art.get())) {
|
|
92
|
+
throw ConstraintException("Data contains duplicates on indexed column(s)");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
119
95
|
return SinkResultType::NEED_MORE_INPUT;
|
|
120
96
|
}
|
|
121
97
|
|
|
122
98
|
void PhysicalCreateIndex::Combine(ExecutionContext &context, GlobalSinkState &gstate_p,
|
|
123
99
|
LocalSinkState &lstate_p) const {
|
|
124
100
|
|
|
125
|
-
// here, we take the sunk data chunks and sort them
|
|
126
|
-
// then, we scan the sorted data and build a local index from it
|
|
127
|
-
// finally, we merge the local index into the global index
|
|
128
|
-
|
|
129
101
|
auto &gstate = (CreateIndexGlobalSinkState &)gstate_p;
|
|
130
102
|
auto &lstate = (CreateIndexLocalSinkState &)lstate_p;
|
|
131
103
|
|
|
132
|
-
auto &allocator = Allocator::Get(table.storage->db);
|
|
133
|
-
|
|
134
|
-
// add local state to global state, which sorts the data
|
|
135
|
-
lstate.global_sort_state->AddLocalState(lstate.local_sort_state);
|
|
136
|
-
lstate.global_sort_state->PrepareMergePhase();
|
|
137
|
-
|
|
138
|
-
// scan the sorted row data and construct the index from it
|
|
139
|
-
{
|
|
140
|
-
IndexLock local_lock;
|
|
141
|
-
lstate.local_index->InitializeLock(local_lock);
|
|
142
|
-
if (!lstate.global_sort_state->sorted_blocks.empty()) {
|
|
143
|
-
PayloadScanner scanner(*lstate.global_sort_state->sorted_blocks[0]->payload_data,
|
|
144
|
-
*lstate.global_sort_state);
|
|
145
|
-
lstate.local_index->ConstructAndMerge(local_lock, scanner, allocator);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
104
|
// merge the local index into the global index
|
|
150
105
|
gstate.global_index->MergeIndexes(lstate.local_index.get());
|
|
151
106
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
|
|
2
|
+
#include "duckdb/execution/operator/projection/physical_projection.hpp"
|
|
2
3
|
#include "duckdb/execution/operator/filter/physical_filter.hpp"
|
|
3
4
|
#include "duckdb/execution/operator/scan/physical_table_scan.hpp"
|
|
4
5
|
#include "duckdb/execution/operator/schema/physical_create_index.hpp"
|
|
6
|
+
#include "duckdb/execution/operator/order/physical_order.hpp"
|
|
5
7
|
#include "duckdb/execution/physical_plan_generator.hpp"
|
|
6
8
|
#include "duckdb/function/table/table_scan.hpp"
|
|
7
9
|
#include "duckdb/planner/filter/null_filter.hpp"
|
|
@@ -12,9 +14,26 @@ namespace duckdb {
|
|
|
12
14
|
|
|
13
15
|
unique_ptr<PhysicalOperator> PhysicalPlanGenerator::CreatePlan(LogicalCreateIndex &op) {
|
|
14
16
|
|
|
17
|
+
// generate a physical plan for the parallel index creation which consists of the following operators
|
|
18
|
+
// table scan - projection (for expression execution) - filter (NOT NULL) - order - create index
|
|
19
|
+
|
|
15
20
|
D_ASSERT(op.children.empty());
|
|
16
21
|
|
|
22
|
+
// validate that all expressions contain valid scalar functions
|
|
23
|
+
// e.g. get_current_timestamp(), random(), and sequence values are not allowed as ART keys
|
|
24
|
+
// because they make deletions and lookups unfeasible
|
|
25
|
+
for (idx_t i = 0; i < op.unbound_expressions.size(); i++) {
|
|
26
|
+
auto &expr = op.unbound_expressions[i];
|
|
27
|
+
if (expr->expression_class == ExpressionClass::BOUND_FUNCTION) {
|
|
28
|
+
auto &func_expr = (BoundFunctionExpression &)*expr;
|
|
29
|
+
if (func_expr.function.side_effects == FunctionSideEffects::HAS_SIDE_EFFECTS) {
|
|
30
|
+
throw BinderException("Index keys cannot contain the \"%s\" function.", func_expr.function.name);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
17
35
|
// table scan operator for index key columns and row IDs
|
|
36
|
+
|
|
18
37
|
unique_ptr<TableFilterSet> table_filters;
|
|
19
38
|
op.info->column_ids.emplace_back(COLUMN_IDENTIFIER_ROW_ID);
|
|
20
39
|
|
|
@@ -31,30 +50,61 @@ unique_ptr<PhysicalOperator> PhysicalPlanGenerator::CreatePlan(LogicalCreateInde
|
|
|
31
50
|
D_ASSERT(op.info->scan_types.size() - 1 <= op.info->names.size());
|
|
32
51
|
D_ASSERT(op.info->scan_types.size() - 1 <= op.info->column_ids.size());
|
|
33
52
|
|
|
53
|
+
// projection to execute expressions on the key columns
|
|
54
|
+
|
|
55
|
+
vector<LogicalType> new_column_types;
|
|
56
|
+
vector<unique_ptr<Expression>> select_list;
|
|
57
|
+
for (idx_t i = 0; i < op.expressions.size(); i++) {
|
|
58
|
+
new_column_types.push_back(op.expressions[i]->return_type);
|
|
59
|
+
select_list.push_back(std::move(op.expressions[i]));
|
|
60
|
+
}
|
|
61
|
+
new_column_types.emplace_back(LogicalType::ROW_TYPE);
|
|
62
|
+
select_list.push_back(make_unique<BoundReferenceExpression>(LogicalType::ROW_TYPE, op.info->scan_types.size() - 1));
|
|
63
|
+
|
|
64
|
+
auto projection =
|
|
65
|
+
make_unique<PhysicalProjection>(new_column_types, std::move(select_list), op.estimated_cardinality);
|
|
66
|
+
projection->children.push_back(std::move(table_scan));
|
|
67
|
+
|
|
34
68
|
// filter operator for IS_NOT_NULL on each key column
|
|
69
|
+
|
|
35
70
|
vector<LogicalType> filter_types;
|
|
36
71
|
vector<unique_ptr<Expression>> filter_select_list;
|
|
37
72
|
|
|
38
|
-
for (idx_t i = 0; i <
|
|
39
|
-
filter_types.push_back(
|
|
73
|
+
for (idx_t i = 0; i < new_column_types.size() - 1; i++) {
|
|
74
|
+
filter_types.push_back(new_column_types[i]);
|
|
40
75
|
auto is_not_null_expr =
|
|
41
76
|
make_unique<BoundOperatorExpression>(ExpressionType::OPERATOR_IS_NOT_NULL, LogicalType::BOOLEAN);
|
|
42
|
-
auto bound_ref =
|
|
43
|
-
make_unique<BoundReferenceExpression>(op.info->names[op.info->column_ids[i]], op.info->scan_types[i], i);
|
|
77
|
+
auto bound_ref = make_unique<BoundReferenceExpression>(new_column_types[i], i);
|
|
44
78
|
is_not_null_expr->children.push_back(std::move(bound_ref));
|
|
45
79
|
filter_select_list.push_back(std::move(is_not_null_expr));
|
|
46
80
|
}
|
|
47
81
|
|
|
48
82
|
auto null_filter =
|
|
49
|
-
make_unique<PhysicalFilter>(std::move(filter_types), std::move(filter_select_list),
|
|
83
|
+
make_unique<PhysicalFilter>(std::move(filter_types), std::move(filter_select_list), op.estimated_cardinality);
|
|
50
84
|
null_filter->types.emplace_back(LogicalType::ROW_TYPE);
|
|
51
|
-
null_filter->children.push_back(std::move(
|
|
85
|
+
null_filter->children.push_back(std::move(projection));
|
|
86
|
+
|
|
87
|
+
// order operator
|
|
88
|
+
|
|
89
|
+
vector<BoundOrderByNode> orders;
|
|
90
|
+
vector<idx_t> projections;
|
|
91
|
+
for (idx_t i = 0; i < new_column_types.size() - 1; i++) {
|
|
92
|
+
auto col_expr = make_unique_base<Expression, BoundReferenceExpression>(new_column_types[i], i);
|
|
93
|
+
orders.emplace_back(OrderType::ASCENDING, OrderByNullType::NULLS_FIRST, std::move(col_expr));
|
|
94
|
+
projections.emplace_back(i);
|
|
95
|
+
}
|
|
96
|
+
projections.emplace_back(new_column_types.size() - 1);
|
|
97
|
+
|
|
98
|
+
auto physical_order = make_unique<PhysicalOrder>(new_column_types, std::move(orders), std::move(projections),
|
|
99
|
+
op.estimated_cardinality);
|
|
100
|
+
physical_order->children.push_back(std::move(null_filter));
|
|
52
101
|
|
|
53
102
|
// actual physical create index operator
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
std::move(op.
|
|
57
|
-
|
|
103
|
+
|
|
104
|
+
auto physical_create_index =
|
|
105
|
+
make_unique<PhysicalCreateIndex>(op, op.table, op.info->column_ids, std::move(op.info),
|
|
106
|
+
std::move(op.unbound_expressions), op.estimated_cardinality);
|
|
107
|
+
physical_create_index->children.push_back(std::move(physical_order));
|
|
58
108
|
return std::move(physical_create_index);
|
|
59
109
|
}
|
|
60
110
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#ifndef DUCKDB_VERSION
|
|
2
|
-
#define DUCKDB_VERSION "0.6.2-
|
|
2
|
+
#define DUCKDB_VERSION "0.6.2-dev1092"
|
|
3
3
|
#endif
|
|
4
4
|
#ifndef DUCKDB_SOURCE_ID
|
|
5
|
-
#define DUCKDB_SOURCE_ID "
|
|
5
|
+
#define DUCKDB_SOURCE_ID "123b6e7bbd"
|
|
6
6
|
#endif
|
|
7
7
|
#include "duckdb/function/table/system_functions.hpp"
|
|
8
8
|
#include "duckdb/main/database.hpp"
|
|
@@ -49,6 +49,7 @@ enum VerifyExistenceType : uint8_t {
|
|
|
49
49
|
|
|
50
50
|
class ART : public Index {
|
|
51
51
|
public:
|
|
52
|
+
//! Constructs an ART containing the bound expressions, which are resolved during index construction
|
|
52
53
|
ART(const vector<column_t> &column_ids, TableIOManager &table_io_manager,
|
|
53
54
|
const vector<unique_ptr<Expression>> &unbound_expressions, IndexConstraintType constraint_type,
|
|
54
55
|
AttachedDatabase &db, idx_t block_id = DConstants::INVALID_INDEX,
|
|
@@ -57,7 +58,7 @@ public:
|
|
|
57
58
|
|
|
58
59
|
//! Root of the tree
|
|
59
60
|
Node *tree;
|
|
60
|
-
|
|
61
|
+
//! Attached database
|
|
61
62
|
AttachedDatabase &db;
|
|
62
63
|
|
|
63
64
|
public:
|
|
@@ -88,8 +89,7 @@ public:
|
|
|
88
89
|
//! Insert data into the index.
|
|
89
90
|
bool Insert(IndexLock &lock, DataChunk &data, Vector &row_ids) override;
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
void ConstructAndMerge(IndexLock &lock, PayloadScanner &scanner, Allocator &allocator) override;
|
|
92
|
+
void ConstructFromSorted(idx_t count, vector<Key> &keys, Vector &row_identifiers);
|
|
93
93
|
|
|
94
94
|
//! Search Equal and fetches the row IDs
|
|
95
95
|
bool SearchEqual(Key &key, idx_t max_count, vector<row_t> &result_ids);
|
|
@@ -88,6 +88,11 @@ public:
|
|
|
88
88
|
virtual idx_t GetNextPos(idx_t pos) {
|
|
89
89
|
return DConstants::INVALID_INDEX;
|
|
90
90
|
}
|
|
91
|
+
//! Get the next position and byte in the node, or DConstants::INVALID_INDEX if there is no next position. if pos ==
|
|
92
|
+
//! DConstants::INVALID_INDEX, then the first valid position in the node is returned
|
|
93
|
+
virtual idx_t GetNextPosAndByte(idx_t pos, uint8_t &byte) {
|
|
94
|
+
return DConstants::INVALID_INDEX;
|
|
95
|
+
}
|
|
91
96
|
//! Get the child at the specified position in the node. pos should be between [0, count). Throws an assertion if
|
|
92
97
|
//! the element is not found
|
|
93
98
|
virtual Node *GetChild(ART &art, idx_t pos);
|
|
@@ -110,9 +115,6 @@ public:
|
|
|
110
115
|
|
|
111
116
|
//! Deserialize this node
|
|
112
117
|
static Node *Deserialize(ART &art, idx_t block_id, idx_t offset);
|
|
113
|
-
//! Merge r_node into l_node at the specified byte
|
|
114
|
-
static bool MergeAtByte(MergeInfo &info, idx_t depth, idx_t &l_child_pos, idx_t &r_pos, uint8_t &key_byte,
|
|
115
|
-
Node *&l_parent, idx_t l_pos);
|
|
116
118
|
//! Merge two ART
|
|
117
119
|
static bool MergeARTs(ART *l_art, ART *r_art);
|
|
118
120
|
|
|
@@ -29,6 +29,8 @@ public:
|
|
|
29
29
|
idx_t GetMin() override;
|
|
30
30
|
//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
|
|
31
31
|
idx_t GetNextPos(idx_t pos) override;
|
|
32
|
+
//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
|
|
33
|
+
idx_t GetNextPosAndByte(idx_t pos, uint8_t &byte) override;
|
|
32
34
|
//! Get Node16 child
|
|
33
35
|
Node *GetChild(ART &art, idx_t pos) override;
|
|
34
36
|
//! Replace child pointer
|
|
@@ -38,8 +40,6 @@ public:
|
|
|
38
40
|
static void InsertChild(Node *&node, uint8_t key_byte, Node *new_child);
|
|
39
41
|
//! Erase the child at pos and (if necessary) shrink to Node4
|
|
40
42
|
static void EraseChild(Node *&node, int pos, ART &art);
|
|
41
|
-
//! Merge Node16 into l_node
|
|
42
|
-
static bool Merge(MergeInfo &info, idx_t depth, Node *&l_parent, idx_t l_pos);
|
|
43
43
|
//! Returns the size (maximum capacity) of the Node16
|
|
44
44
|
static idx_t GetSize();
|
|
45
45
|
};
|
|
@@ -28,6 +28,8 @@ public:
|
|
|
28
28
|
idx_t GetMin() override;
|
|
29
29
|
//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
|
|
30
30
|
idx_t GetNextPos(idx_t pos) override;
|
|
31
|
+
//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
|
|
32
|
+
idx_t GetNextPosAndByte(idx_t pos, uint8_t &byte) override;
|
|
31
33
|
//! Get Node256 child
|
|
32
34
|
Node *GetChild(ART &art, idx_t pos) override;
|
|
33
35
|
//! Replace child pointer
|
|
@@ -37,8 +39,6 @@ public:
|
|
|
37
39
|
static void InsertChild(Node *&node, uint8_t key_byte, Node *new_child);
|
|
38
40
|
//! Erase the child at pos and (if necessary) shrink to Node48
|
|
39
41
|
static void EraseChild(Node *&node, int pos, ART &art);
|
|
40
|
-
//! Merge Node256 into l_node
|
|
41
|
-
static bool Merge(MergeInfo &info, idx_t depth, Node *&l_parent, idx_t l_pos);
|
|
42
42
|
//! Returns the size (maximum capacity) of the Node256
|
|
43
43
|
static idx_t GetSize();
|
|
44
44
|
};
|
|
@@ -31,6 +31,8 @@ public:
|
|
|
31
31
|
idx_t GetMin() override;
|
|
32
32
|
//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
|
|
33
33
|
idx_t GetNextPos(idx_t pos) override;
|
|
34
|
+
//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
|
|
35
|
+
idx_t GetNextPosAndByte(idx_t pos, uint8_t &byte) override;
|
|
34
36
|
//! Get Node4 child
|
|
35
37
|
Node *GetChild(ART &art, idx_t pos) override;
|
|
36
38
|
//! Replace child pointer
|
|
@@ -40,8 +42,6 @@ public:
|
|
|
40
42
|
static void InsertChild(Node *&node, uint8_t key_byte, Node *new_child);
|
|
41
43
|
//! Erase the child at pos and (if necessary) merge with last child
|
|
42
44
|
static void EraseChild(Node *&node, int pos, ART &art);
|
|
43
|
-
//! Merge Node4 into l_node
|
|
44
|
-
static bool Merge(MergeInfo &info, idx_t depth, Node *&l_parent, idx_t l_pos);
|
|
45
45
|
//! Returns the size (maximum capacity) of the Node4
|
|
46
46
|
static idx_t GetSize();
|
|
47
47
|
};
|
|
@@ -29,6 +29,8 @@ public:
|
|
|
29
29
|
idx_t GetMin() override;
|
|
30
30
|
//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
|
|
31
31
|
idx_t GetNextPos(idx_t pos) override;
|
|
32
|
+
//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
|
|
33
|
+
idx_t GetNextPosAndByte(idx_t pos, uint8_t &byte) override;
|
|
32
34
|
//! Get Node48 child
|
|
33
35
|
Node *GetChild(ART &art, idx_t pos) override;
|
|
34
36
|
//! Replace child pointer
|
|
@@ -38,8 +40,6 @@ public:
|
|
|
38
40
|
static void InsertChild(Node *&node, uint8_t key_byte, Node *new_child);
|
|
39
41
|
//! Erase the child at pos and (if necessary) shrink to Node16
|
|
40
42
|
static void EraseChild(Node *&node, int pos, ART &art);
|
|
41
|
-
//! Merge Node48 into l_node
|
|
42
|
-
static bool Merge(MergeInfo &info, idx_t depth, Node *&l_parent, idx_t l_pos);
|
|
43
43
|
//! Returns the size (maximum capacity) of the Node48
|
|
44
44
|
static idx_t GetSize();
|
|
45
45
|
};
|
|
@@ -23,8 +23,10 @@ public:
|
|
|
23
23
|
Prefix(Prefix &other_prefix, uint32_t size);
|
|
24
24
|
~Prefix();
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
uint32_t Size() const
|
|
26
|
+
//! Returns the Prefix's size
|
|
27
|
+
inline uint32_t Size() const {
|
|
28
|
+
return size;
|
|
29
|
+
}
|
|
28
30
|
//! Return a pointer to the prefix data
|
|
29
31
|
uint8_t *GetPrefixData();
|
|
30
32
|
const uint8_t *GetPrefixData() const;
|
|
@@ -18,15 +18,14 @@
|
|
|
18
18
|
|
|
19
19
|
namespace duckdb {
|
|
20
20
|
|
|
21
|
-
//!
|
|
21
|
+
//! Physical CREATE (UNIQUE) INDEX statement
|
|
22
22
|
class PhysicalCreateIndex : public PhysicalOperator {
|
|
23
23
|
public:
|
|
24
24
|
PhysicalCreateIndex(LogicalOperator &op, TableCatalogEntry &table, vector<column_t> column_ids,
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
unique_ptr<CreateIndexInfo> info, vector<unique_ptr<Expression>> unbound_expressions,
|
|
26
|
+
idx_t estimated_cardinality)
|
|
27
27
|
: PhysicalOperator(PhysicalOperatorType::CREATE_INDEX, op.types, estimated_cardinality), table(table),
|
|
28
|
-
|
|
29
|
-
unbound_expressions(std::move(unbound_expressions)) {
|
|
28
|
+
info(std::move(info)), unbound_expressions(std::move(unbound_expressions)) {
|
|
30
29
|
|
|
31
30
|
// convert virtual column ids to storage column ids
|
|
32
31
|
for (auto &column_id : column_ids) {
|
|
@@ -38,21 +37,20 @@ public:
|
|
|
38
37
|
TableCatalogEntry &table;
|
|
39
38
|
//! The list of column IDs required for the index
|
|
40
39
|
vector<column_t> storage_ids;
|
|
41
|
-
//! Set of expressions to index by
|
|
42
|
-
vector<unique_ptr<Expression>> expressions;
|
|
43
40
|
//! Info for index creation
|
|
44
41
|
unique_ptr<CreateIndexInfo> info;
|
|
45
42
|
//! Unbound expressions to be used in the optimizer
|
|
46
43
|
vector<unique_ptr<Expression>> unbound_expressions;
|
|
47
44
|
|
|
48
45
|
public:
|
|
49
|
-
|
|
46
|
+
//! Source interface, NOP for this operator
|
|
50
47
|
void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
|
|
51
48
|
LocalSourceState &lstate) const override;
|
|
52
49
|
|
|
53
50
|
public:
|
|
54
|
-
|
|
51
|
+
//! Sink interface, thread-local sink states
|
|
55
52
|
unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
|
|
53
|
+
//! Sink interface, global sink state
|
|
56
54
|
unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
|
|
57
55
|
|
|
58
56
|
SinkResultType Sink(ExecutionContext &context, GlobalSinkState &gstate_p, LocalSinkState &lstate_p,
|
|
@@ -60,6 +60,8 @@ public:
|
|
|
60
60
|
DUCKDB_API const vector<LogicalType> &GetTypes();
|
|
61
61
|
//! Returns the result names of the prepared statement
|
|
62
62
|
DUCKDB_API const vector<string> &GetNames();
|
|
63
|
+
//! Returns the map of parameter index to the expected type of parameter
|
|
64
|
+
DUCKDB_API vector<LogicalType> GetExpectedParameterTypes() const;
|
|
63
65
|
|
|
64
66
|
//! Create a pending query result of the prepared statement with the given set of arguments
|
|
65
67
|
template <typename... Args>
|
|
@@ -39,7 +39,7 @@ public:
|
|
|
39
39
|
TableIOManager &table_io_manager;
|
|
40
40
|
//! Column identifiers to extract from the base table
|
|
41
41
|
vector<column_t> column_ids;
|
|
42
|
-
//!
|
|
42
|
+
//! Unordered_set of column_ids used by the index
|
|
43
43
|
unordered_set<column_t> column_id_set;
|
|
44
44
|
//! Unbound expressions used by the index
|
|
45
45
|
vector<unique_ptr<Expression>> unbound_expressions;
|
|
@@ -47,7 +47,7 @@ public:
|
|
|
47
47
|
vector<PhysicalType> types;
|
|
48
48
|
//! The logical types of the expressions
|
|
49
49
|
vector<LogicalType> logical_types;
|
|
50
|
-
//! constraint type
|
|
50
|
+
//! Index constraint type (primary key, foreign key, ...)
|
|
51
51
|
IndexConstraintType constraint_type;
|
|
52
52
|
|
|
53
53
|
public:
|
|
@@ -83,8 +83,6 @@ public:
|
|
|
83
83
|
|
|
84
84
|
//! Insert data into the index. Does not lock the index.
|
|
85
85
|
virtual bool Insert(IndexLock &lock, DataChunk &input, Vector &row_identifiers) = 0;
|
|
86
|
-
//! Construct an index from sorted chunks of keys.
|
|
87
|
-
virtual void ConstructAndMerge(IndexLock &lock, PayloadScanner &scanner, Allocator &allocator) = 0;
|
|
88
86
|
|
|
89
87
|
//! Merge other_index into this index.
|
|
90
88
|
virtual bool MergeIndexes(IndexLock &state, Index *other_index) = 0;
|
|
@@ -52,6 +52,19 @@ const vector<string> &PreparedStatement::GetNames() {
|
|
|
52
52
|
return data->names;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
vector<LogicalType> PreparedStatement::GetExpectedParameterTypes() const {
|
|
56
|
+
D_ASSERT(data);
|
|
57
|
+
vector<LogicalType> expected_types(data->value_map.size());
|
|
58
|
+
for (auto &it : data->value_map) {
|
|
59
|
+
D_ASSERT(it.first >= 1);
|
|
60
|
+
idx_t param_index = it.first - 1;
|
|
61
|
+
D_ASSERT(param_index < expected_types.size());
|
|
62
|
+
D_ASSERT(it.second);
|
|
63
|
+
expected_types[param_index] = it.second->value.type();
|
|
64
|
+
}
|
|
65
|
+
return expected_types;
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
unique_ptr<QueryResult> PreparedStatement::Execute(vector<Value> &values, bool allow_stream_result) {
|
|
56
69
|
auto pending = PendingQuery(values, allow_stream_result);
|
|
57
70
|
if (pending->HasError()) {
|
|
@@ -10,7 +10,9 @@ namespace duckdb {
|
|
|
10
10
|
|
|
11
11
|
Index::Index(IndexType type, TableIOManager &table_io_manager, const vector<column_t> &column_ids_p,
|
|
12
12
|
const vector<unique_ptr<Expression>> &unbound_expressions, IndexConstraintType constraint_type_p)
|
|
13
|
+
|
|
13
14
|
: type(type), table_io_manager(table_io_manager), column_ids(column_ids_p), constraint_type(constraint_type_p) {
|
|
15
|
+
|
|
14
16
|
for (auto &expr : unbound_expressions) {
|
|
15
17
|
types.push_back(expr->return_type.InternalType());
|
|
16
18
|
logical_types.push_back(expr->return_type);
|