duckdb 1.1.4-dev9.0 → 1.2.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 (220) hide show
  1. package/LICENSE +1 -1
  2. package/binding.gyp +1 -0
  3. package/package.json +2 -2
  4. package/src/duckdb/extension/core_functions/function_list.cpp +1 -0
  5. package/src/duckdb/extension/core_functions/include/core_functions/scalar/map_functions.hpp +9 -0
  6. package/src/duckdb/extension/core_functions/scalar/date/current.cpp +1 -0
  7. package/src/duckdb/extension/core_functions/scalar/generic/can_implicitly_cast.cpp +2 -2
  8. package/src/duckdb/extension/core_functions/scalar/generic/typeof.cpp +1 -1
  9. package/src/duckdb/extension/core_functions/scalar/list/flatten.cpp +91 -61
  10. package/src/duckdb/extension/core_functions/scalar/map/map_extract.cpp +89 -8
  11. package/src/duckdb/extension/icu/icu-current.cpp +63 -0
  12. package/src/duckdb/extension/icu/icu-makedate.cpp +43 -39
  13. package/src/duckdb/extension/icu/icu-timezone.cpp +63 -63
  14. package/src/duckdb/extension/icu/icu_extension.cpp +2 -0
  15. package/src/duckdb/extension/icu/include/icu-casts.hpp +39 -0
  16. package/src/duckdb/extension/icu/include/icu-current.hpp +17 -0
  17. package/src/duckdb/extension/icu/third_party/icu/stubdata/stubdata.cpp +1 -1
  18. package/src/duckdb/extension/json/json_functions/json_structure.cpp +3 -1
  19. package/src/duckdb/extension/parquet/column_writer.cpp +26 -18
  20. package/src/duckdb/extension/parquet/include/parquet_reader.hpp +0 -6
  21. package/src/duckdb/extension/parquet/include/parquet_writer.hpp +15 -1
  22. package/src/duckdb/extension/parquet/include/resizable_buffer.hpp +1 -0
  23. package/src/duckdb/extension/parquet/parquet_extension.cpp +67 -15
  24. package/src/duckdb/extension/parquet/parquet_reader.cpp +5 -3
  25. package/src/duckdb/extension/parquet/parquet_writer.cpp +5 -6
  26. package/src/duckdb/src/catalog/catalog.cpp +21 -8
  27. package/src/duckdb/src/catalog/catalog_search_path.cpp +17 -1
  28. package/src/duckdb/src/catalog/catalog_set.cpp +1 -1
  29. package/src/duckdb/src/catalog/default/default_functions.cpp +0 -3
  30. package/src/duckdb/src/catalog/dependency_list.cpp +7 -0
  31. package/src/duckdb/src/common/adbc/adbc.cpp +1 -56
  32. package/src/duckdb/src/common/arrow/arrow_converter.cpp +3 -2
  33. package/src/duckdb/src/common/arrow/arrow_type_extension.cpp +58 -28
  34. package/src/duckdb/src/common/arrow/schema_metadata.cpp +1 -1
  35. package/src/duckdb/src/common/compressed_file_system.cpp +6 -2
  36. package/src/duckdb/src/common/enum_util.cpp +26 -22
  37. package/src/duckdb/src/common/error_data.cpp +3 -2
  38. package/src/duckdb/src/common/gzip_file_system.cpp +8 -8
  39. package/src/duckdb/src/common/local_file_system.cpp +2 -2
  40. package/src/duckdb/src/common/multi_file_reader.cpp +1 -1
  41. package/src/duckdb/src/common/random_engine.cpp +4 -1
  42. package/src/duckdb/src/common/serializer/memory_stream.cpp +23 -19
  43. package/src/duckdb/src/common/serializer/serializer.cpp +1 -1
  44. package/src/duckdb/src/common/types/bit.cpp +1 -1
  45. package/src/duckdb/src/common/types/column/column_data_allocator.cpp +0 -5
  46. package/src/duckdb/src/common/types/column/column_data_collection.cpp +4 -1
  47. package/src/duckdb/src/common/types/data_chunk.cpp +2 -1
  48. package/src/duckdb/src/common/types/row/tuple_data_segment.cpp +0 -4
  49. package/src/duckdb/src/common/types.cpp +1 -1
  50. package/src/duckdb/src/execution/index/art/art.cpp +52 -42
  51. package/src/duckdb/src/execution/index/art/leaf.cpp +4 -9
  52. package/src/duckdb/src/execution/index/art/node.cpp +13 -13
  53. package/src/duckdb/src/execution/index/art/prefix.cpp +21 -16
  54. package/src/duckdb/src/execution/index/bound_index.cpp +6 -8
  55. package/src/duckdb/src/execution/index/fixed_size_allocator.cpp +39 -34
  56. package/src/duckdb/src/execution/index/fixed_size_buffer.cpp +2 -1
  57. package/src/duckdb/src/execution/index/unbound_index.cpp +10 -0
  58. package/src/duckdb/src/execution/operator/aggregate/physical_streaming_window.cpp +62 -44
  59. package/src/duckdb/src/execution/operator/csv_scanner/scanner/column_count_scanner.cpp +26 -0
  60. package/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp +69 -40
  61. package/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp +3 -7
  62. package/src/duckdb/src/execution/operator/csv_scanner/sniffer/header_detection.cpp +11 -5
  63. package/src/duckdb/src/execution/operator/csv_scanner/sniffer/type_detection.cpp +4 -0
  64. package/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp +8 -8
  65. package/src/duckdb/src/execution/operator/csv_scanner/util/csv_error.cpp +36 -12
  66. package/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp +12 -9
  67. package/src/duckdb/src/execution/operator/join/physical_hash_join.cpp +0 -1
  68. package/src/duckdb/src/execution/operator/persistent/physical_copy_database.cpp +29 -1
  69. package/src/duckdb/src/execution/operator/persistent/physical_delete.cpp +58 -10
  70. package/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +58 -35
  71. package/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp +2 -1
  72. package/src/duckdb/src/execution/radix_partitioned_hashtable.cpp +9 -4
  73. package/src/duckdb/src/execution/sample/reservoir_sample.cpp +7 -6
  74. package/src/duckdb/src/function/compression_config.cpp +4 -0
  75. package/src/duckdb/src/function/function_binder.cpp +1 -1
  76. package/src/duckdb/src/function/scalar/system/write_log.cpp +2 -2
  77. package/src/duckdb/src/function/table/arrow/arrow_duck_schema.cpp +15 -2
  78. package/src/duckdb/src/function/table/arrow_conversion.cpp +10 -10
  79. package/src/duckdb/src/function/table/copy_csv.cpp +8 -5
  80. package/src/duckdb/src/function/table/read_csv.cpp +21 -4
  81. package/src/duckdb/src/function/table/sniff_csv.cpp +7 -0
  82. package/src/duckdb/src/function/table/system/duckdb_extensions.cpp +4 -0
  83. package/src/duckdb/src/function/table/system/duckdb_secret_types.cpp +71 -0
  84. package/src/duckdb/src/function/table/system_functions.cpp +1 -0
  85. package/src/duckdb/src/function/table/table_scan.cpp +120 -36
  86. package/src/duckdb/src/function/table/version/pragma_version.cpp +4 -4
  87. package/src/duckdb/src/function/window/window_aggregate_function.cpp +6 -1
  88. package/src/duckdb/src/function/window/window_boundaries_state.cpp +135 -11
  89. package/src/duckdb/src/function/window/window_segment_tree.cpp +50 -22
  90. package/src/duckdb/src/function/window/window_token_tree.cpp +4 -3
  91. package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +4 -0
  92. package/src/duckdb/src/include/duckdb/catalog/catalog_search_path.hpp +2 -0
  93. package/src/duckdb/src/include/duckdb/catalog/dependency_list.hpp +1 -0
  94. package/src/duckdb/src/include/duckdb/common/arrow/arrow_type_extension.hpp +4 -2
  95. package/src/duckdb/src/include/duckdb/common/enum_util.hpp +8 -8
  96. package/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp +0 -2
  97. package/src/duckdb/src/include/duckdb/common/serializer/deserializer.hpp +8 -3
  98. package/src/duckdb/src/include/duckdb/common/serializer/memory_stream.hpp +6 -1
  99. package/src/duckdb/src/include/duckdb/common/serializer/serialization_data.hpp +25 -0
  100. package/src/duckdb/src/include/duckdb/common/serializer/serializer.hpp +9 -3
  101. package/src/duckdb/src/include/duckdb/common/types/selection_vector.hpp +1 -1
  102. package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +11 -14
  103. package/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +5 -4
  104. package/src/duckdb/src/include/duckdb/execution/index/bound_index.hpp +21 -10
  105. package/src/duckdb/src/include/duckdb/execution/index/fixed_size_allocator.hpp +6 -5
  106. package/src/duckdb/src/include/duckdb/execution/index/fixed_size_buffer.hpp +37 -32
  107. package/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp +36 -1
  108. package/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/column_count_scanner.hpp +3 -0
  109. package/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/sniffer/csv_sniffer.hpp +2 -0
  110. package/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/state_machine_options.hpp +5 -5
  111. package/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/string_value_scanner.hpp +5 -30
  112. package/src/duckdb/src/include/duckdb/execution/reservoir_sample.hpp +7 -1
  113. package/src/duckdb/src/include/duckdb/function/scalar_function.hpp +3 -3
  114. package/src/duckdb/src/include/duckdb/function/table/arrow/arrow_duck_schema.hpp +1 -0
  115. package/src/duckdb/src/include/duckdb/function/table/system_functions.hpp +4 -0
  116. package/src/duckdb/src/include/duckdb/function/window/window_boundaries_state.hpp +2 -2
  117. package/src/duckdb/src/include/duckdb/logging/logger.hpp +40 -119
  118. package/src/duckdb/src/include/duckdb/logging/logging.hpp +0 -2
  119. package/src/duckdb/src/include/duckdb/main/config.hpp +5 -0
  120. package/src/duckdb/src/include/duckdb/main/connection.hpp +0 -8
  121. package/src/duckdb/src/include/duckdb/main/connection_manager.hpp +2 -1
  122. package/src/duckdb/src/include/duckdb/main/extension.hpp +1 -0
  123. package/src/duckdb/src/include/duckdb/main/extension_entries.hpp +11 -7
  124. package/src/duckdb/src/include/duckdb/main/extension_helper.hpp +1 -0
  125. package/src/duckdb/src/include/duckdb/main/secret/secret.hpp +2 -0
  126. package/src/duckdb/src/include/duckdb/main/secret/secret_manager.hpp +3 -0
  127. package/src/duckdb/src/include/duckdb/main/settings.hpp +10 -0
  128. package/src/duckdb/src/include/duckdb/parser/constraint.hpp +9 -0
  129. package/src/duckdb/src/include/duckdb/parser/expression/window_expression.hpp +36 -9
  130. package/src/duckdb/src/include/duckdb/parser/parsed_data/create_view_info.hpp +2 -1
  131. package/src/duckdb/src/include/duckdb/parser/query_node/set_operation_node.hpp +8 -2
  132. package/src/duckdb/src/include/duckdb/planner/binder.hpp +4 -0
  133. package/src/duckdb/src/include/duckdb/planner/expression/bound_parameter_data.hpp +9 -1
  134. package/src/duckdb/src/include/duckdb/planner/filter/constant_filter.hpp +1 -0
  135. package/src/duckdb/src/include/duckdb/planner/filter/in_filter.hpp +0 -2
  136. package/src/duckdb/src/include/duckdb/planner/filter/optional_filter.hpp +4 -4
  137. package/src/duckdb/src/include/duckdb/planner/table_filter.hpp +1 -1
  138. package/src/duckdb/src/include/duckdb/storage/data_table.hpp +14 -10
  139. package/src/duckdb/src/include/duckdb/storage/index_storage_info.hpp +4 -0
  140. package/src/duckdb/src/include/duckdb/storage/single_file_block_manager.hpp +6 -1
  141. package/src/duckdb/src/include/duckdb/storage/storage_info.hpp +7 -2
  142. package/src/duckdb/src/include/duckdb/storage/storage_manager.hpp +9 -0
  143. package/src/duckdb/src/include/duckdb/storage/storage_options.hpp +2 -0
  144. package/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp +4 -3
  145. package/src/duckdb/src/include/duckdb/storage/table/column_data.hpp +2 -0
  146. package/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp +6 -4
  147. package/src/duckdb/src/include/duckdb/storage/table/table_statistics.hpp +1 -1
  148. package/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp +2 -0
  149. package/src/duckdb/src/include/duckdb/transaction/local_storage.hpp +2 -0
  150. package/src/duckdb/src/include/duckdb/transaction/meta_transaction.hpp +1 -1
  151. package/src/duckdb/src/logging/logger.cpp +8 -66
  152. package/src/duckdb/src/main/attached_database.cpp +3 -1
  153. package/src/duckdb/src/main/client_context.cpp +4 -2
  154. package/src/duckdb/src/main/config.cpp +20 -2
  155. package/src/duckdb/src/main/connection.cpp +2 -29
  156. package/src/duckdb/src/main/connection_manager.cpp +5 -3
  157. package/src/duckdb/src/main/database.cpp +2 -2
  158. package/src/duckdb/src/main/extension/extension_helper.cpp +4 -5
  159. package/src/duckdb/src/main/extension/extension_install.cpp +23 -10
  160. package/src/duckdb/src/main/extension/extension_load.cpp +6 -7
  161. package/src/duckdb/src/main/extension.cpp +27 -9
  162. package/src/duckdb/src/main/secret/secret_manager.cpp +11 -0
  163. package/src/duckdb/src/main/settings/custom_settings.cpp +44 -0
  164. package/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp +6 -0
  165. package/src/duckdb/src/optimizer/filter_combiner.cpp +13 -3
  166. package/src/duckdb/src/optimizer/filter_pushdown.cpp +33 -6
  167. package/src/duckdb/src/optimizer/late_materialization.cpp +14 -3
  168. package/src/duckdb/src/optimizer/remove_unused_columns.cpp +0 -3
  169. package/src/duckdb/src/parser/parsed_data/attach_info.cpp +5 -1
  170. package/src/duckdb/src/parser/parsed_data/create_view_info.cpp +6 -3
  171. package/src/duckdb/src/parser/query_node/set_operation_node.cpp +49 -0
  172. package/src/duckdb/src/parser/transform/expression/transform_columnref.cpp +1 -0
  173. package/src/duckdb/src/parser/transform/expression/transform_function.cpp +50 -12
  174. package/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp +7 -5
  175. package/src/duckdb/src/planner/binder/expression/bind_comparison_expression.cpp +1 -0
  176. package/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp +2 -2
  177. package/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp +12 -2
  178. package/src/duckdb/src/planner/binder/statement/bind_copy_database.cpp +0 -1
  179. package/src/duckdb/src/planner/binder/statement/bind_create.cpp +55 -39
  180. package/src/duckdb/src/planner/binder/statement/bind_execute.cpp +2 -1
  181. package/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp +15 -7
  182. package/src/duckdb/src/planner/binder/tableref/bind_showref.cpp +13 -8
  183. package/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp +8 -3
  184. package/src/duckdb/src/planner/expression/bound_function_expression.cpp +17 -1
  185. package/src/duckdb/src/planner/expression_binder/index_binder.cpp +1 -0
  186. package/src/duckdb/src/planner/filter/conjunction_filter.cpp +1 -0
  187. package/src/duckdb/src/planner/filter/constant_filter.cpp +21 -0
  188. package/src/duckdb/src/planner/filter/in_filter.cpp +4 -7
  189. package/src/duckdb/src/planner/logical_operator.cpp +5 -3
  190. package/src/duckdb/src/planner/planner.cpp +1 -1
  191. package/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp +2 -0
  192. package/src/duckdb/src/storage/checkpoint/table_data_writer.cpp +3 -4
  193. package/src/duckdb/src/storage/checkpoint_manager.cpp +3 -5
  194. package/src/duckdb/src/storage/compression/dictionary/decompression.cpp +4 -4
  195. package/src/duckdb/src/storage/compression/fsst.cpp +2 -2
  196. package/src/duckdb/src/storage/compression/roaring/common.cpp +10 -1
  197. package/src/duckdb/src/storage/compression/string_uncompressed.cpp +11 -6
  198. package/src/duckdb/src/storage/compression/validity_uncompressed.cpp +4 -0
  199. package/src/duckdb/src/storage/compression/zstd.cpp +6 -0
  200. package/src/duckdb/src/storage/data_table.cpp +104 -109
  201. package/src/duckdb/src/storage/local_storage.cpp +8 -6
  202. package/src/duckdb/src/storage/magic_bytes.cpp +1 -1
  203. package/src/duckdb/src/storage/serialization/serialize_dependency.cpp +3 -3
  204. package/src/duckdb/src/storage/serialization/serialize_nodes.cpp +3 -3
  205. package/src/duckdb/src/storage/serialization/serialize_query_node.cpp +7 -5
  206. package/src/duckdb/src/storage/single_file_block_manager.cpp +95 -28
  207. package/src/duckdb/src/storage/storage_info.cpp +38 -0
  208. package/src/duckdb/src/storage/storage_manager.cpp +11 -0
  209. package/src/duckdb/src/storage/table/column_data.cpp +4 -0
  210. package/src/duckdb/src/storage/table/column_data_checkpointer.cpp +3 -3
  211. package/src/duckdb/src/storage/table/row_group_collection.cpp +67 -68
  212. package/src/duckdb/src/storage/table/table_statistics.cpp +4 -4
  213. package/src/duckdb/src/storage/table_index_list.cpp +41 -15
  214. package/src/duckdb/src/storage/wal_replay.cpp +3 -1
  215. package/src/duckdb/src/storage/write_ahead_log.cpp +11 -4
  216. package/src/duckdb/src/transaction/meta_transaction.cpp +1 -1
  217. package/src/duckdb/src/verification/deserialized_statement_verifier.cpp +2 -1
  218. package/src/duckdb/third_party/httplib/httplib.hpp +0 -1
  219. package/src/duckdb/third_party/re2/util/logging.h +10 -10
  220. package/src/duckdb/ub_src_function_table_system.cpp +2 -0
