duckdb 0.8.2-dev4025.0 → 0.8.2-dev4142.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.
Files changed (71) hide show
  1. package/binding.gyp +1 -0
  2. package/package.json +1 -1
  3. package/src/duckdb/extension/json/buffered_json_reader.cpp +76 -74
  4. package/src/duckdb/extension/json/include/buffered_json_reader.hpp +35 -32
  5. package/src/duckdb/extension/json/include/json_scan.hpp +9 -6
  6. package/src/duckdb/extension/json/json_scan.cpp +124 -121
  7. package/src/duckdb/src/catalog/catalog.cpp +20 -0
  8. package/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp +5 -0
  9. package/src/duckdb/src/common/arrow/arrow_converter.cpp +3 -0
  10. package/src/duckdb/src/common/radix_partitioning.cpp +1 -1
  11. package/src/duckdb/src/common/sort/partition_state.cpp +5 -1
  12. package/src/duckdb/src/core_functions/aggregate/holistic/mode.cpp +1 -1
  13. package/src/duckdb/src/core_functions/function_list.cpp +7 -0
  14. package/src/duckdb/src/core_functions/scalar/list/list_cosine_similarity.cpp +78 -0
  15. package/src/duckdb/src/core_functions/scalar/list/list_distance.cpp +72 -0
  16. package/src/duckdb/src/core_functions/scalar/list/list_inner_product.cpp +70 -0
  17. package/src/duckdb/src/execution/index/art/art.cpp +111 -92
  18. package/src/duckdb/src/execution/index/art/iterator.cpp +21 -27
  19. package/src/duckdb/src/execution/index/art/leaf.cpp +72 -153
  20. package/src/duckdb/src/execution/index/art/node.cpp +109 -203
  21. package/src/duckdb/src/execution/index/art/node16.cpp +32 -64
  22. package/src/duckdb/src/execution/index/art/node256.cpp +38 -53
  23. package/src/duckdb/src/execution/index/art/node4.cpp +31 -62
  24. package/src/duckdb/src/execution/index/art/node48.cpp +43 -65
  25. package/src/duckdb/src/execution/index/art/prefix.cpp +70 -141
  26. package/src/duckdb/src/execution/index/fixed_size_allocator.cpp +345 -0
  27. package/src/duckdb/src/execution/index/fixed_size_buffer.cpp +74 -0
  28. package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +1 -1
  29. package/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp +1 -1
  30. package/src/duckdb/src/function/table/system/duckdb_columns.cpp +3 -1
  31. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  32. package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +1 -0
  33. package/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp +2 -0
  34. package/src/duckdb/src/include/duckdb/common/optional_idx.hpp +1 -1
  35. package/src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp +51 -0
  36. package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +17 -7
  37. package/src/duckdb/src/include/duckdb/execution/index/art/iterator.hpp +5 -5
  38. package/src/duckdb/src/include/duckdb/execution/index/art/leaf.hpp +10 -16
  39. package/src/duckdb/src/include/duckdb/execution/index/art/node.hpp +38 -116
  40. package/src/duckdb/src/include/duckdb/execution/index/art/node16.hpp +17 -18
  41. package/src/duckdb/src/include/duckdb/execution/index/art/node256.hpp +17 -23
  42. package/src/duckdb/src/include/duckdb/execution/index/art/node4.hpp +17 -18
  43. package/src/duckdb/src/include/duckdb/execution/index/art/node48.hpp +17 -24
  44. package/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +16 -22
  45. package/src/duckdb/src/include/duckdb/execution/index/fixed_size_allocator.hpp +126 -0
  46. package/src/duckdb/src/include/duckdb/execution/index/fixed_size_buffer.hpp +79 -0
  47. package/src/duckdb/src/include/duckdb/execution/index/index_pointer.hpp +96 -0
  48. package/src/duckdb/src/include/duckdb/main/extension_entries.hpp +1 -0
  49. package/src/duckdb/src/include/duckdb/main/extension_helper.hpp +1 -0
  50. package/src/duckdb/src/include/duckdb/parallel/task_scheduler.hpp +1 -1
  51. package/src/duckdb/src/include/duckdb/storage/block.hpp +1 -1
  52. package/src/duckdb/src/include/duckdb/storage/index.hpp +10 -8
  53. package/src/duckdb/src/include/duckdb/storage/metadata/metadata_writer.hpp +3 -0
  54. package/src/duckdb/src/main/extension/extension_helper.cpp +17 -0
  55. package/src/duckdb/src/main/extension/extension_install.cpp +5 -3
  56. package/src/duckdb/src/main/extension/extension_load.cpp +3 -3
  57. package/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp +14 -5
  58. package/src/duckdb/src/storage/checkpoint/table_data_writer.cpp +2 -3
  59. package/src/duckdb/src/storage/checkpoint_manager.cpp +16 -21
  60. package/src/duckdb/src/storage/data_table.cpp +3 -3
  61. package/src/duckdb/src/storage/index.cpp +7 -1
  62. package/src/duckdb/src/storage/metadata/metadata_manager.cpp +21 -21
  63. package/src/duckdb/src/storage/standard_buffer_manager.cpp +0 -8
  64. package/src/duckdb/src/storage/storage_info.cpp +1 -1
  65. package/src/duckdb/src/storage/table_index_list.cpp +1 -1
  66. package/src/duckdb/src/transaction/commit_state.cpp +5 -1
  67. package/src/duckdb/ub_src_core_functions_scalar_list.cpp +6 -0
  68. package/src/duckdb/ub_src_execution_index.cpp +4 -0
  69. package/src/duckdb/ub_src_execution_index_art.cpp +0 -2
  70. package/src/duckdb/src/execution/index/art/fixed_size_allocator.cpp +0 -238
  71. package/src/duckdb/src/include/duckdb/execution/index/art/fixed_size_allocator.hpp +0 -115
