duckdb 0.7.2-dev14.0 → 0.7.2-dev225.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 (129) hide show
  1. package/binding.gyp +2 -0
  2. package/package.json +1 -1
  3. package/src/duckdb/extension/icu/icu-extension.cpp +2 -0
  4. package/src/duckdb/extension/icu/icu-table-range.cpp +194 -0
  5. package/src/duckdb/extension/icu/include/icu-table-range.hpp +17 -0
  6. package/src/duckdb/extension/parquet/column_writer.cpp +0 -1
  7. package/src/duckdb/extension/parquet/parquet-extension.cpp +11 -2
  8. package/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp +4 -0
  9. package/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp +7 -6
  10. package/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp +20 -1
  11. package/src/duckdb/src/common/enums/statement_type.cpp +2 -0
  12. package/src/duckdb/src/common/types/bit.cpp +95 -58
  13. package/src/duckdb/src/common/types/value.cpp +149 -53
  14. package/src/duckdb/src/common/types/vector.cpp +13 -10
  15. package/src/duckdb/src/execution/operator/persistent/buffered_csv_reader.cpp +1 -1
  16. package/src/duckdb/src/function/aggregate/algebraic/avg.cpp +0 -6
  17. package/src/duckdb/src/function/aggregate/distributive/bitagg.cpp +99 -95
  18. package/src/duckdb/src/function/aggregate/distributive/bitstring_agg.cpp +261 -0
  19. package/src/duckdb/src/function/aggregate/distributive/sum.cpp +0 -3
  20. package/src/duckdb/src/function/aggregate/distributive_functions.cpp +1 -0
  21. package/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +16 -5
  22. package/src/duckdb/src/function/cast/bit_cast.cpp +0 -2
  23. package/src/duckdb/src/function/cast/blob_cast.cpp +0 -1
  24. package/src/duckdb/src/function/scalar/bit/bitstring.cpp +99 -0
  25. package/src/duckdb/src/function/scalar/map/map_entries.cpp +61 -0
  26. package/src/duckdb/src/function/scalar/map/map_keys_values.cpp +97 -0
  27. package/src/duckdb/src/function/scalar/nested_functions.cpp +3 -0
  28. package/src/duckdb/src/function/scalar/operators/add.cpp +0 -9
  29. package/src/duckdb/src/function/scalar/operators/arithmetic.cpp +2 -14
  30. package/src/duckdb/src/function/scalar/operators/bitwise.cpp +0 -63
  31. package/src/duckdb/src/function/scalar/operators/multiply.cpp +0 -6
  32. package/src/duckdb/src/function/scalar/operators/subtract.cpp +0 -6
  33. package/src/duckdb/src/function/scalar/string_functions.cpp +1 -0
  34. package/src/duckdb/src/function/table/read_csv.cpp +9 -0
  35. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  36. package/src/duckdb/src/function/table_function.cpp +19 -0
  37. package/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp +6 -8
  38. package/src/duckdb/src/include/duckdb/common/constants.hpp +0 -19
  39. package/src/duckdb/src/include/duckdb/common/enums/statement_type.hpp +2 -1
  40. package/src/duckdb/src/include/duckdb/common/enums/tableref_type.hpp +2 -1
  41. package/src/duckdb/src/include/duckdb/common/types/bit.hpp +5 -1
  42. package/src/duckdb/src/include/duckdb/common/types/value.hpp +2 -8
  43. package/src/duckdb/src/include/duckdb/common/types.hpp +1 -2
  44. package/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp +5 -0
  45. package/src/duckdb/src/include/duckdb/function/scalar/bit_functions.hpp +4 -0
  46. package/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp +12 -0
  47. package/src/duckdb/src/include/duckdb/function/table_function.hpp +2 -0
  48. package/src/duckdb/src/include/duckdb/main/capi/capi_internal.hpp +2 -0
  49. package/src/duckdb/src/include/duckdb/main/config.hpp +3 -0
  50. package/src/duckdb/src/include/duckdb/main/database.hpp +1 -0
  51. package/src/duckdb/src/include/duckdb/optimizer/join_order/cardinality_estimator.hpp +2 -2
  52. package/src/duckdb/src/include/duckdb/parser/common_table_expression_info.hpp +2 -0
  53. package/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp +2 -1
  54. package/src/duckdb/src/include/duckdb/parser/parsed_data/{alter_function_info.hpp → alter_scalar_function_info.hpp} +13 -13
  55. package/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_function_info.hpp +47 -0
  56. package/src/duckdb/src/include/duckdb/parser/parsed_data/create_table_function_info.hpp +2 -1
  57. package/src/duckdb/src/include/duckdb/parser/query_node.hpp +2 -1
  58. package/src/duckdb/src/include/duckdb/parser/statement/multi_statement.hpp +28 -0
  59. package/src/duckdb/src/include/duckdb/parser/tableref/list.hpp +1 -0
  60. package/src/duckdb/src/include/duckdb/parser/tableref/pivotref.hpp +76 -0
  61. package/src/duckdb/src/include/duckdb/parser/tokens.hpp +2 -0
  62. package/src/duckdb/src/include/duckdb/parser/transformer.hpp +28 -0
  63. package/src/duckdb/src/include/duckdb/planner/binder.hpp +8 -0
  64. package/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +2 -0
  65. package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +76 -44
  66. package/src/duckdb/src/include/duckdb/storage/statistics/base_statistics.hpp +2 -0
  67. package/src/duckdb/src/include/duckdb/storage/statistics/node_statistics.hpp +26 -0
  68. package/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp +1 -1
  69. package/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp +2 -0
  70. package/src/duckdb/src/include/duckdb.h +49 -1
  71. package/src/duckdb/src/include/duckdb.hpp +0 -1
  72. package/src/duckdb/src/main/capi/pending-c.cpp +16 -3
  73. package/src/duckdb/src/main/capi/result-c.cpp +27 -1
  74. package/src/duckdb/src/main/capi/stream-c.cpp +25 -0
  75. package/src/duckdb/src/main/client_context.cpp +8 -1
  76. package/src/duckdb/src/main/database.cpp +10 -2
  77. package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +98 -66
  78. package/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +16 -3
  79. package/src/duckdb/src/parser/parsed_data/alter_info.cpp +7 -3
  80. package/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp +56 -0
  81. package/src/duckdb/src/parser/parsed_data/alter_table_function_info.cpp +51 -0
  82. package/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp +3 -2
  83. package/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp +6 -0
  84. package/src/duckdb/src/parser/parsed_expression_iterator.cpp +8 -0
  85. package/src/duckdb/src/parser/query_node.cpp +1 -1
  86. package/src/duckdb/src/parser/statement/multi_statement.cpp +18 -0
  87. package/src/duckdb/src/parser/tableref/pivotref.cpp +296 -0
  88. package/src/duckdb/src/parser/tableref.cpp +3 -0
  89. package/src/duckdb/src/parser/transform/helpers/transform_alias.cpp +12 -6
  90. package/src/duckdb/src/parser/transform/helpers/transform_cte.cpp +24 -0
  91. package/src/duckdb/src/parser/transform/statement/transform_create_function.cpp +4 -0
  92. package/src/duckdb/src/parser/transform/statement/transform_create_view.cpp +4 -0
  93. package/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp +150 -0
  94. package/src/duckdb/src/parser/transform/statement/transform_select.cpp +8 -0
  95. package/src/duckdb/src/parser/transform/statement/transform_select_node.cpp +1 -1
  96. package/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp +105 -0
  97. package/src/duckdb/src/parser/transform/tableref/transform_tableref.cpp +2 -0
  98. package/src/duckdb/src/parser/transformer.cpp +15 -3
  99. package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +11 -3
  100. package/src/duckdb/src/planner/binder/statement/bind_create.cpp +1 -1
  101. package/src/duckdb/src/planner/binder/statement/bind_logical_plan.cpp +17 -0
  102. package/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp +365 -0
  103. package/src/duckdb/src/planner/binder.cpp +5 -0
  104. package/src/duckdb/src/planner/pragma_handler.cpp +10 -2
  105. package/src/duckdb/src/storage/buffer_manager.cpp +44 -46
  106. package/src/duckdb/src/storage/compression/bitpacking.cpp +25 -21
  107. package/src/duckdb/src/storage/compression/fixed_size_uncompressed.cpp +41 -43
  108. package/src/duckdb/src/storage/compression/rle.cpp +17 -13
  109. package/src/duckdb/src/storage/statistics/base_statistics.cpp +3 -3
  110. package/src/duckdb/src/storage/storage_info.cpp +1 -1
  111. package/src/duckdb/src/storage/table/column_data.cpp +5 -2
  112. package/src/duckdb/src/storage/table/list_column_data.cpp +32 -47
  113. package/src/duckdb/third_party/libpg_query/include/nodes/nodes.hpp +3 -0
  114. package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +34 -1
  115. package/src/duckdb/third_party/libpg_query/include/parser/gram.hpp +1016 -530
  116. package/src/duckdb/third_party/libpg_query/include/parser/kwlist.hpp +5 -0
  117. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +22697 -21987
  118. package/src/duckdb/ub_src_function_aggregate_distributive.cpp +2 -0
  119. package/src/duckdb/ub_src_function_scalar_bit.cpp +2 -0
  120. package/src/duckdb/ub_src_function_scalar_map.cpp +4 -0
  121. package/src/duckdb/ub_src_main_capi.cpp +2 -0
  122. package/src/duckdb/ub_src_parser_parsed_data.cpp +4 -2
  123. package/src/duckdb/ub_src_parser_statement.cpp +2 -0
  124. package/src/duckdb/ub_src_parser_tableref.cpp +2 -0
  125. package/src/duckdb/ub_src_parser_transform_statement.cpp +2 -0
  126. package/src/duckdb/ub_src_parser_transform_tableref.cpp +2 -0
  127. package/src/duckdb/ub_src_planner_binder_tableref.cpp +2 -0
  128. package/src/duckdb/src/include/duckdb/main/loadable_extension.hpp +0 -59
  129. package/src/duckdb/src/parser/parsed_data/alter_function_info.cpp +0 -55
