duckdb 0.3.1-dev511.0 → 0.3.1-dev532.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
- "version": "0.3.1-dev511.0",
4
+ "version": "0.3.1-dev532.0",
5
5
  "description": "DuckDB node.js API",
6
6
  "gypfile": true,
7
7
  "dependencies": {
package/src/duckdb.cpp CHANGED
@@ -9435,7 +9435,11 @@ static DefaultMacro internal_macros[] = {
9435
9435
  {DEFAULT_SCHEMA, "round_even", {"x", "n", nullptr}, "CASE ((abs(x) * power(10, n+1)) % 10) WHEN 5 THEN round(x/2, n) * 2 ELSE round(x, n) END"},
9436
9436
  {DEFAULT_SCHEMA, "roundbankers", {"x", "n", nullptr}, "round_even(x, n)"},
9437
9437
  {DEFAULT_SCHEMA, "nullif", {"a", "b", nullptr}, "CASE WHEN a=b THEN NULL ELSE a END"},
9438
- {nullptr, nullptr, {nullptr}, nullptr}};
9438
+ {DEFAULT_SCHEMA, "list_append", {"l", "e", nullptr}, "list_concat(l, list_value(e))"},
9439
+ {DEFAULT_SCHEMA, "array_append", {"arr", "el", nullptr}, "list_append(arr, el)"},
9440
+ {DEFAULT_SCHEMA, "list_prepend", {"e", "l", nullptr}, "list_concat(list_value(e), l)"},
9441
+ {DEFAULT_SCHEMA, "array_prepend", {"el", "arr", nullptr}, "list_prepend(el, arr)"},
9442
+ {nullptr, nullptr, {nullptr}, nullptr}};
9439
9443
 
