duckdb 1.1.0 → 1.1.1-dev3.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 (147) hide show
  1. package/binding.gyp +2 -1
  2. package/package.json +1 -1
  3. package/src/duckdb/extension/icu/third_party/icu/stubdata/stubdata.cpp +1 -1
  4. package/src/duckdb/extension/json/include/json_common.hpp +14 -4
  5. package/src/duckdb/extension/json/include/json_executors.hpp +11 -3
  6. package/src/duckdb/extension/json/json_extension.cpp +1 -1
  7. package/src/duckdb/extension/json/json_functions/json_extract.cpp +11 -3
  8. package/src/duckdb/extension/json/json_functions/json_value.cpp +4 -3
  9. package/src/duckdb/extension/json/json_functions.cpp +16 -7
  10. package/src/duckdb/extension/parquet/column_reader.cpp +3 -0
  11. package/src/duckdb/extension/parquet/column_writer.cpp +54 -43
  12. package/src/duckdb/extension/parquet/geo_parquet.cpp +19 -0
  13. package/src/duckdb/extension/parquet/include/geo_parquet.hpp +10 -6
  14. package/src/duckdb/extension/parquet/include/templated_column_reader.hpp +3 -3
  15. package/src/duckdb/extension/parquet/parquet_writer.cpp +2 -1
  16. package/src/duckdb/src/common/arrow/arrow_converter.cpp +1 -1
  17. package/src/duckdb/src/common/arrow/arrow_merge_event.cpp +1 -0
  18. package/src/duckdb/src/common/arrow/arrow_util.cpp +60 -0
  19. package/src/duckdb/src/common/arrow/arrow_wrapper.cpp +1 -53
  20. package/src/duckdb/src/common/cgroups.cpp +15 -24
  21. package/src/duckdb/src/common/constants.cpp +8 -0
  22. package/src/duckdb/src/common/enum_util.cpp +331 -326
  23. package/src/duckdb/src/common/http_util.cpp +5 -1
  24. package/src/duckdb/src/common/operator/cast_operators.cpp +6 -60
  25. package/src/duckdb/src/common/types/bit.cpp +1 -1
  26. package/src/duckdb/src/common/types/column/column_data_allocator.cpp +18 -1
  27. package/src/duckdb/src/common/types/row/tuple_data_allocator.cpp +2 -1
  28. package/src/duckdb/src/common/types/row/tuple_data_segment.cpp +5 -0
  29. package/src/duckdb/src/core_functions/aggregate/distributive/arg_min_max.cpp +1 -1
  30. package/src/duckdb/src/core_functions/aggregate/distributive/minmax.cpp +2 -1
  31. package/src/duckdb/src/execution/index/art/iterator.cpp +17 -15
  32. package/src/duckdb/src/execution/index/art/prefix.cpp +9 -34
  33. package/src/duckdb/src/execution/index/fixed_size_buffer.cpp +4 -3
  34. package/src/duckdb/src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp +1 -0
  35. package/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer.cpp +2 -1
  36. package/src/duckdb/src/execution/operator/csv_scanner/scanner/base_scanner.cpp +2 -2
  37. package/src/duckdb/src/execution/operator/csv_scanner/scanner/column_count_scanner.cpp +23 -1
  38. package/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp +33 -4
  39. package/src/duckdb/src/execution/operator/csv_scanner/sniffer/csv_sniffer.cpp +23 -13
  40. package/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp +23 -19
  41. package/src/duckdb/src/execution/operator/csv_scanner/sniffer/header_detection.cpp +12 -11
  42. package/src/duckdb/src/execution/operator/csv_scanner/sniffer/type_detection.cpp +20 -14
  43. package/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp +4 -4
  44. package/src/duckdb/src/execution/operator/csv_scanner/util/csv_error.cpp +3 -1
  45. package/src/duckdb/src/execution/operator/join/physical_piecewise_merge_join.cpp +6 -1
  46. package/src/duckdb/src/function/cast/decimal_cast.cpp +33 -3
  47. package/src/duckdb/src/function/table/arrow/arrow_duck_schema.cpp +9 -0
  48. package/src/duckdb/src/function/table/arrow.cpp +34 -22
  49. package/src/duckdb/src/function/table/sniff_csv.cpp +4 -1
  50. package/src/duckdb/src/function/table/version/pragma_version.cpp +3 -3
  51. package/src/duckdb/src/include/duckdb/common/arrow/arrow_util.hpp +31 -0
  52. package/src/duckdb/src/include/duckdb/common/arrow/arrow_wrapper.hpp +2 -16
  53. package/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp +60 -0
  54. package/src/duckdb/src/include/duckdb/common/types/column/column_data_allocator.hpp +1 -0
  55. package/src/duckdb/src/include/duckdb/common/types/hugeint.hpp +0 -1
  56. package/src/duckdb/src/include/duckdb/common/types/row/row_data_collection.hpp +2 -1
  57. package/src/duckdb/src/include/duckdb/core_functions/aggregate/minmax_n_helpers.hpp +9 -5
  58. package/src/duckdb/src/include/duckdb/execution/executor.hpp +1 -0
  59. package/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp +5 -2
  60. package/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/column_count_scanner.hpp +5 -1
  61. package/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_sniffer.hpp +5 -5
  62. package/src/duckdb/src/include/duckdb/execution/operator/helper/physical_result_collector.hpp +1 -0
  63. package/src/duckdb/src/include/duckdb/function/table/arrow/arrow_duck_schema.hpp +11 -0
  64. package/src/duckdb/src/include/duckdb/main/config.hpp +2 -2
  65. package/src/duckdb/src/include/duckdb/main/extension.hpp +1 -0
  66. package/src/duckdb/src/include/duckdb/main/extension_entries.hpp +14 -5
  67. package/src/duckdb/src/include/duckdb/main/extension_helper.hpp +1 -1
  68. package/src/duckdb/src/include/duckdb/main/settings.hpp +4 -2
  69. package/src/duckdb/src/include/duckdb/parser/keyword_helper.hpp +3 -0
  70. package/src/duckdb/src/include/duckdb/parser/parser.hpp +1 -1
  71. package/src/duckdb/src/include/duckdb/parser/simplified_token.hpp +7 -1
  72. package/src/duckdb/src/include/duckdb/planner/binder.hpp +2 -0
  73. package/src/duckdb/src/include/duckdb/planner/expression_binder/select_binder.hpp +2 -0
  74. package/src/duckdb/src/include/duckdb/planner/expression_binder.hpp +3 -1
  75. package/src/duckdb/src/include/duckdb/storage/block_manager.hpp +3 -1
  76. package/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +7 -4
  77. package/src/duckdb/src/include/duckdb/storage/buffer/buffer_handle.hpp +2 -2
  78. package/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp +2 -1
  79. package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +4 -4
  80. package/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp +3 -4
  81. package/src/duckdb/src/include/duckdb/storage/table/column_data.hpp +1 -1
  82. package/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp +4 -2
  83. package/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp +1 -1
  84. package/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp +1 -0
  85. package/src/duckdb/src/include/duckdb/transaction/local_storage.hpp +1 -0
  86. package/src/duckdb/src/include/duckdb/transaction/transaction_manager.hpp +1 -1
  87. package/src/duckdb/src/include/duckdb.h +8 -8
  88. package/src/duckdb/src/main/appender.cpp +1 -1
  89. package/src/duckdb/src/main/capi/duckdb_value-c.cpp +3 -3
  90. package/src/duckdb/src/main/capi/helper-c.cpp +4 -0
  91. package/src/duckdb/src/main/config.cpp +24 -11
  92. package/src/duckdb/src/main/database.cpp +6 -5
  93. package/src/duckdb/src/main/extension/extension_install.cpp +13 -8
  94. package/src/duckdb/src/main/extension/extension_load.cpp +10 -4
  95. package/src/duckdb/src/main/extension.cpp +1 -1
  96. package/src/duckdb/src/optimizer/filter_pushdown.cpp +10 -1
  97. package/src/duckdb/src/optimizer/join_filter_pushdown_optimizer.cpp +9 -5
  98. package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +14 -8
  99. package/src/duckdb/src/optimizer/join_order/query_graph_manager.cpp +2 -0
  100. package/src/duckdb/src/optimizer/join_order/relation_manager.cpp +15 -0
  101. package/src/duckdb/src/optimizer/optimizer.cpp +4 -1
  102. package/src/duckdb/src/optimizer/pushdown/pushdown_cross_product.cpp +1 -11
  103. package/src/duckdb/src/optimizer/pushdown/pushdown_inner_join.cpp +1 -7
  104. package/src/duckdb/src/optimizer/pushdown/pushdown_left_join.cpp +1 -1
  105. package/src/duckdb/src/optimizer/statistics/expression/propagate_cast.cpp +3 -0
  106. package/src/duckdb/src/optimizer/statistics/operator/propagate_join.cpp +1 -0
  107. package/src/duckdb/src/parser/keyword_helper.cpp +4 -0
  108. package/src/duckdb/src/parser/parser.cpp +20 -18
  109. package/src/duckdb/src/parser/transform/statement/transform_select_node.cpp +8 -3
  110. package/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp +3 -0
  111. package/src/duckdb/src/planner/binder/expression/bind_lambda.cpp +7 -1
  112. package/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp +13 -0
  113. package/src/duckdb/src/planner/binder/statement/bind_copy_database.cpp +7 -11
  114. package/src/duckdb/src/planner/binder/statement/bind_create.cpp +27 -10
  115. package/src/duckdb/src/planner/binder/statement/bind_export.cpp +24 -9
  116. package/src/duckdb/src/planner/binder/tableref/plan_joinref.cpp +1 -3
  117. package/src/duckdb/src/planner/binder.cpp +5 -6
  118. package/src/duckdb/src/planner/expression/bound_cast_expression.cpp +1 -0
  119. package/src/duckdb/src/planner/expression_binder/select_binder.cpp +9 -0
  120. package/src/duckdb/src/planner/operator/logical_copy_to_file.cpp +2 -2
  121. package/src/duckdb/src/planner/operator/logical_positional_join.cpp +1 -0
  122. package/src/duckdb/src/storage/buffer/block_handle.cpp +18 -21
  123. package/src/duckdb/src/storage/buffer/block_manager.cpp +12 -4
  124. package/src/duckdb/src/storage/buffer/buffer_handle.cpp +2 -2
  125. package/src/duckdb/src/storage/buffer/buffer_pool.cpp +12 -2
  126. package/src/duckdb/src/storage/buffer_manager.cpp +3 -2
  127. package/src/duckdb/src/storage/compression/rle.cpp +5 -2
  128. package/src/duckdb/src/storage/compression/string_uncompressed.cpp +2 -1
  129. package/src/duckdb/src/storage/metadata/metadata_manager.cpp +8 -7
  130. package/src/duckdb/src/storage/standard_buffer_manager.cpp +19 -20
  131. package/src/duckdb/src/storage/statistics/column_statistics.cpp +1 -2
  132. package/src/duckdb/src/storage/table/column_data.cpp +5 -2
  133. package/src/duckdb/src/storage/table/column_segment.cpp +2 -2
  134. package/src/duckdb/src/storage/table/row_group_collection.cpp +18 -14
  135. package/src/duckdb/src/storage/table/standard_column_data.cpp +3 -3
  136. package/src/duckdb/src/storage/wal_replay.cpp +2 -3
  137. package/src/duckdb/third_party/libpg_query/include/common/keywords.hpp +1 -0
  138. package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +1 -0
  139. package/src/duckdb/third_party/libpg_query/include/parser/parser.hpp +1 -2
  140. package/src/duckdb/third_party/libpg_query/include/pg_simplified_token.hpp +6 -4
  141. package/src/duckdb/third_party/libpg_query/include/postgres_parser.hpp +1 -1
  142. package/src/duckdb/third_party/libpg_query/postgres_parser.cpp +1 -1
  143. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +801 -799
  144. package/src/duckdb/third_party/libpg_query/src_backend_parser_parser.cpp +6 -2
  145. package/src/duckdb/third_party/libpg_query/src_common_keywords.cpp +0 -1
  146. package/src/duckdb/ub_src_common_arrow.cpp +2 -0
  147. package/vendor.py +1 -2
