duckdb 1.4.0 → 1.4.1

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 (144) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/extension/core_functions/scalar/generic/current_setting.cpp +1 -4
  3. package/src/duckdb/extension/icu/icu-strptime.cpp +2 -1
  4. package/src/duckdb/extension/json/include/json_common.hpp +2 -4
  5. package/src/duckdb/extension/json/json_functions.cpp +5 -1
  6. package/src/duckdb/extension/parquet/column_writer.cpp +31 -21
  7. package/src/duckdb/extension/parquet/geo_parquet.cpp +21 -6
  8. package/src/duckdb/extension/parquet/include/column_writer.hpp +2 -2
  9. package/src/duckdb/extension/parquet/include/geo_parquet.hpp +28 -1
  10. package/src/duckdb/extension/parquet/include/parquet_writer.hpp +7 -2
  11. package/src/duckdb/extension/parquet/include/reader/string_column_reader.hpp +13 -0
  12. package/src/duckdb/extension/parquet/include/writer/array_column_writer.hpp +4 -0
  13. package/src/duckdb/extension/parquet/parquet_extension.cpp +56 -1
  14. package/src/duckdb/extension/parquet/parquet_reader.cpp +4 -1
  15. package/src/duckdb/extension/parquet/parquet_statistics.cpp +5 -7
  16. package/src/duckdb/extension/parquet/parquet_writer.cpp +15 -8
  17. package/src/duckdb/extension/parquet/reader/string_column_reader.cpp +17 -4
  18. package/src/duckdb/extension/parquet/writer/array_column_writer.cpp +22 -28
  19. package/src/duckdb/extension/parquet/writer/primitive_column_writer.cpp +17 -5
  20. package/src/duckdb/extension/parquet/writer/struct_column_writer.cpp +3 -2
  21. package/src/duckdb/src/catalog/catalog_search_path.cpp +2 -2
  22. package/src/duckdb/src/catalog/catalog_set.cpp +1 -2
  23. package/src/duckdb/src/common/enum_util.cpp +20 -0
  24. package/src/duckdb/src/common/file_system.cpp +0 -30
  25. package/src/duckdb/src/common/sorting/sort.cpp +25 -6
  26. package/src/duckdb/src/common/sorting/sorted_run_merger.cpp +1 -0
  27. package/src/duckdb/src/common/string_util.cpp +24 -0
  28. package/src/duckdb/src/common/virtual_file_system.cpp +59 -10
  29. package/src/duckdb/src/execution/index/art/art_merger.cpp +0 -3
  30. package/src/duckdb/src/execution/index/art/prefix.cpp +4 -0
  31. package/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp +1 -1
  32. package/src/duckdb/src/execution/operator/helper/physical_reset.cpp +2 -2
  33. package/src/duckdb/src/execution/operator/schema/physical_attach.cpp +1 -1
  34. package/src/duckdb/src/execution/physical_plan/plan_asof_join.cpp +3 -3
  35. package/src/duckdb/src/function/table/system/duckdb_connection_count.cpp +45 -0
  36. package/src/duckdb/src/function/table/system/duckdb_settings.cpp +11 -1
  37. package/src/duckdb/src/function/table/system_functions.cpp +1 -0
  38. package/src/duckdb/src/function/table/version/pragma_version.cpp +3 -3
  39. package/src/duckdb/src/include/duckdb/common/enum_util.hpp +8 -0
  40. package/src/duckdb/src/include/duckdb/common/string_util.hpp +2 -0
  41. package/src/duckdb/src/include/duckdb/common/virtual_file_system.hpp +4 -1
  42. package/src/duckdb/src/include/duckdb/function/scalar/variant_functions.hpp +1 -1
  43. package/src/duckdb/src/include/duckdb/function/table/system_functions.hpp +4 -0
  44. package/src/duckdb/src/include/duckdb/logging/log_storage.hpp +6 -6
  45. package/src/duckdb/src/include/duckdb/logging/log_type.hpp +26 -3
  46. package/src/duckdb/src/include/duckdb/main/attached_database.hpp +4 -0
  47. package/src/duckdb/src/include/duckdb/main/client_context.hpp +2 -0
  48. package/src/duckdb/src/include/duckdb/main/connection.hpp +0 -1
  49. package/src/duckdb/src/include/duckdb/main/connection_manager.hpp +0 -1
  50. package/src/duckdb/src/include/duckdb/main/database_file_path_manager.hpp +12 -1
  51. package/src/duckdb/src/include/duckdb/main/database_manager.hpp +3 -0
  52. package/src/duckdb/src/include/duckdb/main/relation/create_table_relation.hpp +2 -0
  53. package/src/duckdb/src/include/duckdb/main/relation/create_view_relation.hpp +2 -0
  54. package/src/duckdb/src/include/duckdb/main/relation/delete_relation.hpp +2 -0
  55. package/src/duckdb/src/include/duckdb/main/relation/explain_relation.hpp +2 -0
  56. package/src/duckdb/src/include/duckdb/main/relation/insert_relation.hpp +2 -0
  57. package/src/duckdb/src/include/duckdb/main/relation/query_relation.hpp +1 -0
  58. package/src/duckdb/src/include/duckdb/main/relation/update_relation.hpp +2 -0
  59. package/src/duckdb/src/include/duckdb/main/relation/write_csv_relation.hpp +2 -0
  60. package/src/duckdb/src/include/duckdb/main/relation/write_parquet_relation.hpp +2 -0
  61. package/src/duckdb/src/include/duckdb/main/relation.hpp +2 -1
  62. package/src/duckdb/src/include/duckdb/main/secret/secret.hpp +3 -1
  63. package/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp +3 -2
  64. package/src/duckdb/src/include/duckdb/planner/binder.hpp +62 -3
  65. package/src/duckdb/src/include/duckdb/planner/expression_binder/lateral_binder.hpp +2 -2
  66. package/src/duckdb/src/include/duckdb/planner/operator/logical_cte.hpp +1 -1
  67. package/src/duckdb/src/include/duckdb/planner/operator/logical_dependent_join.hpp +3 -3
  68. package/src/duckdb/src/include/duckdb/planner/subquery/flatten_dependent_join.hpp +2 -2
  69. package/src/duckdb/src/include/duckdb/planner/subquery/has_correlated_expressions.hpp +2 -2
  70. package/src/duckdb/src/include/duckdb/planner/subquery/rewrite_cte_scan.hpp +2 -2
  71. package/src/duckdb/src/include/duckdb/planner/tableref/bound_joinref.hpp +1 -1
  72. package/src/duckdb/src/include/duckdb/storage/compression/alp/alp_analyze.hpp +6 -1
  73. package/src/duckdb/src/include/duckdb/storage/compression/alprd/alprd_analyze.hpp +5 -1
  74. package/src/duckdb/src/include/duckdb/storage/metadata/metadata_manager.hpp +9 -7
  75. package/src/duckdb/src/include/duckdb/storage/statistics/string_stats.hpp +2 -0
  76. package/src/duckdb/src/include/duckdb/storage/table/array_column_data.hpp +4 -4
  77. package/src/duckdb/src/include/duckdb/storage/table/column_data.hpp +6 -6
  78. package/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp +4 -4
  79. package/src/duckdb/src/include/duckdb/storage/table/row_group.hpp +4 -4
  80. package/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp +5 -3
  81. package/src/duckdb/src/include/duckdb/storage/table/row_id_column_data.hpp +4 -4
  82. package/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp +4 -4
  83. package/src/duckdb/src/include/duckdb/storage/table/struct_column_data.hpp +4 -4
  84. package/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp +2 -2
  85. package/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp +2 -1
  86. package/src/duckdb/src/include/duckdb/transaction/update_info.hpp +4 -1
  87. package/src/duckdb/src/include/duckdb/transaction/wal_write_state.hpp +1 -1
  88. package/src/duckdb/src/logging/log_types.cpp +63 -0
  89. package/src/duckdb/src/main/attached_database.cpp +16 -3
  90. package/src/duckdb/src/main/client_context.cpp +27 -19
  91. package/src/duckdb/src/main/connection.cpp +2 -5
  92. package/src/duckdb/src/main/database_file_path_manager.cpp +23 -6
  93. package/src/duckdb/src/main/database_manager.cpp +18 -3
  94. package/src/duckdb/src/main/http/http_util.cpp +3 -1
  95. package/src/duckdb/src/main/relation/create_table_relation.cpp +8 -0
  96. package/src/duckdb/src/main/relation/create_view_relation.cpp +8 -0
  97. package/src/duckdb/src/main/relation/delete_relation.cpp +8 -0
  98. package/src/duckdb/src/main/relation/explain_relation.cpp +8 -0
  99. package/src/duckdb/src/main/relation/insert_relation.cpp +8 -0
  100. package/src/duckdb/src/main/relation/query_relation.cpp +4 -0
  101. package/src/duckdb/src/main/relation/update_relation.cpp +8 -0
  102. package/src/duckdb/src/main/relation/write_csv_relation.cpp +8 -0
  103. package/src/duckdb/src/main/relation/write_parquet_relation.cpp +8 -0
  104. package/src/duckdb/src/main/relation.cpp +2 -2
  105. package/src/duckdb/src/optimizer/filter_combiner.cpp +7 -0
  106. package/src/duckdb/src/optimizer/filter_pushdown.cpp +9 -3
  107. package/src/duckdb/src/optimizer/pushdown/pushdown_get.cpp +4 -1
  108. package/src/duckdb/src/optimizer/rule/comparison_simplification.cpp +3 -7
  109. package/src/duckdb/src/parser/statement/relation_statement.cpp +1 -4
  110. package/src/duckdb/src/parser/transform/statement/transform_create_function.cpp +2 -0
  111. package/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp +8 -6
  112. package/src/duckdb/src/planner/binder/statement/bind_create.cpp +1 -5
  113. package/src/duckdb/src/planner/binder/statement/bind_merge_into.cpp +10 -2
  114. package/src/duckdb/src/planner/binder/statement/bind_pragma.cpp +20 -3
  115. package/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp +8 -3
  116. package/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp +9 -2
  117. package/src/duckdb/src/planner/binder.cpp +2 -2
  118. package/src/duckdb/src/planner/expression_binder/lateral_binder.cpp +9 -13
  119. package/src/duckdb/src/planner/expression_binder/table_function_binder.cpp +4 -0
  120. package/src/duckdb/src/planner/expression_binder.cpp +3 -1
  121. package/src/duckdb/src/planner/operator/logical_dependent_join.cpp +2 -2
  122. package/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp +12 -14
  123. package/src/duckdb/src/planner/subquery/has_correlated_expressions.cpp +1 -1
  124. package/src/duckdb/src/planner/subquery/rewrite_cte_scan.cpp +2 -2
  125. package/src/duckdb/src/storage/compression/bitpacking.cpp +1 -2
  126. package/src/duckdb/src/storage/data_table.cpp +2 -2
  127. package/src/duckdb/src/storage/local_storage.cpp +1 -1
  128. package/src/duckdb/src/storage/metadata/metadata_manager.cpp +67 -25
  129. package/src/duckdb/src/storage/statistics/string_stats.cpp +8 -0
  130. package/src/duckdb/src/storage/table/array_column_data.cpp +6 -5
  131. package/src/duckdb/src/storage/table/column_data.cpp +23 -9
  132. package/src/duckdb/src/storage/table/column_data_checkpointer.cpp +15 -1
  133. package/src/duckdb/src/storage/table/list_column_data.cpp +5 -4
  134. package/src/duckdb/src/storage/table/row_group.cpp +8 -8
  135. package/src/duckdb/src/storage/table/row_group_collection.cpp +12 -8
  136. package/src/duckdb/src/storage/table/row_id_column_data.cpp +5 -4
  137. package/src/duckdb/src/storage/table/standard_column_data.cpp +9 -8
  138. package/src/duckdb/src/storage/table/struct_column_data.cpp +10 -9
  139. package/src/duckdb/src/storage/table/update_segment.cpp +12 -10
  140. package/src/duckdb/src/transaction/commit_state.cpp +18 -0
  141. package/src/duckdb/src/transaction/duck_transaction.cpp +2 -10
  142. package/src/duckdb/src/transaction/wal_write_state.cpp +5 -5
  143. package/src/duckdb/third_party/httplib/httplib.hpp +6 -1
  144. package/src/duckdb/ub_src_function_table_system.cpp +2 -0