9440
9444
  static unique_ptr<CreateFunctionInfo> GetDefaultFunction(const string &schema, const string &name) {
9441
9445
  for (idx_t index = 0; internal_macros[index].name != nullptr; index++) {
@@ -9897,10 +9901,11 @@ public:
9897
9901
 
9898
9902
  class ResultArrowArrayStreamWrapper {
9899
9903
  public:
9900
- explicit ResultArrowArrayStreamWrapper(unique_ptr<QueryResult> result);
9904
+ explicit ResultArrowArrayStreamWrapper(unique_ptr<QueryResult> result, idx_t approx_batch_size);
9901
9905
  ArrowArrayStream stream;
9902
9906
  unique_ptr<QueryResult> result;
9903
9907
  std::string last_error;
9908
+ idx_t vectors_per_chunk;
9904
9909
 
9905
9910
  private:
9906
9911
  static int MyStreamGetSchema(struct ArrowArrayStream *stream, struct ArrowSchema *out);
@@ -10017,13 +10022,21 @@ int ResultArrowArrayStreamWrapper::MyStreamGetNext(struct ArrowArrayStream *stre
10017
10022
  return -1;
10018
10023
  }
10019
10024
  }
10020
- auto data_chunk = result.Fetch();
10021
- if (!data_chunk) {
10022
- //! Nothing to output
10025
+ unique_ptr<DataChunk> chunk_result = result.Fetch();
10026
+ if (!chunk_result) {
10027
+ // Nothing to output
10023
10028
  out->release = nullptr;
10024
10029
  return 0;
10025
10030
  }
10026
- data_chunk->ToArrowArray(out);
10031
+ for (idx_t i = 1; i < my_stream->vectors_per_chunk; i++) {
10032
+ auto new_chunk = result.Fetch();
10033
+ if (!new_chunk) {
10034
+ break;
10035
+ } else {
10036
+ chunk_result->Append(*new_chunk, true);
10037
+ }
10038
+ }
10039
+ chunk_result->ToArrowArray(out);
10027
10040
  return 0;
10028
10041
  }
10029
10042
 
@@ -10043,11 +10056,15 @@ const char *ResultArrowArrayStreamWrapper::MyStreamGetLastError(struct ArrowArra
10043
10056
  auto my_stream = (ResultArrowArrayStreamWrapper *)stream->private_data;
10044
10057
  return my_stream->last_error.c_str();
10045
10058
  }
10046
- ResultArrowArrayStreamWrapper::ResultArrowArrayStreamWrapper(unique_ptr<QueryResult> result_p)
10059
+ ResultArrowArrayStreamWrapper::ResultArrowArrayStreamWrapper(unique_ptr<QueryResult> result_p, idx_t approx_batch_size)
10047
10060
  : result(move(result_p)) {
10048
10061
  //! We first initialize the private data of the stream
10049
10062
  stream.private_data = this;
10050
-
10063
+ //! Ceil Approx_Batch_Size/STANDARD_VECTOR_SIZE
10064
+ if (approx_batch_size == 0) {
10065
+ throw std::runtime_error("Approximate Batch Size of Record Batch MUST be higher than 0");
10066
+ }
10067
+ vectors_per_chunk = (approx_batch_size + STANDARD_VECTOR_SIZE - 1) / STANDARD_VECTOR_SIZE;
10051
10068
  //! We initialize the stream functions
10052
10069
  stream.get_schema = ResultArrowArrayStreamWrapper::MyStreamGetSchema;
10053
10070
  stream.get_next = ResultArrowArrayStreamWrapper::MyStreamGetNext;
@@ -29102,6 +29119,13 @@ namespace duckdb {
29102
29119
  class RowLayout;
29103
29120
  struct LocalSortState;
29104
29121
 
29122
+ struct SortConstants {
29123
+ static constexpr idx_t VALUES_PER_RADIX = 256;
29124
+ static constexpr idx_t MSD_RADIX_LOCATIONS = VALUES_PER_RADIX + 1;
29125
+ static constexpr idx_t INSERTION_SORT_THRESHOLD = 24;
29126
+ static constexpr idx_t MSD_RADIX_SORT_SIZE_THRESHOLD = 4;
29127
+ };
29128
+
29105
29129
  struct SortLayout {
29106
29130
  public:
29107
29131
  explicit SortLayout(const vector<BoundOrderByNode> &orders);
@@ -30403,12 +30427,12 @@ static void ComputeTies(data_ptr_t dataptr, const idx_t &count, const idx_t &col
30403
30427
  }
30404
30428
 
30405
30429
  //! Textbook LSD radix sort
30406
- static void RadixSort(BufferManager &buffer_manager, const data_ptr_t &dataptr, const idx_t &count,
30407
- const idx_t &col_offset, const idx_t &sorting_size, const SortLayout &sort_layout) {
30408
- auto temp_block = buffer_manager.Allocate(MaxValue(count * sort_layout.entry_size, (idx_t)Storage::BLOCK_SIZE));
30430
+ void RadixSortLSD(BufferManager &buffer_manager, const data_ptr_t &dataptr, const idx_t &count, const idx_t &col_offset,
30431
+ const idx_t &row_width, const idx_t &sorting_size) {
30432
+ auto temp_block = buffer_manager.Allocate(MaxValue(count * row_width, (idx_t)Storage::BLOCK_SIZE));
30409
30433
  bool swap = false;
30410
30434
 
30411
- idx_t counts[256];
30435
+ idx_t counts[SortConstants::VALUES_PER_RADIX];
30412
30436
  for (idx_t r = 1; r <= sorting_size; r++) {
30413
30437
  // Init counts to 0
30414
30438
  memset(counts, 0, sizeof(counts));
@@ -30420,24 +30444,129 @@ static void RadixSort(BufferManager &buffer_manager, const data_ptr_t &dataptr,
30420
30444
  data_ptr_t offset_ptr = source_ptr + offset;
30421
30445
  for (idx_t i = 0; i < count; i++) {
30422
30446
  counts[*offset_ptr]++;
30423
- offset_ptr += sort_layout.entry_size;
30447
+ offset_ptr += row_width;
30424
30448
  }
30425
30449
  // Compute offsets from counts
30426
- for (idx_t val = 1; val < 256; val++) {
30450
+ idx_t max_count = counts[0];
30451
+ for (idx_t val = 1; val < SortConstants::VALUES_PER_RADIX; val++) {
30452
+ max_count = MaxValue<idx_t>(max_count, counts[val]);
30427
30453
  counts[val] = counts[val] + counts[val - 1];
30428
30454
  }
30455
+ if (max_count == count) {
30456
+ continue;
30457
+ }
30429
30458
  // Re-order the data in temporary array
30430
- data_ptr_t row_ptr = source_ptr + (count - 1) * sort_layout.entry_size;
30459
+ data_ptr_t row_ptr = source_ptr + (count - 1) * row_width;
30431
30460
  for (idx_t i = 0; i < count; i++) {
30432
30461
  idx_t &radix_offset = --counts[*(row_ptr + offset)];
30433
- memcpy(target_ptr + radix_offset * sort_layout.entry_size, row_ptr, sort_layout.entry_size);
30434
- row_ptr -= sort_layout.entry_size;
30462
+ memcpy(target_ptr + radix_offset * row_width, row_ptr, row_width);
30463
+ row_ptr -= row_width;
30435
30464
  }
30436
30465
  swap = !swap;
30437
30466
  }
30438
30467
  // Move data back to original buffer (if it was swapped)
30439
30468
  if (swap) {
30440
- memcpy(dataptr, temp_block->Ptr(), count * sort_layout.entry_size);
30469
+ memcpy(dataptr, temp_block->Ptr(), count * row_width);
30470
+ }
30471
+ }
30472
+
30473
+ //! Insertion sort, used when count of values is low
30474
+ inline void InsertionSort(const data_ptr_t orig_ptr, const data_ptr_t temp_ptr, const idx_t &count,
30475
+ const idx_t &col_offset, const idx_t &row_width, const idx_t &total_comp_width,
30476
+ const idx_t &offset, bool swap) {
30477
+ const data_ptr_t source_ptr = swap ? temp_ptr : orig_ptr;
30478
+ const data_ptr_t target_ptr = swap ? orig_ptr : temp_ptr;
30479
+ if (count > 1) {
30480
+ const idx_t total_offset = col_offset + offset;
30481
+ auto temp_val = unique_ptr<data_t[]>(new data_t[row_width]);
30482
+ const data_ptr_t val = temp_val.get();
30483
+ const auto comp_width = total_comp_width - offset;
30484
+ for (idx_t i = 1; i < count; i++) {
30485
+ memcpy(val, source_ptr + i * row_width, row_width);
30486
+ idx_t j = i;
30487
+ while (j > 0 &&
30488
+ memcmp(source_ptr + (j - 1) * row_width + total_offset, val + total_offset, comp_width) > 0) {
30489
+ memcpy(source_ptr + j * row_width, source_ptr + (j - 1) * row_width, row_width);
30490
+ j--;
30491
+ }
30492
+ memcpy(source_ptr + j * row_width, val, row_width);
30493
+ }
30494
+ }
30495
+ if (swap) {
30496
+ memcpy(target_ptr, source_ptr, count * row_width);
30497
+ }
30498
+ }
30499
+
30500
+ //! MSD radix sort that switches to insertion sort with low bucket sizes
30501
+ void RadixSortMSD(const data_ptr_t orig_ptr, const data_ptr_t temp_ptr, const idx_t &count, const idx_t &col_offset,
30502
+ const idx_t &row_width, const idx_t &comp_width, const idx_t &offset, idx_t locations[], bool swap) {
30503
+ const data_ptr_t source_ptr = swap ? temp_ptr : orig_ptr;
30504
+ const data_ptr_t target_ptr = swap ? orig_ptr : temp_ptr;
30505
+ // Init counts to 0
30506
+ memset(locations, 0, SortConstants::MSD_RADIX_LOCATIONS * sizeof(idx_t));
30507
+ idx_t *counts = locations + 1;
30508
+ // Collect counts
30509
+ const idx_t total_offset = col_offset + offset;
30510
+ data_ptr_t offset_ptr = source_ptr + total_offset;
30511
+ for (idx_t i = 0; i < count; i++) {
30512
+ counts[*offset_ptr]++;
30513
+ offset_ptr += row_width;
30514
+ }
30515
+ // Compute locations from counts
30516
+ idx_t max_count = 0;
30517
+ for (idx_t radix = 0; radix < SortConstants::VALUES_PER_RADIX; radix++) {
30518
+ max_count = MaxValue<idx_t>(max_count, counts[radix]);
30519
+ counts[radix] += locations[radix];
30520
+ }
30521
+ if (max_count != count) {
30522
+ // Re-order the data in temporary array
30523
+ data_ptr_t row_ptr = source_ptr;
30524
+ for (idx_t i = 0; i < count; i++) {
30525
+ const idx_t &radix_offset = locations[*(row_ptr + total_offset)]++;
30526
+ memcpy(target_ptr + radix_offset * row_width, row_ptr, row_width);
30527
+ row_ptr += row_width;
30528
+ }
30529
+ swap = !swap;
30530
+ }
30531
+ // Check if done
30532
+ if (offset == comp_width - 1) {
30533
+ if (swap) {
30534
+ memcpy(orig_ptr, temp_ptr, count * row_width);
30535
+ }
30536
+ return;
30537
+ }
30538
+ if (max_count == count) {
30539
+ RadixSortMSD(orig_ptr, temp_ptr, count, col_offset, row_width, comp_width, offset + 1,
30540
+ locations + SortConstants::MSD_RADIX_LOCATIONS, swap);
30541
+ return;
30542
+ }
30543
+ // Recurse
30544
+ idx_t radix_count = locations[0];
30545
+ for (idx_t radix = 0; radix < SortConstants::VALUES_PER_RADIX; radix++) {
30546
+ const idx_t loc = (locations[radix] - radix_count) * row_width;
30547
+ if (radix_count > SortConstants::INSERTION_SORT_THRESHOLD) {
30548
+ RadixSortMSD(orig_ptr + loc, temp_ptr + loc, radix_count, col_offset, row_width, comp_width, offset + 1,
30549
+ locations + SortConstants::MSD_RADIX_LOCATIONS, swap);
30550
+ } else if (radix_count != 0) {
30551
+ InsertionSort(orig_ptr + loc, temp_ptr + loc, radix_count, col_offset, row_width, comp_width, offset + 1,
30552
+ swap);
30553
+ }
30554
+ radix_count = locations[radix + 1] - locations[radix];
30555
+ }
30556
+ }
30557
+
30558
+ //! Calls different sort functions, depending on the count and sorting sizes
30559
+ void RadixSort(BufferManager &buffer_manager, const data_ptr_t &dataptr, const idx_t &count, const idx_t &col_offset,
30560
+ const idx_t &sorting_size, const SortLayout &sort_layout) {
30561
+ if (count <= SortConstants::INSERTION_SORT_THRESHOLD) {
30562
+ InsertionSort(dataptr, nullptr, count, 0, sort_layout.entry_size, sort_layout.comparison_size, 0, false);
30563
+ } else if (sorting_size <= SortConstants::MSD_RADIX_SORT_SIZE_THRESHOLD) {
30564
+ RadixSortLSD(buffer_manager, dataptr, count, col_offset, sort_layout.entry_size, sorting_size);
30565
+ } else {
30566
+ auto temp_block = buffer_manager.Allocate(MaxValue(count * sort_layout.entry_size, (idx_t)Storage::BLOCK_SIZE));
30567
+ auto preallocated_array = unique_ptr<idx_t[]>(new idx_t[sorting_size * SortConstants::MSD_RADIX_LOCATIONS]);
30568
+ RadixSortMSD(dataptr, temp_block->Ptr(), count, col_offset, sort_layout.entry_size, sorting_size, 0,
30569
+ preallocated_array.get(), false);
30441
30570
  }
30442
30571
  }
30443
30572
 
@@ -30478,11 +30607,10 @@ void LocalSortState::SortInMemory() {
30478
30607
  idx_t sorting_size = 0;
30479
30608
  idx_t col_offset = 0;
30480
30609
  unique_ptr<bool[]> ties_ptr;
30481
- unique_ptr<BufferHandle> ties_handle;
30482
30610
  bool *ties = nullptr;
30483
30611
  for (idx_t i = 0; i < sort_layout->column_count; i++) {
30484
30612
  sorting_size += sort_layout->column_sizes[i];
30485
- if (sort_layout->constant_size[i] && i < sort_layout->column_count - 1 && sorting_size < 32) {
30613
+ if (sort_layout->constant_size[i] && i < sort_layout->column_count - 1) {
30486
30614
  // Add columns to the sorting size until we reach a variable size column, or the last column
30487
30615
  continue;
30488
30616
  }
@@ -34222,13 +34350,14 @@ public:
34222
34350
 
34223
34351
  namespace duckdb {
34224
34352
 
34225
- DataChunk::DataChunk() : count(0) {
34353
+ DataChunk::DataChunk() : count(0), capacity(STANDARD_VECTOR_SIZE) {
34226
34354
  }
34227
34355
 
34228
34356
  DataChunk::~DataChunk() {
34229
34357
  }
34230
34358
 
34231
34359
  void DataChunk::InitializeEmpty(const vector<LogicalType> &types) {
34360
+ capacity = STANDARD_VECTOR_SIZE;
34232
34361
  D_ASSERT(data.empty()); // can only be initialized once
34233
34362
  D_ASSERT(!types.empty()); // empty chunk not allowed
34234
34363
  for (idx_t i = 0; i < types.size(); i++) {
@@ -34239,6 +34368,7 @@ void DataChunk::InitializeEmpty(const vector<LogicalType> &types) {
34239
34368
  void DataChunk::Initialize(const vector<LogicalType> &types) {
34240
34369
  D_ASSERT(data.empty()); // can only be initialized once
34241
34370
  D_ASSERT(!types.empty()); // empty chunk not allowed
34371
+ capacity = STANDARD_VECTOR_SIZE;
34242
34372
  for (idx_t i = 0; i < types.size(); i++) {
34243
34373
  VectorCache cache(types[i]);
34244
34374
  data.emplace_back(cache);
@@ -34256,12 +34386,14 @@ void DataChunk::Reset() {
34256
34386
  for (idx_t i = 0; i < ColumnCount(); i++) {
34257
34387
  data[i].ResetFromCache(vector_caches[i]);
34258
34388
  }
34389
+ capacity = STANDARD_VECTOR_SIZE;
34259
34390
  SetCardinality(0);
34260
34391
  }
34261
34392
 
34262
34393
  void DataChunk::Destroy() {
34263
34394
  data.clear();
34264
34395
  vector_caches.clear();
34396
+ capacity = 0;
34265
34397
  SetCardinality(0);
34266
34398
  }
34267
34399
 
@@ -34277,6 +34409,7 @@ void DataChunk::SetValue(idx_t col_idx, idx_t index, const Value &val) {
34277
34409
  void DataChunk::Reference(DataChunk &chunk) {
34278
34410
  D_ASSERT(chunk.ColumnCount() <= ColumnCount());
34279
34411
  SetCardinality(chunk);
34412
+ SetCapacity(chunk);
34280
34413
  for (idx_t i = 0; i < chunk.ColumnCount(); i++) {
34281
34414
  data[i].Reference(chunk.data[i]);
34282
34415
  }
@@ -34284,6 +34417,7 @@ void DataChunk::Reference(DataChunk &chunk) {
34284
34417
 
34285
34418
  void DataChunk::Move(DataChunk &chunk) {
34286
34419
  SetCardinality(chunk);
34420
+ SetCapacity(chunk);
34287
34421
  data = move(chunk.data);
34288
34422
  vector_caches = move(chunk.vector_caches);
34289
34423
 
@@ -34329,32 +34463,33 @@ void DataChunk::Split(DataChunk &other, idx_t split_idx) {
34329
34463
  other.SetCardinality(*this);
34330
34464
  }
34331
34465
 
34332
- void DataChunk::Append(const DataChunk &other) {
34466
+ void DataChunk::Append(const DataChunk &other, bool resize, SelectionVector *sel, idx_t sel_count) {
34467
+ idx_t new_size = sel ? size() + sel_count : size() + other.size();
34333
34468
  if (other.size() == 0) {
34334
34469
  return;
34335
34470
  }
34336
34471
  if (ColumnCount() != other.ColumnCount()) {
34337
34472
  throw InternalException("Column counts of appending chunk doesn't match!");
34338
34473
  }
34339
- for (idx_t i = 0; i < ColumnCount(); i++) {
34340
- D_ASSERT(data[i].GetVectorType() == VectorType::FLAT_VECTOR);
34341
- VectorOperations::Copy(other.data[i], data[i], other.size(), 0, size());
34342
- }
34343
- SetCardinality(size() + other.size());
34344
- }
34345
-
34346
- void DataChunk::Append(const DataChunk &other, const SelectionVector &sel, idx_t count) {
34347
- if (other.size() == 0) {
34348
- return;
34349
- }
34350
- if (ColumnCount() != other.ColumnCount()) {
34351
- throw InternalException("Column counts of appending chunk doesn't match!");
34474
+ if (new_size > capacity) {
34475
+ if (resize) {
34476
+ for (idx_t i = 0; i < ColumnCount(); i++) {
34477
+ data[i].Resize(size(), new_size);
34478
+ }
34479
+ capacity = new_size;
34480
+ } else {
34481
+ throw InternalException("Can't append chunk to other chunk without resizing");
34482
+ }
34352
34483
  }
34353
34484
  for (idx_t i = 0; i < ColumnCount(); i++) {
34354
34485
  D_ASSERT(data[i].GetVectorType() == VectorType::FLAT_VECTOR);
34355
- VectorOperations::Copy(other.data[i], data[i], sel, count, 0, size());
34486
+ if (sel) {
34487
+ VectorOperations::Copy(other.data[i], data[i], *sel, sel_count, 0, size());
34488
+ } else {
34489
+ VectorOperations::Copy(other.data[i], data[i], other.size(), 0, size());
34490
+ }
34356
34491
  }
34357
- SetCardinality(size() + count);
34492
+ SetCardinality(new_size);
34358
34493
  }
34359
34494
 
34360
34495
  void DataChunk::Normalify() {
@@ -34451,7 +34586,7 @@ void DataChunk::Hash(Vector &result) {
34451
34586
 
34452
34587
  void DataChunk::Verify() {
34453
34588
  #ifdef DEBUG
34454
- D_ASSERT(size() <= STANDARD_VECTOR_SIZE);
34589
+ D_ASSERT(size() <= capacity);
34455
34590
  // verify that all vectors in this chunk have the chunk selection vector
34456
34591
  for (idx_t i = 0; i < ColumnCount(); i++) {
34457
34592
  data[i].Verify(size());
@@ -54676,8 +54811,8 @@ static void SortCollectionForPartition(WindowOperatorState &state, BoundWindowEx
54676
54811
 
54677
54812
  // Copy the data for each collection.
54678
54813
  if (bin_size) {
54679
- over_partition.Append(over_chunk, sel, bin_size);
54680
- payload_partition.Append(payload_chunk, sel, bin_size);
54814
+ over_partition.Append(over_chunk, false, &sel, bin_size);
54815
+ payload_partition.Append(payload_chunk, false, &sel, bin_size);
54681
54816
  }
54682
54817
  } else {
54683
54818
  local_sort_state.SinkChunk(over_chunk, payload_chunk);
@@ -76623,9 +76758,16 @@ struct MapFun {
76623
76758
  struct MapExtractFun {
76624
76759
  static void RegisterFunction(BuiltinFunctions &set);
76625
76760
  };
76761
+
76626
76762
  struct ListExtractFun {
76627
76763
  static void RegisterFunction(BuiltinFunctions &set);
76628
76764
  };
76765
+
76766
+ struct ListConcatFun {
76767
+ static ScalarFunction GetFunction();
76768
+ static void RegisterFunction(BuiltinFunctions &set);
76769
+ };
76770
+
76629
76771
  struct CardinalityFun {
76630
76772
  static void RegisterFunction(BuiltinFunctions &set);
76631
76773
  };
@@ -83601,11 +83743,6 @@ void ArraySliceFun::RegisterFunction(BuiltinFunctions &set) {
83601
83743
 
83602
83744
 
83603
83745
 
83604
-
83605
-
83606
-
83607
-
83608
-
83609
83746
  //===----------------------------------------------------------------------===//
83610
83747
  // DuckDB
83611
83748
  //
@@ -83645,6 +83782,147 @@ public:
83645
83782
 
83646
83783
 
83647
83784
 
83785
+ namespace duckdb {
83786
+
83787
+ static void ListConcatFunction(DataChunk &args, ExpressionState &state, Vector &result) {
83788
+ D_ASSERT(args.ColumnCount() == 2);
83789
+ auto count = args.size();
83790
+
83791
+ Vector &lhs = args.data[0];
83792
+ Vector &rhs = args.data[1];
83793
+ if (lhs.GetType().id() == LogicalTypeId::SQLNULL) {
83794
+ result.Reference(rhs);
83795
+ return;
83796
+ }
83797
+ if (rhs.GetType().id() == LogicalTypeId::SQLNULL) {
83798
+ result.Reference(lhs);
83799
+ return;
83800
+ }
83801
+
83802
+ VectorData lhs_data;
83803
+ VectorData rhs_data;
83804
+ lhs.Orrify(count, lhs_data);
83805
+ rhs.Orrify(count, rhs_data);
83806
+ auto lhs_entries = (list_entry_t *)lhs_data.data;
83807
+ auto rhs_entries = (list_entry_t *)rhs_data.data;
83808
+
83809
+ auto lhs_list_size = ListVector::GetListSize(lhs);
83810
+ auto rhs_list_size = ListVector::GetListSize(rhs);
83811
+ auto &lhs_child = ListVector::GetEntry(lhs);
83812
+ auto &rhs_child = ListVector::GetEntry(rhs);
83813
+ VectorData lhs_child_data;
83814
+ VectorData rhs_child_data;
83815
+ lhs_child.Orrify(lhs_list_size, lhs_child_data);
83816
+ rhs_child.Orrify(rhs_list_size, rhs_child_data);
83817
+
83818
+ result.SetVectorType(VectorType::FLAT_VECTOR);
83819
+ auto result_entries = FlatVector::GetData<list_entry_t>(result);
83820
+ auto &result_validity = FlatVector::Validity(result);
83821
+
83822
+ idx_t offset = 0;
83823
+ for (idx_t i = 0; i < count; i++) {
83824
+ auto lhs_list_index = lhs_data.sel->get_index(i);
83825
+ auto rhs_list_index = rhs_data.sel->get_index(i);
83826
+ if (!lhs_data.validity.RowIsValid(lhs_list_index) && !rhs_data.validity.RowIsValid(rhs_list_index)) {
83827
+ result_validity.SetInvalid(i);
83828
+ continue;
83829
+ }
83830
+ result_entries[i].offset = offset;
83831
+ result_entries[i].length = 0;
83832
+ if (lhs_data.validity.RowIsValid(lhs_list_index)) {
83833
+ const auto &lhs_entry = lhs_entries[lhs_list_index];
83834
+ result_entries[i].length += lhs_entry.length;
83835
+ ListVector::Append(result, lhs_child, *lhs_child_data.sel, lhs_entry.offset + lhs_entry.length,
83836
+ lhs_entry.offset);
83837
+ }
83838
+ if (rhs_data.validity.RowIsValid(rhs_list_index)) {
83839
+ const auto &rhs_entry = rhs_entries[rhs_list_index];
83840
+ result_entries[i].length += rhs_entry.length;
83841
+ ListVector::Append(result, rhs_child, *rhs_child_data.sel, rhs_entry.offset + rhs_entry.length,
83842
+ rhs_entry.offset);
83843
+ }
83844
+ offset += result_entries[i].length;
83845
+ }
83846
+ D_ASSERT(ListVector::GetListSize(result) == offset);
83847
+
83848
+ if (lhs.GetVectorType() == VectorType::CONSTANT_VECTOR && rhs.GetVectorType() == VectorType::CONSTANT_VECTOR) {
83849
+ result.SetVectorType(VectorType::CONSTANT_VECTOR);
83850
+ }
83851
+ }
83852
+
83853
+ static unique_ptr<FunctionData> ListConcatBind(ClientContext &context, ScalarFunction &bound_function,
83854
+ vector<unique_ptr<Expression>> &arguments) {
83855
+ D_ASSERT(bound_function.arguments.size() == 2);
83856
+
83857
+ auto &lhs = arguments[0]->return_type;
83858
+ auto &rhs = arguments[1]->return_type;
83859
+ if (lhs.id() == LogicalTypeId::SQLNULL && rhs.id() == LogicalTypeId::SQLNULL) {
83860
+ bound_function.return_type = LogicalType::SQLNULL;
83861
+ } else if (lhs.id() == LogicalTypeId::SQLNULL || rhs.id() == LogicalTypeId::SQLNULL) {
83862
+ // we mimic postgres behaviour: list_concat(NULL, my_list) = my_list
83863
+ bound_function.arguments[0] = lhs;
83864
+ bound_function.arguments[1] = rhs;
83865
+ bound_function.return_type = rhs.id() == LogicalTypeId::SQLNULL ? lhs : rhs;
83866
+ } else {
83867
+ D_ASSERT(lhs.id() == LogicalTypeId::LIST);
83868
+ D_ASSERT(rhs.id() == LogicalTypeId::LIST);
83869
+
83870
+ // Resolve list type
83871
+ auto child_type = LogicalType::SQLNULL;
83872
+ for (const auto &argument : arguments) {
83873
+ child_type = LogicalType::MaxLogicalType(child_type, ListType::GetChildType(argument->return_type));
83874
+ }
83875
+ ExpressionBinder::ResolveParameterType(child_type);
83876
+ auto list_type = LogicalType::LIST(move(child_type));
83877
+
83878
+ bound_function.arguments[0] = list_type;
83879
+ bound_function.arguments[1] = list_type;
83880
+ bound_function.return_type = list_type;
83881
+ }
83882
+ return make_unique<VariableReturnBindData>(bound_function.return_type);
83883
+ }
83884
+
83885
+ static unique_ptr<BaseStatistics> ListConcatStats(ClientContext &context, BoundFunctionExpression &expr,
83886
+ FunctionData *bind_data,
83887
+ vector<unique_ptr<BaseStatistics>> &child_stats) {
83888
+ D_ASSERT(child_stats.size() == 2);
83889
+ if (!child_stats[0] || !child_stats[1]) {
83890
+ return nullptr;
83891
+ }
83892
+
83893
+ auto &left_stats = (ListStatistics &)*child_stats[0];
83894
+ auto &right_stats = (ListStatistics &)*child_stats[1];
83895
+
83896
+ auto stats = left_stats.Copy();
83897
+ stats->Merge(right_stats);
83898
+
83899
+ return stats;
83900
+ }
83901
+
83902
+ ScalarFunction ListConcatFun::GetFunction() {
83903
+ // the arguments and return types are actually set in the binder function
83904
+ return ScalarFunction({LogicalType::LIST(LogicalType::ANY), LogicalType::LIST(LogicalType::ANY)},
83905
+ LogicalType::LIST(LogicalType::ANY), ListConcatFunction, false, ListConcatBind, nullptr,
83906
+ ListConcatStats);
83907
+ }
83908
+
83909
+ void ListConcatFun::RegisterFunction(BuiltinFunctions &set) {
83910
+ set.AddFunction({"list_concat", "list_cat", "array_concat", "array_cat"}, GetFunction());
83911
+ }
83912
+
83913
+ } // namespace duckdb
83914
+
83915
+
83916
+
83917
+
83918
+
83919
+
83920
+
83921
+
83922
+
83923
+
83924
+
83925
+
83648
83926
  namespace duckdb {
83649
83927
 
83650
83928
  template <class T, bool HEAP_REF = false, bool VALIDITY_ONLY = false>
@@ -85613,6 +85891,7 @@ void BuiltinFunctions::RegisterNestedFunctions() {
85613
85891
  Register<ArraySliceFun>();
85614
85892
  Register<StructPackFun>();
85615
85893
  Register<StructExtractFun>();
85894
+ Register<ListConcatFun>();
85616
85895
  Register<ListValueFun>();
85617
85896
  Register<ListExtractFun>();
85618
85897
  Register<ListRangeFun>();
@@ -85959,6 +86238,7 @@ struct BitwiseNotFun {
85959
86238
 
85960
86239
 
85961
86240
 
86241
+
85962
86242
  #include <limits>
85963
86243
 
85964
86244
  namespace duckdb {
@@ -86274,6 +86554,8 @@ void AddFun::RegisterFunction(BuiltinFunctions &set) {
86274
86554
 
86275
86555
  functions.AddFunction(GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL));
86276
86556
  functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::TIMESTAMP));
86557
+ // we can add lists together
86558
+ functions.AddFunction(ListConcatFun::GetFunction());
86277
86559
 
86278
86560
  set.AddFunction(functions);
86279
86561
  }
@@ -87856,6 +88138,7 @@ void CHR::RegisterFunction(BuiltinFunctions &set) {
87856
88138
 
87857
88139
 
87858
88140
 
88141
+
87859
88142
  #include <string.h>
87860
88143
 
87861
88144
  namespace duckdb {
@@ -88101,6 +88384,7 @@ void ConcatFun::RegisterFunction(BuiltinFunctions &set) {
88101
88384
  concat_op.AddFunction(
88102
88385
  ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, ConcatOperator));
88103
88386
  concat_op.AddFunction(ScalarFunction({LogicalType::BLOB, LogicalType::BLOB}, LogicalType::BLOB, ConcatOperator));
88387
+ concat_op.AddFunction(ListConcatFun::GetFunction());
88104
88388
  set.AddFunction(concat_op);
88105
88389
 
88106
88390
  ScalarFunction concat_ws = ScalarFunction("concat_ws", {LogicalType::VARCHAR, LogicalType::VARCHAR},
package/src/duckdb.hpp CHANGED
@@ -10,8 +10,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
10
10
 
11
11
  #pragma once
12
12
  #define DUCKDB_AMALGAMATION 1
13
- #define DUCKDB_SOURCE_ID "c0d4ec2d7"
14
- #define DUCKDB_VERSION "0.3.1-dev511"
13
+ #define DUCKDB_SOURCE_ID "b36732a57"
14
+ #define DUCKDB_VERSION "0.3.1-dev532"
15
15
  //===----------------------------------------------------------------------===//
16
16
  // DuckDB
17
17
  //
@@ -3660,12 +3660,15 @@ public:
3660
3660
  return data.size();
3661
3661
  }
3662
3662
  void SetCardinality(idx_t count_p) {
3663
- D_ASSERT(count <= STANDARD_VECTOR_SIZE);
3663
+ D_ASSERT(count_p <= capacity);
3664
3664
  this->count = count_p;
3665
3665
  }
3666
3666
  void SetCardinality(const DataChunk &other) {
3667
3667
  this->count = other.size();
3668
3668
  }
3669
+ void SetCapacity(const DataChunk &other) {
3670
+ this->capacity = other.capacity;
3671
+ }
3669
3672
 
3670
3673
  DUCKDB_API Value GetValue(idx_t col_idx, idx_t index) const;
3671
3674
  DUCKDB_API void SetValue(idx_t col_idx, idx_t index, const Value &val);
@@ -3684,10 +3687,10 @@ public:
3684
3687
  void InitializeEmpty(const vector<LogicalType> &types);
3685
3688
  //! Append the other DataChunk to this one. The column count and types of
3686
3689
  //! the two DataChunks have to match exactly. Throws an exception if there
3687
- //! is not enough space in the chunk.
3688
- DUCKDB_API void Append(const DataChunk &other);
3689
- //! Append a selection of the other DataChunk to this one
3690
- DUCKDB_API void Append(const DataChunk &other, const SelectionVector &sel, idx_t count);
3690
+ //! is not enough space in the chunk and resize is not allowed.
3691
+ DUCKDB_API void Append(const DataChunk &other, bool resize = false, SelectionVector *sel = nullptr,
3692
+ idx_t count = 0);
3693
+
3691
3694
  //! Destroy all data and columns owned by this DataChunk
3692
3695
  DUCKDB_API void Destroy();
3693
3696
 
@@ -3739,6 +3742,8 @@ public:
3739
3742
  private:
3740
3743
  //! The amount of tuples stored in the data chunk
3741
3744
  idx_t count;
3745
+ //! The amount of tuples that can be stored in the data chunk
3746
+ idx_t capacity;
3742
3747
  //! Vector caches, used to store data when ::Initialize is called
3743
3748
  vector<VectorCache> vector_caches;
3744
3749
  };