@@ -12,6 +12,7 @@
12
12
  #include "duckdb/storage/table/table_index_list.hpp"
13
13
  #include "duckdb/storage/table/table_statistics.hpp"
14
14
  #include "duckdb/storage/optimistic_data_writer.hpp"
15
+ #include "duckdb/common/error_data.hpp"
15
16
  #include "duckdb/common/reference_map.hpp"
16
17
 
17
18
  namespace duckdb {
@@ -12,7 +12,7 @@
12
12
  #include "duckdb/common/common.hpp"
13
13
  #include "duckdb/common/mutex.hpp"
14
14
  #include "duckdb/common/vector.hpp"
15
-
15
+ #include "duckdb/common/error_data.hpp"
16
16
  #include "duckdb/common/atomic.hpp"
17
17
 
18
18
  namespace duckdb {
@@ -133,6 +133,8 @@ typedef enum DUCKDB_TYPE {
133
133
  DUCKDB_TYPE_ANY = 34,
134
134
  // duckdb_varint
135
135
  DUCKDB_TYPE_VARINT = 35,
136
+ // SQLNULL type
137
+ DUCKDB_TYPE_SQLNULL = 36,
136
138
  } duckdb_type;
137
139
  //! An enum over the returned state of different functions.
138
140
  typedef enum duckdb_state { DuckDBSuccess = 0, DuckDBError = 1 } duckdb_state;
@@ -866,8 +868,8 @@ Returns the number of rows present in the result object.
866
868
  * @return The number of rows present in the result object.
867
869
  */
868
870
  DUCKDB_API idx_t duckdb_row_count(duckdb_result *result);
869
- #endif
870
871
 
872
+ #endif
871
873
  /*!
872
874
  Returns the number of rows changed by the query stored in the result. This is relevant only for INSERT/UPDATE/DELETE
873
875
  queries. For other queries the rows_changed will be 0.
@@ -898,9 +900,7 @@ printf("Data for row %d: %d\n", row, data[row]);
898
900
  * @return The column data of the specified column.
899
901
  */
900
902
  DUCKDB_API void *duckdb_column_data(duckdb_result *result, idx_t col);
901
- #endif
902
903
 
903
- #ifndef DUCKDB_API_NO_DEPRECATED
904
904
  /*!
905
905
  **DEPRECATED**: Prefer using `duckdb_result_get_chunk` instead.
906
906
 
@@ -923,8 +923,8 @@ if (nullmask[row]) {
923
923
  * @return The nullmask of the specified column.
924
924
  */
925
925
  DUCKDB_API bool *duckdb_nullmask_data(duckdb_result *result, idx_t col);
926
- #endif
927
926
 
927
+ #endif
928
928
  /*!
929
929
  Returns the error message contained within the result. The error is only set if `duckdb_query` returns `DuckDBError`.
930
930
 
@@ -990,6 +990,7 @@ Returns the number of data chunks present in the result.
990
990
  */
991
991
  DUCKDB_API idx_t duckdb_result_chunk_count(duckdb_result result);
992
992
 
993
+ #endif
993
994
  /*!
994
995
  Returns the return_type of the given result, or DUCKDB_RETURN_TYPE_INVALID on error
995
996
 
@@ -998,7 +999,6 @@ Returns the return_type of the given result, or DUCKDB_RETURN_TYPE_INVALID on er
998
999
  */
999
1000
  DUCKDB_API duckdb_result_type duckdb_result_return_type(duckdb_result result);
1000
1001
 
1001
- #endif
1002
1002
  //===--------------------------------------------------------------------===//
1003
1003
  // Safe Fetch Functions
1004
1004
  //===--------------------------------------------------------------------===//
@@ -1663,8 +1663,8 @@ Note that the result must be freed with `duckdb_destroy_result`.
1663
1663
  */
1664
1664
  DUCKDB_API duckdb_state duckdb_execute_prepared_streaming(duckdb_prepared_statement prepared_statement,
1665
1665
  duckdb_result *out_result);
1666
- #endif
1667
1666
 
1667
+ #endif
1668
1668
  //===--------------------------------------------------------------------===//
1669
1669
  // Extract Statements
1670
1670
  //===--------------------------------------------------------------------===//
@@ -1754,8 +1754,8 @@ Note that after calling `duckdb_pending_prepared_streaming`, the pending result
1754
1754
  */
1755
1755
  DUCKDB_API duckdb_state duckdb_pending_prepared_streaming(duckdb_prepared_statement prepared_statement,
1756
1756
  duckdb_pending_result *out_result);
1757
- #endif
1758
1757
 
1758
+ #endif
1759
1759
  /*!
1760
1760
  Closes the pending result and de-allocates all memory allocated for the result.
1761
1761
 
@@ -4038,8 +4038,8 @@ It is not known beforehand how many chunks will be returned by this result.
4038
4038
  * @return The resulting data chunk. Returns `NULL` if the result has an error.
4039
4039
  */
4040
4040
  DUCKDB_API duckdb_data_chunk duckdb_stream_fetch_chunk(duckdb_result result);
4041
- #endif
4042
4041
 
4042
+ #endif
4043
4043
  /*!
4044
4044
  Fetches a data chunk from a duckdb_result. This function should be called repeatedly until the result is exhausted.
4045
4045
 
@@ -114,7 +114,7 @@ void BaseAppender::BeginRow() {
114
114
  void BaseAppender::EndRow() {
115
115
  // check that all rows have been appended to
116
116
  if (column != chunk.ColumnCount()) {
117
- throw InvalidInputException("Call to EndRow before all rows have been appended to!");
117
+ throw InvalidInputException("Call to EndRow before all columns have been appended to!");
118
118
  }
119
119
  column = 0;
120
120
  chunk.SetCardinality(chunk.size() + 1);
@@ -282,7 +282,7 @@ idx_t duckdb_get_map_size(duckdb_value value) {
282
282
  }
283
283
 
284
284
  auto val = UnwrapValue(value);
285
- if (val.type() != LogicalTypeId::MAP) {
285
+ if (val.type().id() != LogicalTypeId::MAP) {
286
286
  return 0;
287
287
  }
288
288
 
@@ -296,7 +296,7 @@ duckdb_value duckdb_get_map_key(duckdb_value value, idx_t index) {
296
296
  }
297
297
 
298
298
  auto val = UnwrapValue(value);
299
- if (val.type() != LogicalTypeId::MAP) {
299
+ if (val.type().id() != LogicalTypeId::MAP) {
300
300
  return nullptr;
301
301
  }
302
302
 
@@ -316,7 +316,7 @@ duckdb_value duckdb_get_map_value(duckdb_value value, idx_t index) {
316
316
  }
317
317
 
318
318
  auto val = UnwrapValue(value);
319
- if (val.type() != LogicalTypeId::MAP) {
319
+ if (val.type().id() != LogicalTypeId::MAP) {
320
320
  return nullptr;
321
321
  }
322
322
 
@@ -74,6 +74,8 @@ LogicalTypeId ConvertCTypeToCPP(duckdb_type c_type) {
74
74
  return LogicalTypeId::TIMESTAMP_TZ;
75
75
  case DUCKDB_TYPE_ANY:
76
76
  return LogicalTypeId::ANY;
77
+ case DUCKDB_TYPE_SQLNULL:
78
+ return LogicalTypeId::SQLNULL;
77
79
  default: // LCOV_EXCL_START
78
80
  D_ASSERT(0);
79
81
  return LogicalTypeId::INVALID;
@@ -154,6 +156,8 @@ duckdb_type ConvertCPPTypeToC(const LogicalType &sql_type) {
154
156
  return DUCKDB_TYPE_ARRAY;
155
157
  case LogicalTypeId::ANY:
156
158
  return DUCKDB_TYPE_ANY;
159
+ case LogicalTypeId::SQLNULL:
160
+ return DUCKDB_TYPE_SQLNULL;
157
161
  default: // LCOV_EXCL_START
158
162
  D_ASSERT(0);
159
163
  return DUCKDB_TYPE_INVALID;
@@ -363,16 +363,22 @@ idx_t DBConfig::GetSystemMaxThreads(FileSystem &fs) {
363
363
  }
364
364
 
365
365
  idx_t DBConfig::GetSystemAvailableMemory(FileSystem &fs) {
366
+ #ifdef __linux__
366
367
  // Check SLURM environment variables first
367
368
  const char *slurm_mem_per_node = getenv("SLURM_MEM_PER_NODE");
368
369
  const char *slurm_mem_per_cpu = getenv("SLURM_MEM_PER_CPU");
369
370
 
370
371
  if (slurm_mem_per_node) {
371
- return ParseMemoryLimitSlurm(slurm_mem_per_node);
372
+ auto limit = ParseMemoryLimitSlurm(slurm_mem_per_node);
373
+ if (limit.IsValid()) {
374
+ return limit.GetIndex();
375
+ }
372
376
  } else if (slurm_mem_per_cpu) {
373
- idx_t mem_per_cpu = ParseMemoryLimitSlurm(slurm_mem_per_cpu);
374
- idx_t num_threads = GetSystemMaxThreads(fs);
375
- return mem_per_cpu * num_threads;
377
+ auto mem_per_cpu = ParseMemoryLimitSlurm(slurm_mem_per_cpu);
378
+ if (mem_per_cpu.IsValid()) {
379
+ idx_t num_threads = GetSystemMaxThreads(fs);
380
+ return mem_per_cpu.GetIndex() * num_threads;
381
+ }
376
382
  }
377
383
 
378
384
  // Check cgroup memory limit
@@ -380,8 +386,9 @@ idx_t DBConfig::GetSystemAvailableMemory(FileSystem &fs) {
380
386
  if (cgroup_memory_limit.IsValid()) {
381
387
  return cgroup_memory_limit.GetIndex();
382
388
  }
389
+ #endif
383
390
 
384
- // Fall back to system memory detection
391
+ // System memory detection
385
392
  auto memory = FileSystem::GetAvailableMemory();
386
393
  if (!memory.IsValid()) {
387
394
  return DBConfigOptions().maximum_memory;
@@ -451,9 +458,9 @@ idx_t DBConfig::ParseMemoryLimit(const string &arg) {
451
458
  return LossyNumericCast<idx_t>(static_cast<double>(multiplier) * limit);
452
459
  }
453
460
 
454
- idx_t DBConfig::ParseMemoryLimitSlurm(const string &arg) {
461
+ optional_idx DBConfig::ParseMemoryLimitSlurm(const string &arg) {
455
462
  if (arg.empty()) {
456
- return 0;
463
+ return optional_idx();
457
464
  }
458
465
 
459
466
  string number_str = arg;
@@ -475,13 +482,19 @@ idx_t DBConfig::ParseMemoryLimitSlurm(const string &arg) {
475
482
  }
476
483
 
477
484
  // Parse the number
478
- double limit = Cast::Operation<string_t, double>(string_t(number_str));
485
+ double limit;
486
+ if (!TryCast::Operation<string_t, double>(string_t(number_str), limit)) {
487
+ return optional_idx();
488
+ }
479
489
 
480
490
  if (limit < 0) {
481
- return NumericLimits<idx_t>::Maximum();
491
+ return static_cast<idx_t>(NumericLimits<int64_t>::Maximum());
482
492
  }
483
-
484
- return LossyNumericCast<idx_t>(static_cast<double>(multiplier) * limit);
493
+ idx_t actual_limit = LossyNumericCast<idx_t>(static_cast<double>(multiplier) * limit);
494
+ if (actual_limit == NumericLimits<idx_t>::Maximum()) {
495
+ return static_cast<idx_t>(NumericLimits<int64_t>::Maximum());
496
+ }
497
+ return actual_limit;
485
498
  }
486
499
 
487
500
  // Right now we only really care about access mode when comparing DBConfigs
@@ -2,29 +2,29 @@
2
2
 
3
3
  #include "duckdb/catalog/catalog.hpp"
4
4
  #include "duckdb/common/virtual_file_system.hpp"
5
+ #include "duckdb/execution/index/index_type_set.hpp"
5
6
  #include "duckdb/execution/operator/helper/physical_set.hpp"
6
7
  #include "duckdb/function/cast/cast_function_set.hpp"
7
8
  #include "duckdb/function/compression_function.hpp"
8
9
  #include "duckdb/main/attached_database.hpp"
9
10
  #include "duckdb/main/client_context.hpp"
10
11
  #include "duckdb/main/connection_manager.hpp"
12
+ #include "duckdb/main/database_file_opener.hpp"
11
13
  #include "duckdb/main/database_manager.hpp"
12
14
  #include "duckdb/main/database_path_and_type.hpp"
15
+ #include "duckdb/main/db_instance_cache.hpp"
13
16
  #include "duckdb/main/error_manager.hpp"
14
17
  #include "duckdb/main/extension_helper.hpp"
15
18
  #include "duckdb/main/secret/secret_manager.hpp"
16
19
  #include "duckdb/parallel/task_scheduler.hpp"
17
20
  #include "duckdb/parser/parsed_data/attach_info.hpp"
21
+ #include "duckdb/planner/collation_binding.hpp"
18
22
  #include "duckdb/planner/extension_callback.hpp"
19
23
  #include "duckdb/storage/object_cache.hpp"
20
24
  #include "duckdb/storage/standard_buffer_manager.hpp"
21
25
  #include "duckdb/storage/storage_extension.hpp"
22
26
  #include "duckdb/storage/storage_manager.hpp"
23
27
  #include "duckdb/transaction/transaction_manager.hpp"
24
- #include "duckdb/execution/index/index_type_set.hpp"
25
- #include "duckdb/main/database_file_opener.hpp"
26
- #include "duckdb/planner/collation_binding.hpp"
27
- #include "duckdb/main/db_instance_cache.hpp"
28
28
 
29
29
  #ifndef DUCKDB_NO_THREADS
30
30
  #include "duckdb/common/thread.hpp"
@@ -436,7 +436,8 @@ void DatabaseInstance::Configure(DBConfig &new_config, const char *database_path
436
436
  config.buffer_pool = std::move(new_config.buffer_pool);
437
437
  } else {
438
438
  config.buffer_pool = make_shared_ptr<BufferPool>(config.options.maximum_memory,
439
- config.options.buffer_manager_track_eviction_timestamps);
439
+ config.options.buffer_manager_track_eviction_timestamps,
440
+ config.options.allocator_bulk_deallocation_flush_threshold);
440
441
  }
441
442
  }
442
443
 
@@ -268,15 +268,20 @@ static unique_ptr<ExtensionInstallInfo> DirectInstallExtension(DatabaseInstance
268
268
  const string &local_extension_path,
269
269
  ExtensionInstallOptions &options,
270
270
  optional_ptr<ClientContext> context) {
271
- string file = fs.ConvertSeparators(path);
272
-
273
- // Try autoloading httpfs for loading extensions over https
274
- if (context) {
275
- auto &db = DatabaseInstance::GetDatabase(*context);
276
- if (StringUtil::StartsWith(path, "https://") && !db.ExtensionIsLoaded("httpfs") &&
277
- db.config.options.autoload_known_extensions) {
278
- ExtensionHelper::AutoLoadExtension(*context, "httpfs");
271
+ string extension;
272
+ string file;
273
+ if (fs.IsRemoteFile(path, extension)) {
274
+ file = path;
275
+ // Try autoloading httpfs for loading extensions over https
276
+ if (context) {
277
+ auto &db = DatabaseInstance::GetDatabase(*context);
278
+ if (extension == "httpfs" && !db.ExtensionIsLoaded("httpfs") &&
279
+ db.config.options.autoload_known_extensions) {
280
+ ExtensionHelper::AutoLoadExtension(*context, "httpfs");
281
+ }
279
282
  }
283
+ } else {
284
+ file = fs.ConvertSeparators(path);
280
285
  }
281
286
 
282
287
  // Check if file exists
@@ -173,7 +173,7 @@ static string FilterZeroAtEnd(string s) {
173
173
  return s;
174
174
  }
175
175
 
176
- ParsedExtensionMetaData ExtensionHelper::ParseExtensionMetaData(const char *metadata) {
176
+ ParsedExtensionMetaData ExtensionHelper::ParseExtensionMetaData(const char *metadata) noexcept {
177
177
  ParsedExtensionMetaData result;
178
178
 
179
179
  vector<string> metadata_field;
@@ -194,12 +194,18 @@ ParsedExtensionMetaData ExtensionHelper::ParseExtensionMetaData(const char *meta
194
194
 
195
195
  result.extension_version = FilterZeroAtEnd(metadata_field[3]);
196
196
 
197
- result.abi_type = EnumUtil::FromString<ExtensionABIType>(FilterZeroAtEnd(metadata_field[4]));
197
+ auto extension_abi_metadata = FilterZeroAtEnd(metadata_field[4]);
198
198
 
199
- if (result.abi_type == ExtensionABIType::C_STRUCT) {
199
+ if (extension_abi_metadata == "C_STRUCT") {
200
+ result.abi_type = ExtensionABIType::C_STRUCT;
200
201
  result.duckdb_capi_version = FilterZeroAtEnd(metadata_field[2]);
201
- } else if (result.abi_type == ExtensionABIType::CPP) {
202
+ } else if (extension_abi_metadata == "CPP" || extension_abi_metadata.empty()) {
203
+ result.abi_type = ExtensionABIType::CPP;
202
204
  result.duckdb_version = FilterZeroAtEnd(metadata_field[2]);
205
+ } else {
206
+ result.abi_type = ExtensionABIType::UNKNOWN;
207
+ result.duckdb_version = "unknown";
208
+ result.extension_abi_metadata = extension_abi_metadata;
203
209
  }
204
210
 
205
211
  result.signature = string(metadata, ParsedExtensionMetaData::FOOTER_SIZE - ParsedExtensionMetaData::SIGNATURE_SIZE);
@@ -62,7 +62,7 @@ string ParsedExtensionMetaData::GetInvalidMetadataError() {
62
62
  DUCKDB_EXTENSION_API_VERSION_MINOR, DUCKDB_EXTENSION_API_VERSION_PATCH);
63
63
  }
64
64
  } else {
65
- throw InternalException("Unknown ABI type for extension: " + EnumUtil::ToString(abi_type));
65
+ throw InternalException("Unknown ABI type for extension: " + extension_abi_metadata);
66
66
  }
67
67
 
68
68
  if (engine_platform != platform) {
@@ -93,9 +93,14 @@ unique_ptr<LogicalOperator> FilterPushdown::Rewrite(unique_ptr<LogicalOperator>
93
93
  // we can just push directly through these operations without any rewriting
94
94
  op->children[0] = Rewrite(std::move(op->children[0]));
95
95
  return op;
96
- case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE:
96
+ case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: {
97
+ // we can't push filters into the materialized CTE (LHS), but we do want to recurse into it
98
+ FilterPushdown pushdown(optimizer, convert_mark_joins);
99
+ op->children[0] = pushdown.Rewrite(std::move(op->children[0]));
100
+ // we can push filters into the rest of the query plan (RHS)
97
101
  op->children[1] = Rewrite(std::move(op->children[1]));
98
102
  return op;
103
+ }
99
104
  case LogicalOperatorType::LOGICAL_GET:
100
105
  return PushdownGet(std::move(op));
101
106
  case LogicalOperatorType::LOGICAL_LIMIT:
@@ -127,6 +132,10 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownJoin(unique_ptr<LogicalOpera
127
132
 
128
133
  switch (join.join_type) {
129
134
  case JoinType::INNER:
135
+ // AsOf joins can't push anything into the RHS, so treat it as a left join
136
+ if (op->type == LogicalOperatorType::LOGICAL_ASOF_JOIN) {
137
+ return PushdownLeftJoin(std::move(op), left_bindings, right_bindings);
138
+ }
130
139
  return PushdownInnerJoin(std::move(op), left_bindings, right_bindings);
131
140
  case JoinType::LEFT:
132
141
  return PushdownLeftJoin(std::move(op), left_bindings, right_bindings);
@@ -118,11 +118,6 @@ void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &joi
118
118
  }
119
119
  }
120
120
  // pushdown can be performed
121
- // set up the dynamic filters (if we don't have any yet)
122
- if (!get.dynamic_filters) {
123
- get.dynamic_filters = make_shared_ptr<DynamicTableFilterSet>();
124
- }
125
- pushdown_info->dynamic_filters = get.dynamic_filters;
126
121
 
127
122
  // set up the min/max aggregates for each of the filters
128
123
  vector<AggregateFunction> aggr_functions;
@@ -135,9 +130,18 @@ void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &joi
135
130
  aggr_children.push_back(join.conditions[filter.join_condition].right->Copy());
136
131
  auto aggr_expr = function_binder.BindAggregateFunction(aggr, std::move(aggr_children), nullptr,
137
132
  AggregateType::NON_DISTINCT);
133
+ if (aggr_expr->children.size() != 1) {
134
+ // min/max with collation - not supported
135
+ return;
136
+ }
138
137
  pushdown_info->min_max_aggregates.push_back(std::move(aggr_expr));
139
138
  }
140
139
  }
140
+ // set up the dynamic filters (if we don't have any yet)
141
+ if (!get.dynamic_filters) {
142
+ get.dynamic_filters = make_shared_ptr<DynamicTableFilterSet>();
143
+ }
144
+ pushdown_info->dynamic_filters = get.dynamic_filters;
141
145
 
142
146
  // set up the filter pushdown in the join itself
143
147
  join.filter_pushdown = std::move(pushdown_info);
@@ -2,10 +2,10 @@
2
2
  #include "duckdb/common/enums/join_type.hpp"
3
3
  #include "duckdb/common/limits.hpp"
4
4
  #include "duckdb/common/printer.hpp"
5
- #include "duckdb/planner/expression_iterator.hpp"
6
5
  #include "duckdb/function/table/table_scan.hpp"
7
6
  #include "duckdb/optimizer/join_order/join_node.hpp"
8
7
  #include "duckdb/optimizer/join_order/query_graph_manager.hpp"
8
+ #include "duckdb/planner/expression_iterator.hpp"
9
9
  #include "duckdb/planner/operator/logical_comparison_join.hpp"
10
10
  #include "duckdb/storage/data_table.hpp"
11
11
 
@@ -291,10 +291,18 @@ DenomInfo CardinalityEstimator::GetDenominator(JoinRelationSet &set) {
291
291
  // and we start to choose the filters that join relations in the set.
292
292
 
293
293
  // edges are guaranteed to be in order of largest tdom to smallest tdom.
294
+ unordered_set<idx_t> unused_edge_tdoms;
294
295
  auto edges = GetEdges(relations_to_tdoms, set);
295
296
  for (auto &edge : edges) {
296
- auto subgraph_connections = SubgraphsConnectedByEdge(edge, subgraphs);
297
+ if (subgraphs.size() == 1 && subgraphs.at(0).relations->ToString() == set.ToString()) {
298
+ // the first subgraph has connected all the desired relations, just skip the rest of the edges
299
+ if (edge.has_tdom_hll) {
300
+ unused_edge_tdoms.insert(edge.tdom_hll);
301
+ }
302
+ continue;
303
+ }
297
304
 
305
+ auto subgraph_connections = SubgraphsConnectedByEdge(edge, subgraphs);
298
306
  if (subgraph_connections.empty()) {
299
307
  // create a subgraph out of left and right, then merge right into left and add left to subgraphs.
300
308
  // this helps cover a case where there are no subgraphs yet, and the only join filter is a SEMI JOIN
@@ -342,13 +350,11 @@ DenomInfo CardinalityEstimator::GetDenominator(JoinRelationSet &set) {
342
350
  [](Subgraph2Denominator &s) { return !s.relations; });
343
351
  subgraphs.erase(remove_start, subgraphs.end());
344
352
  }
345
- if (subgraphs.size() == 1 && subgraphs.at(0).relations->ToString() == set.ToString()) {
346
- // the first subgraph has connected all the desired relations, no need to iterate
347
- // through the rest of the edges.
348
- break;
349
- }
350
353
  }
351
354
 
355
+ // Slight penalty to cardinality for unused edges
356
+ auto denom_multiplier = 1.0 + static_cast<double>(unused_edge_tdoms.size());
357
+
352
358
  // It's possible cross-products were added and are not present in the filters in the relation_2_tdom
353
359
  // structures. When that's the case, merge all remaining subgraphs.
354
360
  if (subgraphs.size() > 1) {
@@ -367,7 +373,7 @@ DenomInfo CardinalityEstimator::GetDenominator(JoinRelationSet &set) {
367
373
  // denominator is 1 and numerators are a cross product of cardinalities.
368
374
  return DenomInfo(set, 1, 1);
369
375
  }
370
- return DenomInfo(*subgraphs.at(0).numerator_relations, 1, subgraphs.at(0).denom);
376
+ return DenomInfo(*subgraphs.at(0).numerator_relations, 1, subgraphs.at(0).denom * denom_multiplier);
371
377
  }
372
378
 
373
379
  template <>
@@ -253,7 +253,9 @@ GenerateJoinRelation QueryGraphManager::GenerateJoins(vector<unique_ptr<LogicalO
253
253
  auto right = GenerateJoins(extracted_relations, node->right_set);
254
254
  if (dp_entry->second->info->filters.empty()) {
255
255
  // no filters, create a cross product
256
+ auto cardinality = left.op->estimated_cardinality * right.op->estimated_cardinality;
256
257
  result_operator = LogicalCrossProduct::Create(std::move(left.op), std::move(right.op));
258
+ result_operator->SetEstimatedCardinality(cardinality);
257
259
  } else {
258
260
  // we have filters, create a join node
259
261
  auto chosen_filter = node->info->filters.at(0);
@@ -85,6 +85,7 @@ static bool OperatorNeedsRelation(LogicalOperatorType op_type) {
85
85
  case LogicalOperatorType::LOGICAL_PROJECTION:
86
86
  case LogicalOperatorType::LOGICAL_EXPRESSION_GET:
87
87
  case LogicalOperatorType::LOGICAL_GET:
88
+ case LogicalOperatorType::LOGICAL_UNNEST:
88
89
  case LogicalOperatorType::LOGICAL_DELIM_GET:
89
90
  case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY:
90
91
  case LogicalOperatorType::LOGICAL_WINDOW:
@@ -269,6 +270,20 @@ bool RelationManager::ExtractJoinRelations(JoinOrderOptimizer &optimizer, Logica
269
270
  AddAggregateOrWindowRelation(input_op, parent, operator_stats, op->type);
270
271
  return true;
271
272
  }
273
+ case LogicalOperatorType::LOGICAL_UNNEST: {
274
+ // optimize children of unnest
275
+ RelationStats child_stats;
276
+ auto child_optimizer = optimizer.CreateChildOptimizer();
277
+ op->children[0] = child_optimizer.Optimize(std::move(op->children[0]), &child_stats);
278
+ // the extracted cardinality should be set for window
279
+ if (!datasource_filters.empty()) {
280
+ child_stats.cardinality = LossyNumericCast<idx_t>(static_cast<double>(child_stats.cardinality) *
281
+ RelationStatisticsHelper::DEFAULT_SELECTIVITY);
282
+ }
283
+ ModifyStatsIfLimit(limit_op.get(), child_stats);
284
+ AddRelation(input_op, parent, child_stats);
285
+ return true;
286
+ }
272
287
  case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: {
273
288
  auto &join = op->Cast<LogicalComparisonJoin>();
274
289
  // Adding relations of the left side to the current join order optimizer
@@ -95,7 +95,10 @@ void Optimizer::RunBuiltInOptimizers() {
95
95
  case LogicalOperatorType::LOGICAL_CREATE_SECRET:
96
96
  case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR:
97
97
  // skip optimizing simple & often-occurring plans unaffected by rewrites
98
- return;
98
+ if (plan->children.empty()) {
99
+ return;
100
+ }
101
+ break;
99
102
  default:
100
103
  break;
101
104
  }
@@ -14,9 +14,6 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownCrossProduct(unique_ptr<Logi
14
14
  switch (op->type) {
15
15
  case LogicalOperatorType::LOGICAL_CROSS_PRODUCT:
16
16
  break;
17
- case LogicalOperatorType::LOGICAL_ASOF_JOIN:
18
- join_ref_type = JoinRefType::ASOF;
19
- break;
20
17
  default:
21
18
  throw InternalException("Unsupported join type for cross product push down");
22
19
  }
@@ -33,14 +30,7 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownCrossProduct(unique_ptr<Logi
33
30
  // bindings match left side: push into left
34
31
  left_pushdown.filters.push_back(std::move(f));
35
32
  } else if (side == JoinSide::RIGHT) {
36
- // bindings match right side: push into right
37
- if (join_ref_type == JoinRefType::ASOF) {
38
- // AsOf is really a table lookup, so we don't push filters
39
- // down into the lookup (right) table
40
- join_expressions.push_back(std::move(f->filter));
41
- } else {
42
- right_pushdown.filters.push_back(std::move(f));
43
- }
33
+ right_pushdown.filters.push_back(std::move(f));
44
34
  } else {
45
35
  D_ASSERT(side == JoinSide::BOTH || side == JoinSide::NONE);
46
36
  // bindings match both: turn into join condition
@@ -26,8 +26,7 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownInnerJoin(unique_ptr<Logical
26
26
  }
27
27
  } else {
28
28
  // comparison join
29
- D_ASSERT(op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN ||
30
- op->type == LogicalOperatorType::LOGICAL_ASOF_JOIN);
29
+ D_ASSERT(op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN);
31
30
  auto &comp_join = join.Cast<LogicalComparisonJoin>();
32
31
  // turn the conditions into filters
33
32
  for (auto &i : comp_join.conditions) {
@@ -40,11 +39,6 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownInnerJoin(unique_ptr<Logical
40
39
  }
41
40
  GenerateFilters();
42
41
 
43
- // For AsOf joins, just use the original op
44
- if (op->type == LogicalOperatorType::LOGICAL_ASOF_JOIN) {
45
- return PushdownCrossProduct(std::move(op));
46
- }
47
-
48
42
  // turn the inner join into a cross product
49
43
  auto cross_product = make_uniq<LogicalCrossProduct>(std::move(op->children[0]), std::move(op->children[1]));
50
44
 
@@ -93,7 +93,7 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownLeftJoin(unique_ptr<LogicalO
93
93
  // erase the filter from the list of filters
94
94
  filters.erase_at(i);
95
95
  i--;
96
- } else {
96
+ } else if (op->type != LogicalOperatorType::LOGICAL_ASOF_JOIN) {
97
97
  // bindings match right side or both sides: we cannot directly push it into the right
98
98
  // however, if the filter removes rows with null values from the RHS we can turn the left outer join
99
99
  // in an inner join, and then push down as we would push down an inner join
@@ -27,6 +27,9 @@ static unique_ptr<BaseStatistics> StatisticsNumericCastSwitch(const BaseStatisti
27
27
  case LogicalTypeId::TIME: {
28
28
  switch (input.GetType().id()) {
29
29
  case LogicalTypeId::TIMESTAMP:
30
+ case LogicalTypeId::TIMESTAMP_SEC:
31
+ case LogicalTypeId::TIMESTAMP_MS:
32
+ case LogicalTypeId::TIMESTAMP_NS:
30
33
  case LogicalTypeId::TIMESTAMP_TZ:
31
34
  return nullptr;
32
35
  default:
@@ -104,6 +104,7 @@ void StatisticsPropagator::PropagateStatistics(LogicalComparisonJoin &join, uniq
104
104
  // TODO: write better CE logic for limits so that we can just look at
105
105
  // join.children[1].estimated_cardinality.
106
106
  auto limit = make_uniq<LogicalLimit>(BoundLimitNode::ConstantValue(1), BoundLimitNode());
107
+ limit->SetEstimatedCardinality(1);
107
108
  limit->AddChild(std::move(join.children[1]));
108
109
  auto cross_product = LogicalCrossProduct::Create(std::move(join.children[0]), std::move(limit));
109
110
  node_ptr = std::move(cross_product);
@@ -5,6 +5,10 @@
5
5
  namespace duckdb {
6
6
 
7
7
  bool KeywordHelper::IsKeyword(const string &text) {
8
+ return Parser::IsKeyword(text) != KeywordCategory::KEYWORD_NONE;
9
+ }
10
+
11
+ KeywordCategory KeywordHelper::KeywordCategoryType(const string &text) {
8
12
  return Parser::IsKeyword(text);
9
13
  }
10
14