@@ -23,23 +23,75 @@ class DatabaseInstance;
23
23
  class TemporaryDirectoryHandle;
24
24
  struct EvictionQueue;
25
25
 
26
+ //! The BufferPool is in charge of handling memory management for one or more databases. It defines memory limits
27
+ //! and implements priority eviction among all users of the pool.
28
+ class BufferPool {
29
+ friend class BlockHandle;
30
+ friend class BlockManager;
31
+ friend class BufferManager;
32
+
33
+ public:
34
+ explicit BufferPool(idx_t maximum_memory);
35
+ virtual ~BufferPool();
36
+
37
+ //! Set a new memory limit to the buffer pool, throws an exception if the new limit is too low and not enough
38
+ //! blocks can be evicted
39
+ void SetLimit(idx_t limit, const char *exception_postscript);
40
+
41
+ idx_t GetUsedMemory() {
42
+ return current_memory;
43
+ }
44
+ idx_t GetMaxMemory() {
45
+ return maximum_memory;
46
+ }
47
+
48
+ protected:
49
+ //! Evict blocks until the currently used memory + extra_memory fit, returns false if this was not possible
50
+ //! (i.e. not enough blocks could be evicted)
51
+ //! If the "buffer" argument is specified AND the system can find a buffer to re-use for the given allocation size
52
+ //! "buffer" will be made to point to the re-usable memory. Note that this is not guaranteed.
53
+ //! Returns a pair. result.first indicates if eviction was successful. result.second contains the
54
+ //! reservation handle, which can be moved to the BlockHandle that will own the reservation.
55
+ struct EvictionResult {
56
+ bool success;
57
+ TempBufferPoolReservation reservation;
58
+ };
59
+ virtual EvictionResult EvictBlocks(idx_t extra_memory, idx_t memory_limit,
60
+ unique_ptr<FileBuffer> *buffer = nullptr);
61
+
62
+ //! Garbage collect eviction queue
63
+ void PurgeQueue();
64
+ void AddToEvictionQueue(shared_ptr<BlockHandle> &handle);
65
+
66
+ private:
67
+ //! The lock for changing the memory limit
68
+ mutex limit_lock;
69
+ //! The current amount of memory that is occupied by the buffer manager (in bytes)
70
+ atomic<idx_t> current_memory;
71
+ //! The maximum amount of memory that the buffer manager can keep (in bytes)
72
+ atomic<idx_t> maximum_memory;
73
+ //! Eviction queue
74
+ unique_ptr<EvictionQueue> queue;
75
+ //! Total number of insertions into the eviction queue. This guides the schedule for calling PurgeQueue.
76
+ atomic<uint32_t> queue_insertions;
77
+ };
78
+
26
79
  struct TemporaryFileInformation {
27
80
  string path;
28
81
  idx_t size;
29
82
  };
