duckdb 0.8.2-dev4871.0 → 0.8.2-dev5080.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 (85) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/extension/icu/icu-strptime.cpp +1 -0
  3. package/src/duckdb/extension/json/json_functions/copy_json.cpp +1 -1
  4. package/src/duckdb/src/common/enum_util.cpp +5 -0
  5. package/src/duckdb/src/common/operator/cast_operators.cpp +18 -0
  6. package/src/duckdb/src/common/row_operations/row_matcher.cpp +5 -38
  7. package/src/duckdb/src/common/types/data_chunk.cpp +47 -10
  8. package/src/duckdb/src/common/types/vector.cpp +0 -1
  9. package/src/duckdb/src/common/types.cpp +10 -1
  10. package/src/duckdb/src/core_functions/scalar/date/strftime.cpp +2 -2
  11. package/src/duckdb/src/core_functions/scalar/list/array_slice.cpp +18 -8
  12. package/src/duckdb/src/core_functions/scalar/list/list_sort.cpp +10 -1
  13. package/src/duckdb/src/core_functions/scalar/map/map_concat.cpp +0 -2
  14. package/src/duckdb/src/core_functions/scalar/struct/struct_pack.cpp +12 -6
  15. package/src/duckdb/src/execution/nested_loop_join/nested_loop_join_inner.cpp +20 -27
  16. package/src/duckdb/src/execution/nested_loop_join/nested_loop_join_mark.cpp +21 -9
  17. package/src/duckdb/src/execution/operator/aggregate/physical_hash_aggregate.cpp +7 -7
  18. package/src/duckdb/src/execution/operator/csv_scanner/csv_reader_options.cpp +1 -1
  19. package/src/duckdb/src/execution/operator/csv_scanner/parallel_csv_reader.cpp +0 -2
  20. package/src/duckdb/src/execution/operator/csv_scanner/sniffer/type_detection.cpp +14 -2
  21. package/src/duckdb/src/execution/operator/persistent/physical_export.cpp +1 -1
  22. package/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp +13 -8
  23. package/src/duckdb/src/function/cast/struct_cast.cpp +8 -0
  24. package/src/duckdb/src/function/cast/time_casts.cpp +12 -0
  25. package/src/duckdb/src/function/cast/union_casts.cpp +5 -0
  26. package/src/duckdb/src/function/function_binder.cpp +11 -2
  27. package/src/duckdb/src/function/pragma/pragma_functions.cpp +5 -0
  28. package/src/duckdb/src/function/pragma/pragma_queries.cpp +3 -0
  29. package/src/duckdb/src/function/scalar/strftime_format.cpp +29 -8
  30. package/src/duckdb/src/function/table/arrow.cpp +4 -0
  31. package/src/duckdb/src/function/table/copy_csv.cpp +2 -1
  32. package/src/duckdb/src/function/table/read_csv.cpp +4 -1
  33. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  34. package/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp +5 -0
  35. package/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp +27 -0
  36. package/src/duckdb/src/include/duckdb/common/operator/comparison_operators.hpp +38 -2
  37. package/src/duckdb/src/include/duckdb/common/types.hpp +1 -0
  38. package/src/duckdb/src/include/duckdb/core_functions/scalar/bit_functions.hpp +4 -4
  39. package/src/duckdb/src/include/duckdb/core_functions/scalar/blob_functions.hpp +4 -4
  40. package/src/duckdb/src/include/duckdb/core_functions/scalar/date_functions.hpp +5 -5
  41. package/src/duckdb/src/include/duckdb/core_functions/scalar/enum_functions.hpp +7 -7
  42. package/src/duckdb/src/include/duckdb/core_functions/scalar/generic_functions.hpp +12 -12
  43. package/src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp +12 -12
  44. package/src/duckdb/src/include/duckdb/core_functions/scalar/map_functions.hpp +3 -3
  45. package/src/duckdb/src/include/duckdb/core_functions/scalar/math_functions.hpp +33 -33
  46. package/src/duckdb/src/include/duckdb/core_functions/scalar/operators_functions.hpp +2 -2
  47. package/src/duckdb/src/include/duckdb/core_functions/scalar/random_functions.hpp +3 -3
  48. package/src/duckdb/src/include/duckdb/core_functions/scalar/string_functions.hpp +12 -12
  49. package/src/duckdb/src/include/duckdb/core_functions/scalar/struct_functions.hpp +2 -2
  50. package/src/duckdb/src/include/duckdb/core_functions/scalar/union_functions.hpp +2 -2
  51. package/src/duckdb/src/include/duckdb/function/scalar/strftime_format.hpp +2 -1
  52. package/src/duckdb/src/include/duckdb/main/client_config.hpp +2 -0
  53. package/src/duckdb/src/include/duckdb/main/prepared_statement_data.hpp +1 -0
  54. package/src/duckdb/src/include/duckdb/planner/bound_parameter_map.hpp +28 -1
  55. package/src/duckdb/src/include/duckdb/planner/expression/bound_parameter_data.hpp +0 -18
  56. package/src/duckdb/src/include/duckdb/planner/expression/bound_parameter_expression.hpp +1 -1
  57. package/src/duckdb/src/include/duckdb/planner/expression_binder/base_select_binder.hpp +1 -0
  58. package/src/duckdb/src/include/duckdb/planner/operator/logical_create_table.hpp +1 -2
  59. package/src/duckdb/src/include/duckdb/planner/operator/logical_delete.hpp +1 -1
  60. package/src/duckdb/src/include/duckdb/planner/operator/logical_insert.hpp +1 -1
  61. package/src/duckdb/src/include/duckdb/planner/operator/logical_update.hpp +1 -1
  62. package/src/duckdb/src/include/duckdb/planner/planner.hpp +1 -1
  63. package/src/duckdb/src/include/duckdb/storage/data_table.hpp +1 -1
  64. package/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp +1 -1
  65. package/src/duckdb/src/main/capi/prepared-c.cpp +9 -3
  66. package/src/duckdb/src/planner/binder/expression/bind_comparison_expression.cpp +1 -0
  67. package/src/duckdb/src/planner/binder/expression/bind_parameter_expression.cpp +9 -19
  68. package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +28 -6
  69. package/src/duckdb/src/planner/binder/statement/bind_drop.cpp +3 -0
  70. package/src/duckdb/src/planner/bound_parameter_map.cpp +67 -0
  71. package/src/duckdb/src/planner/expression_binder/base_select_binder.cpp +14 -6
  72. package/src/duckdb/src/planner/operator/logical_create_table.cpp +3 -3
  73. package/src/duckdb/src/planner/operator/logical_delete.cpp +3 -2
  74. package/src/duckdb/src/planner/operator/logical_insert.cpp +3 -2
  75. package/src/duckdb/src/planner/operator/logical_update.cpp +3 -2
  76. package/src/duckdb/src/planner/planner.cpp +2 -2
  77. package/src/duckdb/src/storage/data_table.cpp +8 -8
  78. package/src/duckdb/src/storage/local_storage.cpp +2 -3
  79. package/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp +64 -80
  80. package/src/duckdb/src/storage/storage_manager.cpp +6 -2
  81. package/src/duckdb/src/storage/table/row_group.cpp +6 -0
  82. package/src/duckdb/src/storage/table/row_group_collection.cpp +4 -3
  83. package/src/duckdb/src/storage/table/struct_column_data.cpp +5 -0
  84. package/src/duckdb/src/transaction/duck_transaction.cpp +1 -0
  85. package/src/duckdb/ub_src_planner.cpp +2 -0
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
4
  "types": "./lib/duckdb.d.ts",