@@ -45,7 +45,7 @@ ART::ART(const string &name, const IndexConstraintType index_constraint_type, co
45
45
  const shared_ptr<array<unsafe_unique_ptr<FixedSizeAllocator>, ALLOCATOR_COUNT>> &allocators_ptr,
46
46
  const IndexStorageInfo &info)
47
47
  : BoundIndex(name, ART::TYPE_NAME, index_constraint_type, column_ids, table_io_manager, unbound_expressions, db),
48
- allocators(allocators_ptr), owns_data(false), append_mode(ARTAppendMode::DEFAULT) {
48
+ allocators(allocators_ptr), owns_data(false) {
49
49
 
50
50
  // FIXME: Use the new byte representation function to support nested types.
51
51
  for (idx_t i = 0; i < types.size(); i++) {
@@ -480,10 +480,11 @@ bool ART::Construct(unsafe_vector<ARTKey> &keys, unsafe_vector<ARTKey> &row_ids,
480
480
  //===--------------------------------------------------------------------===//
481
481
 
482
482
  ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids) {
483
- return Insert(l, chunk, row_ids, nullptr);
483
+ IndexAppendInfo info;
484
+ return Insert(l, chunk, row_ids, info);
484
485
  }
485
486
 
486
- ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, optional_ptr<BoundIndex> delete_index) {
487
+ ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, IndexAppendInfo &info) {
487
488
  D_ASSERT(row_ids.GetType().InternalType() == ROW_TYPE);
488
489
  auto row_count = chunk.size();
489
490
 
@@ -493,8 +494,8 @@ ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, optional_
493
494
  GenerateKeyVectors(allocator, chunk, row_ids, keys, row_id_keys);
494
495
 
495
496
  optional_ptr<ART> delete_art;
496
- if (delete_index) {
497
- delete_art = delete_index->Cast<ART>();
497
+ if (info.delete_index) {
498
+ delete_art = info.delete_index->Cast<ART>();
498
499
  }
499
500
 
500
501
  auto conflict_type = ARTConflictType::NO_CONFLICT;
@@ -506,7 +507,7 @@ ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, optional_
506
507
  if (keys[i].Empty()) {
507
508
  continue;
508
509
  }
509
- conflict_type = Insert(tree, keys[i], 0, row_id_keys[i], tree.GetGateStatus(), delete_art);
510
+ conflict_type = Insert(tree, keys[i], 0, row_id_keys[i], tree.GetGateStatus(), delete_art, info.append_mode);
510
511
  if (conflict_type != ARTConflictType::NO_CONFLICT) {
511
512
  conflict_idx = i;
512
513
  break;
@@ -557,27 +558,27 @@ ErrorData ART::Append(IndexLock &l, DataChunk &chunk, Vector &row_ids) {
557
558
  ExecuteExpressions(chunk, expr_chunk);
558
559
 
559
560
  // Now insert the data chunk.
560
- return Insert(l, expr_chunk, row_ids, nullptr);
561
+ IndexAppendInfo info;
562
+ return Insert(l, expr_chunk, row_ids, info);
561
563
  }
562
564
 
563
- ErrorData ART::AppendWithDeleteIndex(IndexLock &l, DataChunk &chunk, Vector &row_ids,
564
- optional_ptr<BoundIndex> delete_index) {
565
+ ErrorData ART::Append(IndexLock &l, DataChunk &chunk, Vector &row_ids, IndexAppendInfo &info) {
565
566
  // Execute all column expressions before inserting the data chunk.
566
567
  DataChunk expr_chunk;
567
568
  expr_chunk.Initialize(Allocator::DefaultAllocator(), logical_types);
568
569
  ExecuteExpressions(chunk, expr_chunk);
569
570
 
570
571
  // Now insert the data chunk.
571
- return Insert(l, expr_chunk, row_ids, delete_index);
572
+ return Insert(l, expr_chunk, row_ids, info);
572
573
  }
573
574
 
574
- void ART::VerifyAppend(DataChunk &chunk, optional_ptr<BoundIndex> delete_index, optional_ptr<ConflictManager> manager) {
575
+ void ART::VerifyAppend(DataChunk &chunk, IndexAppendInfo &info, optional_ptr<ConflictManager> manager) {
575
576
  if (manager) {
576
577
  D_ASSERT(manager->LookupType() == VerifyExistenceType::APPEND);
577
- return VerifyConstraint(chunk, delete_index, *manager);
578
+ return VerifyConstraint(chunk, info, *manager);
578
579
  }
579
580
  ConflictManager local_manager(VerifyExistenceType::APPEND, chunk.size());
580
- VerifyConstraint(chunk, delete_index, local_manager);
581
+ VerifyConstraint(chunk, info, local_manager);
581
582
  }
582
583
 
583
584
  void ART::InsertIntoEmpty(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id,
@@ -598,15 +599,16 @@ void ART::InsertIntoEmpty(Node &node, const ARTKey &key, const idx_t depth, cons
598
599
  }
599
600
 
600
601
  ARTConflictType ART::InsertIntoInlined(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id,
601
- const GateStatus status, optional_ptr<ART> delete_art) {
602
+ const GateStatus status, optional_ptr<ART> delete_art,
603
+ const IndexAppendMode append_mode) {
602
604
 
603
- if (!IsUnique() || append_mode == ARTAppendMode::INSERT_DUPLICATES) {
605
+ if (!IsUnique() || append_mode == IndexAppendMode::INSERT_DUPLICATES) {
604
606
  Leaf::InsertIntoInlined(*this, node, row_id, depth, status);
605
607
  return ARTConflictType::NO_CONFLICT;
606
608
  }
607
609
 
608
610
  if (!delete_art) {
609
- if (append_mode == ARTAppendMode::IGNORE_DUPLICATES) {
611
+ if (append_mode == IndexAppendMode::IGNORE_DUPLICATES) {
610
612
  return ARTConflictType::NO_CONFLICT;
611
613
  }
612
614
  return ARTConflictType::CONSTRAINT;
@@ -633,14 +635,15 @@ ARTConflictType ART::InsertIntoInlined(Node &node, const ARTKey &key, const idx_
633
635
  }
634
636
 
635
637
  ARTConflictType ART::InsertIntoNode(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id,
636
- const GateStatus status, optional_ptr<ART> delete_art) {
638
+ const GateStatus status, optional_ptr<ART> delete_art,
639
+ const IndexAppendMode append_mode) {
637
640
  D_ASSERT(depth < key.len);
638
641
  auto child = node.GetChildMutable(*this, key[depth]);
639
642
 
640
643
  // Recurse, if a child exists at key[depth].
641
644
  if (child) {
642
645
  D_ASSERT(child->HasMetadata());
643
- auto conflict_type = Insert(*child, key, depth + 1, row_id, status, delete_art);
646
+ auto conflict_type = Insert(*child, key, depth + 1, row_id, status, delete_art, append_mode);
644
647
  node.ReplaceChild(*this, key[depth], *child);
645
648
  return conflict_type;
646
649
  }
@@ -649,7 +652,7 @@ ARTConflictType ART::InsertIntoNode(Node &node, const ARTKey &key, const idx_t d
649
652
  if (status == GateStatus::GATE_SET) {
650
653
  Node remainder;
651
654
  auto byte = key[depth];
652
- auto conflict_type = Insert(remainder, key, depth + 1, row_id, status, delete_art);
655
+ auto conflict_type = Insert(remainder, key, depth + 1, row_id, status, delete_art, append_mode);
653
656
  Node::InsertChild(*this, node, byte, remainder);
654
657
  return conflict_type;
655
658
  }
@@ -671,7 +674,7 @@ ARTConflictType ART::InsertIntoNode(Node &node, const ARTKey &key, const idx_t d
671
674
  }
672
675
 
673
676
  ARTConflictType ART::Insert(Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id, const GateStatus status,
674
- optional_ptr<ART> delete_art) {
677
+ optional_ptr<ART> delete_art, const IndexAppendMode append_mode) {
675
678
  if (!node.HasMetadata()) {
676
679
  InsertIntoEmpty(node, key, depth, row_id, status);
677
680
  return ARTConflictType::NO_CONFLICT;
@@ -688,17 +691,17 @@ ARTConflictType ART::Insert(Node &node, const ARTKey &key, idx_t depth, const AR
688
691
  // incoming transaction must fail here.
689
692
  return ARTConflictType::TRANSACTION;
690
693
  }
691
- return Insert(node, row_id, 0, row_id, GateStatus::GATE_SET, delete_art);
694
+ return Insert(node, row_id, 0, row_id, GateStatus::GATE_SET, delete_art, append_mode);
692
695
  }
693
696
 
694
697
  auto type = node.GetType();
695
698
  switch (type) {
696
699
  case NType::LEAF_INLINED: {
697
- return InsertIntoInlined(node, key, depth, row_id, status, delete_art);
700
+ return InsertIntoInlined(node, key, depth, row_id, status, delete_art, append_mode);
698
701
  }
699
702
  case NType::LEAF: {
700
703
  Leaf::TransformToNested(*this, node);
701
- return Insert(node, key, depth, row_id, status, delete_art);
704
+ return Insert(node, key, depth, row_id, status, delete_art, append_mode);
702
705
  }
703
706
  case NType::NODE_7_LEAF:
704
707
  case NType::NODE_15_LEAF:
@@ -712,9 +715,9 @@ ARTConflictType ART::Insert(Node &node, const ARTKey &key, idx_t depth, const AR
712
715
  case NType::NODE_16:
713
716
  case NType::NODE_48:
714
717
  case NType::NODE_256:
715
- return InsertIntoNode(node, key, depth, row_id, status, delete_art);
718
+ return InsertIntoNode(node, key, depth, row_id, status, delete_art, append_mode);
716
719
  case NType::PREFIX:
717
- return Prefix::Insert(*this, node, key, depth, row_id, status, delete_art);
720
+ return Prefix::Insert(*this, node, key, depth, row_id, status, delete_art, append_mode);
718
721
  default:
719
722
  throw InternalException("Invalid node type for ART::Insert.");
720
723
  }
@@ -732,6 +735,8 @@ void ART::CommitDrop(IndexLock &index_lock) {
732
735
  }
733
736
 
734
737
  void ART::Delete(IndexLock &state, DataChunk &input, Vector &row_ids) {
738
+ // FIXME: We could pass a row_count in here, as we sometimes don't have to delete all row IDs in the chunk,
739
+ // FIXME: but rather all row IDs up to the conflicting row.
735
740
  auto row_count = input.size();
736
741
 
737
742
  DataChunk expr_chunk;
@@ -777,10 +782,9 @@ void ART::Erase(Node &node, reference<const ARTKey> key, idx_t depth, reference<
777
782
  // Traverse the prefix.
778
783
  reference<Node> next(node);
779
784
  if (next.get().GetType() == NType::PREFIX) {
780
- Prefix::TraverseMutable(*this, next, key, depth);
781
-
782
- // Prefixes don't match: nothing to erase.
783
- if (next.get().GetType() == NType::PREFIX && next.get().GetGateStatus() == GateStatus::GATE_NOT_SET) {
785
+ auto pos = Prefix::TraverseMutable(*this, next, key, depth);
786
+ if (pos.IsValid()) {
787
+ // Prefixes don't match: nothing to erase.
784
788
  return;
785
789
  }
786
790
  }
@@ -841,10 +845,9 @@ void ART::Erase(Node &node, reference<const ARTKey> key, idx_t depth, reference<
841
845
  reference<Node> ref(*child);
842
846
 
843
847
  if (ref.get().GetType() == NType::PREFIX) {
844
- Prefix::TraverseMutable(*this, ref, key, temp_depth);
845
-
846
- // Prefixes don't match: nothing to erase.
847
- if (ref.get().GetType() == NType::PREFIX && ref.get().GetGateStatus() == GateStatus::GATE_NOT_SET) {
848
+ auto pos = Prefix::TraverseMutable(*this, ref, key, temp_depth);
849
+ if (pos.IsValid()) {
850
+ // Prefixes don't match: nothing to erase.
848
851
  return;
849
852
  }
850
853
  }
@@ -880,8 +883,8 @@ const unsafe_optional_ptr<const Node> ART::Lookup(const Node &node, const ARTKey
880
883
 
881
884
  // Traverse the prefix.
882
885
  if (ref.get().GetType() == NType::PREFIX) {
883
- Prefix::Traverse(*this, ref, key, depth);
884
- if (ref.get().GetType() == NType::PREFIX && ref.get().GetGateStatus() == GateStatus::GATE_NOT_SET) {
886
+ auto pos = Prefix::Traverse(*this, ref, key, depth);
887
+ if (pos.IsValid()) {
885
888
  // Prefix mismatch, return nullptr.
886
889
  return nullptr;
887
890
  }
@@ -1056,9 +1059,12 @@ void ART::VerifyLeaf(const Node &leaf, const ARTKey &key, optional_ptr<ART> dele
1056
1059
 
1057
1060
  // Get the delete_leaf.
1058
1061
  // All leaves in the delete ART are inlined.
1059
- auto deleted_leaf = delete_art->Lookup(delete_art->tree, key, 0);
1062
+ unsafe_optional_ptr<const Node> deleted_leaf;
1063
+ if (delete_art) {
1064
+ deleted_leaf = delete_art->Lookup(delete_art->tree, key, 0);
1065
+ }
1060
1066
 
1061
- // The leaf is inlined, and the same key does not exist in the delete ART.
1067
+ // The leaf is inlined, and there is no deleted leaf with the same key.
1062
1068
  if (leaf.GetType() == NType::LEAF_INLINED && !deleted_leaf) {
1063
1069
  if (manager.AddHit(i, leaf.GetRowId())) {
1064
1070
  conflict_idx = i;
@@ -1068,6 +1074,7 @@ void ART::VerifyLeaf(const Node &leaf, const ARTKey &key, optional_ptr<ART> dele
1068
1074
 
1069
1075
  // The leaf is inlined, and the same key exists in the delete ART.
1070
1076
  if (leaf.GetType() == NType::LEAF_INLINED && deleted_leaf) {
1077
+ D_ASSERT(deleted_leaf->GetType() == NType::LEAF_INLINED);
1071
1078
  auto deleted_row_id = deleted_leaf->GetRowId();
1072
1079
  auto this_row_id = leaf.GetRowId();
1073
1080
 
@@ -1084,6 +1091,10 @@ void ART::VerifyLeaf(const Node &leaf, const ARTKey &key, optional_ptr<ART> dele
1084
1091
  return;
1085
1092
  }
1086
1093
 
1094
+ // FIXME: proper foreign key + delete ART support.
1095
+ // This implicitly works for foreign keys, as we do not have to consider the actual row IDs.
1096
+ // We only need to know that there are conflicts (for now), as we still perform over-eager constraint checking.
1097
+
1087
1098
  // Scan the two row IDs in the leaf.
1088
1099
  Iterator it(*this);
1089
1100
  it.FindMinimum(leaf);
@@ -1092,14 +1103,13 @@ void ART::VerifyLeaf(const Node &leaf, const ARTKey &key, optional_ptr<ART> dele
1092
1103
  it.Scan(empty_key, 2, row_ids, false);
1093
1104
 
1094
1105
  if (!deleted_leaf) {
1095
- if (manager.AddHit(i, row_ids[0]) || manager.AddHit(i, row_ids[0])) {
1106
+ if (manager.AddHit(i, row_ids[0]) || manager.AddHit(i, row_ids[1])) {
1096
1107
  conflict_idx = i;
1097
1108
  }
1098
1109
  return;
1099
1110
  }
1100
1111
 
1101
1112
  auto deleted_row_id = deleted_leaf->GetRowId();
1102
-
1103
1113
  if (deleted_row_id == row_ids[0] || deleted_row_id == row_ids[1]) {
1104
1114
  if (manager.AddMiss(i)) {
1105
1115
  conflict_idx = i;
@@ -1112,7 +1122,7 @@ void ART::VerifyLeaf(const Node &leaf, const ARTKey &key, optional_ptr<ART> dele
1112
1122
  }
1113
1123
  }
1114
1124
 
1115
- void ART::VerifyConstraint(DataChunk &chunk, optional_ptr<BoundIndex> delete_index, ConflictManager &manager) {
1125
+ void ART::VerifyConstraint(DataChunk &chunk, IndexAppendInfo &info, ConflictManager &manager) {
1116
1126
  // Lock the index during constraint checking.
1117
1127
  lock_guard<mutex> l(lock);
1118
1128
 
@@ -1125,8 +1135,8 @@ void ART::VerifyConstraint(DataChunk &chunk, optional_ptr<BoundIndex> delete_ind
1125
1135
  GenerateKeys<>(arena_allocator, expr_chunk, keys);
1126
1136
 
1127
1137
  optional_ptr<ART> delete_art;
1128
- if (delete_index) {
1129
- delete_art = delete_index->Cast<ART>();
1138
+ if (info.delete_index) {
1139
+ delete_art = info.delete_index->Cast<ART>();
1130
1140
  }
1131
1141
 
1132
1142
  optional_idx conflict_idx;
@@ -26,7 +26,7 @@ void Leaf::New(ART &art, reference<Node> &node, const unsafe_vector<ARTKey> &row
26
26
  // We cannot recurse into the leaf during Construct(...) because row IDs are not sorted.
27
27
  for (idx_t i = 0; i < count; i++) {
28
28
  idx_t offset = start + i;
29
- art.Insert(node, row_ids[offset], 0, row_ids[offset], GateStatus::GATE_SET, nullptr);
29
+ art.Insert(node, row_ids[offset], 0, row_ids[offset], GateStatus::GATE_SET, nullptr, IndexAppendMode::DEFAULT);
30
30
  }
31
31
  node.get().SetGateStatus(GateStatus::GATE_SET);
32
32
  }
@@ -36,7 +36,7 @@ void Leaf::MergeInlined(ART &art, Node &l_node, Node &r_node) {
36
36
 
37
37
  ArenaAllocator arena_allocator(Allocator::Get(art.db));
38
38
  auto key = ARTKey::CreateARTKey<row_t>(arena_allocator, r_node.GetRowId());
39
- art.Insert(l_node, key, 0, key, l_node.GetGateStatus(), nullptr);
39
+ art.Insert(l_node, key, 0, key, l_node.GetGateStatus(), nullptr, IndexAppendMode::DEFAULT);
40
40
  r_node.Clear();
41
41
  }
42
42
 
@@ -96,18 +96,14 @@ void Leaf::TransformToNested(ART &art, Node &node) {
96
96
  ArenaAllocator allocator(Allocator::Get(art.db));
97
97
  Node root = Node();
98
98
 
99
- // Temporarily disable constraint checking.
100
- if (art.IsUnique() && art.append_mode == ARTAppendMode::DEFAULT) {
101
- art.append_mode = ARTAppendMode::INSERT_DUPLICATES;
102
- }
103
-
104
99
  // Move all row IDs into the nested leaf.
105
100
  reference<const Node> leaf_ref(node);
106
101
  while (leaf_ref.get().HasMetadata()) {
107
102
  auto &leaf = Node::Ref<const Leaf>(art, leaf_ref, LEAF);
108
103
  for (uint8_t i = 0; i < leaf.count; i++) {
109
104
  auto row_id = ARTKey::CreateARTKey<row_t>(allocator, leaf.row_ids[i]);
110
- auto conflict_type = art.Insert(root, row_id, 0, row_id, GateStatus::GATE_SET, nullptr);
105
+ auto conflict_type =
106
+ art.Insert(root, row_id, 0, row_id, GateStatus::GATE_SET, nullptr, IndexAppendMode::INSERT_DUPLICATES);
111
107
  if (conflict_type != ARTConflictType::NO_CONFLICT) {
112
108
  throw InternalException("invalid conflict type in Leaf::TransformToNested");
113
109
  }
@@ -115,7 +111,6 @@ void Leaf::TransformToNested(ART &art, Node &node) {
115
111
  leaf_ref = leaf.ptr;
116
112
  }
117
113
 
118
- art.append_mode = ARTAppendMode::DEFAULT;
119
114
  root.SetGateStatus(GateStatus::GATE_SET);
120
115
  Node::Free(art, node);
121
116
  node = root;
@@ -44,7 +44,7 @@ void Node::New(ART &art, Node &node, NType type) {
44
44
  Node256::New(art, node);
45
45
  break;
46
46
  default:
47
- throw InternalException("Invalid node type for New: %d.", static_cast<uint8_t>(type));
47
+ throw InternalException("Invalid node type for New: %s.", EnumUtil::ToString(type));
48
48
  }
49
49
  }
50
50
 
@@ -113,7 +113,7 @@ uint8_t Node::GetAllocatorIdx(const NType type) {
113
113
  case NType::NODE_256_LEAF:
114
114
  return 8;
115
115
  default:
116
- throw InternalException("Invalid node type for GetAllocatorIdx: %d.", static_cast<uint8_t>(type));
116
+ throw InternalException("Invalid node type for GetAllocatorIdx: %s.", EnumUtil::ToString(type));
117
117
  }
118
118
  }
119
119
 
@@ -135,7 +135,7 @@ void Node::ReplaceChild(const ART &art, const uint8_t byte, const Node child) co
135
135
  case NType::NODE_256:
136
136
  return Ref<Node256>(art, *this, type).ReplaceChild(byte, child);
137
137
  default:
138
- throw InternalException("Invalid node type for ReplaceChild: %d.", static_cast<uint8_t>(type));
138
+ throw InternalException("Invalid node type for ReplaceChild: %s.", EnumUtil::ToString(type));
139
139
  }
140
140
  }
141
141
 
@@ -159,7 +159,7 @@ void Node::InsertChild(ART &art, Node &node, const uint8_t byte, const Node chil
159
159
  case NType::NODE_256_LEAF:
160
160
  return Node256Leaf::InsertByte(art, node, byte);
161
161
  default:
162
- throw InternalException("Invalid node type for InsertChild: %d.", static_cast<uint8_t>(type));
162
+ throw InternalException("Invalid node type for InsertChild: %s.", EnumUtil::ToString(type));
163
163
  }
164
164
  }
165
165
 
@@ -188,7 +188,7 @@ void Node::DeleteChild(ART &art, Node &node, Node &prefix, const uint8_t byte, c
188
188
  case NType::NODE_256_LEAF:
189
189
  return Node256Leaf::DeleteByte(art, node, byte);
190
190
  default:
191
- throw InternalException("Invalid node type for DeleteChild: %d.", static_cast<uint8_t>(type));
191
+ throw InternalException("Invalid node type for DeleteChild: %s.", EnumUtil::ToString(type));
192
192
  }
193
193
  }
194
194
 
@@ -212,7 +212,7 @@ unsafe_optional_ptr<Node> GetChildInternal(ART &art, NODE &node, const uint8_t b
212
212
  return Node256::GetChild(Node::Ref<Node256>(art, node, type), byte);
213
213
  }
214
214
  default:
215
- throw InternalException("Invalid node type for GetChildInternal: %d.", static_cast<uint8_t>(type));
215
+ throw InternalException("Invalid node type for GetChildInternal: %s.", EnumUtil::ToString(type));
216
216
  }
217
217
  }
218
218
 
@@ -239,7 +239,7 @@ unsafe_optional_ptr<Node> GetNextChildInternal(ART &art, NODE &node, uint8_t &by
239
239
  case NType::NODE_256:
240
240
  return Node256::GetNextChild(Node::Ref<Node256>(art, node, type), byte);
241
241
  default:
242
- throw InternalException("Invalid node type for GetNextChildInternal: %d.", static_cast<uint8_t>(type));
242
+ throw InternalException("Invalid node type for GetNextChildInternal: %s.", EnumUtil::ToString(type));
243
243
  }
244
244
  }
245
245
 
@@ -263,7 +263,7 @@ bool Node::HasByte(ART &art, uint8_t &byte) const {
263
263
  case NType::NODE_256_LEAF:
264
264
  return Ref<Node256Leaf>(art, *this, NType::NODE_256_LEAF).HasByte(byte);
265
265
  default:
266
- throw InternalException("Invalid node type for GetNextByte: %d.", static_cast<uint8_t>(type));
266
+ throw InternalException("Invalid node type for GetNextByte: %s.", EnumUtil::ToString(type));
267
267
  }
268
268
  }
269
269
 
@@ -279,7 +279,7 @@ bool Node::GetNextByte(ART &art, uint8_t &byte) const {
279
279
  case NType::NODE_256_LEAF:
280
280
  return Ref<Node256Leaf>(art, *this, NType::NODE_256_LEAF).GetNextByte(byte);
281
281
  default:
282
- throw InternalException("Invalid node type for GetNextByte: %d.", static_cast<uint8_t>(type));
282
+ throw InternalException("Invalid node type for GetNextByte: %s.", EnumUtil::ToString(type));
283
283
  }
284
284
  }
285
285
 
@@ -304,7 +304,7 @@ idx_t GetCapacity(NType type) {
304
304
  case NType::NODE_256:
305
305
  return Node256::CAPACITY;
306
306
  default:
307
- throw InternalException("Invalid node type for GetCapacity: %d.", static_cast<uint8_t>(type));
307
+ throw InternalException("Invalid node type for GetCapacity: %s.", EnumUtil::ToString(type));
308
308
  }
309
309
  }
310
310
 
@@ -572,7 +572,7 @@ bool Node::MergeInternal(ART &art, Node &other, const GateStatus status) {
572
572
  ArenaAllocator allocator(Allocator::Get(art.db));
573
573
  for (idx_t i = 0; i < row_ids.size(); i++) {
574
574
  auto row_id = ARTKey::CreateARTKey<row_t>(allocator, row_ids[i]);
575
- art.Insert(*this, row_id, 0, row_id, GateStatus::GATE_SET, nullptr);
575
+ art.Insert(*this, row_id, 0, row_id, GateStatus::GATE_SET, nullptr, IndexAppendMode::DEFAULT);
576
576
  }
577
577
  return true;
578
578
  }
@@ -637,7 +637,7 @@ void Node::Vacuum(ART &art, const unordered_set<uint8_t> &indexes) {
637
637
  case NType::NODE_256_LEAF:
638
638
  return;
639
639
  default:
640
- throw InternalException("Invalid node type for Vacuum: %d.", static_cast<uint8_t>(type));
640
+ throw InternalException("Invalid node type for Vacuum: %s.", EnumUtil::ToString(type));
641
641
  }
642
642
  }
643
643
 
@@ -670,7 +670,7 @@ void Node::TransformToDeprecated(ART &art, Node &node, unsafe_unique_ptr<FixedSi
670
670
  case NType::NODE_256:
671
671
  return TransformToDeprecatedInternal(art, InMemoryRef<Node256>(art, node, type), allocator);
672
672
  default:
673
- throw InternalException("Invalid node type for TransformToDeprecated: %d.", static_cast<uint8_t>(type));
673
+ throw InternalException("Invalid node type for TransformToDeprecated: %s.", EnumUtil::ToString(type));
674
674
  }
675
675
  }
676
676
 
@@ -40,7 +40,7 @@ idx_t Prefix::GetMismatchWithOther(const Prefix &l_prefix, const Prefix &r_prefi
40
40
  return DConstants::INVALID_INDEX;
41
41
  }
42
42
 
43
- idx_t Prefix::GetMismatchWithKey(ART &art, const Node &node, const ARTKey &key, idx_t &depth) {
43
+ optional_idx Prefix::GetMismatchWithKey(ART &art, const Node &node, const ARTKey &key, idx_t &depth) {
44
44
  Prefix prefix(art, node);
45
45
  for (idx_t i = 0; i < prefix.data[Prefix::Count(art)]; i++) {
46
46
  if (prefix.data[i] != key[depth]) {
@@ -48,7 +48,7 @@ idx_t Prefix::GetMismatchWithKey(ART &art, const Node &node, const ARTKey &key,
48
48
  }
49
49
  depth++;
50
50
  }
51
- return DConstants::INVALID_INDEX;
51
+ return optional_idx::Invalid();
52
52
  }
53
53
 
54
54
  uint8_t Prefix::GetByte(const ART &art, const Node &node, const uint8_t pos) {
@@ -160,14 +160,14 @@ void Prefix::Concat(ART &art, Node &parent, uint8_t byte, const GateStatus old_s
160
160
  }
161
161
 
162
162
  template <class NODE>
163
- idx_t TraverseInternal(ART &art, reference<NODE> &node, const ARTKey &key, idx_t &depth,
164
- const bool is_mutable = false) {
163
+ optional_idx TraverseInternal(ART &art, reference<NODE> &node, const ARTKey &key, idx_t &depth,
164
+ const bool is_mutable = false) {
165
165
  D_ASSERT(node.get().HasMetadata());
166
166
  D_ASSERT(node.get().GetType() == NType::PREFIX);
167
167
 
168
168
  while (node.get().GetType() == NType::PREFIX) {
169
169
  auto pos = Prefix::GetMismatchWithKey(art, node, key, depth);
170
- if (pos != DConstants::INVALID_INDEX) {
170
+ if (pos.IsValid()) {
171
171
  return pos;
172
172
  }
173
173
 
@@ -177,14 +177,18 @@ idx_t TraverseInternal(ART &art, reference<NODE> &node, const ARTKey &key, idx_t
177
177
  break;
178
178
  }
179
179
  }
180
- return DConstants::INVALID_INDEX;
180
+
181
+ // We return an invalid index, if (and only if) the next node is:
182
+ // 1. not a prefix, or
183
+ // 2. a gate.
184
+ return optional_idx::Invalid();
181
185
  }
182
186
 
183
- idx_t Prefix::Traverse(ART &art, reference<const Node> &node, const ARTKey &key, idx_t &depth) {
187
+ optional_idx Prefix::Traverse(ART &art, reference<const Node> &node, const ARTKey &key, idx_t &depth) {
184
188
  return TraverseInternal<const Node>(art, node, key, depth);
185
189
  }
186
190
 
187
- idx_t Prefix::TraverseMutable(ART &art, reference<Node> &node, const ARTKey &key, idx_t &depth) {
191
+ optional_idx Prefix::TraverseMutable(ART &art, reference<Node> &node, const ARTKey &key, idx_t &depth) {
188
192
  return TraverseInternal<Node>(art, node, key, depth, true);
189
193
  }
190
194
 
@@ -292,22 +296,22 @@ GateStatus Prefix::Split(ART &art, reference<Node> &node, Node &child, const uin
292
296
  }
293
297
 
294
298
  ARTConflictType Prefix::Insert(ART &art, Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id,
295
- const GateStatus status, optional_ptr<ART> delete_art) {
299
+ const GateStatus status, optional_ptr<ART> delete_art,
300
+ const IndexAppendMode append_mode) {
296
301
  reference<Node> next(node);
297
302
  auto pos = TraverseMutable(art, next, key, depth);
298
303
 
299
304
  // We recurse into the next node, if
300
305
  // (1) the prefix matches the key.
301
306
  // (2) we reach a gate.
302
- if (pos == DConstants::INVALID_INDEX) {
303
- if (next.get().GetType() != NType::PREFIX || next.get().GetGateStatus() == GateStatus::GATE_SET) {
304
- return art.Insert(next, key, depth, row_id, status, delete_art);
305
- }
307
+ if (!pos.IsValid()) {
308
+ D_ASSERT(next.get().GetType() != NType::PREFIX || next.get().GetGateStatus() == GateStatus::GATE_SET);
309
+ return art.Insert(next, key, depth, row_id, status, delete_art, append_mode);
306
310
  }
307
311
 
308
312
  Node remainder;
309
- auto byte = GetByte(art, next, UnsafeNumericCast<uint8_t>(pos));
310
- auto split_status = Split(art, next, remainder, UnsafeNumericCast<uint8_t>(pos));
313
+ auto byte = GetByte(art, next, UnsafeNumericCast<uint8_t>(pos.GetIndex()));
314
+ auto split_status = Split(art, next, remainder, UnsafeNumericCast<uint8_t>(pos.GetIndex()));
311
315
  Node4::New(art, next);
312
316
  next.get().SetGateStatus(split_status);
313
317
 
@@ -315,7 +319,7 @@ ARTConflictType Prefix::Insert(ART &art, Node &node, const ARTKey &key, idx_t de
315
319
  Node4::InsertChild(art, next, byte, remainder);
316
320
 
317
321
  if (status == GateStatus::GATE_SET) {
318
- D_ASSERT(pos != ROW_ID_COUNT);
322
+ D_ASSERT(pos.GetIndex() != ROW_ID_COUNT);
319
323
  Node new_row_id;
320
324
  Leaf::New(new_row_id, key.GetRowId());
321
325
  Node::InsertChild(art, next, key[depth], new_row_id);
@@ -329,6 +333,7 @@ ARTConflictType Prefix::Insert(ART &art, Node &node, const ARTKey &key, idx_t de
329
333
  auto count = key.len - depth - 1;
330
334
  Prefix::New(art, ref, key, depth + 1, count);
331
335
  }
336
+
332
337
  // Create the inlined leaf.
333
338
  Leaf::New(ref, row_id.GetRowId());
334
339
  Node4::InsertChild(art, next, key[depth], leaf);
@@ -38,24 +38,22 @@ ErrorData BoundIndex::Append(DataChunk &chunk, Vector &row_ids) {
38
38
  return Append(l, chunk, row_ids);
39
39
  }
40
40
 
41
- ErrorData BoundIndex::AppendWithDeleteIndex(IndexLock &l, DataChunk &chunk, Vector &row_ids,
42
- optional_ptr<BoundIndex> delete_index) {
41
+ ErrorData BoundIndex::Append(IndexLock &l, DataChunk &chunk, Vector &row_ids, IndexAppendInfo &info) {
43
42
  // Fallback to the old Append.
44
43
  return Append(l, chunk, row_ids);
45
44
  }
46
45
 
47
- ErrorData BoundIndex::AppendWithDeleteIndex(DataChunk &chunk, Vector &row_ids, optional_ptr<BoundIndex> delete_index) {
46
+ ErrorData BoundIndex::Append(DataChunk &chunk, Vector &row_ids, IndexAppendInfo &info) {
48
47
  IndexLock l;
49
48
  InitializeLock(l);
50
- return AppendWithDeleteIndex(l, chunk, row_ids, delete_index);
49
+ return Append(l, chunk, row_ids, info);
51
50
  }
52
51
 
53
- void BoundIndex::VerifyAppend(DataChunk &chunk, optional_ptr<BoundIndex> delete_index,
54
- optional_ptr<ConflictManager> manager) {
52
+ void BoundIndex::VerifyAppend(DataChunk &chunk, IndexAppendInfo &info, optional_ptr<ConflictManager> manager) {
55
53
  throw NotImplementedException("this implementation of VerifyAppend does not exist.");
56
54
  }
57
55
 
58
- void BoundIndex::VerifyConstraint(DataChunk &chunk, optional_ptr<BoundIndex> delete_index, ConflictManager &manager) {
56
+ void BoundIndex::VerifyConstraint(DataChunk &chunk, IndexAppendInfo &info, ConflictManager &manager) {
59
57
  throw NotImplementedException("this implementation of VerifyConstraint does not exist.");
60
58
  }
61
59
 
@@ -71,7 +69,7 @@ void BoundIndex::Delete(DataChunk &entries, Vector &row_identifiers) {
71
69
  Delete(state, entries, row_identifiers);
72
70
  }
73
71
 
74
- ErrorData BoundIndex::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, optional_ptr<BoundIndex> delete_index) {
72
+ ErrorData BoundIndex::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, IndexAppendInfo &info) {
75
73
  throw NotImplementedException("this implementation of Insert does not exist.");
76
74
  }
77
75