30
83
 
31
- //! The buffer manager is in charge of handling memory management for the database. It hands out memory buffers that can
32
- //! be used by the database internally.
33
- //
34
- //! BlockIds are NOT unique within the context of a BufferManager. A buffer manager
35
- //! can be shared by many BlockManagers.
84
+ //! The BufferManager is in charge of handling memory management for a singke database. It cooperatively shares a
85
+ //! BufferPool with other BufferManagers, belonging to different databases. It hands out memory buffers that can
86
+ //! be used by the database internally, and offers configuration options specific to a database, which need not be
87
+ //! shared by the BufferPool, including whether to support swapping temp buffers to disk, and where to swap them to.
36
88
  class BufferManager {
37
89
  friend class BufferHandle;
38
90
  friend class BlockHandle;
39
91
  friend class BlockManager;
40
92
 
41
93
  public:
42
- BufferManager(DatabaseInstance &db, string temp_directory, idx_t maximum_memory);
94
+ BufferManager(DatabaseInstance &db, string temp_directory);
43
95
  virtual ~BufferManager();
44
96
 
45
97
  //! Registers an in-memory buffer that cannot be unloaded until it is destroyed
@@ -58,21 +110,17 @@ public:
58
110
  BufferHandle Pin(shared_ptr<BlockHandle> &handle);
59
111
  void Unpin(shared_ptr<BlockHandle> &handle);
60
112
 
61
- //! Set a new memory limit to the buffer manager, throws an exception if the new limit is too low and not enough
62
- //! blocks can be evicted
63
- void SetLimit(idx_t limit = (idx_t)-1);
64
-
65
113
  DUCKDB_API static BufferManager &GetBufferManager(ClientContext &context);
66
114
  DUCKDB_API static BufferManager &GetBufferManager(DatabaseInstance &db);
67
115
  DUCKDB_API static BufferManager &GetBufferManager(AttachedDatabase &db);
68
116
 
69
117
  //! Returns the currently allocated memory
70
118
  idx_t GetUsedMemory() {
71
- return current_memory;
119
+ return buffer_pool.current_memory;
72
120
  }
73
121
  //! Returns the maximum available memory
74
122
  idx_t GetMaxMemory() {
75
- return maximum_memory;
123
+ return buffer_pool.maximum_memory;
76
124
  }
77
125
 
78
126
  //! Increases the currently allocated memory, but the actual allocation does not go through the buffer manager
@@ -92,6 +140,10 @@ public:
92
140
  return db;
93
141
  }