@@ -1542,7 +1542,7 @@ void DataTable::Update(TableUpdateState &state, ClientContext &context, Vector &
1542
1542
  row_ids_slice.Slice(row_ids, sel_global_update, n_global_update);
1543
1543
  row_ids_slice.Flatten(n_global_update);
1544
1544
 
1545
- row_groups->Update(transaction, FlatVector::GetData<row_t>(row_ids_slice), column_ids, updates_slice);
1545
+ row_groups->Update(transaction, *this, FlatVector::GetData<row_t>(row_ids_slice), column_ids, updates_slice);
1546
1546
  }
1547
1547
  }
1548
1548
 
@@ -1566,7 +1566,7 @@ void DataTable::UpdateColumn(TableCatalogEntry &table, ClientContext &context, V
1566
1566
 
1567
1567
  updates.Flatten();
1568
1568
  row_ids.Flatten(updates.size());
1569
- row_groups->UpdateColumn(transaction, row_ids, column_path, updates);
1569
+ row_groups->UpdateColumn(transaction, *this, row_ids, column_path, updates);
1570
1570
  }
1571
1571
 
1572
1572
  //===--------------------------------------------------------------------===//
@@ -563,7 +563,7 @@ void LocalStorage::Update(DataTable &table, Vector &row_ids, const vector<Physic
563
563
  D_ASSERT(storage);
564
564
 
565
565
  auto ids = FlatVector::GetData<row_t>(row_ids);
566
- storage->row_groups->Update(TransactionData(0, 0), ids, column_ids, updates);
566
+ storage->row_groups->Update(TransactionData(0, 0), table, ids, column_ids, updates);
567
567
  }