@@ -7,8 +7,8 @@
7
7
  //===----------------------------------------------------------------------===//
8
8
  #pragma once
9
9
 
10
+ #include "duckdb/execution/index/fixed_size_allocator.hpp"
10
11
  #include "duckdb/execution/index/art/art.hpp"
11
- #include "duckdb/execution/index/art/fixed_size_allocator.hpp"
12
12
  #include "duckdb/execution/index/art/node.hpp"
13
13
 
14
14
  namespace duckdb {
@@ -17,30 +17,28 @@ namespace duckdb {
17
17
  class ARTKey;
18
18
 
19
19
  //! The Prefix is a special node type that contains up to PREFIX_SIZE bytes, and one byte for the count,
20
- //! and a Node pointer. This pointer either points to another prefix
21
- //! node or the 'actual' ART node.
20
+ //! and a Node pointer. This pointer either points to a prefix node or another Node.
22
21
  class Prefix {
23
22
  public:
23
+ //! Delete copy constructors, as any Prefix can never own its memory
24
+ Prefix(const Prefix &) = delete;
25
+ Prefix &operator=(const Prefix &) = delete;
26
+
24
27
  //! Up to PREFIX_SIZE bytes of prefix data and the count
25
28
  uint8_t data[Node::PREFIX_SIZE + 1];
26
- //! A pointer to the next ART node
29
+ //! A pointer to the next Node
27
30
  Node ptr;
28
31
 
29
32
  public:
30
33
  //! Get a new empty prefix node, might cause a new buffer allocation
31
34
  static Prefix &New(ART &art, Node &node);
32
35
  //! Create a new prefix node containing a single byte and a pointer to a next node
33
- static Prefix &New(ART &art, Node &node, uint8_t byte, Node next);
36
+ static Prefix &New(ART &art, Node &node, uint8_t byte, const Node &next = Node());
34
37
  //! Get a new chain of prefix nodes, might cause new buffer allocations,
35
38
  //! with the node parameter holding the tail of the chain
36
39
  static void New(ART &art, reference<Node> &node, const ARTKey &key, const uint32_t depth, uint32_t count);
37
40
  //! Free the node (and its subtree)
38
41
  static void Free(ART &art, Node &node);
39
- //! Get a reference to the prefix
40
- static inline Prefix &Get(const ART &art, const Node ptr) {
41
- D_ASSERT(!ptr.IsSerialized());
42
- return *Node::GetAllocator(art, NType::PREFIX).Get<Prefix>(ptr);
43
- }
44
42
 
45
43
  //! Initializes a merge by incrementing the buffer ID of the prefix and its child node(s)
46
44
  static void InitializeMerge(ART &art, Node &node, const ARTFlags &flags);
@@ -51,13 +49,17 @@ public:
51
49
  static void Concatenate(ART &art, Node &prefix_node, const uint8_t byte, Node &child_prefix_node);
52
50
  //! Traverse a prefix and a key until (1) encountering a non-prefix node, or (2) encountering
53
51
  //! a mismatching byte, in which case depth indexes the mismatching byte in the key
54
- static idx_t Traverse(ART &art, reference<Node> &prefix_node, const ARTKey &key, idx_t &depth);
52
+ static idx_t Traverse(ART &art, reference<const Node> &prefix_node, const ARTKey &key, idx_t &depth);
53
+ //! Traverse a prefix and a key until (1) encountering a non-prefix node, or (2) encountering
54
+ //! a mismatching byte, in which case depth indexes the mismatching byte in the key
55
+ static idx_t TraverseMutable(ART &art, reference<Node> &prefix_node, const ARTKey &key, idx_t &depth);
55
56
  //! Traverse two prefixes to find (1) that they match (so far), or (2) that they have a mismatching position,
56
- //! or (3) that one prefix contains the other prefix
57
+ //! or (3) that one prefix contains the other prefix. This function aids in merging Nodes, and, therefore,
58
+ //! the nodes are not const
57
59
  static bool Traverse(ART &art, reference<Node> &l_node, reference<Node> &r_node, idx_t &mismatch_position);
58
60
  //! Returns the byte at position
59
61
  static inline uint8_t GetByte(const ART &art, const Node &prefix_node, const idx_t position) {
60
- auto prefix = Prefix::Get(art, prefix_node);
62
+ auto &prefix = Node::Ref<const Prefix>(art, prefix_node, NType::PREFIX);
61
63
  D_ASSERT(position < Node::PREFIX_SIZE);
62
64
  D_ASSERT(position < prefix.data[Node::PREFIX_SIZE]);
63
65
  return prefix.data[position];
@@ -71,12 +73,7 @@ public:
71
73
  static void Split(ART &art, reference<Node> &prefix_node, Node &child_node, idx_t position);
72
74
 
73
75
  //! Returns the string representation of the node, or only traverses and verifies the node and its subtree
74
- static string VerifyAndToString(ART &art, Node &node, const bool only_verify);
75
-
76
- //! Serialize this node and all subsequent nodes
77
- static BlockPointer Serialize(ART &art, Node &node, MetadataWriter &writer);
78
- //! Deserialize this node and all subsequent prefix nodes
79
- static void Deserialize(ART &art, Node &node, MetadataReader &reader);
76
+ static string VerifyAndToString(ART &art, const Node &node, const bool only_verify);
80
77
 
81
78
  //! Vacuum the child of the node
82
79
  static void Vacuum(ART &art, Node &node, const ARTFlags &flags);
@@ -88,8 +85,5 @@ private:
88
85
  //! Appends the other_prefix and all its subsequent prefix nodes to this prefix node.
89
86
  //! Also frees all copied/appended nodes
90
87
  void Append(ART &art, Node other_prefix);
91
- //! Get the total count of bytes in the chain of prefixes, with the node reference pointing to first non-prefix node
92
- static idx_t TotalCount(ART &art, reference<Node> &node);
93
88
  };
94
-
95
89
  } // namespace duckdb
@@ -0,0 +1,126 @@
1
+ //===----------------------------------------------------------------------===//
2
+ // DuckDB
3
+ //
4
+ // duckdb/execution/index/fixed_size_allocator.hpp
5
+ //
6
+ //
7
+ //===----------------------------------------------------------------------===//
8
+
9
+ #pragma once
10
+
11
+ #include "duckdb/common/types/validity_mask.hpp"
12
+ #include "duckdb/common/unordered_set.hpp"
13
+ #include "duckdb/storage/buffer_manager.hpp"
14
+ #include "duckdb/storage/metadata/metadata_manager.hpp"
15
+ #include "duckdb/storage/metadata/metadata_writer.hpp"
16
+ #include "duckdb/execution/index/fixed_size_buffer.hpp"
17
+ #include "duckdb/execution/index/index_pointer.hpp"
18
+ #include "duckdb/common/unordered_map.hpp"
19
+ #include "duckdb/common/constants.hpp"
20
+ #include "duckdb/common/map.hpp"
21
+
22
+ namespace duckdb {
23
+
24
+ //! The FixedSizeAllocator provides pointers to fixed-size memory segments of pre-allocated memory buffers.
25
+ //! The pointers are IndexPointers, and the leftmost byte (metadata) must always be zero.
26
+ //! It is also possible to directly request a C++ pointer to the underlying segment of an index pointer.
27
+ class FixedSizeAllocator {
28
+ public:
29
+ //! We can vacuum 10% or more of the total in-memory footprint
30
+ static constexpr uint8_t VACUUM_THRESHOLD = 10;
31
+
32
+ //! Constants for fast offset calculations in the bitmask
33
+ static constexpr idx_t BASE[] = {0x00000000FFFFFFFF, 0x0000FFFF, 0x00FF, 0x0F, 0x3, 0x1};
34
+ static constexpr uint8_t SHIFT[] = {32, 16, 8, 4, 2, 1};
35
+
36
+ public:
37
+ FixedSizeAllocator(const idx_t segment_size, BlockManager &block_manager);
38
+
39
+ //! Block manager of the database instance
40
+ BlockManager &block_manager;
41
+ //! Buffer manager of the database instance
42
+ BufferManager &buffer_manager;
43
+ //! Metadata manager for (de)serialization
44
+ MetadataManager &metadata_manager;
45
+
46
+ public:
47
+ //! Get a new IndexPointer to a segment, might cause a new buffer allocation
48
+ IndexPointer New();
49
+ //! Free the segment of the IndexPointer
50
+ void Free(const IndexPointer ptr);
51
+ //! Returns a pointer of type T to a segment. If dirty is false, then T should be a const class
52
+ template <class T>
53
+ inline T *Get(const IndexPointer ptr, const bool dirty = true) {
54
+ return (T *)Get(ptr, dirty);
55
+ }
56
+
57
+ //! Resets the allocator, e.g., during 'DELETE FROM table'
58
+ void Reset();
59
+
60
+ //! Returns the in-memory usage in bytes
61
+ inline idx_t GetMemoryUsage() const;
62
+
63
+ //! Returns the upper bound of the available buffer IDs, i.e., upper_bound > max_buffer_id
64
+ idx_t GetUpperBoundBufferId() const;
65
+ //! Merge another FixedSizeAllocator into this allocator. Both must have the same segment size
66
+ void Merge(FixedSizeAllocator &other);
67
+
68
+ //! Initialize a vacuum operation, and return true, if the allocator needs a vacuum
69
+ bool InitializeVacuum();
70
+ //! Finalize a vacuum operation by freeing all vacuumed buffers
71
+ void FinalizeVacuum();
72
+ //! Returns true, if an IndexPointer qualifies for a vacuum operation, and false otherwise
73
+ inline bool NeedsVacuum(const IndexPointer ptr) const {
74
+ if (vacuum_buffers.find(ptr.GetBufferId()) != vacuum_buffers.end()) {
75
+ return true;
76
+ }
77
+ return false;
78
+ }
79
+ //! Vacuums an IndexPointer
80
+ IndexPointer VacuumPointer(const IndexPointer ptr);
81
+
82
+ //! Serializes all in-memory buffers and the metadata
83
+ BlockPointer Serialize(MetadataWriter &writer);
84
+ //! Deserializes all metadata
85
+ void Deserialize(const BlockPointer &block_pointer);
86
+
87
+ private:
88
+ //! Allocation size of one segment in a buffer
89
+ //! We only need this value to calculate bitmask_count, bitmask_offset, and
90
+ //! available_segments_per_buffer
91
+ idx_t segment_size;
92
+
93
+ //! Number of validity_t values in the bitmask
94
+ idx_t bitmask_count;
95
+ //! First starting byte of the payload (segments)
96
+ idx_t bitmask_offset;
97
+ //! Number of possible segment allocations per buffer
98
+ idx_t available_segments_per_buffer;
99
+
100
+ //! Total number of allocated segments in all buffers
101
+ //! We can recalculate this by iterating over all buffers
102
+ idx_t total_segment_count;
103
+
104
+ //! Buffers containing the segments
105
+ unordered_map<idx_t, FixedSizeBuffer> buffers;
106
+ //! Buffers with free space
107
+ unordered_set<idx_t> buffers_with_free_space;
108
+ //! Buffers qualifying for a vacuum (helper field to allow for fast NeedsVacuum checks)
109
+ unordered_set<idx_t> vacuum_buffers;
110
+
111
+ private:
112
+ //! Returns the data_ptr_t to a segment, and sets the dirty flag of the buffer containing that segment
113
+ inline data_ptr_t Get(const IndexPointer ptr, const bool dirty = true) {
114
+ D_ASSERT(ptr.GetOffset() < available_segments_per_buffer);
115
+ D_ASSERT(buffers.find(ptr.GetBufferId()) != buffers.end());
116
+ auto &buffer = buffers.find(ptr.GetBufferId())->second;
117
+ auto buffer_ptr = buffer.Get(dirty);
118
+ return buffer_ptr + ptr.GetOffset() * segment_size + bitmask_offset;
119
+ }
120
+ //! Returns the first free offset in a bitmask
121
+ uint32_t GetOffset(ValidityMask &mask, const idx_t segment_count);
122
+ //! Returns an available buffer id
123
+ idx_t GetAvailableBufferId() const;
124
+ };
125
+
126
+ } // namespace duckdb
@@ -0,0 +1,79 @@
1
+ //===----------------------------------------------------------------------===//
2
+ // DuckDB
3
+ //
4
+ // duckdb/execution/index/fixed_size_buffer.hpp
5
+ //
6
+ //
7
+ //===----------------------------------------------------------------------===//
8
+
9
+ #pragma once
10
+
11
+ #include "duckdb/common/typedefs.hpp"
12
+ #include "duckdb/storage/buffer/block_handle.hpp"
13
+ #include "duckdb/storage/buffer/buffer_handle.hpp"
14
+
15
+ namespace duckdb {
16
+
17
+ class FixedSizeAllocator;
18
+ class MetadataWriter;
19
+
20
+ //! A fixed-size buffer holds fixed-size segments of data. It lazily deserializes a buffer, if on-disk and not
21
+ //! yet in memory, and it only serializes dirty and non-written buffers to disk during
22
+ //! serialization.
23
+ class FixedSizeBuffer {
24
+ public:
25
+ //! Constructor for a new in-memory buffer
26
+ explicit FixedSizeBuffer(BlockManager &block_manager);
27
+ //! Constructor for deserializing buffer metadata from disk
28
+ FixedSizeBuffer(BlockManager &block_manager, const idx_t segment_count, const block_id_t &block_id);
29
+
30
+ //! Block manager of the database instance
31
+ BlockManager &block_manager;
32
+
33
+ //! The number of allocated segments
34
+ idx_t segment_count;
35
+
36
+ //! True: the in-memory buffer is no longer consistent with a (possibly existing) copy on disk
37
+ bool dirty;
38
+ //! True: can be vacuumed after the vacuum operation
39
+ bool vacuum;
40
+
41
+ public:
42
+ //! Returns true, if the buffer is in-memory
43
+ inline bool InMemory() const {
44
+ return buffer_handle.IsValid();
45
+ }
46
+ //! Returns true, if the block is on-disk
47
+ inline bool OnDisk() const {
48
+ return (block_handle != nullptr) && (block_handle->BlockId() < MAXIMUM_BLOCK);
49
+ }
50
+ //! Returns the block ID
51
+ inline block_id_t BlockId() const {
52
+ D_ASSERT(OnDisk());
53
+ return block_handle->BlockId();
54
+ }
55
+ //! Returns a pointer to the buffer in memory, and calls Deserialize, if the buffer is not in memory
56
+ inline data_ptr_t Get(const bool dirty_p = true) {
57
+ if (!InMemory()) {
58
+ Pin();
59
+ }
60
+ if (dirty_p) {
61
+ dirty = dirty_p;
62
+ }
63
+ return buffer_handle.Ptr();
64
+ }
65
+ //! Destroys the in-memory buffer and the on-disk block
66
+ void Destroy();
67
+ //! Serializes a buffer (if dirty or not on disk)
68
+ void Serialize();
69
+ //! Pin a buffer (if not in-memory)
70
+ void Pin();
71
+
72
+ private:
73
+ //! The buffer handle of the in-memory buffer
74
+ BufferHandle buffer_handle;
75
+ //! The block handle of the on-disk buffer
76
+ shared_ptr<BlockHandle> block_handle;
77
+ };
78
+
79
+ } // namespace duckdb
@@ -0,0 +1,96 @@
1
+ //===----------------------------------------------------------------------===//
2
+ // DuckDB
3
+ //
4
+ // duckdb/execution/index/index_pointer.hpp
5
+ //
6
+ //
7
+ //===----------------------------------------------------------------------===//
8
+
9
+ #pragma once
10
+
11
+ #include "duckdb/common/typedefs.hpp"
12
+
13
+ namespace duckdb {
14
+
15
+ class IndexPointer {
16
+ public:
17
+ //! Bit-shifting
18
+ static constexpr idx_t SHIFT_OFFSET = 32;
19
+ static constexpr idx_t SHIFT_METADATA = 56;
20
+ //! AND operations
21
+ static constexpr idx_t AND_OFFSET = 0x0000000000FFFFFF;
22
+ static constexpr idx_t AND_BUFFER_ID = 0x00000000FFFFFFFF;
23
+ static constexpr idx_t AND_METADATA = 0xFF00000000000000;
24
+
25
+ public:
26
+ //! Constructs an empty IndexPointer
27
+ IndexPointer() : data(0) {};
28
+ //! Constructs an in-memory IndexPointer with a buffer ID and an offset
29
+ IndexPointer(const uint32_t buffer_id, const uint32_t offset) : data(0) {
30
+ auto shifted_offset = ((idx_t)offset) << SHIFT_OFFSET;
31
+ data += shifted_offset;
32
+ data += buffer_id;
33
+ };
34
+
35
+ public:
36
+ //! Get data (all 64 bits)
37
+ inline idx_t Get() const {
38
+ return data;
39
+ }
40
+ //! Set data (all 64 bits)
41
+ inline void Set(const idx_t data_p) {
42
+ data = data_p;
43
+ }
44
+
45
+ //! Returns false, if the metadata is empty
46
+ inline bool HasMetadata() const {
47
+ return data & AND_METADATA;
48
+ }
49
+ //! Get metadata (zero to 7th bit)
50
+ inline uint8_t GetMetadata() const {
51
+ return data >> SHIFT_METADATA;
52
+ }
53
+ //! Set metadata (zero to 7th bit)
54
+ inline void SetMetadata(const uint8_t metadata) {
55
+ data += (idx_t)metadata << SHIFT_METADATA;
56
+ }
57
+
58
+ //! Get the offset (8th to 23rd bit)
59
+ inline idx_t GetOffset() const {
60
+ auto offset = data >> SHIFT_OFFSET;
61
+ return offset & AND_OFFSET;
62
+ }
63
+ //! Get the buffer ID (24th to 63rd bit)
64
+ inline idx_t GetBufferId() const {
65
+ return data & AND_BUFFER_ID;
66
+ }
67
+
68
+ //! Resets the IndexPointer
69
+ inline void Clear() {
70
+ data = 0;
71
+ }
72
+
73
+ //! Adds an idx_t to a buffer ID, the rightmost 32 bits of data contain the buffer ID
74
+ inline void IncreaseBufferId(const idx_t summand) {
75
+ data += summand;
76
+ }
77
+
78
+ //! Comparison operator
79
+ inline bool operator==(const IndexPointer &ptr) const {
80
+ return data == ptr.data;
81
+ }
82
+
83
+ private:
84
+ //! Data holds all the information contained in an IndexPointer
85
+ //! [0 - 7: metadata,
86
+ //! 8 - 23: offset, 24 - 63: buffer ID]
87
+ //! NOTE: we do not use bit fields because when using bit fields Windows compiles
88
+ //! the IndexPointer class into 16 bytes instead of the intended 8 bytes, doubling the
89
+ //! space requirements
90
+ //! https://learn.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-170
91
+ idx_t data;
92
+ };
93
+
94
+ static_assert(sizeof(IndexPointer) == sizeof(idx_t), "Invalid size for IndexPointer.");
95
+
96
+ } // namespace duckdb
@@ -234,6 +234,7 @@ static constexpr ExtensionEntry EXTENSION_FILE_CONTAINS[] = {{".parquet?", "parq
234
234
 
235
235
  static constexpr const char *AUTOLOADABLE_EXTENSIONS[] = {
236
236
  // "azure",
237
+ "aws",
237
238
  "autocomplete",
238
239
  "excel",
239
240
  "fts",
@@ -51,6 +51,7 @@ public:
51
51
 
52
52
  //! Autoload an extension by name. Depending on the current settings, this will either load or install+load
53
53
  static void AutoLoadExtension(ClientContext &context, const string &extension_name);
54
+ DUCKDB_API static bool TryAutoLoadExtension(ClientContext &context, const string &extension_name) noexcept;
54
55
 
55
56
  static string ExtensionDirectory(ClientContext &context);
56
57
  static string ExtensionDirectory(DBConfig &config, FileSystem &fs);
@@ -68,7 +68,7 @@ public:
68
68
  void Signal(idx_t n);
69
69
 
70
70
  //! Yield to other threads
71
- void YieldThread();
71
+ static void YieldThread();
72
72
 
73
73
  //! Set the allocator flush threshold
74
74
  void SetAllocatorFlushTreshold(idx_t threshold);
@@ -35,7 +35,7 @@ struct BlockPointer {
35
35
  block_id_t block_id;
36
36
  uint32_t offset;
37
37
 
38
- bool IsValid() {
38
+ bool IsValid() const {
39
39
  return block_id != INVALID_BLOCK;
40
40
  }
41
41
  };
@@ -54,8 +54,6 @@ public:
54
54
 
55
55
  //! Attached database instance
56
56
  AttachedDatabase &db;
57
- //! Buffer manager of the database instance
58
- BufferManager &buffer_manager;
59
57
 
60
58
  public:
61
59
  //! Initialize a single predicate scan on the index with the given expression and column IDs
@@ -85,6 +83,10 @@ public:
85
83
  //! Performs constraint checking for a chunk of input data
86
84
  virtual void CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_manager) = 0;
87
85
 
86
+ //! Deletes all data from the index. The lock obtained from InitializeLock must be held
87
+ virtual void CommitDrop(IndexLock &index_lock) = 0;
88
+ //! Deletes all data from the index
89
+ void CommitDrop();
88
90
  //! Delete a chunk of entries from the index. The lock obtained from InitializeLock must be held
89
91
  virtual void Delete(IndexLock &state, DataChunk &entries, Vector &row_identifiers) = 0;
90
92
  //! Obtains a lock and calls Delete while holding that lock
@@ -125,11 +127,11 @@ public:
125
127
  return (constraint_type == IndexConstraintType::FOREIGN);
126
128
  }
127
129
 
128
- //! Serializes the index and returns the pair of block_id offset positions
130
+ //! Serializes the index to disk
129
131
  virtual BlockPointer Serialize(MetadataWriter &writer);
130
- //! Returns the serialized data pointer to the block and offset of the serialized index
131
- BlockPointer GetSerializedDataPointer() const {
132
- return serialized_data_pointer;
132
+ //! Returns the serialized root block pointer
133
+ BlockPointer GetRootBlockPointer() const {
134
+ return root_block_pointer;
133
135
  }
134
136
 
135
137
  //! Execute the index expressions on an input chunk
@@ -139,8 +141,8 @@ public:
139
141
  protected:
140
142
  //! Lock used for any changes to the index
141
143
  mutex lock;
142
- //! Pointer to serialized index data
143
- BlockPointer serialized_data_pointer;
144
+ //! Pointer to the index on disk
145
+ BlockPointer root_block_pointer;
144
146
 
145
147
  private:
146
148
  //! Bound expressions used during expression execution
@@ -14,6 +14,9 @@ namespace duckdb {
14
14
 
15
15
  class MetadataWriter : public Serializer {
16
16
  public:
17
+ MetadataWriter(const MetadataWriter &) = delete;
18
+ MetadataWriter &operator=(const MetadataWriter &) = delete;
19
+
17
20
  explicit MetadataWriter(MetadataManager &manager);
18
21
  ~MetadataWriter() override;
19
22
 
@@ -194,13 +194,30 @@ string ExtensionHelper::AddExtensionInstallHintToErrorMsg(ClientContext &context
194
194
  return base_error;
195
195
  }
196
196
 
197
+ bool ExtensionHelper::TryAutoLoadExtension(ClientContext &context, const string &extension_name) noexcept {
198
+ auto &dbconfig = DBConfig::GetConfig(context);
199
+ try {
200
+ if (dbconfig.options.autoinstall_known_extensions) {
201
+ ExtensionHelper::InstallExtension(context, extension_name, false,
202
+ context.config.autoinstall_extension_repo);
203
+ }
204
+ ExtensionHelper::LoadExternalExtension(context, extension_name);
205
+ return true;
206
+ } catch (...) {
207
+ return false;
208
+ }
209
+ return false;
210
+ }
211
+
197
212
  void ExtensionHelper::AutoLoadExtension(ClientContext &context, const string &extension_name) {
198
213
  auto &dbconfig = DBConfig::GetConfig(context);
199
214
  try {
215
+ #ifndef DUCKDB_WASM
200
216
  if (dbconfig.options.autoinstall_known_extensions) {
201
217
  ExtensionHelper::InstallExtension(context, extension_name, false,
202
218
  context.config.autoinstall_extension_repo);
203
219
  }
220
+ #endif
204
221
  ExtensionHelper::LoadExternalExtension(context, extension_name);
205
222
  } catch (Exception &e) {
206
223
  throw AutoloadException(extension_name, e);
@@ -45,7 +45,7 @@ const vector<string> ExtensionHelper::PathComponents() {
45
45
 
46
46
  string ExtensionHelper::ExtensionDirectory(DBConfig &config, FileSystem &fs) {
47
47
  #ifdef WASM_LOADABLE_EXTENSIONS
48
- static_assert(0, "ExtensionDirectory functionality is not supported in duckdb-wasm");
48
+ throw PermissionException("ExtensionDirectory functionality is not supported in duckdb-wasm");
49
49
  #endif
50
50
  string extension_directory;
51
51
  if (!config.options.extension_directory.empty()) { // create the extension directory if not present
@@ -159,9 +159,11 @@ void WriteExtensionFileToDisk(FileSystem &fs, const string &path, void *data, id
159
159
 
160
160
  string ExtensionHelper::ExtensionUrlTemplate(optional_ptr<const ClientConfig> client_config, const string &repository) {
161
161
  string default_endpoint = "http://extensions.duckdb.org";
162
- string versioned_path = "/${REVISION}/${PLATFORM}/${NAME}.duckdb_extension.gz";
162
+ string versioned_path = "/${REVISION}/${PLATFORM}/${NAME}.duckdb_extension";
163
163
  #ifdef WASM_LOADABLE_EXTENSIONS
164
- versioned_path = "/duckdb-wasm" + versioned_path;
164
+ versioned_path = "/duckdb-wasm" + versioned_path + ".wasm";
165
+ #else
166
+ versioned_path = versioned_path + ".gz";
165
167
  #endif
166
168
  string custom_endpoint = client_config ? client_config->custom_extension_repo : string();
167
169
  string endpoint;
@@ -70,14 +70,15 @@ bool ExtensionHelper::TryInitialLoad(DBConfig &config, FileSystem &fs, const str
70
70
 
71
71
  // shorthand case
72
72
  if (!ExtensionHelper::IsFullPath(extension)) {
73
+ string extension_name = ApplyExtensionAlias(extension);
73
74
  #ifdef WASM_LOADABLE_EXTENSIONS
74
75
  string url_template = ExtensionUrlTemplate(client_config, "");
75
76
  string url = ExtensionFinalizeUrlTemplate(url_template, extension_name);
76
77
 
77
78
  char *str = (char *)EM_ASM_PTR(
78
79
  {
79
- var jsString = ((typeof runtime == = 'object') && runtime &&
80
- (typeof runtime.whereToLoad == = 'function') && runtime.whereToLoad)
80
+ var jsString = ((typeof runtime == 'object') && runtime && (typeof runtime.whereToLoad == 'function') &&
81
+ runtime.whereToLoad)
81
82
  ? runtime.whereToLoad(UTF8ToString($0))
82
83
  : (UTF8ToString($1));
83
84
  var lengthBytes = lengthBytesUTF8(jsString) + 1;
@@ -105,7 +106,6 @@ bool ExtensionHelper::TryInitialLoad(DBConfig &config, FileSystem &fs, const str
105
106
  for (auto &path_ele : path_components) {
106
107
  local_path = fs.JoinPath(local_path, path_ele);
107
108
  }
108
- string extension_name = ApplyExtensionAlias(extension);
109
109
  filename = fs.JoinPath(local_path, extension_name + ".duckdb_extension");
110
110
  #endif
111
111
  }
@@ -69,21 +69,30 @@ BindResult ExpressionBinder::BindExpression(FunctionExpression &function, idx_t
69
69
  }
70
70
 
71
71
  switch (func->type) {
72
- case CatalogType::SCALAR_FUNCTION_ENTRY:
72
+ case CatalogType::SCALAR_FUNCTION_ENTRY: {
73
73
  // scalar function
74
74
 
75
75
  // check for lambda parameters, ignore ->> operator (JSON extension)
76
+ bool try_bind_lambda = false;
76
77
  if (function.function_name != "->>") {
77
78
  for (auto &child : function.children) {
78
79
  if (child->expression_class == ExpressionClass::LAMBDA) {
79
- return BindLambdaFunction(function, func->Cast<ScalarFunctionCatalogEntry>(), depth);
80
+ try_bind_lambda = true;
80
81
  }
81
82
  }
82
83
  }
83
84
 
85
+ if (try_bind_lambda) {
86
+ auto result = BindLambdaFunction(function, func->Cast<ScalarFunctionCatalogEntry>(), depth);
87
+ if (!result.HasError()) {
88
+ // Lambda bind successful
89
+ return result;
90
+ }
91
+ }
92
+
84
93
  // other scalar function
85
94
  return BindFunction(function, func->Cast<ScalarFunctionCatalogEntry>(), depth);
86
-
95
+ }
87
96
  case CatalogType::MACRO_ENTRY:
88
97
  // macro function
89
98
  return BindMacro(function, func->Cast<ScalarMacroCatalogEntry>(), depth, expr_ptr);
@@ -134,7 +143,7 @@ BindResult ExpressionBinder::BindLambdaFunction(FunctionExpression &function, Sc
134
143
  string error;
135
144
 
136
145
  if (function.children.size() != 2) {
137
- throw BinderException("Invalid function arguments!");
146
+ return BindResult("Invalid function arguments!");
138
147
  }
139
148
  D_ASSERT(function.children[1]->GetExpressionClass() == ExpressionClass::LAMBDA);
140
149
 
@@ -148,7 +157,7 @@ BindResult ExpressionBinder::BindLambdaFunction(FunctionExpression &function, Sc
148
157
  auto &list_child = BoundExpression::GetExpression(*function.children[0]);
149
158
  if (list_child->return_type.id() != LogicalTypeId::LIST && list_child->return_type.id() != LogicalTypeId::SQLNULL &&
150
159
  list_child->return_type.id() != LogicalTypeId::UNKNOWN) {
151
- throw BinderException(" Invalid LIST argument to " + function.function_name + "!");
160
+ return BindResult(" Invalid LIST argument to " + function.function_name + "!");
152
161
  }
153
162
 
154
163
  LogicalType list_child_type = list_child->return_type.id();
@@ -69,9 +69,8 @@ void SingleFileTableDataWriter::FinalizeTable(TableStatistics &&global_stats, Da
69
69
 
70
70
  // Write-off to metadata block ids and offsets of indexes
71
71
  meta_data_writer.Write<idx_t>(index_pointers.size());
72
- for (auto &block_info : index_pointers) {
73
- meta_data_writer.Write<block_id_t>(block_info.block_id);
74
- meta_data_writer.Write<uint32_t>(block_info.offset);
72
+ for (const auto &index_pointer : index_pointers) {
73
+ meta_data_writer.Write<BlockPointer>(index_pointer);
75
74
  }
76
75
  }
77
76