94
142
 
143
+ BufferPool &GetBufferPool() {
144
+ return buffer_pool;
145
+ }
146
+
95
147
  static idx_t GetAllocSize(idx_t block_size) {
96
148
  return AlignValue<idx_t, Storage::SECTOR_SIZE>(block_size + Storage::BLOCK_HEADER_SIZE);
97
149
  }
@@ -103,6 +155,11 @@ public:
103
155
  DUCKDB_API void ReserveMemory(idx_t size);
104
156
  DUCKDB_API void FreeReservedMemory(idx_t size);
105
157
 
158
+ //! Set a new memory limit to the buffer pool, throws an exception if the new limit is too low and not enough
159
+ //! blocks can be evicted. (Sugar for calling method directly on the BufferPool.)
160
+ void SetLimit(idx_t limit = (idx_t)-1) {
161
+ buffer_pool.SetLimit(limit, InMemoryWarning());
162
+ }
106
163
  //! Returns a list of all temporary files
107
164
  vector<TemporaryFileInformation> GetTemporaryFiles();
108
165
 
@@ -113,25 +170,6 @@ private:
113
170
  //! This needs to be private to prevent creating blocks without ever pinning them:
114
171
  //! blocks that are never pinned are never added to the eviction queue
115
172
  shared_ptr<BlockHandle> RegisterMemory(idx_t block_size, bool can_destroy);
116
- //! Evict blocks until the currently used memory + extra_memory fit, returns false if this was not possible
117
- //! (i.e. not enough blocks could be evicted)
118
- //! If the "buffer" argument is specified AND the system can find a buffer to re-use for the given allocation size
119
- //! "buffer" will be made to point to the re-usable memory. Note that this is not guaranteed.
120
- //! Returns a pair. result.first indicates if eviction was successful. result.second contains the
121
- //! reservation handle, which can be moved to the BlockHandle that will own the reservation.
122
- struct EvictionResult {
123
- bool success;
124
- TempBufferPoolReservation reservation;
125
- };
126
- EvictionResult EvictBlocks(idx_t extra_memory, idx_t memory_limit, unique_ptr<FileBuffer> *buffer = nullptr);
127
-
128
- //! Helper
129
- template <typename... ARGS>
130
- TempBufferPoolReservation EvictBlocksOrThrow(idx_t extra_memory, idx_t limit, unique_ptr<FileBuffer> *buffer,
131
- ARGS...);
132
-
133
- //! Garbage collect eviction queue
134
- void PurgeQueue();
135
173
 
136
174
  //! Write a temporary buffer to disk
137
175
  void WriteTemporaryBuffer(block_id_t block_id, FileBuffer &buffer);
@@ -144,9 +182,7 @@ private:
144
182
 
145
183
  void RequireTemporaryDirectory();
146
184
 
147
- void AddToEvictionQueue(shared_ptr<BlockHandle> &handle);
148
-
149
- string InMemoryWarning();
185
+ const char *InMemoryWarning();
150
186
 
151
187
  static data_ptr_t BufferAllocatorAllocate(PrivateAllocatorData *private_data, idx_t size);
152
188
  static void BufferAllocatorFree(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t size);
@@ -157,27 +193,23 @@ private:
157
193
  //! overwrites the data within with garbage. Any readers that do not hold the pin will notice
158
194
  void VerifyZeroReaders(shared_ptr<BlockHandle> &handle);
159
195
 
196
+ //! Helper
197
+ template <typename... ARGS>
198
+ TempBufferPoolReservation EvictBlocksOrThrow(idx_t extra_memory, unique_ptr<FileBuffer> *buffer, ARGS...);
199
+
160
200
  private:
161
201
  //! The database instance
162
202
  DatabaseInstance &db;