5
- "version": "0.8.2-dev4871.0",
5
+ "version": "0.8.2-dev5080.0",
6
6
  "description": "DuckDB node.js API",
7
7
  "gypfile": true,
8
8
  "dependencies": {
@@ -75,6 +75,7 @@ struct ICUStrptime : public ICUDateFunc {
75
75
  calendar->set(UCAL_MINUTE, parsed.data[4]);
76
76
  calendar->set(UCAL_SECOND, parsed.data[5]);
77
77
  calendar->set(UCAL_MILLISECOND, parsed.data[6] / Interval::MICROS_PER_MSEC);
78
+ micros = parsed.data[6] % Interval::MICROS_PER_MSEC;
78
79
 
79
80
  // This overrides the TZ setting, so only use it if an offset was parsed.
80
81
  // Note that we don't bother/worry about the DST setting because the two just combine.
@@ -101,7 +101,7 @@ static BoundStatement CopyToJSONPlan(Binder &binder, CopyStatement &stmt) {
101
101
  info.options["quote"] = {""};
102
102
  info.options["escape"] = {""};
103
103
  info.options["delimiter"] = {"\n"};
104
- info.options["header"] = {0};
104
+ info.options["header"] = {{0}};
105
105
 
106
106
  return binder.Bind(*stmt_copy);
107
107
  }
@@ -5503,6 +5503,8 @@ const char* EnumUtil::ToChars<StrTimeSpecifier>(StrTimeSpecifier value) {
5503
5503
  return "LOCALE_APPROPRIATE_DATE";
5504
5504
  case StrTimeSpecifier::LOCALE_APPROPRIATE_TIME:
5505
5505
  return "LOCALE_APPROPRIATE_TIME";
5506
+ case StrTimeSpecifier::NANOSECOND_PADDED:
5507
+ return "NANOSECOND_PADDED";
5506
5508
  default:
5507
5509
  throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented", value));
5508
5510
  }
@@ -5606,6 +5608,9 @@ StrTimeSpecifier EnumUtil::FromString<StrTimeSpecifier>(const char *value) {
5606
5608
  if (StringUtil::Equals(value, "LOCALE_APPROPRIATE_TIME")) {
5607
5609
  return StrTimeSpecifier::LOCALE_APPROPRIATE_TIME;
5608
5610
  }
5611
+ if (StringUtil::Equals(value, "NANOSECOND_PADDED")) {
5612
+ return StrTimeSpecifier::NANOSECOND_PADDED;
5613
+ }
5609
5614
  throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented", value));
5610
5615
  }
5611
5616
 
@@ -1373,6 +1373,12 @@ timestamp_t CastTimestampMsToUs::Operation(timestamp_t input) {
1373
1373
  return Timestamp::FromEpochMs(input.value);
1374
1374
  }
1375
1375
 
1376
+ template <>
1377
+ timestamp_t CastTimestampMsToNs::Operation(timestamp_t input) {
1378
+ auto us = CastTimestampMsToUs::Operation<timestamp_t, timestamp_t>(input);
1379
+ return CastTimestampUsToNs::Operation<timestamp_t, timestamp_t>(us);
1380
+ }
1381
+
1376
1382
  template <>
1377
1383
  timestamp_t CastTimestampNsToUs::Operation(timestamp_t input) {
1378
1384
  return Timestamp::FromEpochNanoSeconds(input.value);
@@ -1383,6 +1389,18 @@ timestamp_t CastTimestampSecToUs::Operation(timestamp_t input) {
1383
1389
  return Timestamp::FromEpochSeconds(input.value);
1384
1390
  }
1385
1391
 
1392
+ template <>
1393
+ timestamp_t CastTimestampSecToMs::Operation(timestamp_t input) {
1394
+ auto us = CastTimestampSecToUs::Operation<timestamp_t, timestamp_t>(input);
1395
+ return CastTimestampUsToMs::Operation<timestamp_t, timestamp_t>(us);
1396
+ }
1397
+
1398
+ template <>
1399
+ timestamp_t CastTimestampSecToNs::Operation(timestamp_t input) {
1400
+ auto us = CastTimestampSecToUs::Operation<timestamp_t, timestamp_t>(input);
1401
+ return CastTimestampUsToNs::Operation<timestamp_t, timestamp_t>(us);
1402
+ }
1403
+
1386
1404
  //===--------------------------------------------------------------------===//
1387
1405
  // Cast To Timestamp
1388
1406
  //===--------------------------------------------------------------------===//
@@ -8,44 +8,11 @@ namespace duckdb {
8
8
 
9
9
  using ValidityBytes = TupleDataLayout::ValidityBytes;
10
10
 
11
- template <class OP>
12
- struct RowMatchOperator {
13
- static constexpr const bool COMPARE_NULL = false;
14
-
15
- template <class T>
16
- static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
17
- if (right_null || left_null) {
18
- return false;
19
- }
20
- return OP::template Operation<T>(left, right);
21
- }
22
- };
23
-
24
- template <>
25
- struct RowMatchOperator<DistinctFrom> {
26
- static constexpr const bool COMPARE_NULL = true;
27
-
28
- template <class T>
29
- static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
30
- return DistinctFrom::template Operation<T>(left, right, left_null, right_null);
31
- }
32
- };
33
-
34
- template <>
35
- struct RowMatchOperator<NotDistinctFrom> {
36
- static constexpr const bool COMPARE_NULL = true;
37
-
38
- template <class T>
39
- static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) {
40
- return NotDistinctFrom::template Operation<T>(left, right, left_null, right_null);
41
- }
42
- };
43
-
44
11
  template <bool NO_MATCH_SEL, class T, class OP>
45
12
  static idx_t TemplatedMatch(Vector &, const TupleDataVectorFormat &lhs_format, SelectionVector &sel, const idx_t count,
46
13
  const TupleDataLayout &rhs_layout, Vector &rhs_row_locations, const idx_t col_idx,
47
14
  const vector<MatchFunction> &, SelectionVector *no_match_sel, idx_t &no_match_count) {
48
- using MATCH_OP = RowMatchOperator<OP>;
15
+ using COMPARISON_OP = ComparisonOperationWrapper<OP>;
49
16
 
50
17
  // LHS
51
18
  const auto &lhs_sel = *lhs_format.unified.sel;
@@ -70,8 +37,8 @@ static idx_t TemplatedMatch(Vector &, const TupleDataVectorFormat &lhs_format, S
70
37
  const ValidityBytes rhs_mask(rhs_location);
71
38
  const auto rhs_null = !rhs_mask.RowIsValid(rhs_mask.GetValidityEntryUnsafe(entry_idx), idx_in_entry);
72
39
 
73
- if (MATCH_OP::template Operation<T>(lhs_data[lhs_idx], Load<T>(rhs_location + rhs_offset_in_row), lhs_null,
74
- rhs_null)) {
40
+ if (COMPARISON_OP::template Operation<T>(lhs_data[lhs_idx], Load<T>(rhs_location + rhs_offset_in_row), lhs_null,
41
+ rhs_null)) {
75
42
  sel.set_index(match_count++, idx);
76
43
  } else if (NO_MATCH_SEL) {
77
44
  no_match_sel->set_index(no_match_count++, idx);
@@ -85,7 +52,7 @@ static idx_t StructMatchEquality(Vector &lhs_vector, const TupleDataVectorFormat
85
52
  const idx_t count, const TupleDataLayout &rhs_layout, Vector &rhs_row_locations,
86
53
  const idx_t col_idx, const vector<MatchFunction> &child_functions,
87
54
  SelectionVector *no_match_sel, idx_t &no_match_count) {
88
- using MATCH_OP = RowMatchOperator<OP>;
55
+ using COMPARISON_OP = ComparisonOperationWrapper<OP>;
89
56
 
90
57
  // LHS
91
58
  const auto &lhs_sel = *lhs_format.unified.sel;
@@ -111,7 +78,7 @@ static idx_t StructMatchEquality(Vector &lhs_vector, const TupleDataVectorFormat
111
78
  // For structs there is no value to compare, here we match NULLs and let recursion do the rest
112
79
  // So we use the comparison only if rhs or LHS is NULL and COMPARE_NULL is true
113
80
  if (!(lhs_null || rhs_null) ||
114
- (MATCH_OP::COMPARE_NULL && MATCH_OP::template Operation<uint32_t>(0, 0, lhs_null, rhs_null))) {
81
+ (COMPARISON_OP::COMPARE_NULL && COMPARISON_OP::template Operation<uint32_t>(0, 0, lhs_null, rhs_null))) {
115
82
  sel.set_index(match_count++, idx);
116
83
  } else if (NO_MATCH_SEL) {
117
84
  no_match_sel->set_index(no_match_count++, idx);
@@ -13,6 +13,10 @@
13
13
  #include "duckdb/common/vector_operations/vector_operations.hpp"
14
14
  #include "duckdb/execution/execution_context.hpp"
15
15
 
16
+ #include "duckdb/common/serializer/memory_stream.hpp"
17
+ #include "duckdb/common/serializer/binary_serializer.hpp"
18
+ #include "duckdb/common/serializer/binary_deserializer.hpp"
19
+
16
20
  namespace duckdb {
17
21
 
18
22
  DataChunk::DataChunk() : count(0), capacity(STANDARD_VECTOR_SIZE) {
@@ -231,16 +235,20 @@ string DataChunk::ToString() const {
231
235
  }
232
236
 
233
237
  void DataChunk::Serialize(Serializer &serializer) const {
238
+
234
239
  // write the count
235
240
  auto row_count = size();
236
241
  serializer.WriteProperty<sel_t>(100, "rows", row_count);
242
+
243
+ // we should never try to serialize empty data chunks
237
244
  auto column_count = ColumnCount();
245
+ D_ASSERT(column_count);
238
246
 
239
- // Write the types
247
+ // write the types
240
248
  serializer.WriteList(101, "types", column_count,
241
249
  [&](Serializer::List &list, idx_t i) { list.WriteElement(data[i].GetType()); });
242
250
 
243
- // Write the data
251
+ // write the data
244
252
  serializer.WriteList(102, "columns", column_count, [&](Serializer::List &list, idx_t i) {
245
253
  list.WriteObject([&](Serializer &object) {
246
254
  // Reference the vector to avoid potentially mutating it during serialization
@@ -252,21 +260,23 @@ void DataChunk::Serialize(Serializer &serializer) const {
252
260
  }
253
261
 
254
262
  void DataChunk::Deserialize(Deserializer &deserializer) {
255
- // read the count
263
+
264
+ // read and set the row count
256
265
  auto row_count = deserializer.ReadProperty<sel_t>(100, "rows");
257
266
 
258
- // Read the types
267
+ // read the types
259
268
  vector<LogicalType> types;
260
269
  deserializer.ReadList(101, "types", [&](Deserializer::List &list, idx_t i) {
261
270
  auto type = list.ReadElement<LogicalType>();
262
271
  types.push_back(type);
263
272
  });
264
- Initialize(Allocator::DefaultAllocator(), types);
265
273
 
266
- // now load the column data
274
+ // initialize the data chunk
275
+ D_ASSERT(!types.empty());
276
+ Initialize(Allocator::DefaultAllocator(), types);
267
277
  SetCardinality(row_count);
268
278
 
269
- // Read the data
279
+ // read the data
270
280
  deserializer.ReadList(102, "columns", [&](Deserializer::List &list, idx_t i) {
271
281
  list.ReadObject([&](Deserializer &object) { data[i].Deserialize(object, row_count); });
272
282
  });
@@ -296,11 +306,11 @@ void DataChunk::Slice(DataChunk &other, const SelectionVector &sel, idx_t count_
296
306
  }
297
307
 
298
308
  unsafe_unique_array<UnifiedVectorFormat> DataChunk::ToUnifiedFormat() {
299
- auto orrified_data = make_unsafe_uniq_array<UnifiedVectorFormat>(ColumnCount());
309
+ auto unified_data = make_unsafe_uniq_array<UnifiedVectorFormat>(ColumnCount());
300
310
  for (idx_t col_idx = 0; col_idx < ColumnCount(); col_idx++) {
301
- data[col_idx].ToUnifiedFormat(size(), orrified_data[col_idx]);
311
+ data[col_idx].ToUnifiedFormat(size(), unified_data[col_idx]);
302
312
  }
303
- return orrified_data;
313
+ return unified_data;
304
314
  }
305
315
 
306
316
  void DataChunk::Hash(Vector &result) {
@@ -324,10 +334,37 @@ void DataChunk::Hash(vector<idx_t> &column_ids, Vector &result) {
324
334
  void DataChunk::Verify() {
325
335
  #ifdef DEBUG
326
336
  D_ASSERT(size() <= capacity);
337
+
327
338
  // verify that all vectors in this chunk have the chunk selection vector
328
339
  for (idx_t i = 0; i < ColumnCount(); i++) {
329
340
  data[i].Verify(size());
330
341
  }
342
+
343
+ if (!ColumnCount()) {
344
+ // don't try to round-trip dummy data chunks with no data
345
+ // e.g., these exist in queries like 'SELECT distinct(col0, col1) FROM tbl', where we have groups, but no
346
+ // payload so the payload will be such an empty data chunk
347
+ return;
348
+ }
349
+
350
+ // verify that we can round-trip chunk serialization
351
+ MemoryStream mem_stream;
352
+ BinarySerializer serializer(mem_stream);
353
+
354
+ serializer.Begin();
355
+ Serialize(serializer);
356
+ serializer.End();
357
+
358
+ mem_stream.Rewind();
359
+
360
+ BinaryDeserializer deserializer(mem_stream);
361
+ DataChunk new_chunk;
362
+
363
+ deserializer.Begin();
364
+ new_chunk.Deserialize(deserializer);
365
+ deserializer.End();
366
+
367
+ D_ASSERT(size() == new_chunk.size());
331
368
  #endif
332
369
  }
333
370
 
@@ -960,7 +960,6 @@ void Vector::Serialize(Serializer &serializer, idx_t count) {
960
960
  break;
961
961
  }
962
962
  case PhysicalType::STRUCT: {
963
- Flatten(count);
964
963
  auto &entries = StructVector::GetEntries(*this);
965
964
 
966
965
  // Serialize entries as a list
@@ -434,7 +434,7 @@ LogicalType TransformStringToLogicalType(const string &str) {
434
434
 
435
435
  LogicalType GetUserTypeRecursive(const LogicalType &type, ClientContext &context) {
436
436
  if (type.id() == LogicalTypeId::USER && type.HasAlias()) {
437
- return Catalog::GetSystemCatalog(context).GetType(context, SYSTEM_CATALOG, DEFAULT_SCHEMA, type.GetAlias());
437
+ return Catalog::GetType(context, INVALID_CATALOG, INVALID_SCHEMA, type.GetAlias());
438
438
  }
439
439
  // Look for LogicalTypeId::USER in nested types
440
440
  if (type.id() == LogicalTypeId::STRUCT) {
@@ -659,6 +659,10 @@ LogicalType LogicalType::MaxLogicalType(const LogicalType &left, const LogicalTy
659
659
  return right;
660
660
  } else if (right.id() == LogicalTypeId::UNKNOWN) {
661
661
  return left;
662
+ } else if ((right.id() == LogicalTypeId::ENUM || left.id() == LogicalTypeId::ENUM) && right.id() != left.id()) {
663
+ // if one is an enum and the other is not, compare strings, not enums
664
+ // see https://github.com/duckdb/duckdb/issues/8561
665
+ return LogicalTypeId::VARCHAR;
662
666
  } else if (left.id() < right.id()) {
663
667
  return right;
664
668
  }
@@ -911,6 +915,11 @@ const string &StructType::GetChildName(const LogicalType &type, idx_t index) {
911
915
  idx_t StructType::GetChildCount(const LogicalType &type) {
912
916
  return StructType::GetChildTypes(type).size();
913
917
  }
918
+ bool StructType::IsUnnamed(const LogicalType &type) {
919
+ auto &child_types = StructType::GetChildTypes(type);
920
+ D_ASSERT(child_types.size() > 0);
921
+ return child_types[0].first.empty();
922
+ }
914
923
 
915
924
  LogicalType LogicalType::STRUCT(child_list_t<LogicalType> children) {
916
925
  auto info = make_shared<StructTypeInfo>(std::move(children));
@@ -183,7 +183,7 @@ struct StrpTimeFunction {
183
183
  auto &func_expr = state.expr.Cast<BoundFunctionExpression>();
184
184
  auto &info = func_expr.bind_info->Cast<StrpTimeBindData>();
185
185
 
186
- if (ConstantVector::IsNull(args.data[1])) {
186
+ if (args.data[1].GetVectorType() == VectorType::CONSTANT_VECTOR && ConstantVector::IsNull(args.data[1])) {
187
187
  result.SetVectorType(VectorType::CONSTANT_VECTOR);
188
188
  ConstantVector::SetNull(result, true);
189
189
  return;
@@ -203,7 +203,7 @@ struct StrpTimeFunction {
203
203
  auto &func_expr = state.expr.Cast<BoundFunctionExpression>();
204
204
  auto &info = func_expr.bind_info->Cast<StrpTimeBindData>();
205
205
 
206
- if (ConstantVector::IsNull(args.data[1])) {
206
+ if (args.data[1].GetVectorType() == VectorType::CONSTANT_VECTOR && ConstantVector::IsNull(args.data[1])) {
207
207
  result.SetVectorType(VectorType::CONSTANT_VECTOR);
208
208
  ConstantVector::SetNull(result, true);
209
209
  return;
@@ -191,9 +191,11 @@ static void ExecuteConstantSlice(Vector &result, Vector &str_vector, Vector &beg
191
191
  }
192
192
 
193
193
  auto sel_length = 0;
194
+ bool sel_valid = false;
194
195
  if (step_vector && step_valid && str_valid && begin_valid && end_valid && step != 1 && end - begin > 0) {
195
196
  sel_length = CalculateSliceLength(begin, end, step, step_valid);
196
197
  sel.Initialize(sel_length);
198
+ sel_valid = true;
197
199
  }
198
200
 
199
201
  // Try to slice
@@ -205,8 +207,9 @@ static void ExecuteConstantSlice(Vector &result, Vector &str_vector, Vector &beg
205
207
  result_data[0] = SliceValueWithSteps<INPUT_TYPE, INDEX_TYPE>(result, sel, str, begin, end, step, sel_idx);
206
208
  }
207
209
 
208
- if (step_vector && step != 0 && end - begin > 0) {
210
+ if (sel_valid) {
209
211
  result_child_vector->Slice(sel, sel_length);
212
+ ListVector::SetListSize(result, sel_length);
210
213
  }
211
214
  }
212
215
 
@@ -234,6 +237,16 @@ static void ExecuteFlatSlice(Vector &result, Vector &list_vector, Vector &begin_
234
237
  auto end_idx = end_data.sel->get_index(i);
235
238
  auto step_idx = step_vector ? step_data.sel->get_index(i) : 0;
236
239
 
240
+ auto list_valid = list_data.validity.RowIsValid(list_idx);
241
+ auto begin_valid = begin_data.validity.RowIsValid(begin_idx);
242
+ auto end_valid = end_data.validity.RowIsValid(end_idx);
243
+ auto step_valid = step_vector && step_data.validity.RowIsValid(step_idx);
244
+
245
+ if (!list_valid || !begin_valid || !end_valid || (step_vector && !step_valid)) {
246
+ result_mask.SetInvalid(i);
247
+ continue;
248
+ }
249
+
237
250
  auto sliced = reinterpret_cast<INPUT_TYPE *>(list_data.data)[list_idx];
238
251
  auto begin = begin_is_empty ? 0 : reinterpret_cast<INDEX_TYPE *>(begin_data.data)[begin_idx];
239
252
  auto end = end_is_empty ? ValueLength<INPUT_TYPE, INDEX_TYPE>(sliced)
@@ -245,23 +258,19 @@ static void ExecuteFlatSlice(Vector &result, Vector &list_vector, Vector &begin_
245
258
  begin = end_is_empty ? 0 : begin;
246
259
  end = begin_is_empty ? ValueLength<INPUT_TYPE, INDEX_TYPE>(sliced) : end;
247
260
  }
248
- auto list_valid = list_data.validity.RowIsValid(list_idx);
249
- auto begin_valid = begin_data.validity.RowIsValid(begin_idx);
250
- auto end_valid = end_data.validity.RowIsValid(end_idx);
251
- auto step_valid = step_vector && step_data.validity.RowIsValid(step_idx);
252
261
 
253
262
  bool clamp_result = false;
254
- if (list_valid && begin_valid && end_valid && (step_valid || step == 1)) {
263
+ if (step_valid || step == 1) {
255
264
  clamp_result = ClampSlice(sliced, begin, end);
256
265
  }
257
266
 
258
267
  auto length = 0;
259
- if (step_vector && step_valid && list_valid && begin_valid && end_valid && end - begin > 0) {
268
+ if (end - begin > 0) {
260
269
  length = CalculateSliceLength(begin, end, step, step_valid);
261
270
  }
262
271
  sel_length += length;
263
272
 
264
- if (!list_valid || !begin_valid || !end_valid || (step_vector && !step_valid) || !clamp_result) {
273
+ if (!clamp_result) {
265
274
  result_mask.SetInvalid(i);
266
275
  } else if (!step_vector) {
267
276
  result_data[i] = SliceValue<INPUT_TYPE, INDEX_TYPE>(result, sliced, begin, end);
@@ -276,6 +285,7 @@ static void ExecuteFlatSlice(Vector &result, Vector &list_vector, Vector &begin_
276
285
  new_sel.set_index(i, sel.get_index(i));
277
286
  }
278
287
  result_child_vector->Slice(new_sel, sel_length);
288
+ ListVector::SetListSize(result, sel_length);
279
289
  }
280
290
  }
281
291
 
@@ -236,9 +236,18 @@ static void ListSortFunction(DataChunk &args, ExpressionState &state, Vector &re
236
236
  static unique_ptr<FunctionData> ListSortBind(ClientContext &context, ScalarFunction &bound_function,
237
237
  vector<unique_ptr<Expression>> &arguments, OrderType &order,
238
238
  OrderByNullType &null_order) {
239
+
240
+ LogicalType child_type;
241
+ if (arguments[0]->return_type == LogicalTypeId::UNKNOWN) {
242
+ bound_function.arguments[0] = LogicalTypeId::UNKNOWN;
243
+ bound_function.return_type = LogicalType::SQLNULL;
244
+ child_type = bound_function.return_type;
245
+ return make_uniq<ListSortBindData>(order, null_order, bound_function.return_type, child_type, context);
246
+ }
247
+
239
248
  bound_function.arguments[0] = arguments[0]->return_type;
240
249
  bound_function.return_type = arguments[0]->return_type;
241
- auto child_type = ListType::GetChildType(arguments[0]->return_type);
250
+ child_type = ListType::GetChildType(arguments[0]->return_type);
242
251
 
243
252
  return make_uniq<ListSortBindData>(order, null_order, bound_function.return_type, child_type, context);
244
253
  }
@@ -97,7 +97,6 @@ static void MapConcatFunction(DataChunk &args, ExpressionState &state, Vector &r
97
97
  auto &values = MapVector::GetValues(map);
98
98
  values_list.push_back(values.GetValue(mapping.key_index));
99
99
  }
100
- idx_t entries_count = keys_list.size();
101
100
  D_ASSERT(values_list.size() == keys_list.size());
102
101
  result_entry.offset = ListVector::GetListSize(result);
103
102
  result_entry.length = values_list.size();
@@ -105,7 +104,6 @@ static void MapConcatFunction(DataChunk &args, ExpressionState &state, Vector &r
105
104
  for (auto &list_entry : list_entries) {
106
105
  ListVector::PushBack(result, list_entry);
107
106
  }
108
- ListVector::SetListSize(result, ListVector::GetListSize(result) + entries_count);
109
107
  }
110
108
 
111
109
  if (args.AllConstant()) {
@@ -39,15 +39,21 @@ static unique_ptr<FunctionData> StructPackBind(ClientContext &context, ScalarFun
39
39
  throw Exception("Can't pack nothing into a struct");
40
40
  }
41
41
  child_list_t<LogicalType> struct_children;
42
+ bool unnamed = false;
42
43
  for (idx_t i = 0; i < arguments.size(); i++) {
43
44
  auto &child = arguments[i];
44
- if (child->alias.empty() && bound_function.name == "struct_pack") {
45
- throw BinderException("Need named argument for struct pack, e.g. STRUCT_PACK(a := b)");
45
+ if (child->alias.empty()) {
46
+ if (bound_function.name == "struct_pack") {
47
+ throw BinderException("Need named argument for struct pack, e.g. STRUCT_PACK(a := b)");
48
+ } else {
49
+ D_ASSERT(bound_function.name == "row");
50
+ if (i > 1) {
51
+ D_ASSERT(unnamed);
52
+ }
53
+ unnamed = true;
54
+ }
46
55
  }
47
- if (child->alias.empty() && bound_function.name == "row") {
48
- child->alias = "v" + std::to_string(i + 1);
49
- }
50
- if (name_collision_set.find(child->alias) != name_collision_set.end()) {
56
+ if (!child->alias.empty() && name_collision_set.find(child->alias) != name_collision_set.end()) {
51
57
  throw BinderException("Duplicate struct entry name \"%s\"", child->alias);
52
58
  }
53
59
  name_collision_set.insert(child->alias);
@@ -3,21 +3,12 @@
3
3
 
4
4
  namespace duckdb {
5
5
 
6
- template <class OP>
7
- struct ComparisonOperationWrapper {
8
- template <class T>
9
- static inline bool Operation(T left, T right, bool left_is_null, bool right_is_null) {
10
- if (left_is_null || right_is_null) {
11
- return false;
12
- }
13
- return OP::Operation(left, right);
14
- }
15
- };
16
-
17
6
  struct InitialNestedLoopJoin {
18
7
  template <class T, class OP>
19
8
  static idx_t Operation(Vector &left, Vector &right, idx_t left_size, idx_t right_size, idx_t &lpos, idx_t &rpos,
20
9
  SelectionVector &lvector, SelectionVector &rvector, idx_t current_match_count) {
10
+ using MATCH_OP = ComparisonOperationWrapper<OP>;
11
+
21
12
  // initialize phase of nested loop join
22
13
  // fill lvector and rvector with matches from the base vectors
23
14
  UnifiedVectorFormat left_data, right_data;
@@ -37,7 +28,7 @@ struct InitialNestedLoopJoin {
37
28
  }
38
29
  idx_t left_position = left_data.sel->get_index(lpos);
39
30
  bool left_is_valid = left_data.validity.RowIsValid(left_position);
40
- if (OP::Operation(ldata[left_position], rdata[right_position], !left_is_valid, !right_is_valid)) {
31
+ if (MATCH_OP::Operation(ldata[left_position], rdata[right_position], !left_is_valid, !right_is_valid)) {
41
32
  // emit tuple
42
33
  lvector.set_index(result_count, lpos);
43
34
  rvector.set_index(result_count, rpos);
@@ -54,6 +45,8 @@ struct RefineNestedLoopJoin {
54
45
  template <class T, class OP>
55
46
  static idx_t Operation(Vector &left, Vector &right, idx_t left_size, idx_t right_size, idx_t &lpos, idx_t &rpos,
56
47
  SelectionVector &lvector, SelectionVector &rvector, idx_t current_match_count) {
48
+ using MATCH_OP = ComparisonOperationWrapper<OP>;
49
+
57
50
  UnifiedVectorFormat left_data, right_data;
58
51
  left.ToUnifiedFormat(left_size, left_data);
59
52
  right.ToUnifiedFormat(right_size, right_data);
@@ -72,7 +65,7 @@ struct RefineNestedLoopJoin {
72
65
  auto right_idx = right_data.sel->get_index(ridx);
73
66
  bool left_is_valid = left_data.validity.RowIsValid(left_idx);
74
67
  bool right_is_valid = right_data.validity.RowIsValid(right_idx);
75
- if (OP::Operation(ldata[left_idx], rdata[right_idx], !left_is_valid, !right_is_valid)) {
68
+ if (MATCH_OP::Operation(ldata[left_idx], rdata[right_idx], !left_is_valid, !right_is_valid)) {
76
69
  lvector.set_index(result_count, lidx);
77
70
  rvector.set_index(result_count, ridx);
78
71
  result_count++;
@@ -139,26 +132,26 @@ idx_t NestedLoopJoinComparisonSwitch(Vector &left, Vector &right, idx_t left_siz
139
132
  D_ASSERT(left.GetType() == right.GetType());
140
133
  switch (comparison_type) {
141
134
  case ExpressionType::COMPARE_EQUAL:
142
- return NestedLoopJoinTypeSwitch<NLTYPE, ComparisonOperationWrapper<duckdb::Equals>>(
143
- left, right, left_size, right_size, lpos, rpos, lvector, rvector, current_match_count);
135
+ return NestedLoopJoinTypeSwitch<NLTYPE, Equals>(left, right, left_size, right_size, lpos, rpos, lvector,
136
+ rvector, current_match_count);
144
137
  case ExpressionType::COMPARE_NOTEQUAL:
145
- return NestedLoopJoinTypeSwitch<NLTYPE, ComparisonOperationWrapper<duckdb::NotEquals>>(
146
- left, right, left_size, right_size, lpos, rpos, lvector, rvector, current_match_count);
138
+ return NestedLoopJoinTypeSwitch<NLTYPE, NotEquals>(left, right, left_size, right_size, lpos, rpos, lvector,
139
+ rvector, current_match_count);
147
140
  case ExpressionType::COMPARE_LESSTHAN:
148
- return NestedLoopJoinTypeSwitch<NLTYPE, ComparisonOperationWrapper<duckdb::LessThan>>(
149
- left, right, left_size, right_size, lpos, rpos, lvector, rvector, current_match_count);
141
+ return NestedLoopJoinTypeSwitch<NLTYPE, LessThan>(left, right, left_size, right_size, lpos, rpos, lvector,
142
+ rvector, current_match_count);
150
143
  case ExpressionType::COMPARE_GREATERTHAN:
151
- return NestedLoopJoinTypeSwitch<NLTYPE, ComparisonOperationWrapper<duckdb::GreaterThan>>(
152
- left, right, left_size, right_size, lpos, rpos, lvector, rvector, current_match_count);
144
+ return NestedLoopJoinTypeSwitch<NLTYPE, GreaterThan>(left, right, left_size, right_size, lpos, rpos, lvector,
145
+ rvector, current_match_count);
153
146
  case ExpressionType::COMPARE_LESSTHANOREQUALTO:
154
- return NestedLoopJoinTypeSwitch<NLTYPE, ComparisonOperationWrapper<duckdb::LessThanEquals>>(
155
- left, right, left_size, right_size, lpos, rpos, lvector, rvector, current_match_count);
147
+ return NestedLoopJoinTypeSwitch<NLTYPE, LessThanEquals>(left, right, left_size, right_size, lpos, rpos, lvector,
148
+ rvector, current_match_count);
156
149
  case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
157
- return NestedLoopJoinTypeSwitch<NLTYPE, ComparisonOperationWrapper<duckdb::GreaterThanEquals>>(
158
- left, right, left_size, right_size, lpos, rpos, lvector, rvector, current_match_count);
150
+ return NestedLoopJoinTypeSwitch<NLTYPE, GreaterThanEquals>(left, right, left_size, right_size, lpos, rpos,
151
+ lvector, rvector, current_match_count);
159
152
  case ExpressionType::COMPARE_DISTINCT_FROM:
160
- return NestedLoopJoinTypeSwitch<NLTYPE, duckdb::DistinctFrom>(left, right, left_size, right_size, lpos, rpos,
161
- lvector, rvector, current_match_count);
153
+ return NestedLoopJoinTypeSwitch<NLTYPE, DistinctFrom>(left, right, left_size, right_size, lpos, rpos, lvector,
154
+ rvector, current_match_count);
162
155
  default:
163
156
  throw NotImplementedException("Unimplemented comparison type for join!");
164
157
  }
@@ -6,6 +6,8 @@ namespace duckdb {
6
6
 
7
7
  template <class T, class OP>
8
8
  static void TemplatedMarkJoin(Vector &left, Vector &right, idx_t lcount, idx_t rcount, bool found_match[]) {
9
+ using MATCH_OP = ComparisonOperationWrapper<OP>;
10
+
9
11
  UnifiedVectorFormat left_data, right_data;
10
12
  left.ToUnifiedFormat(lcount, left_data);
11
13
  right.ToUnifiedFormat(rcount, right_data);
@@ -17,15 +19,17 @@ static void TemplatedMarkJoin(Vector &left, Vector &right, idx_t lcount, idx_t r
17
19
  continue;
18
20
  }
19
21
  auto lidx = left_data.sel->get_index(i);
20
- if (!left_data.validity.RowIsValid(lidx)) {
22
+ const auto left_null = !left_data.validity.RowIsValid(lidx);
23
+ if (!MATCH_OP::COMPARE_NULL && left_null) {
21
24
  continue;
22
25
  }
23
26
  for (idx_t j = 0; j < rcount; j++) {
24
27
  auto ridx = right_data.sel->get_index(j);
25
- if (!right_data.validity.RowIsValid(ridx)) {
28
+ const auto right_null = !right_data.validity.RowIsValid(ridx);
29
+ if (!MATCH_OP::COMPARE_NULL && right_null) {
26
30
  continue;
27
31
  }
28
- if (OP::Operation(ldata[lidx], rdata[ridx])) {
32
+ if (MATCH_OP::template Operation<T>(ldata[lidx], rdata[ridx], left_null, right_null)) {
29
33
  found_match[i] = true;
30
34
  break;
31
35
  }
@@ -62,6 +66,12 @@ static void MarkJoinNested(Vector &left, Vector &right, idx_t lcount, idx_t rcou
62
66
  case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
63
67
  count = VectorOperations::GreaterThanEquals(left_reference, right, nullptr, rcount, nullptr, nullptr);
64
68
  break;
69
+ case ExpressionType::COMPARE_DISTINCT_FROM:
70
+ count = VectorOperations::DistinctFrom(left_reference, right, nullptr, rcount, nullptr, nullptr);
71
+ break;
72
+ case ExpressionType::COMPARE_NOT_DISTINCT_FROM:
73
+ count = VectorOperations::NotDistinctFrom(left_reference, right, nullptr, rcount, nullptr, nullptr);
74
+ break;
65
75
  default:
66
76
  throw InternalException("Unsupported comparison type for MarkJoinNested");
67
77
  }
@@ -116,17 +126,19 @@ static void MarkJoinComparisonSwitch(Vector &left, Vector &right, idx_t lcount,
116
126
  D_ASSERT(left.GetType() == right.GetType());
117
127
  switch (comparison_type) {
118
128
  case ExpressionType::COMPARE_EQUAL:
119
- return MarkJoinSwitch<duckdb::Equals>(left, right, lcount, rcount, found_match);
129
+ return MarkJoinSwitch<Equals>(left, right, lcount, rcount, found_match);
120
130
  case ExpressionType::COMPARE_NOTEQUAL:
121
- return MarkJoinSwitch<duckdb::NotEquals>(left, right, lcount, rcount, found_match);
131
+ return MarkJoinSwitch<NotEquals>(left, right, lcount, rcount, found_match);
122
132
  case ExpressionType::COMPARE_LESSTHAN:
123
- return MarkJoinSwitch<duckdb::LessThan>(left, right, lcount, rcount, found_match);
133
+ return MarkJoinSwitch<LessThan>(left, right, lcount, rcount, found_match);
124
134
  case ExpressionType::COMPARE_GREATERTHAN:
125
- return MarkJoinSwitch<duckdb::GreaterThan>(left, right, lcount, rcount, found_match);
135
+ return MarkJoinSwitch<GreaterThan>(left, right, lcount, rcount, found_match);
126
136
  case ExpressionType::COMPARE_LESSTHANOREQUALTO:
127
- return MarkJoinSwitch<duckdb::LessThanEquals>(left, right, lcount, rcount, found_match);
137
+ return MarkJoinSwitch<LessThanEquals>(left, right, lcount, rcount, found_match);
128
138
  case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
129
- return MarkJoinSwitch<duckdb::GreaterThanEquals>(left, right, lcount, rcount, found_match);
139
+ return MarkJoinSwitch<GreaterThanEquals>(left, right, lcount, rcount, found_match);
140
+ case ExpressionType::COMPARE_DISTINCT_FROM:
141
+ return MarkJoinSwitch<DistinctFrom>(left, right, lcount, rcount, found_match);
130
142
  default:
131
143
  throw NotImplementedException("Unimplemented comparison type for join!");
132
144
  }