duckdb 0.3.1-dev501.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-dev501.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());
@@ -35946,20 +36081,30 @@ bool Hugeint::TryCast(hugeint_t input, float &result) {
35946
36081
  return true;
35947
36082
  }
35948
36083
 
35949
- template <>
35950
- bool Hugeint::TryCast(hugeint_t input, double &result) {
36084
+ template <class REAL_T>
36085
+ bool CastBigintToFloating(hugeint_t input, REAL_T &result) {
35951
36086
  switch (input.upper) {
35952
36087
  case -1:
35953
36088
  // special case for upper = -1 to avoid rounding issues in small negative numbers
35954
- result = -double(NumericLimits<uint64_t>::Maximum() - input.lower) - 1;
36089
+ result = -REAL_T(NumericLimits<uint64_t>::Maximum() - input.lower) - 1;
35955
36090
  break;
35956
36091
  default:
35957
- result = double(input.lower) + double(input.upper) * double(NumericLimits<uint64_t>::Maximum());
36092
+ result = REAL_T(input.lower) + REAL_T(input.upper) * REAL_T(NumericLimits<uint64_t>::Maximum());
35958
36093
  break;
35959
36094
  }
35960
36095
  return true;
35961
36096
  }
35962
36097
 
36098
+ template <>
36099
+ bool Hugeint::TryCast(hugeint_t input, double &result) {
36100
+ return CastBigintToFloating<double>(input, result);
36101
+ }
36102
+
36103
+ template <>
36104
+ bool Hugeint::TryCast(hugeint_t input, long double &result) {
36105
+ return CastBigintToFloating<long double>(input, result);
36106
+ }
36107
+
35963
36108
  template <class DST>
35964
36109
  hugeint_t HugeintConvertInteger(DST input) {
35965
36110
  hugeint_t result;
@@ -36017,8 +36162,8 @@ bool Hugeint::TryConvert(float value, hugeint_t &result) {
36017
36162
  return Hugeint::TryConvert(double(value), result);
36018
36163
  }
36019
36164
 
36020
- template <>
36021
- bool Hugeint::TryConvert(double value, hugeint_t &result) {
36165
+ template <class REAL_T>
36166
+ bool ConvertFloatingToBigint(REAL_T value, hugeint_t &result) {
36022
36167
  if (value <= -170141183460469231731687303715884105728.0 || value >= 170141183460469231731687303715884105727.0) {
36023
36168
  return false;
36024
36169
  }
@@ -36026,14 +36171,24 @@ bool Hugeint::TryConvert(double value, hugeint_t &result) {
36026
36171
  if (negative) {
36027
36172
  value = -value;
36028
36173
  }
36029
- result.lower = (uint64_t)fmod(value, double(NumericLimits<uint64_t>::Maximum()));
36030
- result.upper = (uint64_t)(value / double(NumericLimits<uint64_t>::Maximum()));
36174
+ result.lower = (uint64_t)fmod(value, REAL_T(NumericLimits<uint64_t>::Maximum()));
36175
+ result.upper = (uint64_t)(value / REAL_T(NumericLimits<uint64_t>::Maximum()));
36031
36176
  if (negative) {
36032
- NegateInPlace(result);
36177
+ Hugeint::NegateInPlace(result);
36033
36178
  }
36034
36179
  return true;
36035
36180
  }
36036
36181
 
36182
+ template <>
36183
+ bool Hugeint::TryConvert(double value, hugeint_t &result) {
36184
+ return ConvertFloatingToBigint<double>(value, result);
36185
+ }
36186
+
36187
+ template <>
36188
+ bool Hugeint::TryConvert(long double value, hugeint_t &result) {
36189
+ return ConvertFloatingToBigint<long double>(value, result);
36190
+ }
36191
+
36037
36192
  //===--------------------------------------------------------------------===//
36038
36193
  // hugeint_t operators
36039
36194
  //===--------------------------------------------------------------------===//
@@ -54656,8 +54811,8 @@ static void SortCollectionForPartition(WindowOperatorState &state, BoundWindowEx
54656
54811
 
54657
54812
  // Copy the data for each collection.
54658
54813
  if (bin_size) {
54659
- over_partition.Append(over_chunk, sel, bin_size);
54660
- 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);
54661
54816
  }
54662
54817
  } else {
54663
54818
  local_sort_state.SinkChunk(over_chunk, payload_chunk);
@@ -70552,6 +70707,45 @@ struct VarianceFun {
70552
70707
 
70553
70708
  namespace duckdb {
70554
70709
 
70710
+ static inline void KahanAddInternal(double input, double &summed, double &err) {
70711
+ double diff = input - err;
70712
+ double newval = summed + diff;
70713
+ err = (newval - summed) - diff;
70714
+ summed = newval;
70715
+ }
70716
+
70717
+ template <class T>
70718
+ struct SumState {
70719
+ bool isset;
70720
+ T value;
70721
+
70722
+ void Initialize() {
70723
+ this->isset = false;
70724
+ }
70725
+
70726
+ void Combine(const SumState<T> &other) {
70727
+ this->isset = other.isset || this->isset;
70728
+ this->value += other.value;
70729
+ }
70730
+ };
70731
+
70732
+ struct KahanSumState {
70733
+ bool isset;
70734
+ double value;
70735
+ double err;
70736
+
70737
+ void Initialize() {
70738
+ this->isset = false;
70739
+ this->err = 0.0;
70740
+ }
70741
+
70742
+ void Combine(const KahanSumState &other) {
70743
+ this->isset = other.isset || this->isset;
70744
+ KahanAddInternal(other.value, this->value, this->err);
70745
+ KahanAddInternal(other.err, this->value, this->err);
70746
+ }
70747
+ };
70748
+
70555
70749
  struct RegularAdd {
70556
70750
  template <class STATE, class T>
70557
70751
  static void AddNumber(STATE &state, T input) {
@@ -70564,6 +70758,18 @@ struct RegularAdd {
70564
70758
  }
70565
70759
  };
70566
70760
 
70761
+ struct KahanAdd {
70762
+ template <class STATE, class T>
70763
+ static void AddNumber(STATE &state, T input) {
70764
+ KahanAddInternal(input, state.value, state.err);
70765
+ }
70766
+
70767
+ template <class STATE, class T>
70768
+ static void AddConstant(STATE &state, T input, idx_t count) {
70769
+ KahanAddInternal(input * count, state.value, state.err);
70770
+ }
70771
+ };
70772
+
70567
70773
  struct HugeintAdd {
70568
70774
  static void AddValue(hugeint_t &result, uint64_t value, int positive) {
70569
70775
  // integer summation taken from Tim Gubner et al. - Efficient Query Processing
@@ -70659,8 +70865,34 @@ namespace duckdb {
70659
70865
 
70660
70866
  template <class T>
70661
70867
  struct AvgState {
70868
+ uint64_t count;
70662
70869
  T value;
70870
+
70871
+ void Initialize() {
70872
+ this->count = 0;
70873
+ }
70874
+
70875
+ void Combine(const AvgState<T> &other) {
70876
+ this->count += other.count;
70877
+ this->value += other.value;
70878
+ }
70879
+ };
70880
+
70881
+ struct KahanAvgState {
70663
70882
  uint64_t count;
70883
+ double value;
70884
+ double err;
70885
+
70886
+ void Initialize() {
70887
+ this->count = 0;
70888
+ this->err = 0.0;
70889
+ }
70890
+
70891
+ void Combine(const KahanAvgState &other) {
70892
+ this->count += other.count;
70893
+ KahanAddInternal(other.value, this->value, this->err);
70894
+ KahanAddInternal(other.err, this->value, this->err);
70895
+ }
70664
70896
  };
70665
70897
 
70666
70898
  struct AverageDecimalBindData : public FunctionData {
@@ -70678,12 +70910,11 @@ public:
70678
70910
  struct AverageSetOperation {
70679
70911
  template <class STATE>
70680
70912
  static void Initialize(STATE *state) {
70681
- state->count = 0;
70913
+ state->Initialize();
70682
70914
  }
70683
70915
  template <class STATE>
70684
70916
  static void Combine(const STATE &source, STATE *target) {
70685
- target->count += source.count;
70686
- target->value += source.value;
70917
+ target->Combine(source);
70687
70918
  }
70688
70919
  template <class STATE>
70689
70920
  static void AddValues(STATE *state, idx_t count) {
@@ -70691,8 +70922,9 @@ struct AverageSetOperation {
70691
70922
  }
70692
70923
  };
70693
70924
 
70694
- static double GetAverageDivident(uint64_t count, FunctionData *bind_data) {
70695
- double divident = double(count);
70925
+ template <class T>
70926
+ static T GetAverageDivident(uint64_t count, FunctionData *bind_data) {
70927
+ T divident = T(count);
70696
70928
  if (bind_data) {
70697
70929
  auto &avg_bind_data = (AverageDecimalBindData &)*bind_data;
70698
70930
  divident *= avg_bind_data.scale;
@@ -70707,7 +70939,7 @@ struct IntegerAverageOperation : public BaseSumOperation<AverageSetOperation, Re
70707
70939
  if (state->count == 0) {
70708
70940
  mask.SetInvalid(idx);
70709
70941
  } else {
70710
- double divident = GetAverageDivident(state->count, bind_data);
70942
+ double divident = GetAverageDivident<double>(state->count, bind_data);
70711
70943
  target[idx] = double(state->value) / divident;
70712
70944
  }
70713
70945
  }
@@ -70720,8 +70952,8 @@ struct IntegerAverageOperationHugeint : public BaseSumOperation<AverageSetOperat
70720
70952
  if (state->count == 0) {
70721
70953
  mask.SetInvalid(idx);
70722
70954
  } else {
70723
- double divident = GetAverageDivident(state->count, bind_data);
70724
- target[idx] = Hugeint::Cast<double>(state->value) / divident;
70955
+ long double divident = GetAverageDivident<long double>(state->count, bind_data);
70956
+ target[idx] = Hugeint::Cast<long double>(state->value) / divident;
70725
70957
  }
70726
70958
  }
70727
70959
  };
@@ -70733,8 +70965,8 @@ struct HugeintAverageOperation : public BaseSumOperation<AverageSetOperation, Re
70733
70965
  if (state->count == 0) {
70734
70966
  mask.SetInvalid(idx);
70735
70967
  } else {
70736
- double divident = GetAverageDivident(state->count, bind_data);
70737
- target[idx] = Hugeint::Cast<double>(state->value) / divident;
70968
+ long double divident = GetAverageDivident<long double>(state->count, bind_data);
70969
+ target[idx] = Hugeint::Cast<long double>(state->value) / divident;
70738
70970
  }
70739
70971
  }
70740
70972
  };
@@ -70748,7 +70980,21 @@ struct NumericAverageOperation : public BaseSumOperation<AverageSetOperation, Re
70748
70980
  if (!Value::DoubleIsValid(state->value)) {
70749
70981
  throw OutOfRangeException("AVG is out of range!");
70750
70982
  }
70751
- target[idx] = state->value / state->count;
70983
+ target[idx] = (state->value / state->count);
70984
+ }
70985
+ }
70986
+ };
70987
+
70988
+ struct KahanAverageOperation : public BaseSumOperation<AverageSetOperation, KahanAdd> {
70989
+ template <class T, class STATE>
70990
+ static void Finalize(Vector &result, FunctionData *, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
70991
+ if (state->count == 0) {
70992
+ mask.SetInvalid(idx);
70993
+ } else {
70994
+ if (!Value::DoubleIsValid(state->value)) {
70995
+ throw OutOfRangeException("AVG is out of range!");
70996
+ }
70997
+ target[idx] = (state->value / state->count) + (state->err / state->count);
70752
70998
  }
70753
70999
  }
70754
71000
  };
@@ -70800,6 +71046,11 @@ void AvgFun::RegisterFunction(BuiltinFunctions &set) {
70800
71046
  avg.AddFunction(AggregateFunction::UnaryAggregate<AvgState<double>, double, double, NumericAverageOperation>(
70801
71047
  LogicalType::DOUBLE, LogicalType::DOUBLE));
70802
71048
  set.AddFunction(avg);
71049
+
71050
+ AggregateFunctionSet favg("favg");
71051
+ favg.AddFunction(AggregateFunction::UnaryAggregate<KahanAvgState, double, double, KahanAverageOperation>(
71052
+ LogicalType::DOUBLE, LogicalType::DOUBLE));
71053
+ set.AddFunction(favg);
70803
71054
  }
70804
71055
 
70805
71056
  } // namespace duckdb
@@ -73480,21 +73731,14 @@ void StringAggFun::RegisterFunction(BuiltinFunctions &set) {
73480
73731
 
73481
73732
  namespace duckdb {
73482
73733
 
73483
- template <class T>
73484
- struct SumState {
73485
- T value;
73486
- bool isset;
73487
- };
73488
-
73489
73734
  struct SumSetOperation {
73490
73735
  template <class STATE>
73491
73736
  static void Initialize(STATE *state) {
73492
- state->isset = false;
73737
+ state->Initialize();
73493
73738
  }
73494
73739
  template <class STATE>
73495
73740
  static void Combine(const STATE &source, STATE *target) {
73496
- target->isset = source.isset || target->isset;
73497
- target->value += source.value;
73741
+ target->Combine(source);
73498
73742
  }
73499
73743
  template <class STATE>
73500
73744
  static void AddValues(STATE *state, idx_t count) {
@@ -73524,7 +73768,8 @@ struct SumToHugeintOperation : public BaseSumOperation<SumSetOperation, HugeintA
73524
73768
  }
73525
73769
  };
73526
73770
 
73527
- struct NumericSumOperation : public BaseSumOperation<SumSetOperation, RegularAdd> {
73771
+ template <class ADD_OPERATOR>
73772
+ struct DoubleSumOperation : public BaseSumOperation<SumSetOperation, ADD_OPERATOR> {
73528
73773
  template <class T, class STATE>
73529
73774
  static void Finalize(Vector &result, FunctionData *, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
73530
73775
  if (!state->isset) {
@@ -73538,6 +73783,9 @@ struct NumericSumOperation : public BaseSumOperation<SumSetOperation, RegularAdd
73538
73783
  }
73539
73784
  };
73540
73785
 
73786
+ using NumericSumOperation = DoubleSumOperation<RegularAdd>;
73787
+ using KahanSumOperation = DoubleSumOperation<KahanAdd>;
73788
+
73541
73789
  struct HugeintSumOperation : public BaseSumOperation<SumSetOperation, RegularAdd> {
73542
73790
  template <class T, class STATE>
73543
73791
  static void Finalize(Vector &result, FunctionData *, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
@@ -73646,12 +73894,23 @@ void SumFun::RegisterFunction(BuiltinFunctions &set) {
73646
73894
  sum.AddFunction(GetSumAggregate(PhysicalType::INT32));
73647
73895
  sum.AddFunction(GetSumAggregate(PhysicalType::INT64));
73648
73896
  sum.AddFunction(GetSumAggregate(PhysicalType::INT128));
73649
- // float sums to float
73650
- // FIXME: implement http://ic.ese.upenn.edu/pdf/parallel_fpaccum_tc2016.pdf for parallel FP sums
73651
73897
  sum.AddFunction(AggregateFunction::UnaryAggregate<SumState<double>, double, double, NumericSumOperation>(
73652
73898
  LogicalType::DOUBLE, LogicalType::DOUBLE));
73653
73899
 
73654
73900
  set.AddFunction(sum);
73901
+
73902
+ // fsum
73903
+ AggregateFunctionSet fsum("fsum");
73904
+ fsum.AddFunction(AggregateFunction::UnaryAggregate<KahanSumState, double, double, KahanSumOperation>(
73905
+ LogicalType::DOUBLE, LogicalType::DOUBLE));
73906
+
73907
+ set.AddFunction(fsum);
73908
+
73909
+ fsum.name = "kahan_sum";
73910
+ set.AddFunction(fsum);
73911
+
73912
+ fsum.name = "sumKahan";
73913
+ set.AddFunction(fsum);
73655
73914
  }
73656
73915
 
73657
73916
  } // namespace duckdb
@@ -74963,14 +75222,12 @@ struct QuantileState {
74963
75222
  // Regular aggregation
74964
75223
  std::vector<SaveType> v;
74965
75224
 
74966
- // Windowed Aggregation
75225
+ // Windowed Quantile indirection
74967
75226
  std::vector<idx_t> w;
74968
75227
  idx_t pos;
74969
75228
 
74970
- // List temporaries
74971
- std::vector<idx_t> disturbed;
74972
- std::vector<idx_t> lower;
74973
- std::vector<idx_t> upper;
75229
+ // Windowed MAD indirection
75230
+ std::vector<idx_t> m;
74974
75231
 
74975
75232
  QuantileState() : pos(0) {
74976
75233
  }
@@ -75052,33 +75309,28 @@ static idx_t ReplaceIndex(idx_t *index, const FrameBounds &frame, const FrameBou
75052
75309
  }
75053
75310
 
75054
75311
  template <class INPUT_TYPE>
75055
- static inline bool CanReplace(const idx_t *index, const INPUT_TYPE *fdata, const idx_t j, const idx_t k0,
75056
- const idx_t k1, const QuantileNotNull &validity) {
75057
- auto replace = false;
75058
-
75312
+ static inline int CanReplace(const idx_t *index, const INPUT_TYPE *fdata, const idx_t j, const idx_t k0, const idx_t k1,
75313
+ const QuantileNotNull &validity) {
75059
75314
  D_ASSERT(index);
75060
75315
 
75061
- // NULLs can replace NULLs
75062
- // and NULLs are at the end, so we only have to check the first one
75316
+ // NULLs sort to the end, so if we have inserted a NULL,
75317
+ // it must be past the end of the quantile to be replaceable.
75318
+ // Note that the quantile values are never NULL.
75063
75319
  const auto ij = index[j];
75064
- const auto ik0 = index[k0];
75065
- const auto ik1 = index[k1];
75066
- const auto nullj = !validity(ij);
75067
- const auto nullk0 = !validity(ik0);
75068
- if (nullj || nullk0) {
75069
- return nullj == nullk0;
75320
+ if (!validity(ij)) {
75321
+ return k1 < j ? 1 : 0;
75070
75322
  }
75071
75323
 
75072
75324
  auto curr = fdata[ij];
75073
75325
  if (k1 < j) {
75074
- auto hi = fdata[ik0];
75075
- replace = hi < curr;
75326
+ auto hi = fdata[index[k0]];
75327
+ return hi < curr ? 1 : 0;
75076
75328
  } else if (j < k0) {
75077
- auto lo = fdata[ik1];
75078
- replace = curr < lo;
75329
+ auto lo = fdata[index[k1]];
75330
+ return curr < lo ? -1 : 0;
75079
75331
  }
75080
75332
 
75081
- return replace;
75333
+ return 0;
75082
75334
  }
75083
75335
 
75084
75336
  template <class INPUT_TYPE>
@@ -75195,7 +75447,8 @@ struct QuantileLess {
75195
75447
  // Continuous interpolation
75196
75448
  template <bool DISCRETE>
75197
75449
  struct Interpolator {
75198
- Interpolator(const double q, const idx_t n_p) : n(n_p), RN((double)(n_p - 1) * q), FRN(floor(RN)), CRN(ceil(RN)) {
75450
+ Interpolator(const double q, const idx_t n_p)
75451
+ : n(n_p), RN((double)(n_p - 1) * q), FRN(floor(RN)), CRN(ceil(RN)), begin(0), end(n_p) {
75199
75452
  }
75200
75453
 
75201
75454
  template <class INPUT_TYPE, class TARGET_TYPE, typename ACCESSOR = QuantileDirect<INPUT_TYPE>>
@@ -75203,11 +75456,11 @@ struct Interpolator {
75203
75456
  using ACCESS_TYPE = typename ACCESSOR::RESULT_TYPE;
75204
75457
  QuantileLess<ACCESSOR> comp(accessor);
75205
75458
  if (CRN == FRN) {
75206
- std::nth_element(v_t, v_t + FRN, v_t + n, comp);
75459
+ std::nth_element(v_t + begin, v_t + FRN, v_t + end, comp);
75207
75460
  return CastInterpolation::Cast<ACCESS_TYPE, TARGET_TYPE>(accessor(v_t[FRN]), result);
75208
75461
  } else {
75209
- std::nth_element(v_t, v_t + FRN, v_t + n, comp);
75210
- std::nth_element(v_t + FRN, v_t + CRN, v_t + n, comp);
75462
+ std::nth_element(v_t + begin, v_t + FRN, v_t + end, comp);
75463
+ std::nth_element(v_t + FRN, v_t + CRN, v_t + end, comp);
75211
75464
  auto lo = CastInterpolation::Cast<ACCESS_TYPE, TARGET_TYPE>(accessor(v_t[FRN]), result);
75212
75465
  auto hi = CastInterpolation::Cast<ACCESS_TYPE, TARGET_TYPE>(accessor(v_t[CRN]), result);
75213
75466
  return CastInterpolation::Interpolate<TARGET_TYPE>(lo, RN - FRN, hi);
@@ -75230,19 +75483,23 @@ struct Interpolator {
75230
75483
  const double RN;
75231
75484
  const idx_t FRN;
75232
75485
  const idx_t CRN;
75486
+
75487
+ idx_t begin;
75488
+ idx_t end;
75233
75489
  };
75234
75490
 
75235
75491
  // Discrete "interpolation"
75236
75492
  template <>
75237
75493
  struct Interpolator<true> {
75238
- Interpolator(const double q, const idx_t n_p) : n(n_p), RN((double)(n_p - 1) * q), FRN(floor(RN)), CRN(FRN) {
75494
+ Interpolator(const double q, const idx_t n_p)
75495
+ : n(n_p), RN((double)(n_p - 1) * q), FRN(floor(RN)), CRN(FRN), begin(0), end(n_p) {
75239
75496
  }
75240
75497
 
75241
75498
  template <class INPUT_TYPE, class TARGET_TYPE, typename ACCESSOR = QuantileDirect<INPUT_TYPE>>
75242
75499
  TARGET_TYPE Operation(INPUT_TYPE *v_t, Vector &result, const ACCESSOR &accessor = ACCESSOR()) const {
75243
75500
  using ACCESS_TYPE = typename ACCESSOR::RESULT_TYPE;
75244
75501
  QuantileLess<ACCESSOR> comp(accessor);
75245
- std::nth_element(v_t, v_t + FRN, v_t + n, comp);
75502
+ std::nth_element(v_t + begin, v_t + FRN, v_t + end, comp);
75246
75503
  return CastInterpolation::Cast<ACCESS_TYPE, TARGET_TYPE>(accessor(v_t[FRN]), result);
75247
75504
  }
75248
75505
 
@@ -75256,6 +75513,9 @@ struct Interpolator<true> {
75256
75513
  const double RN;
75257
75514
  const idx_t FRN;
75258
75515
  const idx_t CRN;
75516
+
75517
+ idx_t begin;
75518
+ idx_t end;
75259
75519
  };
75260
75520
 
75261
75521
  struct QuantileBindData : public FunctionData {
@@ -75328,7 +75588,9 @@ static void ExecuteListFinalize(Vector &states, FunctionData *bind_data_p, Vecto
75328
75588
 
75329
75589
  D_ASSERT(bind_data_p);
75330
75590
  auto bind_data = (QuantileBindData *)bind_data_p;
75331
- ListVector::SetListSize(result, 0);
75591
+ if (offset == 0) {
75592
+ ListVector::SetListSize(result, 0);
75593
+ }
75332
75594
 
75333
75595
  if (states.GetVectorType() == VectorType::CONSTANT_VECTOR) {
75334
75596
  result.SetVectorType(VectorType::CONSTANT_VECTOR);
@@ -75406,7 +75668,7 @@ struct QuantileScalarOperation : public QuantileOperation {
75406
75668
  if (frame.first == prev.first + 1 && frame.second == prev.second + 1) {
75407
75669
  // Fixed frame size
75408
75670
  const auto j = ReplaceIndex(index, frame, prev);
75409
- // We can only replace if the number of NULls has not changed
75671
+ // We can only replace if the number of NULLs has not changed
75410
75672
  if (dmask.AllValid() || not_null(prev.first) == not_null(prev.second)) {
75411
75673
  Interpolator<DISCRETE> interp(q, prev_pos);
75412
75674
  replace = CanReplace(index, data, j, interp.FRN, interp.CRN, not_null);
@@ -75515,15 +75777,19 @@ struct QuantileListOperation : public QuantileOperation {
75515
75777
  auto v_t = state->v.data();
75516
75778
  D_ASSERT(v_t);
75517
75779
 
75518
- target[idx].offset = ridx;
75519
- for (const auto &quantile : bind_data->quantiles) {
75780
+ auto &entry = target[idx];
75781
+ entry.offset = ridx;
75782
+ idx_t lower = 0;
75783
+ for (const auto &q : bind_data->order) {
75784
+ const auto &quantile = bind_data->quantiles[q];
75520
75785
  Interpolator<DISCRETE> interp(quantile, state->v.size());
75521
- rdata[ridx] = interp.template Operation<typename STATE::SaveType, CHILD_TYPE>(v_t, result);
75522
- ++ridx;
75786
+ interp.begin = lower;
75787
+ rdata[ridx + q] = interp.template Operation<typename STATE::SaveType, CHILD_TYPE>(v_t, result);
75788
+ lower = interp.FRN;
75523
75789
  }
75524
- target[idx].length = bind_data->quantiles.size();
75790
+ entry.length = bind_data->quantiles.size();
75525
75791
 
75526
- ListVector::SetListSize(result_list, ridx);
75792
+ ListVector::SetListSize(result_list, entry.offset + entry.length);
75527
75793
  }
75528
75794
 
75529
75795
  template <class STATE, class INPUT_TYPE, class RESULT_TYPE>
@@ -75547,57 +75813,75 @@ struct QuantileListOperation : public QuantileOperation {
75547
75813
  auto rdata = FlatVector::GetData<CHILD_TYPE>(result);
75548
75814
 
75549
75815
  // Lazily initialise frame state
75550
- const auto prev_valid = state->w.size() == (prev.second - prev.first);
75816
+ auto prev_pos = state->pos;
75551
75817
  state->SetPos(frame.second - frame.first);
75552
75818
 
75553
75819
  auto index = state->w.data();
75554
75820
 
75555
- bool fixed = false;
75556
- auto j = state->pos;
75557
- if (prev_valid && dmask.AllValid() && frame.first == prev.first + 1 && frame.second == prev.second + 1) {
75821
+ // We can generalise replacement for quantile lists by observing that when a replacement is
75822
+ // valid for a single quantile, it is valid for all quantiles greater/less than that quantile
75823
+ // based on whether the insertion is below/above the quantile location.
75824
+ // So if a replaced index in an IQR is located between Q25 and Q50, but has a value below Q25,
75825
+ // then Q25 must be recomputed, but Q50 and Q75 are unaffected.
75826
+ // For a single element list, this reduces to the scalar case.
75827
+ std::pair<idx_t, idx_t> replaceable {state->pos, 0};
75828
+ if (frame.first == prev.first + 1 && frame.second == prev.second + 1) {
75558
75829
  // Fixed frame size
75559
- j = ReplaceIndex(index, frame, prev);
75560
- fixed = true;
75830
+ const auto j = ReplaceIndex(index, frame, prev);
75831
+ // We can only replace if the number of NULLs has not changed
75832
+ if (dmask.AllValid() || not_null(prev.first) == not_null(prev.second)) {
75833
+ for (const auto &q : bind_data->order) {
75834
+ const auto &quantile = bind_data->quantiles[q];
75835
+ Interpolator<DISCRETE> interp(quantile, prev_pos);
75836
+ const auto replace = CanReplace(index, data, j, interp.FRN, interp.CRN, not_null);
75837
+ if (replace < 0) {
75838
+ // Replacement is before this quantile, so the rest will be replaceable too.
75839
+ replaceable.first = MinValue(replaceable.first, interp.FRN);
75840
+ replaceable.second = prev_pos;
75841
+ break;
75842
+ } else if (replace > 0) {
75843
+ // Replacement is after this quantile, so everything before it is replaceable too.
75844
+ replaceable.first = 0;
75845
+ replaceable.second = MaxValue(replaceable.second, interp.CRN);
75846
+ }
75847
+ }
75848
+ if (replaceable.first < replaceable.second) {
75849
+ state->pos = prev_pos;
75850
+ }
75851
+ }
75561
75852
  } else {
75562
75853
  ReuseIndexes(index, frame, prev);
75563
- if (!dmask.AllValid()) {
75564
- state->pos = std::partition(index, index + state->pos, not_null) - index;
75565
- }
75566
75854
  }
75567
75855
 
75568
- if (!state->pos) {
75569
- lmask.Set(lidx, false);
75570
- return;
75856
+ if (replaceable.first >= replaceable.second && !dmask.AllValid()) {
75857
+ // Remove the NULLs
75858
+ state->pos = std::partition(index, index + state->pos, not_null) - index;
75571
75859
  }
75572
75860
 
75573
- // First pass: Fill in the undisturbed values and find the islands of stability.
75574
- QuantileIndirect<INPUT_TYPE> indirect(data);
75575
- state->disturbed.clear();
75576
- state->lower.clear();
75577
- state->upper.clear();
75578
- idx_t lb = 0;
75579
- for (idx_t i = 0; i < bind_data->order.size(); ++i) {
75580
- const auto q = bind_data->order[i];
75581
- const auto &quantile = bind_data->quantiles[q];
75582
- Interpolator<DISCRETE> interp(quantile, state->pos);
75583
-
75584
- if (fixed && CanReplace(index, data, j, interp.FRN, interp.CRN, not_null)) {
75585
- rdata[lentry.offset + q] = interp.template Replace<idx_t, CHILD_TYPE>(index, result, indirect);
75586
- state->upper.resize(state->lower.size(), interp.FRN);
75587
- } else {
75588
- state->disturbed.push_back(q);
75589
- state->lower.push_back(MinValue(lb, interp.FRN));
75861
+ if (state->pos) {
75862
+ using ID = QuantileIndirect<INPUT_TYPE>;
75863
+ ID indirect(data);
75864
+ for (const auto &q : bind_data->order) {
75865
+ const auto &quantile = bind_data->quantiles[q];
75866
+ Interpolator<DISCRETE> interp(quantile, state->pos);
75867
+ if (replaceable.first <= interp.FRN && interp.CRN <= replaceable.second) {
75868
+ rdata[lentry.offset + q] = interp.template Replace<idx_t, CHILD_TYPE, ID>(index, result, indirect);
75869
+ } else {
75870
+ // Make sure we don't disturb any replacements
75871
+ if (replaceable.first < replaceable.second) {
75872
+ if (interp.FRN < replaceable.first) {
75873
+ interp.end = replaceable.first;
75874
+ }
75875
+ if (replaceable.second < interp.CRN) {
75876
+ interp.begin = replaceable.second;
75877
+ }
75878
+ }
75879
+ rdata[lentry.offset + q] =
75880
+ interp.template Operation<idx_t, CHILD_TYPE, ID>(index, result, indirect);
75881
+ }
75590
75882
  }
75591
- lb = interp.CRN + 1;
75592
- }
75593
- state->upper.resize(state->lower.size(), state->pos);
75594
-
75595
- // Second pass: select the disturbed values
75596
- for (idx_t i = 0; i < state->disturbed.size(); ++i) {
75597
- const auto &q = state->disturbed[i];
75598
- const auto &quantile = bind_data->quantiles[q];
75599
- Interpolator<DISCRETE> interp(quantile, state->pos);
75600
- rdata[lentry.offset + q] = interp.template Operation<idx_t, CHILD_TYPE>(index, result, indirect);
75883
+ } else {
75884
+ lmask.Set(lidx, false);
75601
75885
  }
75602
75886
  }
75603
75887
  };
@@ -75877,12 +76161,11 @@ struct MedianAbsoluteDeviationOperation : public QuantileOperation {
75877
76161
  D_ASSERT(index);
75878
76162
 
75879
76163
  // We need a second index for the second pass.
75880
- // so repurpose disturbed as the second index.
75881
- if (state->pos > state->disturbed.size()) {
75882
- state->disturbed.resize(state->pos);
76164
+ if (state->pos > state->m.size()) {
76165
+ state->m.resize(state->pos);
75883
76166
  }
75884
76167
 
75885
- auto index2 = state->disturbed.data();
76168
+ auto index2 = state->m.data();
75886
76169
  D_ASSERT(index2);
75887
76170
 
75888
76171
  // The replacement trick does not work on the second index because if
@@ -76475,9 +76758,16 @@ struct MapFun {
76475
76758
  struct MapExtractFun {
76476
76759
  static void RegisterFunction(BuiltinFunctions &set);
76477
76760
  };
76761
+
76478
76762
  struct ListExtractFun {
76479
76763
  static void RegisterFunction(BuiltinFunctions &set);
76480
76764
  };
76765
+
76766
+ struct ListConcatFun {
76767
+ static ScalarFunction GetFunction();
76768
+ static void RegisterFunction(BuiltinFunctions &set);
76769
+ };
76770
+
76481
76771
  struct CardinalityFun {
76482
76772
  static void RegisterFunction(BuiltinFunctions &set);
76483
76773
  };
@@ -83453,11 +83743,6 @@ void ArraySliceFun::RegisterFunction(BuiltinFunctions &set) {
83453
83743
 
83454
83744
 
83455
83745
 
83456
-
83457
-
83458
-
83459
-
83460
-
83461
83746
  //===----------------------------------------------------------------------===//
83462
83747
  // DuckDB
83463
83748
  //
@@ -83497,6 +83782,147 @@ public:
83497
83782
 
83498
83783
 
83499
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
+
83500
83926
  namespace duckdb {
83501
83927
 
83502
83928
  template <class T, bool HEAP_REF = false, bool VALIDITY_ONLY = false>
@@ -85465,6 +85891,7 @@ void BuiltinFunctions::RegisterNestedFunctions() {
85465
85891
  Register<ArraySliceFun>();
85466
85892
  Register<StructPackFun>();
85467
85893
  Register<StructExtractFun>();
85894
+ Register<ListConcatFun>();
85468
85895
  Register<ListValueFun>();
85469
85896
  Register<ListExtractFun>();
85470
85897
  Register<ListRangeFun>();
@@ -85811,6 +86238,7 @@ struct BitwiseNotFun {
85811
86238
 
85812
86239
 
85813
86240
 
86241
+
85814
86242
  #include <limits>
85815
86243
 
85816
86244
  namespace duckdb {
@@ -86126,6 +86554,8 @@ void AddFun::RegisterFunction(BuiltinFunctions &set) {
86126
86554
 
86127
86555
  functions.AddFunction(GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL));
86128
86556
  functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::TIMESTAMP));
86557
+ // we can add lists together
86558
+ functions.AddFunction(ListConcatFun::GetFunction());
86129
86559
 
86130
86560
  set.AddFunction(functions);
86131
86561
  }
@@ -87708,6 +88138,7 @@ void CHR::RegisterFunction(BuiltinFunctions &set) {
87708
88138
 
87709
88139
 
87710
88140
 
88141
+
87711
88142
  #include <string.h>
87712
88143
 
87713
88144
  namespace duckdb {
@@ -87953,6 +88384,7 @@ void ConcatFun::RegisterFunction(BuiltinFunctions &set) {
87953
88384
  concat_op.AddFunction(
87954
88385
  ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, ConcatOperator));
87955
88386
  concat_op.AddFunction(ScalarFunction({LogicalType::BLOB, LogicalType::BLOB}, LogicalType::BLOB, ConcatOperator));
88387
+ concat_op.AddFunction(ListConcatFun::GetFunction());
87956
88388
  set.AddFunction(concat_op);
87957
88389
 
87958
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 "fbeb407d4"
14
- #define DUCKDB_VERSION "0.3.1-dev501"
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
  };
@@ -5957,6 +5962,8 @@ template <>
5957
5962
  bool Hugeint::TryCast(hugeint_t input, float &result);
5958
5963
  template <>
5959
5964
  bool Hugeint::TryCast(hugeint_t input, double &result);
5965
+ template <>
5966
+ bool Hugeint::TryCast(hugeint_t input, long double &result);
5960
5967
 
5961
5968
  template <>
5962
5969
  bool Hugeint::TryConvert(int8_t value, hugeint_t &result);
@@ -5978,6 +5985,8 @@ template <>
5978
5985
  bool Hugeint::TryConvert(float value, hugeint_t &result);
5979
5986
  template <>
5980
5987
  bool Hugeint::TryConvert(double value, hugeint_t &result);
5988
+ template <>
5989
+ bool Hugeint::TryConvert(long double value, hugeint_t &result);
5981
5990
 
5982
5991
  } // namespace duckdb
5983
5992