163
- //! The lock for changing the memory limit
164
- mutex limit_lock;
165
- //! The current amount of memory that is occupied by the buffer manager (in bytes)
166
- atomic<idx_t> current_memory;
167
- //! The maximum amount of memory that the buffer manager can keep (in bytes)
168
- atomic<idx_t> maximum_memory;
203
+ //! The buffer pool
204
+ BufferPool &buffer_pool;
169
205
  //! The directory name where temporary files are stored
170
206
  string temp_directory;
171
207
  //! Lock for creating the temp handle
172
208
  mutex temp_handle_lock;
173
209
  //! Handle for the temporary directory
174
210
  unique_ptr<TemporaryDirectoryHandle> temp_directory_handle;
175
- //! Eviction queue
176
- unique_ptr<EvictionQueue> queue;
177
211
  //! The temporary id used for managed buffers
178
212
  atomic<block_id_t> temporary_id;
179
- //! Total number of insertions into the eviction queue. This guides the schedule for calling PurgeQueue.
180
- atomic<uint32_t> queue_insertions;
181
213
  //! Allocator associated with the buffer manager, that passes all allocations through this buffer manager
182
214
  Allocator buffer_allocator;
183
215
  //! Block manager for temp data
@@ -39,6 +39,8 @@ public:
39
39
  unique_ptr<BaseStatistics> validity_stats;
40
40
  //! The approximate count distinct stats of the column (if any)
41
41
  unique_ptr<BaseStatistics> distinct_stats;
42
+ idx_t distinct_count; // estimate that one may have even if distinct_stats==nullptr
43
+
42
44
  //! Whether these are 'global' stats, i.e., over a whole table, or just over a segment
43
45
  //! Some statistics are more expensive to keep, therefore we only keep them globally
44
46
  StatisticsType stats_type;
@@ -9,6 +9,7 @@
9
9
  #pragma once
10
10
 
11
11
  #include "duckdb/common/common.hpp"
12
+ #include "duckdb/common/serializer.hpp"
12
13
 
13
14
  namespace duckdb {
14
15
 
@@ -23,6 +24,31 @@ public:
23
24
  : has_estimated_cardinality(true), estimated_cardinality(estimated_cardinality), has_max_cardinality(true),
24
25
  max_cardinality(max_cardinality) {
25
26
  }
27
+ void Serialize(Serializer &serializer) const {
28
+ serializer.Write(has_estimated_cardinality);
29
+ if (has_estimated_cardinality) {
30
+ serializer.Write(estimated_cardinality);
31
+ serializer.Write(has_max_cardinality);
32
+ if (has_max_cardinality) {
33
+ serializer.Write(max_cardinality);
34
+ }
35
+ } else {
36
+ D_ASSERT(!has_max_cardinality);
37
+ }
38
+ }
39
+ static unique_ptr<NodeStatistics> Deserialize(Deserializer &source) {
40
+ bool has_estimated_cardinality = source.Read<bool>();
41
+ if (!has_estimated_cardinality) {
42
+ return make_unique<NodeStatistics>();
43
+ }
44
+ idx_t estimated_cardinality = source.Read<idx_t>();
45
+ bool has_max_cardinality = source.Read<bool>();
46
+ if (!has_max_cardinality) {
47
+ return make_unique<NodeStatistics>(estimated_cardinality);
48
+ }
49
+ idx_t max_cardinality = source.Read<idx_t>();
50
+ return make_unique<NodeStatistics>(estimated_cardinality, max_cardinality);
51
+ }
26
52
 
27
53
  //! Whether or not the node has an estimated cardinality specified
28
54
  bool has_estimated_cardinality;
@@ -61,7 +61,7 @@ public:
61
61
  void GetStorageInfo(idx_t row_group_index, vector<idx_t> col_path, TableStorageInfo &result) override;
62
62
 
63
63
  private:
64
- list_entry_t FetchListEntry(idx_t row_idx);
64
+ uint64_t FetchListOffset(idx_t row_idx);
65
65
  };
66
66
 
67
67
  } // namespace duckdb