568
568
 
569
569
  void LocalStorage::Flush(DataTable &table, LocalTableStorage &storage, optional_ptr<StorageCommitState> commit_state) {
@@ -54,6 +54,8 @@ MetadataManager::~MetadataManager() {
54
54
  MetadataHandle MetadataManager::AllocateHandle() {
55
55
  // check if there is any free space left in an existing block
56
56
  // if not allocate a new block
57
+ MetadataPointer pointer;
58
+ unique_lock<mutex> guard(block_lock);
57
59
  block_id_t free_block = INVALID_BLOCK;
58
60
  for (auto &kv : blocks) {
59
61
  auto &block = kv.second;
@@ -63,13 +65,16 @@ MetadataHandle MetadataManager::AllocateHandle() {
63
65
  break;
64
66
  }
65
67
  }
68
+ guard.unlock();
66
69
  if (free_block == INVALID_BLOCK || free_block > PeekNextBlockId()) {
67
- free_block = AllocateNewBlock();
70
+ free_block = AllocateNewBlock(guard);
71
+ } else {
72
+ guard.lock();
68
73
  }
74
+ D_ASSERT(guard.owns_lock());
69
75
  D_ASSERT(free_block != INVALID_BLOCK);
70
76
 
71
77
  // select the first free metadata block we can find
72
- MetadataPointer pointer;
73
78
  pointer.block_index = UnsafeNumericCast<idx_t>(free_block);
74
79
  auto &block = blocks[free_block];
75
80
  // the block is now dirty
@@ -77,7 +82,7 @@ MetadataHandle MetadataManager::AllocateHandle() {
77
82
  if (block.block->BlockId() < MAXIMUM_BLOCK) {
78
83
  // this block is a disk-backed block, yet we are planning to write to it
79
84
  // we need to convert it into a transient block before we can write to it
80
- ConvertToTransient(block);
85
+ ConvertToTransient(guard, block);
81
86
  D_ASSERT(block.block->BlockId() >= MAXIMUM_BLOCK);
82
87
  }
83
88
  D_ASSERT(!block.free_blocks.empty());
@@ -85,6 +90,7 @@ MetadataHandle MetadataManager::AllocateHandle() {
85
90
  // mark the block as used
86
91
  block.free_blocks.pop_back();
87
92
  D_ASSERT(pointer.index < METADATA_BLOCK_COUNT);
93
+ guard.unlock();
88
94
  // pin the block
89
95
  return Pin(pointer);
90
96
  }
@@ -95,25 +101,34 @@ MetadataHandle MetadataManager::Pin(const MetadataPointer &pointer) {
95
101
 
96
102
  MetadataHandle MetadataManager::Pin(QueryContext context, const MetadataPointer &pointer) {
97
103
  D_ASSERT(pointer.index < METADATA_BLOCK_COUNT);
98
- auto &block = blocks[UnsafeNumericCast<int64_t>(pointer.block_index)];
104
+ shared_ptr<BlockHandle> block_handle;
105
+ {
106
+ lock_guard<mutex> guard(block_lock);
107
+ auto &block = blocks[UnsafeNumericCast<int64_t>(pointer.block_index)];
99
108
  #ifdef DEBUG
100
- for (auto &free_block : block.free_blocks) {
101
- if (free_block == pointer.index) {
102
- throw InternalException("Pinning block %d.%d but it is marked as a free block", block.block_id, free_block);
109
+ for (auto &free_block : block.free_blocks) {
110
+ if (free_block == pointer.index) {
111
+ throw InternalException("Pinning block %d.%d but it is marked as a free block", block.block_id,
112
+ free_block);
113
+ }
103
114
  }
104
- }
105
115
  #endif
116
+ block_handle = block.block;
117
+ }
106
118
 
107
119
  MetadataHandle handle;
108
120
  handle.pointer.block_index = pointer.block_index;
109
121
  handle.pointer.index = pointer.index;
110
- handle.handle = buffer_manager.Pin(block.block);
122
+ handle.handle = buffer_manager.Pin(block_handle);
111
123
  return handle;
112
124
  }
113
125
 
114
- void MetadataManager::ConvertToTransient(MetadataBlock &metadata_block) {
126
+ void MetadataManager::ConvertToTransient(unique_lock<mutex> &block_lock, MetadataBlock &metadata_block) {
127
+ D_ASSERT(block_lock.owns_lock());
128
+ auto old_block = metadata_block.block;
129
+ block_lock.unlock();
115
130
  // pin the old block
116
- auto old_buffer = buffer_manager.Pin(metadata_block.block);
131
+ auto old_buffer = buffer_manager.Pin(old_block);
117
132
 
118
133
  // allocate a new transient block to replace it
119
134
  auto new_buffer = buffer_manager.Allocate(MemoryTag::METADATA, &block_manager, false);
@@ -121,14 +136,17 @@ void MetadataManager::ConvertToTransient(MetadataBlock &metadata_block) {
121
136
 
122
137
  // copy the data to the transient block
123
138
  memcpy(new_buffer.Ptr(), old_buffer.Ptr(), block_manager.GetBlockSize());
124
- metadata_block.block = std::move(new_block);
125
- metadata_block.dirty = true;
126
139
 
127
140
  // unregister the old block
128
141
  block_manager.UnregisterBlock(metadata_block.block_id);
142
+
143
+ block_lock.lock();
144
+ metadata_block.block = std::move(new_block);
145
+ metadata_block.dirty = true;
129
146
  }
130
147
 
131
- block_id_t MetadataManager::AllocateNewBlock() {
148
+ block_id_t MetadataManager::AllocateNewBlock(unique_lock<mutex> &block_lock) {
149
+ D_ASSERT(!block_lock.owns_lock());
132
150
  auto new_block_id = GetNextBlockId();
133
151
 
134
152
  MetadataBlock new_block;
@@ -141,11 +159,14 @@ block_id_t MetadataManager::AllocateNewBlock() {
141
159
  new_block.dirty = true;
142
160
  // zero-initialize the handle
143
161
  memset(handle.Ptr(), 0, block_manager.GetBlockSize());
144
- AddBlock(std::move(new_block));
162
+
163
+ block_lock.lock();
164
+ AddBlock(block_lock, std::move(new_block));
145
165
  return new_block_id;
146
166
  }
147
167
 
148
- void MetadataManager::AddBlock(MetadataBlock new_block, bool if_exists) {
168
+ void MetadataManager::AddBlock(unique_lock<mutex> &block_lock, MetadataBlock new_block, bool if_exists) {
169
+ D_ASSERT(block_lock.owns_lock());
149
170
  if (blocks.find(new_block.block_id) != blocks.end()) {
150
171
  if (if_exists) {
151
172
  return;
@@ -155,15 +176,17 @@ void MetadataManager::AddBlock(MetadataBlock new_block, bool if_exists) {
155
176
  blocks[new_block.block_id] = std::move(new_block);
156
177
  }
157
178
 
158
- void MetadataManager::AddAndRegisterBlock(MetadataBlock block) {
179
+ void MetadataManager::AddAndRegisterBlock(unique_lock<mutex> &block_lock, MetadataBlock block) {
159
180
  if (block.block) {
160
181
  throw InternalException("Calling AddAndRegisterBlock on block that already exists");
161
182
  }
162
183
  if (block.block_id >= MAXIMUM_BLOCK) {
163
184
  throw InternalException("AddAndRegisterBlock called with a transient block id");
164
185
  }
186
+ block_lock.unlock();
165
187
  block.block = block_manager.RegisterBlock(block.block_id);
166
- AddBlock(std::move(block), true);
188
+ block_lock.lock();
189
+ AddBlock(block_lock, std::move(block), true);
167
190
  }
168
191
 
169
192
  MetaBlockPointer MetadataManager::GetDiskPointer(const MetadataPointer &pointer, uint32_t offset) {
@@ -181,8 +204,14 @@ uint32_t MetaBlockPointer::GetBlockIndex() const {
181
204
  }
182
205
 
183
206
  MetadataPointer MetadataManager::FromDiskPointer(MetaBlockPointer pointer) {
207
+ unique_lock<mutex> guard(block_lock);
208
+ return FromDiskPointerInternal(guard, pointer);
209
+ }
210
+
211
+ MetadataPointer MetadataManager::FromDiskPointerInternal(unique_lock<mutex> &block_lock, MetaBlockPointer pointer) {
184
212
  auto block_id = pointer.GetBlockId();
185
213
  auto index = pointer.GetBlockIndex();
214
+
186
215
  auto entry = blocks.find(block_id);
187
216
  if (entry == blocks.end()) { // LCOV_EXCL_START
188
217
  throw InternalException("Failed to load metadata pointer (id %llu, idx %llu, ptr %llu)\n", block_id, index,
@@ -195,11 +224,13 @@ MetadataPointer MetadataManager::FromDiskPointer(MetaBlockPointer pointer) {
195
224
  }
196
225
 
197
226
  MetadataPointer MetadataManager::RegisterDiskPointer(MetaBlockPointer pointer) {
227
+ unique_lock<mutex> guard(block_lock);
228
+
198
229
  auto block_id = pointer.GetBlockId();
199
230
  MetadataBlock block;
200
231
  block.block_id = block_id;
201
- AddAndRegisterBlock(std::move(block));
202
- return FromDiskPointer(pointer);
232
+ AddAndRegisterBlock(guard, std::move(block));
233
+ return FromDiskPointerInternal(guard, pointer);
203
234
  }
204
235
 
205
236
  BlockPointer MetadataManager::ToBlockPointer(MetaBlockPointer meta_pointer, const idx_t metadata_block_size) {
@@ -232,6 +263,7 @@ void MetadataManager::Flush() {
232
263
  // Write the blocks of the metadata manager to disk.
233
264
  const idx_t total_metadata_size = GetMetadataBlockSize() * METADATA_BLOCK_COUNT;
234
265
 
266
+ unique_lock<mutex> guard(block_lock, std::defer_lock);
235
267
  for (auto &kv : blocks) {
236
268
  auto &block = kv.second;
237
269
  if (!block.dirty) {
@@ -245,9 +277,13 @@ void MetadataManager::Flush() {
245
277
  memset(handle.Ptr() + total_metadata_size, 0, block_manager.GetBlockSize() - total_metadata_size);
246
278
  D_ASSERT(kv.first == block.block_id);
247
279
  if (block.block->BlockId() >= MAXIMUM_BLOCK) {
280
+ auto new_block =
281
+ block_manager.ConvertToPersistent(QueryContext(), kv.first, block.block, std::move(handle));
282
+
248
283
  // Convert the temporary block to a persistent block.
249
- block.block =
250
- block_manager.ConvertToPersistent(QueryContext(), kv.first, std::move(block.block), std::move(handle));
284
+ guard.lock();
285
+ block.block = std::move(new_block);
286
+ guard.unlock();
251
287
  } else {
252
288
  // Already a persistent block, so we only need to write it.
253
289
  D_ASSERT(block.block->BlockId() == block.block_id);
@@ -269,10 +305,12 @@ void MetadataManager::Read(ReadStream &source) {
269
305
  auto block_count = source.Read<uint64_t>();
270
306
  for (idx_t i = 0; i < block_count; i++) {
271
307
  auto block = MetadataBlock::Read(source);
308
+
309
+ unique_lock<mutex> guard(block_lock);
272
310
  auto entry = blocks.find(block.block_id);
273
311
  if (entry == blocks.end()) {
274
312
  // block does not exist yet
275
- AddAndRegisterBlock(std::move(block));
313
+ AddAndRegisterBlock(guard, std::move(block));
276
314
  } else {
277
315
  // block was already created - only copy over the free list
278
316
  entry->second.free_blocks = std::move(block.free_blocks);
@@ -349,6 +387,7 @@ void MetadataManager::MarkBlocksAsModified() {
349
387
  }
350
388
 
351
389
  modified_blocks.clear();
390
+
352
391
  for (auto &kv : blocks) {
353
392
  auto &block = kv.second;
354
393
  idx_t free_list = block.FreeBlocksToInteger();
@@ -361,6 +400,7 @@ void MetadataManager::ClearModifiedBlocks(const vector<MetaBlockPointer> &pointe
361
400
  if (pointers.empty()) {
362
401
  return;
363
402
  }
403
+ unique_lock<mutex> guard(block_lock);
364
404
  for (auto &pointer : pointers) {
365
405
  auto block_id = pointer.GetBlockId();
366
406
  auto block_index = pointer.GetBlockIndex();
@@ -376,6 +416,7 @@ void MetadataManager::ClearModifiedBlocks(const vector<MetaBlockPointer> &pointe
376
416
 
377
417
  vector<MetadataBlockInfo> MetadataManager::GetMetadataInfo() const {
378
418
  vector<MetadataBlockInfo> result;
419
+ unique_lock<mutex> guard(block_lock);
379
420
  for (auto &block : blocks) {
380
421
  MetadataBlockInfo block_info;
381
422
  block_info.block_id = block.second.block_id;
@@ -393,17 +434,18 @@ vector<MetadataBlockInfo> MetadataManager::GetMetadataInfo() const {
393
434
 
394
435
  vector<shared_ptr<BlockHandle>> MetadataManager::GetBlocks() const {
395
436
  vector<shared_ptr<BlockHandle>> result;
437
+ unique_lock<mutex> guard(block_lock);
396
438
  for (auto &entry : blocks) {
397
439
  result.push_back(entry.second.block);
398
440
  }
399
441
  return result;
400
442
  }
401
443
 
402
- block_id_t MetadataManager::PeekNextBlockId() {
444
+ block_id_t MetadataManager::PeekNextBlockId() const {
403
445
  return block_manager.PeekFreeBlockId();
404
446
  }
405
447
 
406
- block_id_t MetadataManager::GetNextBlockId() {
448
+ block_id_t MetadataManager::GetNextBlockId() const {
407
449
  return block_manager.GetFreeBlockId();
408
450
  }
409
451
 
@@ -170,6 +170,14 @@ void StringStats::Update(BaseStatistics &stats, const string_t &value) {
170
170
  }
171
171
  }
172
172
 
173
+ void StringStats::SetMin(BaseStatistics &stats, const string_t &value) {
174
+ ConstructValue(const_data_ptr_cast(value.GetData()), value.GetSize(), GetDataUnsafe(stats).min);
175
+ }
176
+
177
+ void StringStats::SetMax(BaseStatistics &stats, const string_t &value) {
178
+ ConstructValue(const_data_ptr_cast(value.GetData()), value.GetSize(), GetDataUnsafe(stats).max);
179
+ }
180
+
173
181
  void StringStats::Merge(BaseStatistics &stats, const BaseStatistics &other) {
174
182
  if (other.GetType().id() == LogicalTypeId::VALIDITY) {
175
183
  return;
@@ -97,7 +97,7 @@ idx_t ArrayColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t c
97
97
 
98
98
  void ArrayColumnData::Select(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result,
99
99
  SelectionVector &sel, idx_t sel_count) {
100
- bool is_supported = !child_column->type.IsNested();
100
+ bool is_supported = !child_column->type.IsNested() && child_column->type.InternalType() != PhysicalType::VARCHAR;
101
101
  if (!is_supported) {
102
102
  ColumnData::Select(transaction, vector_index, state, result, sel, sel_count);
103
103
  return;
@@ -224,13 +224,14 @@ idx_t ArrayColumnData::Fetch(ColumnScanState &state, row_t row_id, Vector &resul
224
224
  throw NotImplementedException("Array Fetch");
225
225
  }
226
226
 
227
- void ArrayColumnData::Update(TransactionData transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
228
- idx_t update_count) {
227
+ void ArrayColumnData::Update(TransactionData transaction, DataTable &data_table, idx_t column_index,
228
+ Vector &update_vector, row_t *row_ids, idx_t update_count) {
229
229
  throw NotImplementedException("Array Update is not supported.");
230
230
  }
231
231
 
232
- void ArrayColumnData::UpdateColumn(TransactionData transaction, const vector<column_t> &column_path,
233
- Vector &update_vector, row_t *row_ids, idx_t update_count, idx_t depth) {
232
+ void ArrayColumnData::UpdateColumn(TransactionData transaction, DataTable &data_table,
233
+ const vector<column_t> &column_path, Vector &update_vector, row_t *row_ids,
234
+ idx_t update_count, idx_t depth) {
234
235
  throw NotImplementedException("Array Update Column is not supported");
235
236
  }
236
237
 
@@ -293,13 +293,13 @@ void ColumnData::FetchUpdateRow(TransactionData transaction, row_t row_id, Vecto
293
293
  updates->FetchRow(transaction, NumericCast<idx_t>(row_id), result, result_idx);
294
294
  }
295
295
 
296
- void ColumnData::UpdateInternal(TransactionData transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
297
- idx_t update_count, Vector &base_vector) {
296
+ void ColumnData::UpdateInternal(TransactionData transaction, DataTable &data_table, idx_t column_index,
297
+ Vector &update_vector, row_t *row_ids, idx_t update_count, Vector &base_vector) {
298
298
  lock_guard<mutex> update_guard(update_lock);
299
299
  if (!updates) {
300
300
  updates = make_uniq<UpdateSegment>(*this);
301
301
  }
302
- updates->Update(transaction, column_index, update_vector, row_ids, update_count, base_vector);
302
+ updates->Update(transaction, data_table, column_index, update_vector, row_ids, update_count, base_vector);
303
303
  }
304
304
 
305
305
  idx_t ColumnData::ScanVector(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result,
@@ -578,20 +578,20 @@ idx_t ColumnData::FetchUpdateData(ColumnScanState &state, row_t *row_ids, Vector
578
578
  return fetch_count;
579
579
  }
580
580
 
581
- void ColumnData::Update(TransactionData transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
582
- idx_t update_count) {
581
+ void ColumnData::Update(TransactionData transaction, DataTable &data_table, idx_t column_index, Vector &update_vector,
582
+ row_t *row_ids, idx_t update_count) {
583
583
  Vector base_vector(type);
584
584
  ColumnScanState state;
585
585
  FetchUpdateData(state, row_ids, base_vector);
586
586
 
587
- UpdateInternal(transaction, column_index, update_vector, row_ids, update_count, base_vector);
587
+ UpdateInternal(transaction, data_table, column_index, update_vector, row_ids, update_count, base_vector);
588
588
  }
589
589
 
590
- void ColumnData::UpdateColumn(TransactionData transaction, const vector<column_t> &column_path, Vector &update_vector,
591
- row_t *row_ids, idx_t update_count, idx_t depth) {
590
+ void ColumnData::UpdateColumn(TransactionData transaction, DataTable &data_table, const vector<column_t> &column_path,
591
+ Vector &update_vector, row_t *row_ids, idx_t update_count, idx_t depth) {
592
592
  // this method should only be called at the end of the path in the base column case
593
593
  D_ASSERT(depth >= column_path.size());
594
- ColumnData::Update(transaction, column_path[0], update_vector, row_ids, update_count);
594
+ ColumnData::Update(transaction, data_table, column_path[0], update_vector, row_ids, update_count);
595
595
  }
596
596
 
597
597
  void ColumnData::AppendTransientSegment(SegmentLock &l, idx_t start_row) {
@@ -873,6 +873,17 @@ PersistentColumnData ColumnData::Serialize() {
873
873
  return result;
874
874
  }
875
875
 
876
+ void RealignColumnData(PersistentColumnData &column_data, idx_t new_start) {
877
+ idx_t current_start = new_start;
878
+ for (auto &pointer : column_data.pointers) {
879
+ pointer.row_start = current_start;
880
+ current_start += pointer.tuple_count;
881
+ }
882
+ for (auto &child : column_data.child_columns) {
883
+ RealignColumnData(child, new_start);
884
+ }
885
+ }
886
+
876
887
  shared_ptr<ColumnData> ColumnData::Deserialize(BlockManager &block_manager, DataTableInfo &info, idx_t column_index,
877
888
  idx_t start_row, ReadStream &source, const LogicalType &type) {
878
889
  auto entry = ColumnData::CreateColumn(block_manager, info, column_index, start_row, type, nullptr);
@@ -890,6 +901,9 @@ shared_ptr<ColumnData> ColumnData::Deserialize(BlockManager &block_manager, Data
890
901
  deserializer.Unset<DatabaseInstance>();
891
902
  deserializer.End();
892
903
 
904
+ // re-align data segments, in case our start_row has changed
905
+ RealignColumnData(persistent_column_data, start_row);
906
+
893
907
  // initialize the column
894
908
  entry->InitializeColumn(persistent_column_data, entry->stats->statistics);
895
909
  return entry;
@@ -376,8 +376,22 @@ void ColumnDataCheckpointer::WritePersistentSegments(ColumnCheckpointState &stat
376
376
  for (idx_t segment_idx = 0; segment_idx < nodes.size(); segment_idx++) {
377
377
  auto segment = nodes[segment_idx].node.get();
378
378
  if (segment->start != current_row) {
379
+ string extra_info;
380
+ for (auto &s : nodes) {
381
+ extra_info += "\n";
382
+ extra_info += StringUtil::Format("Start %d, count %d", s.node->start, s.node->count.load());
383
+ }
384
+ const_reference<ColumnData> root = col_data;
385
+ while (root.get().HasParent()) {
386
+ root = root.get().Parent();
387
+ }
379
388
  throw InternalException(
380
- "Failure in RowGroup::Checkpoint - column data pointer is unaligned with row group start");
389
+ "Failure in RowGroup::Checkpoint - column data pointer is unaligned with row group "
390
+ "start\nRow group start: %d\nRow group count %d\nCurrent row: %d\nSegment start: %d\nColumn index: "
391
+ "%d\nColumn type: %s\nRoot type: %s\nTable: %s.%s\nAll segments:%s",
392
+ row_group.start, row_group.count.load(), current_row, segment->start, root.get().column_index,
393
+ col_data.type, root.get().type, root.get().info.GetSchemaName(), root.get().info.GetTableName(),
394
+ extra_info);
381
395
  }
382
396
  current_row += segment->count;
383
397
  auto pointer = segment->GetDataPointer();
@@ -263,13 +263,14 @@ idx_t ListColumnData::Fetch(ColumnScanState &state, row_t row_id, Vector &result
263
263
  throw NotImplementedException("List Fetch");
264
264
  }
265
265
 
266
- void ListColumnData::Update(TransactionData transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
267
- idx_t update_count) {
266
+ void ListColumnData::Update(TransactionData transaction, DataTable &data_table, idx_t column_index,
267
+ Vector &update_vector, row_t *row_ids, idx_t update_count) {
268
268
  throw NotImplementedException("List Update is not supported.");
269
269
  }
270
270
 
271
- void ListColumnData::UpdateColumn(TransactionData transaction, const vector<column_t> &column_path,
272
- Vector &update_vector, row_t *row_ids, idx_t update_count, idx_t depth) {
271
+ void ListColumnData::UpdateColumn(TransactionData transaction, DataTable &data_table,
272
+ const vector<column_t> &column_path, Vector &update_vector, row_t *row_ids,
273
+ idx_t update_count, idx_t depth) {
273
274
  throw NotImplementedException("List Update Column is not supported");
274
275
  }
275
276
 
@@ -859,8 +859,8 @@ void RowGroup::CleanupAppend(transaction_t lowest_transaction, idx_t start, idx_
859
859
  vinfo.CleanupAppend(lowest_transaction, start, count);
860
860
  }
861
861
 
862
- void RowGroup::Update(TransactionData transaction, DataChunk &update_chunk, row_t *ids, idx_t offset, idx_t count,
863
- const vector<PhysicalIndex> &column_ids) {
862
+ void RowGroup::Update(TransactionData transaction, DataTable &data_table, DataChunk &update_chunk, row_t *ids,
863
+ idx_t offset, idx_t count, const vector<PhysicalIndex> &column_ids) {
864
864
  #ifdef DEBUG
865
865
  for (size_t i = offset; i < offset + count; i++) {
866
866
  D_ASSERT(ids[i] >= row_t(this->start) && ids[i] < row_t(this->start + this->count));
@@ -873,16 +873,16 @@ void RowGroup::Update(TransactionData transaction, DataChunk &update_chunk, row_
873
873
  if (offset > 0) {
874
874
  Vector sliced_vector(update_chunk.data[i], offset, offset + count);
875
875
  sliced_vector.Flatten(count);
876
- col_data.Update(transaction, column.index, sliced_vector, ids + offset, count);
876
+ col_data.Update(transaction, data_table, column.index, sliced_vector, ids + offset, count);
877
877
  } else {
878
- col_data.Update(transaction, column.index, update_chunk.data[i], ids, count);
878
+ col_data.Update(transaction, data_table, column.index, update_chunk.data[i], ids, count);
879
879
  }
880
880
  MergeStatistics(column.index, *col_data.GetUpdateStatistics());
881
881
  }
882
882
  }
883
883
 
884
- void RowGroup::UpdateColumn(TransactionData transaction, DataChunk &updates, Vector &row_ids, idx_t offset, idx_t count,
885
- const vector<column_t> &column_path) {
884
+ void RowGroup::UpdateColumn(TransactionData transaction, DataTable &data_table, DataChunk &updates, Vector &row_ids,
885
+ idx_t offset, idx_t count, const vector<column_t> &column_path) {
886
886
  D_ASSERT(updates.ColumnCount() == 1);
887
887
  auto ids = FlatVector::GetData<row_t>(row_ids);
888
888
 
@@ -892,9 +892,9 @@ void RowGroup::UpdateColumn(TransactionData transaction, DataChunk &updates, Vec
892
892
  if (offset > 0) {
893
893
  Vector sliced_vector(updates.data[0], offset, offset + count);
894
894
  sliced_vector.Flatten(count);
895
- col_data.UpdateColumn(transaction, column_path, sliced_vector, ids + offset, count, 1);
895
+ col_data.UpdateColumn(transaction, data_table, column_path, sliced_vector, ids + offset, count, 1);
896
896
  } else {
897
- col_data.UpdateColumn(transaction, column_path, updates.data[0], ids, count, 1);
897
+ col_data.UpdateColumn(transaction, data_table, column_path, updates.data[0], ids, count, 1);
898
898
  }
899
899
  MergeStatistics(primary_column_idx, *col_data.GetUpdateStatistics());
900
900
  }
@@ -645,14 +645,14 @@ optional_ptr<RowGroup> RowGroupCollection::NextUpdateRowGroup(row_t *ids, idx_t
645
645
  return row_group;
646
646
  }
647
647
 
648
- void RowGroupCollection::Update(TransactionData transaction, row_t *ids, const vector<PhysicalIndex> &column_ids,
649
- DataChunk &updates) {
648
+ void RowGroupCollection::Update(TransactionData transaction, DataTable &data_table, row_t *ids,
649
+ const vector<PhysicalIndex> &column_ids, DataChunk &updates) {
650
650
  D_ASSERT(updates.size() >= 1);
651
651
  idx_t pos = 0;
652
652
  do {
653
653
  idx_t start = pos;
654
654
  auto row_group = NextUpdateRowGroup(ids, pos, updates.size());
655
- row_group->Update(transaction, updates, ids, start, pos - start, column_ids);
655
+ row_group->Update(transaction, data_table, updates, ids, start, pos - start, column_ids);
656
656
 
657
657
  auto l = stats.GetLock();
658
658
  for (idx_t i = 0; i < column_ids.size(); i++) {
@@ -764,15 +764,15 @@ void RowGroupCollection::RemoveFromIndexes(TableIndexList &indexes, Vector &row_
764
764
  }
765
765
  }
766
766
 
767
- void RowGroupCollection::UpdateColumn(TransactionData transaction, Vector &row_ids, const vector<column_t> &column_path,
768
- DataChunk &updates) {
767
+ void RowGroupCollection::UpdateColumn(TransactionData transaction, DataTable &data_table, Vector &row_ids,
768
+ const vector<column_t> &column_path, DataChunk &updates) {
769
769
  D_ASSERT(updates.size() >= 1);
770
770
  auto ids = FlatVector::GetData<row_t>(row_ids);
771
771
  idx_t pos = 0;
772
772
  do {
773
773
  idx_t start = pos;
774
774
  auto row_group = NextUpdateRowGroup(ids, pos, updates.size());
775
- row_group->UpdateColumn(transaction, updates, row_ids, start, pos - start, column_path);
775
+ row_group->UpdateColumn(transaction, data_table, updates, row_ids, start, pos - start, column_path);
776
776
 
777
777
  auto lock = stats.GetLock();
778
778
  auto primary_column_idx = column_path[0];
@@ -1008,8 +1008,8 @@ bool RowGroupCollection::ScheduleVacuumTasks(CollectionCheckpointState &checkpoi
1008
1008
  }
1009
1009
  idx_t merge_rows;
1010
1010
  idx_t next_idx = 0;
1011
- idx_t merge_count;
1012
- idx_t target_count;
1011
+ idx_t merge_count = 0;
1012
+ idx_t target_count = 0;
1013
1013
  bool perform_merge = false;
1014
1014
  // check if we can merge row groups adjacent to the current segment_idx
1015
1015
  // we try merging row groups into batches of 1-3 row groups
@@ -1061,6 +1061,8 @@ bool RowGroupCollection::ScheduleVacuumTasks(CollectionCheckpointState &checkpoi
1061
1061
  return false;
1062
1062
  }
1063
1063
  // schedule the vacuum task
1064
+ DUCKDB_LOG(checkpoint_state.writer.GetDatabase(), CheckpointLogType, GetAttached(), *info, segment_idx, merge_count,
1065
+ target_count, merge_rows, state.row_start);
1064
1066
  auto vacuum_task = make_uniq<VacuumTask>(checkpoint_state, state, segment_idx, merge_count, target_count,
1065
1067
  merge_rows, state.row_start);
1066
1068
  checkpoint_state.executor->ScheduleTask(std::move(vacuum_task));
@@ -1107,6 +1109,8 @@ void RowGroupCollection::Checkpoint(TableDataWriter &writer, TableStatistics &gl
1107
1109
  // schedule a checkpoint task for this row group
1108
1110
  entry.node->MoveToCollection(*this, vacuum_state.row_start);
1109
1111
  if (writer.GetCheckpointType() != CheckpointType::VACUUM_ONLY) {
1112
+ DUCKDB_LOG(checkpoint_state.writer.GetDatabase(), CheckpointLogType, GetAttached(), *info, segment_idx,
1113
+ *entry.node);
1110
1114
  auto checkpoint_task = GetCheckpointTask(checkpoint_state, segment_idx);
1111
1115
  checkpoint_state.executor->ScheduleTask(std::move(checkpoint_task));
1112
1116
  }
@@ -138,13 +138,14 @@ void RowIdColumnData::RevertAppend(row_t start_row) {
138
138
  throw InternalException("RowIdColumnData cannot be appended to");
139
139
  }
140
140
 
141
- void RowIdColumnData::Update(TransactionData transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
142
- idx_t update_count) {
141
+ void RowIdColumnData::Update(TransactionData transaction, DataTable &data_table, idx_t column_index,
142
+ Vector &update_vector, row_t *row_ids, idx_t update_count) {
143
143
  throw InternalException("RowIdColumnData cannot be updated");
144
144
  }
145
145
 
146
- void RowIdColumnData::UpdateColumn(TransactionData transaction, const vector<column_t> &column_path,
147
- Vector &update_vector, row_t *row_ids, idx_t update_count, idx_t depth) {
146
+ void RowIdColumnData::UpdateColumn(TransactionData transaction, DataTable &data_table,
147
+ const vector<column_t> &column_path, Vector &update_vector, row_t *row_ids,
148
+ idx_t update_count, idx_t depth) {
148
149
  throw InternalException("RowIdColumnData cannot be updated");
149
150
  }
150
151
 
@@ -152,8 +152,8 @@ idx_t StandardColumnData::Fetch(ColumnScanState &state, row_t row_id, Vector &re
152
152
  return scan_count;
153
153
  }
154
154
 
155
- void StandardColumnData::Update(TransactionData transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
156
- idx_t update_count) {
155
+ void StandardColumnData::Update(TransactionData transaction, DataTable &data_table, idx_t column_index,
156
+ Vector &update_vector, row_t *row_ids, idx_t update_count) {
157
157
  ColumnScanState standard_state, validity_state;
158
158
  Vector base_vector(type);
159
159
  auto standard_fetch = FetchUpdateData(standard_state, row_ids, base_vector);
@@ -162,18 +162,19 @@ void StandardColumnData::Update(TransactionData transaction, idx_t column_index,
162
162
  throw InternalException("Unaligned fetch in validity and main column data for update");
163
163
  }
164
164
 
165
- UpdateInternal(transaction, column_index, update_vector, row_ids, update_count, base_vector);
166
- validity.UpdateInternal(transaction, column_index, update_vector, row_ids, update_count, base_vector);
165
+ UpdateInternal(transaction, data_table, column_index, update_vector, row_ids, update_count, base_vector);
166
+ validity.UpdateInternal(transaction, data_table, column_index, update_vector, row_ids, update_count, base_vector);
167
167
  }
168
168
 
169
- void StandardColumnData::UpdateColumn(TransactionData transaction, const vector<column_t> &column_path,
170
- Vector &update_vector, row_t *row_ids, idx_t update_count, idx_t depth) {
169
+ void StandardColumnData::UpdateColumn(TransactionData transaction, DataTable &data_table,
170
+ const vector<column_t> &column_path, Vector &update_vector, row_t *row_ids,
171
+ idx_t update_count, idx_t depth) {
171
172
  if (depth >= column_path.size()) {
172
173
  // update this column
173
- ColumnData::Update(transaction, column_path[0], update_vector, row_ids, update_count);
174
+ ColumnData::Update(transaction, data_table, column_path[0], update_vector, row_ids, update_count);
174
175
  } else {
175
176
  // update the child column (i.e. the validity column)
176
- validity.UpdateColumn(transaction, column_path, update_vector, row_ids, update_count, depth + 1);
177
+ validity.UpdateColumn(transaction, data_table, column_path, update_vector, row_ids, update_count, depth + 1);
177
178
  }
178
179
  }
179
180
 
@@ -207,17 +207,18 @@ idx_t StructColumnData::Fetch(ColumnScanState &state, row_t row_id, Vector &resu
207
207
  return scan_count;
208
208
  }
209
209
 
210
- void StructColumnData::Update(TransactionData transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
211
- idx_t update_count) {
212
- validity.Update(transaction, column_index, update_vector, row_ids, update_count);
210
+ void StructColumnData::Update(TransactionData transaction, DataTable &data_table, idx_t column_index,
211
+ Vector &update_vector, row_t *row_ids, idx_t update_count) {
212
+ validity.Update(transaction, data_table, column_index, update_vector, row_ids, update_count);
213
213
  auto &child_entries = StructVector::GetEntries(update_vector);
214
214
  for (idx_t i = 0; i < child_entries.size(); i++) {
215
- sub_columns[i]->Update(transaction, column_index, *child_entries[i], row_ids, update_count);
215
+ sub_columns[i]->Update(transaction, data_table, column_index, *child_entries[i], row_ids, update_count);
216
216
  }
217
217
  }
218
218
 
219
- void StructColumnData::UpdateColumn(TransactionData transaction, const vector<column_t> &column_path,
220
- Vector &update_vector, row_t *row_ids, idx_t update_count, idx_t depth) {
219
+ void StructColumnData::UpdateColumn(TransactionData transaction, DataTable &data_table,
220
+ const vector<column_t> &column_path, Vector &update_vector, row_t *row_ids,
221
+ idx_t update_count, idx_t depth) {
221
222
  // we can never DIRECTLY update a struct column
222
223
  if (depth >= column_path.size()) {
223
224
  throw InternalException("Attempting to directly update a struct column - this should not be possible");
@@ -225,13 +226,13 @@ void StructColumnData::UpdateColumn(TransactionData transaction, const vector<co
225
226
  auto update_column = column_path[depth];
226
227
  if (update_column == 0) {
227
228
  // update the validity column
228
- validity.UpdateColumn(transaction, column_path, update_vector, row_ids, update_count, depth + 1);
229
+ validity.UpdateColumn(transaction, data_table, column_path, update_vector, row_ids, update_count, depth + 1);
229
230
  } else {
230
231
  if (update_column > sub_columns.size()) {
231
232
  throw InternalException("Update column_path out of range");
232
233
  }
233
- sub_columns[update_column - 1]->UpdateColumn(transaction, column_path, update_vector, row_ids, update_count,
234
- depth + 1);
234
+ sub_columns[update_column - 1]->UpdateColumn(transaction, data_table, column_path, update_vector, row_ids,
235
+ update_count, depth + 1);
235
236
  }
236
237
  }
237
238