@@ -64,6 +64,8 @@ struct ColumnScanState {
64
64
  //! We initialize one SegmentScanState per segment, however, if scanning a DataChunk requires us to scan over more
65
65
  //! than one Segment, we need to keep the scan states of the previous segments around
66
66
  vector<unique_ptr<SegmentScanState>> previous_states;
67
+ //! The last read offset in the child state (used for LIST columns only)
68
+ idx_t last_offset = 0;
67
69
 
68
70
  public:
69
71
  //! Move the scan state forward by "count" rows (including all child states)
@@ -35,7 +35,10 @@
35
35
  #endif
36
36
  #endif
37
37
 
38
- // duplicate of duckdb/common/constants.hpp
38
+ // API versions
39
+ // if no explicit API version is defined, the latest API version is used
40
+ // Note that using older API versions (i.e. not using DUCKDB_API_LATEST) is deprecated.
41
+ // These will not be supported long-term, and will be removed in future versions.
39
42
  #ifndef DUCKDB_API_0_3_1
40
43
  #define DUCKDB_API_0_3_1 1
41
44
  #endif
@@ -570,6 +573,14 @@ Use `duckdb_result_chunk_count` to figure out how many chunks there are in the r
570
573
  */
571
574
  DUCKDB_API duckdb_data_chunk duckdb_result_get_chunk(duckdb_result result, idx_t chunk_index);
572
575
 
576
+ /*!
577
+ Checks if the type of the internal result is StreamQueryResult.
578
+
579
+ * result: The result object to check.
580
+ * returns: Whether or not the result object is of the type StreamQueryResult
581
+ */
582
+ DUCKDB_API bool duckdb_result_is_streaming(duckdb_result result);
583
+
573
584
  /*!
574
585
  Returns the number of data chunks present in the result.
575
586
 
@@ -1106,6 +1117,21 @@ Note that after calling `duckdb_pending_prepared`, the pending result should alw
1106
1117
  DUCKDB_API duckdb_state duckdb_pending_prepared(duckdb_prepared_statement prepared_statement,
1107
1118
  duckdb_pending_result *out_result);
1108
1119
 
1120
+ /*!
1121
+ Executes the prepared statement with the given bound parameters, and returns a pending result.
1122
+ This pending result will create a streaming duckdb_result when executed.
1123
+ The pending result represents an intermediate structure for a query that is not yet fully executed.
1124
+
1125
+ Note that after calling `duckdb_pending_prepared_streaming`, the pending result should always be destroyed using
1126
+ `duckdb_destroy_pending`, even if this function returns DuckDBError.
1127
+
1128
+ * prepared_statement: The prepared statement to execute.
1129
+ * out_result: The pending query result.
1130
+ * returns: `DuckDBSuccess` on success or `DuckDBError` on failure.
1131
+ */
1132
+ DUCKDB_API duckdb_state duckdb_pending_prepared_streaming(duckdb_prepared_statement prepared_statement,
1133
+ duckdb_pending_result *out_result);
1134
+
1109
1135
  /*!
1110
1136
  Closes the pending result and de-allocates all memory allocated for the result.
1111
1137
 
@@ -2319,6 +2345,28 @@ Returns true if execution of the current query is finished.
2319
2345
  */
2320
2346
  DUCKDB_API bool duckdb_execution_is_finished(duckdb_connection con);
2321
2347
 
2348
+ //===--------------------------------------------------------------------===//
2349
+ // Streaming Result Interface
2350
+ //===--------------------------------------------------------------------===//
2351
+
2352
+ /*!
2353
+ Fetches a data chunk from the (streaming) duckdb_result. This function should be called repeatedly until the result is
2354
+ exhausted.
2355
+
2356
+ The result must be destroyed with `duckdb_destroy_data_chunk`.
2357
+
2358
+ This function can only be used on duckdb_results created with 'duckdb_pending_prepared_streaming'
2359
+
2360
+ If this function is used, none of the other result functions can be used and vice versa (i.e. this function cannot be
2361
+ mixed with the legacy result functions or the materialized result functions).
2362
+
2363
+ It is not known beforehand how many chunks will be returned by this result.
2364
+
2365
+ * result: The result object to fetch the data chunk from.
2366
+ * returns: The resulting data chunk. Returns `NULL` if the result has an error.
2367
+ */
2368
+ DUCKDB_API duckdb_data_chunk duckdb_stream_fetch_chunk(duckdb_result result);
2369
+
2322
2370
  #ifdef __cplusplus
2323
2371
  }
2324
2372
  #endif
@@ -11,5 +11,4 @@
11
11
  #include "duckdb/main/connection.hpp"
12
12
  #include "duckdb/main/database.hpp"
13
13
  #include "duckdb/main/query_result.hpp"
14
- #include "duckdb/main/loadable_extension.hpp"
15
14
  #include "duckdb/main/appender.hpp"
@@ -9,14 +9,16 @@ using duckdb::PendingQueryResult;
9
9
  using duckdb::PendingStatementWrapper;
10
10
  using duckdb::PreparedStatementWrapper;
11
11
 
12
- duckdb_state duckdb_pending_prepared(duckdb_prepared_statement prepared_statement, duckdb_pending_result *out_result) {
12
+ duckdb_state duckdb_pending_prepared_internal(duckdb_prepared_statement prepared_statement,
13
+ duckdb_pending_result *out_result, bool allow_streaming) {
13
14
  if (!prepared_statement || !out_result) {
14
15
  return DuckDBError;
15
16
  }
16
17
  auto wrapper = (PreparedStatementWrapper *)prepared_statement;
17
18
  auto result = new PendingStatementWrapper();
19
+ result->allow_streaming = allow_streaming;
18
20
  try {
19
- result->statement = wrapper->statement->PendingQuery(wrapper->values, false);
21
+ result->statement = wrapper->statement->PendingQuery(wrapper->values, allow_streaming);
20
22
  } catch (const duckdb::Exception &ex) {
21
23
  result->statement = make_unique<PendingQueryResult>(duckdb::PreservedError(ex));
22
24
  } catch (std::exception &ex) {
@@ -28,6 +30,15 @@ duckdb_state duckdb_pending_prepared(duckdb_prepared_statement prepared_statemen
28
30
  return return_value;
29
31
  }
30
32
 
33
+ duckdb_state duckdb_pending_prepared(duckdb_prepared_statement prepared_statement, duckdb_pending_result *out_result) {
34
+ return duckdb_pending_prepared_internal(prepared_statement, out_result, false);
35
+ }
36
+
37
+ duckdb_state duckdb_pending_prepared_streaming(duckdb_prepared_statement prepared_statement,
38
+ duckdb_pending_result *out_result) {
39
+ return duckdb_pending_prepared_internal(prepared_statement, out_result, true);
40
+ }
41
+
31
42
  void duckdb_destroy_pending(duckdb_pending_result *pending_result) {
32
43
  if (!pending_result || !*pending_result) {
33
44
  return;
@@ -90,7 +101,9 @@ duckdb_state duckdb_execute_pending(duckdb_pending_result pending_result, duckdb
90
101
  if (!wrapper->statement) {
91
102
  return DuckDBError;
92
103
  }
93
- auto result = wrapper->statement->Execute();
104
+
105
+ std::unique_ptr<duckdb::QueryResult> result;
106
+ result = wrapper->statement->Execute();
94
107
  wrapper->statement.reset();
95
108
  return duckdb_translate_result(std::move(result), out_result);
96
109
  }
@@ -292,6 +292,10 @@ bool deprecated_materialize_result(duckdb_result *result) {
292
292
  // already used as a new result set
293
293
  return false;
294
294
  }
295
+ if (result_data->result_set_type == CAPIResultSetType::CAPI_RESULT_TYPE_STREAMING) {
296
+ // already used as a streaming result
297
+ return false;
298
+ }
295
299
  // materialize as deprecated result set
296
300
  result_data->result_set_type = CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED;
297
301
  auto column_count = result_data->result->ColumnCount();
@@ -413,6 +417,10 @@ idx_t duckdb_row_count(duckdb_result *result) {
413
417
  return 0;
414
418
  }
415
419
  auto &result_data = *((duckdb::DuckDBResultData *)result->internal_data);
420
+ if (result_data.result->type == duckdb::QueryResultType::STREAM_RESULT) {
421
+ // We can't know the row count beforehand
422
+ return 0;
423
+ }
416
424
  auto &materialized = (duckdb::MaterializedQueryResult &)*result_data.result;
417
425
  return materialized.RowCount();
418
426
  }
@@ -463,7 +471,10 @@ idx_t duckdb_result_chunk_count(duckdb_result result) {
463
471
  if (result_data.result_set_type == duckdb::CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED) {
464
472
  return 0;
465
473
  }
466
- D_ASSERT(result_data.result->type == duckdb::QueryResultType::MATERIALIZED_RESULT);
474
+ if (result_data.result->type != duckdb::QueryResultType::MATERIALIZED_RESULT) {
475
+ // Can't know beforehand how many chunks are returned.
476
+ return 0;
477
+ }
467
478
  auto &materialized = (duckdb::MaterializedQueryResult &)*result_data.result;
468
479
  return materialized.Collection().ChunkCount();
469
480
  }
@@ -476,6 +487,10 @@ duckdb_data_chunk duckdb_result_get_chunk(duckdb_result result, idx_t chunk_idx)
476
487
  if (result_data.result_set_type == duckdb::CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED) {
477
488
  return nullptr;
478
489
  }
490
+ if (result_data.result->type != duckdb::QueryResultType::MATERIALIZED_RESULT) {
491
+ // This API is only supported for materialized query results
492
+ return nullptr;
493
+ }
479
494
  result_data.result_set_type = duckdb::CAPIResultSetType::CAPI_RESULT_TYPE_MATERIALIZED;
480
495
  auto &materialized = (duckdb::MaterializedQueryResult &)*result_data.result;
481
496
  auto &collection = materialized.Collection();
@@ -487,3 +502,14 @@ duckdb_data_chunk duckdb_result_get_chunk(duckdb_result result, idx_t chunk_idx)
487
502
  collection.FetchChunk(chunk_idx, *chunk);
488
503
  return reinterpret_cast<duckdb_data_chunk>(chunk.release());
489
504
  }
505
+
506
+ bool duckdb_result_is_streaming(duckdb_result result) {
507
+ if (!result.internal_data) {
508
+ return false;
509
+ }
510
+ if (duckdb_result_error(&result) != nullptr) {
511
+ return false;
512
+ }
513
+ auto &result_data = *((duckdb::DuckDBResultData *)result.internal_data);
514
+ return result_data.result->type == duckdb::QueryResultType::STREAM_RESULT;
515
+ }
@@ -0,0 +1,25 @@
1
+ #include "duckdb/main/capi/capi_internal.hpp"
2
+ #include "duckdb/common/types/timestamp.hpp"
3
+ #include "duckdb/common/allocator.hpp"
4
+
5
+ duckdb_data_chunk duckdb_stream_fetch_chunk(duckdb_result result) {
6
+ if (!result.internal_data) {
7
+ return nullptr;
8
+ }
9
+ auto &result_data = *((duckdb::DuckDBResultData *)result.internal_data);
10
+ if (result_data.result_set_type == duckdb::CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED) {
11
+ return nullptr;
12
+ }
13
+ if (result_data.result->type != duckdb::QueryResultType::STREAM_RESULT) {
14
+ // We can only fetch from a StreamQueryResult
15
+ return nullptr;
16
+ }
17
+ result_data.result_set_type = duckdb::CAPIResultSetType::CAPI_RESULT_TYPE_STREAMING;
18
+ auto &streaming = (duckdb::StreamQueryResult &)*result_data.result;
19
+ if (!streaming.IsOpen()) {
20
+ return nullptr;
21
+ }
22
+ // FetchRaw ? Do we care about flattening them?
23
+ auto chunk = streaming.Fetch();
24
+ return reinterpret_cast<duckdb_data_chunk>(chunk.release());
25
+ }
@@ -813,12 +813,14 @@ unique_ptr<QueryResult> ClientContext::Query(const string &query, bool allow_str
813
813
 
814
814
  unique_ptr<QueryResult> result;
815
815
  QueryResult *last_result = nullptr;
816
+ bool last_had_result = false;
816
817
  for (idx_t i = 0; i < statements.size(); i++) {
817
818
  auto &statement = statements[i];
818
819
  bool is_last_statement = i + 1 == statements.size();
819
820
  PendingQueryParameters parameters;
820
821
  parameters.allow_stream_result = allow_stream_result && is_last_statement;
821
822
  auto pending_query = PendingQueryInternal(*lock, std::move(statement), parameters);
823
+ auto has_result = pending_query->properties.return_type == StatementReturnType::QUERY_RESULT;
822
824
  unique_ptr<QueryResult> current_result;
823
825
  if (pending_query->HasError()) {
824
826
  current_result = make_unique<MaterializedQueryResult>(pending_query->GetErrorObject());
@@ -826,12 +828,17 @@ unique_ptr<QueryResult> ClientContext::Query(const string &query, bool allow_str
826
828
  current_result = ExecutePendingQueryInternal(*lock, *pending_query);
827
829
  }
828
830
  // now append the result to the list of results
829
- if (!last_result) {
831
+ if (!last_result || !last_had_result) {
830
832
  // first result of the query
831
833
  result = std::move(current_result);
832
834
  last_result = result.get();
835
+ last_had_result = has_result;
833
836
  } else {
834
837
  // later results; attach to the result chain
838
+ // but only if there is a result
839
+ if (!has_result) {
840
+ continue;
841
+ }
835
842
  last_result->next = std::move(current_result);
836
843
  last_result = last_result->next.get();
837
844
  }
@@ -191,8 +191,7 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf
191
191
  }
192
192
 
193
193
  db_manager = make_unique<DatabaseManager>(*this);
194
- buffer_manager =
195
- make_unique<BufferManager>(*this, config.options.temporary_directory, config.options.maximum_memory);
194
+ buffer_manager = make_unique<BufferManager>(*this, config.options.temporary_directory);
196
195
  scheduler = make_unique<TaskScheduler>(*this);
197
196
  object_cache = make_unique<ObjectCache>();
198
197
  connection_manager = make_unique<ConnectionManager>();
@@ -271,6 +270,10 @@ BufferManager &DatabaseInstance::GetBufferManager() {
271
270
  return *buffer_manager;
272
271
  }
273
272
 
273
+ BufferPool &DatabaseInstance::GetBufferPool() {
274
+ return *config.buffer_pool;
275
+ }
276
+
274
277
  DatabaseManager &DatabaseManager::Get(DatabaseInstance &db) {
275
278
  return db.GetDatabaseManager();
276
279
  }
@@ -340,6 +343,11 @@ void DatabaseInstance::Configure(DBConfig &new_config) {
340
343
  if (!config.default_allocator) {
341
344
  config.default_allocator = Allocator::DefaultAllocatorReference();
342
345
  }
346
+ if (new_config.buffer_pool) {
347
+ config.buffer_pool = std::move(new_config.buffer_pool);
348
+ } else {
349
+ config.buffer_pool = make_shared<BufferPool>(config.options.maximum_memory);
350
+ }
343
351
  }
344
352
 
345
353
  DBConfig &DBConfig::GetConfig(ClientContext &context) {