duckdb 0.3.2-dev788.0 → 0.3.2-dev841.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/src/duckdb.cpp CHANGED
@@ -21139,6 +21139,7 @@ public:
21139
21139
 
21140
21140
  int64_t GetFileSize(FileHandle &handle) override;
21141
21141
 
21142
+ void Reset(FileHandle &handle) override;
21142
21143
  bool OnDiskFile(FileHandle &handle) override {
21143
21144
  return false;
21144
21145
  };
@@ -21181,6 +21182,10 @@ int64_t PipeFile::WriteChunk(void *buffer, int64_t nr_bytes) {
21181
21182
  return child_handle->Write(buffer, nr_bytes);
21182
21183
  }
21183
21184
 
21185
+ void PipeFileSystem::Reset(FileHandle &handle) {
21186
+ throw InternalException("Cannot reset pipe file system");
21187
+ }
21188
+
21184
21189
  int64_t PipeFileSystem::Read(FileHandle &handle, void *buffer, int64_t nr_bytes) {
21185
21190
  auto &pipe = (PipeFile &)handle;
21186
21191
  return pipe.ReadChunk(buffer, nr_bytes);
@@ -56617,6 +56622,125 @@ string PhysicalTopN::ParamsToString() const {
56617
56622
 
56618
56623
  namespace duckdb {
56619
56624
 
56625
+ struct CSVFileHandle {
56626
+ public:
56627
+ explicit CSVFileHandle(unique_ptr<FileHandle> file_handle_p) : file_handle(move(file_handle_p)) {
56628
+ can_seek = file_handle->CanSeek();
56629
+ plain_file_source = file_handle->OnDiskFile() && can_seek;
56630
+ file_size = file_handle->GetFileSize();
56631
+ }
56632
+
56633
+ bool CanSeek() {
56634
+ return can_seek;
56635
+ }
56636
+ void Seek(idx_t position) {
56637
+ if (!can_seek) {
56638
+ throw InternalException("Cannot seek in this file");
56639
+ }
56640
+ file_handle->Seek(position);
56641
+ }
56642
+ idx_t SeekPosition() {
56643
+ if (!can_seek) {
56644
+ throw InternalException("Cannot seek in this file");
56645
+ }
56646
+ return file_handle->SeekPosition();
56647
+ }
56648
+ void Reset() {
56649
+ if (plain_file_source) {
56650
+ file_handle->Reset();
56651
+ } else {
56652
+ if (!reset_enabled) {
56653
+ throw InternalException("Reset called but reset is not enabled for this CSV Handle");
56654
+ }
56655
+ read_position = 0;
56656
+ }
56657
+ }
56658
+ bool PlainFileSource() {
56659
+ return plain_file_source;
56660
+ }
56661
+
56662
+ idx_t FileSize() {
56663
+ return file_size;
56664
+ }
56665
+
56666
+ idx_t Read(void *buffer, idx_t nr_bytes) {
56667
+ if (!plain_file_source) {
56668
+ // not a plain file source: we need to do some bookkeeping around the reset functionality
56669
+ idx_t result_offset = 0;
56670
+ if (read_position < buffer_size) {
56671
+ // we need to read from our cached buffer
56672
+ auto buffer_read_count = MinValue<idx_t>(nr_bytes, buffer_size - read_position);
56673
+ memcpy(buffer, cached_buffer.get() + read_position, buffer_read_count);
56674
+ result_offset += buffer_read_count;
56675
+ read_position += buffer_read_count;
56676
+ if (result_offset == nr_bytes) {
56677
+ return nr_bytes;
56678
+ }
56679
+ } else if (!reset_enabled && cached_buffer) {
56680
+ // reset is disabled but we still have cached data
56681
+ // we can remove any cached data
56682
+ cached_buffer.reset();
56683
+ buffer_size = 0;
56684
+ buffer_capacity = 0;
56685
+ read_position = 0;
56686
+ }
56687
+ // we have data left to read from the file
56688
+ // read directly into the buffer
56689
+ auto bytes_read = file_handle->Read((char *)buffer + result_offset, nr_bytes - result_offset);
56690
+ read_position += bytes_read;
56691
+ if (reset_enabled) {
56692
+ // if reset caching is enabled, we need to cache the bytes that we have read
56693
+ if (buffer_size + bytes_read >= buffer_capacity) {
56694
+ // no space; first enlarge the buffer
56695
+ buffer_capacity = MaxValue<idx_t>(NextPowerOfTwo(buffer_size + bytes_read), buffer_capacity * 2);
56696
+
56697
+ auto new_buffer = unique_ptr<data_t[]>(new data_t[buffer_capacity]);
56698
+ if (buffer_size > 0) {
56699
+ memcpy(new_buffer.get(), cached_buffer.get(), buffer_size);
56700
+ }
56701
+ cached_buffer = move(new_buffer);
56702
+ }
56703
+ memcpy(cached_buffer.get() + buffer_size, (char *)buffer + result_offset, bytes_read);
56704
+ buffer_size += bytes_read;
56705
+ }
56706
+
56707
+ return result_offset + bytes_read;
56708
+ } else {
56709
+ return file_handle->Read(buffer, nr_bytes);
56710
+ }
56711
+ }
56712
+
56713
+ string ReadLine() {
56714
+ string result;
56715
+ char buffer[1];
56716
+ while (true) {
56717
+ idx_t tuples_read = Read(buffer, 1);
56718
+ if (tuples_read == 0 || buffer[0] == '\n') {
56719
+ return result;
56720
+ }
56721
+ if (buffer[0] != '\r') {
56722
+ result += buffer[0];
56723
+ }
56724
+ }
56725
+ }
56726
+
56727
+ void DisableReset() {
56728
+ this->reset_enabled = false;
56729
+ }
56730
+
56731
+ private:
56732
+ unique_ptr<FileHandle> file_handle;
56733
+ bool reset_enabled = true;
56734
+ bool can_seek = false;
56735
+ bool plain_file_source = false;
56736
+ idx_t file_size = 0;
56737
+ // reset support
56738
+ unique_ptr<data_t[]> cached_buffer;
56739
+ idx_t read_position = 0;
56740
+ idx_t buffer_size = 0;
56741
+ idx_t buffer_capacity = 0;
56742
+ };
56743
+
56620
56744
  void BufferedCSVReaderOptions::SetDelimiter(const string &input) {
56621
56745
  this->delimiter = StringUtil::Replace(input, "\\t", "\t");
56622
56746
  this->has_delimiter = true;
@@ -56749,6 +56873,13 @@ BufferedCSVReader::BufferedCSVReader(ClientContext &context, BufferedCSVReaderOp
56749
56873
  requested_types) {
56750
56874
  }
56751
56875
 
56876
+ BufferedCSVReader::~BufferedCSVReader() {
56877
+ }
56878
+
56879
+ idx_t BufferedCSVReader::GetFileSize() {
56880
+ return file_handle ? file_handle->FileSize() : 0;
56881
+ }
56882
+
56752
56883
  void BufferedCSVReader::Initialize(const vector<LogicalType> &requested_types) {
56753
56884
  PrepareComplexParser();
56754
56885
  if (options.auto_detect) {
@@ -56765,6 +56896,9 @@ void BufferedCSVReader::Initialize(const vector<LogicalType> &requested_types) {
56765
56896
  SkipRowsAndReadHeader(options.skip_rows, options.header);
56766
56897
  }
56767
56898
  InitParseChunk(sql_types.size());
56899
+ // we only need reset support during the automatic CSV type detection
56900
+ // since reset support might require caching (in the case of streams), we disable it for the remainder
56901
+ file_handle->DisableReset();
56768
56902
  }
56769
56903
 
56770
56904
  void BufferedCSVReader::PrepareComplexParser() {
@@ -56773,12 +56907,10 @@ void BufferedCSVReader::PrepareComplexParser() {
56773
56907
  quote_search = TextSearchShiftArray(options.quote);
56774
56908
  }
56775
56909
 
56776
- unique_ptr<FileHandle> BufferedCSVReader::OpenCSV(const BufferedCSVReaderOptions &options) {
56777
- auto result = fs.OpenFile(options.file_path.c_str(), FileFlags::FILE_FLAGS_READ, FileLockType::NO_LOCK,
56778
- options.compression, this->opener);
56779
- plain_file_source = result->OnDiskFile() && result->CanSeek();
56780
- file_size = result->GetFileSize();
56781
- return result;
56910
+ unique_ptr<CSVFileHandle> BufferedCSVReader::OpenCSV(const BufferedCSVReaderOptions &options) {
56911
+ auto file_handle = fs.OpenFile(options.file_path.c_str(), FileFlags::FILE_FLAGS_READ, FileLockType::NO_LOCK,
56912
+ options.compression, this->opener);
56913
+ return make_unique<CSVFileHandle>(move(file_handle));
56782
56914
  }
56783
56915
 
56784
56916
  // Helper function to generate column names
@@ -56944,7 +57076,7 @@ bool BufferedCSVReader::JumpToNextSample() {
56944
57076
  // assess if it makes sense to jump, based on size of the first chunk relative to size of the entire file
56945
57077
  if (sample_chunk_idx == 0) {
56946
57078
  idx_t bytes_first_chunk = bytes_in_chunk;
56947
- double chunks_fit = (file_size / (double)bytes_first_chunk);
57079
+ double chunks_fit = (file_handle->FileSize() / (double)bytes_first_chunk);
56948
57080
  jumping_samples = chunks_fit >= options.sample_chunks;
56949
57081
 
56950
57082
  // jump back to the beginning
@@ -56959,7 +57091,7 @@ bool BufferedCSVReader::JumpToNextSample() {
56959
57091
 
56960
57092
  // if we deal with any other sources than plaintext files, jumping_samples can be tricky. In that case
56961
57093
  // we just read x continuous chunks from the stream TODO: make jumps possible for zipfiles.
56962
- if (!plain_file_source || !jumping_samples) {
57094
+ if (!file_handle->PlainFileSource() || !jumping_samples) {
56963
57095
  sample_chunk_idx++;
56964
57096
  return true;
56965
57097
  }
@@ -56969,13 +57101,13 @@ bool BufferedCSVReader::JumpToNextSample() {
56969
57101
  bytes_per_line_avg = ((bytes_per_line_avg * (sample_chunk_idx)) + bytes_per_line) / (sample_chunk_idx + 1);
56970
57102
 
56971
57103
  // if none of the previous conditions were met, we can jump
56972
- idx_t partition_size = (idx_t)round(file_size / (double)options.sample_chunks);
57104
+ idx_t partition_size = (idx_t)round(file_handle->FileSize() / (double)options.sample_chunks);
56973
57105
 
56974
57106
  // calculate offset to end of the current partition
56975
57107
  int64_t offset = partition_size - bytes_in_chunk - remaining_bytes_in_buffer;
56976
57108
  auto current_pos = file_handle->SeekPosition();
56977
57109
 
56978
- if (current_pos + offset < file_size) {
57110
+ if (current_pos + offset < file_handle->FileSize()) {
56979
57111
  // set position in stream and clear failure bits
56980
57112
  file_handle->Seek(current_pos + offset);
56981
57113
 
@@ -56986,10 +57118,10 @@ bool BufferedCSVReader::JumpToNextSample() {
56986
57118
  // seek backwards from the end in last chunk and hope to catch the end of the file
56987
57119
  // TODO: actually it would be good to make sure that the end of file is being reached, because
56988
57120
  // messy end-lines are quite common. For this case, however, we first need a skip_end detection anyways.
56989
- file_handle->Seek(file_size - bytes_in_chunk);
57121
+ file_handle->Seek(file_handle->FileSize() - bytes_in_chunk);
56990
57122
 
56991
57123
  // estimate linenr
56992
- linenr = (idx_t)round((file_size - bytes_in_chunk) / bytes_per_line_avg);
57124
+ linenr = (idx_t)round((file_handle->FileSize() - bytes_in_chunk) / bytes_per_line_avg);
56993
57125
  linenr_estimated = true;
56994
57126
  }
56995
57127
 
@@ -57143,6 +57275,7 @@ void BufferedCSVReader::DetectDialect(const vector<LogicalType> &requested_types
57143
57275
 
57144
57276
  JumpToBeginning(original_options.skip_rows);
57145
57277
  sniffed_column_counts.clear();
57278
+
57146
57279
  if (!TryParseCSV(ParserMode::SNIFFING_DIALECT)) {
57147
57280
  continue;
57148
57281
  }
@@ -88587,9 +88720,9 @@ static void GenerateUUIDFunction(DataChunk &args, ExpressionState &state, Vector
88587
88720
  }
88588
88721
 
88589
88722
  void UUIDFun::RegisterFunction(BuiltinFunctions &set) {
88723
+ ScalarFunction uuid_function({}, LogicalType::UUID, GenerateUUIDFunction, true, UUIDRandomBind);
88590
88724
  // generate a random uuid
88591
- set.AddFunction(
88592
- ScalarFunction("gen_random_uuid", {}, LogicalType::UUID, GenerateUUIDFunction, true, UUIDRandomBind));
88725
+ set.AddFunction({"uuid", "gen_random_uuid"}, uuid_function);
88593
88726
  }
88594
88727
 
88595
88728
  } // namespace duckdb
@@ -91542,7 +91675,7 @@ static unique_ptr<FunctionOperatorData> ReadCSVInit(ClientContext &context, cons
91542
91675
  result->csv_reader = make_unique<BufferedCSVReader>(context, bind_data.options, bind_data.sql_types);
91543
91676
  }
91544
91677
  bind_data.bytes_read = 0;
91545
- bind_data.file_size = result->csv_reader->file_size;
91678
+ bind_data.file_size = result->csv_reader->GetFileSize();
91546
91679
  result->file_index = 1;
91547
91680
  return move(result);
91548
91681
  }
@@ -98287,8 +98420,8 @@ string ClientContext::VerifyQuery(ClientContextLock &lock, const string &query,
98287
98420
  } catch (std::exception &ex) {
98288
98421
  original_result->error = ex.what();
98289
98422
  original_result->success = false;
98290
- interrupted = false;
98291
98423
  }
98424
+ interrupted = false;
98292
98425
 
98293
98426
  // check explain, only if q does not already contain EXPLAIN
98294
98427
  if (original_result->success) {
@@ -98308,8 +98441,8 @@ string ClientContext::VerifyQuery(ClientContextLock &lock, const string &query,
98308
98441
  } catch (std::exception &ex) {
98309
98442
  copied_result->error = ex.what();
98310
98443
  copied_result->success = false;
98311
- interrupted = false;
98312
98444
  }
98445
+ interrupted = false;
98313
98446
  // now execute the deserialized statement
98314
98447
  try {
98315
98448
  auto result = RunStatementInternal(lock, query, move(deserialized_stmt), false, false);
@@ -98317,8 +98450,8 @@ string ClientContext::VerifyQuery(ClientContextLock &lock, const string &query,
98317
98450
  } catch (std::exception &ex) {
98318
98451
  deserialized_result->error = ex.what();
98319
98452
  deserialized_result->success = false;
98320
- interrupted = false;
98321
98453
  }
98454
+ interrupted = false;
98322
98455
  // now execute the unoptimized statement
98323
98456
  config.enable_optimizer = false;
98324
98457
  try {
@@ -98327,8 +98460,8 @@ string ClientContext::VerifyQuery(ClientContextLock &lock, const string &query,
98327
98460
  } catch (std::exception &ex) {
98328
98461
  unoptimized_result->error = ex.what();
98329
98462
  unoptimized_result->success = false;
98330
- interrupted = false;
98331
98463
  }
98464
+ interrupted = false;
98332
98465
  config.enable_optimizer = true;
98333
98466
 
98334
98467
  if (profiling_is_enabled) {
@@ -112849,7 +112982,10 @@ void ExpressionRewriter::VisitExpression(unique_ptr<Expression> *expression) {
112849
112982
 
112850
112983
 
112851
112984
 
112985
+
112986
+
112852
112987
  #include <functional>
112988
+ #include <map>
112853
112989
 
112854
112990
  namespace duckdb {
112855
112991
 
@@ -112887,6 +113023,37 @@ private:
112887
113023
  idx_t GetEquivalenceSet(Expression *expr);
112888
113024
  FilterResult AddConstantComparison(vector<ExpressionValueInformation> &info_list, ExpressionValueInformation info);
112889
113025
 
113026
+ //! Functions used to push and generate OR Filters
113027
+ void LookUpConjunctions(Expression *expr);
113028
+ bool BFSLookUpConjunctions(BoundConjunctionExpression *conjunction);
113029
+ void VerifyOrsToPush(Expression &expr);
113030
+
113031
+ bool UpdateConjunctionFilter(BoundComparisonExpression *comparison_expr);
113032
+ bool UpdateFilterByColumn(BoundColumnRefExpression *column_ref, BoundComparisonExpression *comparison_expr);
113033
+ void GenerateORFilters(TableFilterSet &table_filter, vector<idx_t> &column_ids);
113034
+
113035
+ template <typename CONJUNCTION_TYPE>
113036
+ void GenerateConjunctionFilter(BoundConjunctionExpression *conjunction, ConjunctionFilter *last_conj_filter) {
113037
+ auto new_filter = NextConjunctionFilter<CONJUNCTION_TYPE>(conjunction);
113038
+ auto conj_filter_ptr = (ConjunctionFilter *)new_filter.get();
113039
+ last_conj_filter->child_filters.push_back(move(new_filter));
113040
+ last_conj_filter = conj_filter_ptr;
113041
+ }
113042
+
113043
+ template <typename CONJUNCTION_TYPE>
113044
+ unique_ptr<TableFilter> NextConjunctionFilter(BoundConjunctionExpression *conjunction) {
113045
+ unique_ptr<ConjunctionFilter> conj_filter = make_unique<CONJUNCTION_TYPE>();
113046
+ for (auto &expr : conjunction->children) {
113047
+ auto comp_expr = (BoundComparisonExpression *)expr.get();
113048
+ auto &const_expr =
113049
+ (comp_expr->left->type == ExpressionType::VALUE_CONSTANT) ? *comp_expr->left : *comp_expr->right;
113050
+ auto const_value = ExpressionExecutor::EvaluateScalar(const_expr);
113051
+ auto const_filter = make_unique<ConstantFilter>(comp_expr->type, const_value);
113052
+ conj_filter->child_filters.push_back(move(const_filter));
113053
+ }
113054
+ return move(conj_filter);
113055
+ }
113056
+
112890
113057
  private:
112891
113058
  vector<unique_ptr<Expression>> remaining_filters;
112892
113059
 
@@ -112895,6 +113062,26 @@ private:
112895
113062
  unordered_map<idx_t, vector<ExpressionValueInformation>> constant_values;
112896
113063
  unordered_map<idx_t, vector<Expression *>> equivalence_map;
112897
113064
  idx_t set_index = 0;
113065
+
113066
+ //! Structures used for OR Filters
113067
+
113068
+ struct ConjunctionsToPush {
113069
+ BoundConjunctionExpression *root_or;
113070
+
113071
+ // only preserve AND if there is a single column in the expression
113072
+ bool preserve_and = true;
113073
+
113074
+ // conjunction chain for this column
113075
+ vector<unique_ptr<BoundConjunctionExpression>> conjunctions;
113076
+ };
113077
+
113078
+ expression_map_t<vector<unique_ptr<ConjunctionsToPush>>> map_col_conjunctions;
113079
+ vector<BoundColumnRefExpression *> vec_colref_insertion_order;
113080
+
113081
+ BoundConjunctionExpression *cur_root_or;
113082
+ BoundConjunctionExpression *cur_conjunction;
113083
+
113084
+ BoundColumnRefExpression *cur_colref_to_push;
112898
113085
  };
112899
113086
 
112900
113087
  } // namespace duckdb
@@ -112916,6 +113103,7 @@ private:
112916
113103
 
112917
113104
 
112918
113105
 
113106
+
112919
113107
  namespace duckdb {
112920
113108
 
112921
113109
  using ExpressionValueInformation = FilterCombiner::ExpressionValueInformation;
@@ -112978,6 +113166,7 @@ FilterResult FilterCombiner::AddConstantComparison(vector<ExpressionValueInforma
112978
113166
  }
112979
113167
 
112980
113168
  FilterResult FilterCombiner::AddFilter(unique_ptr<Expression> expr) {
113169
+ LookUpConjunctions(expr.get());
112981
113170
  // try to push the filter into the combiner
112982
113171
  auto result = AddFilter(expr.get());
112983
113172
  if (result == FilterResult::UNSUPPORTED) {
@@ -113450,6 +113639,8 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(vector<idx_t> &column_id
113450
113639
  }
113451
113640
  }
113452
113641
 
113642
+ GenerateORFilters(table_filters, column_ids);
113643
+
113453
113644
  return table_filters;
113454
113645
  }
113455
113646
 
@@ -113887,6 +114078,176 @@ ValueComparisonResult CompareValueInformation(ExpressionValueInformation &left,
113887
114078
  }
113888
114079
  }
113889
114080
 
114081
+ void FilterCombiner::LookUpConjunctions(Expression *expr) {
114082
+ if (expr->GetExpressionType() == ExpressionType::CONJUNCTION_OR) {
114083
+ auto root_or_expr = (BoundConjunctionExpression *)expr;
114084
+ for (const auto &entry : map_col_conjunctions) {
114085
+ for (const auto &conjs_to_push : entry.second) {
114086
+ if (conjs_to_push->root_or->Equals(root_or_expr)) {
114087
+ return;
114088
+ }
114089
+ }
114090
+ }
114091
+
114092
+ cur_root_or = root_or_expr;
114093
+ cur_conjunction = root_or_expr;
114094
+ cur_colref_to_push = nullptr;
114095
+ if (!BFSLookUpConjunctions(cur_root_or)) {
114096
+ if (cur_colref_to_push) {
114097
+ auto entry = map_col_conjunctions.find(cur_colref_to_push);
114098
+ auto &vec_conjs_to_push = entry->second;
114099
+ if (vec_conjs_to_push.size() == 1) {
114100
+ map_col_conjunctions.erase(entry);
114101
+ return;
114102
+ }
114103
+ vec_conjs_to_push.pop_back();
114104
+ }
114105
+ }
114106
+ return;
114107
+ }
114108
+
114109
+ // Verify if the expression has a column already pushed down by other OR expression
114110
+ VerifyOrsToPush(*expr);
114111
+ }
114112
+
114113
+ bool FilterCombiner::BFSLookUpConjunctions(BoundConjunctionExpression *conjunction) {
114114
+ vector<BoundConjunctionExpression *> conjunctions_to_visit;
114115
+
114116
+ for (auto &child : conjunction->children) {
114117
+ switch (child->GetExpressionClass()) {
114118
+ case ExpressionClass::BOUND_CONJUNCTION: {
114119
+ auto child_conjunction = (BoundConjunctionExpression *)child.get();
114120
+ conjunctions_to_visit.emplace_back(child_conjunction);
114121
+ break;
114122
+ }
114123
+ case ExpressionClass::BOUND_COMPARISON: {
114124
+ if (!UpdateConjunctionFilter((BoundComparisonExpression *)child.get())) {
114125
+ return false;
114126
+ }
114127
+ break;
114128
+ }
114129
+ default: {
114130
+ return false;
114131
+ }
114132
+ }
114133
+ }
114134
+
114135
+ for (auto child_conjunction : conjunctions_to_visit) {
114136
+ cur_conjunction = child_conjunction;
114137
+ // traverse child conjuction
114138
+ if (!BFSLookUpConjunctions(child_conjunction)) {
114139
+ return false;
114140
+ }
114141
+ }
114142
+ return true;
114143
+ }
114144
+
114145
+ void FilterCombiner::VerifyOrsToPush(Expression &expr) {
114146
+ if (expr.type == ExpressionType::BOUND_COLUMN_REF) {
114147
+ auto colref = (BoundColumnRefExpression *)&expr;
114148
+ auto entry = map_col_conjunctions.find(colref);
114149
+ if (entry == map_col_conjunctions.end()) {
114150
+ return;
114151
+ }
114152
+ map_col_conjunctions.erase(entry);
114153
+ }
114154
+ ExpressionIterator::EnumerateChildren(expr, [&](Expression &child) { VerifyOrsToPush(child); });
114155
+ }
114156
+
114157
+ bool FilterCombiner::UpdateConjunctionFilter(BoundComparisonExpression *comparison_expr) {
114158
+ bool left_is_scalar = comparison_expr->left->IsFoldable();
114159
+ bool right_is_scalar = comparison_expr->right->IsFoldable();
114160
+
114161
+ Expression *non_scalar_expr;
114162
+ if (left_is_scalar || right_is_scalar) {
114163
+ // only support comparison with scalar
114164
+ non_scalar_expr = left_is_scalar ? comparison_expr->right.get() : comparison_expr->left.get();
114165
+
114166
+ if (non_scalar_expr->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) {
114167
+ return UpdateFilterByColumn((BoundColumnRefExpression *)non_scalar_expr, comparison_expr);
114168
+ }
114169
+ }
114170
+
114171
+ return false;
114172
+ }
114173
+
114174
+ bool FilterCombiner::UpdateFilterByColumn(BoundColumnRefExpression *column_ref,
114175
+ BoundComparisonExpression *comparison_expr) {
114176
+ if (cur_colref_to_push == nullptr) {
114177
+ cur_colref_to_push = column_ref;
114178
+
114179
+ auto or_conjunction = make_unique<BoundConjunctionExpression>(ExpressionType::CONJUNCTION_OR);
114180
+ or_conjunction->children.emplace_back(comparison_expr->Copy());
114181
+
114182
+ unique_ptr<ConjunctionsToPush> conjs_to_push = make_unique<ConjunctionsToPush>();
114183
+ conjs_to_push->conjunctions.emplace_back(move(or_conjunction));
114184
+ conjs_to_push->root_or = cur_root_or;
114185
+
114186
+ auto &&vec_col_conjs = map_col_conjunctions[column_ref];
114187
+ vec_col_conjs.emplace_back(move(conjs_to_push));
114188
+ vec_colref_insertion_order.emplace_back(column_ref);
114189
+ return true;
114190
+ }
114191
+
114192
+ auto entry = map_col_conjunctions.find(cur_colref_to_push);
114193
+ D_ASSERT(entry != map_col_conjunctions.end());
114194
+ auto &conjunctions_to_push = entry->second.back();
114195
+
114196
+ if (!cur_colref_to_push->Equals(column_ref)) {
114197
+ // check for multiple colunms in the same root OR node
114198
+ if (cur_root_or == cur_conjunction) {
114199
+ return false;
114200
+ }
114201
+ // found an AND using a different column, we should stop the look up
114202
+ if (cur_conjunction->GetExpressionType() == ExpressionType::CONJUNCTION_AND) {
114203
+ return false;
114204
+ }
114205
+
114206
+ // found a different column, AND conditions cannot be preserved anymore
114207
+ conjunctions_to_push->preserve_and = false;
114208
+ return true;
114209
+ }
114210
+
114211
+ auto &last_conjunction = conjunctions_to_push->conjunctions.back();
114212
+ if (cur_conjunction->GetExpressionType() == last_conjunction->GetExpressionType()) {
114213
+ last_conjunction->children.emplace_back(comparison_expr->Copy());
114214
+ } else {
114215
+ auto new_conjunction = make_unique<BoundConjunctionExpression>(cur_conjunction->GetExpressionType());
114216
+ new_conjunction->children.emplace_back(comparison_expr->Copy());
114217
+ conjunctions_to_push->conjunctions.emplace_back(move(new_conjunction));
114218
+ }
114219
+ return true;
114220
+ }
114221
+
114222
+ void FilterCombiner::GenerateORFilters(TableFilterSet &table_filter, vector<idx_t> &column_ids) {
114223
+ for (const auto colref : vec_colref_insertion_order) {
114224
+ auto column_index = column_ids[colref->binding.column_index];
114225
+ if (column_index == COLUMN_IDENTIFIER_ROW_ID) {
114226
+ break;
114227
+ }
114228
+
114229
+ for (const auto &conjunctions_to_push : map_col_conjunctions[colref]) {
114230
+ // root OR filter to push into the TableFilter
114231
+ auto root_or_filter = make_unique<ConjunctionOrFilter>();
114232
+ // variable to hold the last conjuntion filter pointer
114233
+ // the next filter will be added into it, i.e., we create a chain of conjunction filters
114234
+ ConjunctionFilter *last_conj_filter = root_or_filter.get();
114235
+
114236
+ for (auto &conjunction : conjunctions_to_push->conjunctions) {
114237
+ if (conjunction->GetExpressionType() == ExpressionType::CONJUNCTION_AND &&
114238
+ conjunctions_to_push->preserve_and) {
114239
+ GenerateConjunctionFilter<ConjunctionAndFilter>(conjunction.get(), last_conj_filter);
114240
+ } else {
114241
+ GenerateConjunctionFilter<ConjunctionOrFilter>(conjunction.get(), last_conj_filter);
114242
+ }
114243
+ }
114244
+ table_filter.PushFilter(column_index, move(root_or_filter));
114245
+ }
114246
+ }
114247
+ map_col_conjunctions.clear();
114248
+ vec_colref_insertion_order.clear();
114249
+ }
114250
+
113890
114251
  } // namespace duckdb
113891
114252
  //===----------------------------------------------------------------------===//
113892
114253
  // DuckDB
@@ -119023,6 +119384,10 @@ FilterPropagateResult StatisticsPropagator::PropagateComparison(BaseStatistics &
119023
119384
  // only handle numerics for now
119024
119385
  switch (left.type.InternalType()) {
119025
119386
  case PhysicalType::BOOL:
119387
+ case PhysicalType::UINT8:
119388
+ case PhysicalType::UINT16:
119389
+ case PhysicalType::UINT32:
119390
+ case PhysicalType::UINT64:
119026
119391
  case PhysicalType::INT8:
119027
119392
  case PhysicalType::INT16:
119028
119393
  case PhysicalType::INT32:
@@ -119150,6 +119515,10 @@ namespace duckdb {
119150
119515
  unique_ptr<BaseStatistics> StatisticsPropagator::StatisticsFromValue(const Value &input) {
119151
119516
  switch (input.type().InternalType()) {
119152
119517
  case PhysicalType::BOOL:
119518
+ case PhysicalType::UINT8:
119519
+ case PhysicalType::UINT16:
119520
+ case PhysicalType::UINT32:
119521
+ case PhysicalType::UINT64:
119153
119522
  case PhysicalType::INT8:
119154
119523
  case PhysicalType::INT16:
119155
119524
  case PhysicalType::INT32:
@@ -149839,7 +150208,7 @@ void ExpressionIterator::EnumerateQueryNodeChildren(BoundQueryNode &node,
149839
150208
 
149840
150209
  namespace duckdb {
149841
150210
 
149842
- ConjunctionOrFilter::ConjunctionOrFilter() : TableFilter(TableFilterType::CONJUNCTION_OR) {
150211
+ ConjunctionOrFilter::ConjunctionOrFilter() : ConjunctionFilter(TableFilterType::CONJUNCTION_OR) {
149843
150212
  }
149844
150213
 
149845
150214
  FilterPropagateResult ConjunctionOrFilter::CheckStatistics(BaseStatistics &stats) {
@@ -149868,7 +150237,7 @@ string ConjunctionOrFilter::ToString(const string &column_name) {
149868
150237
  }
149869
150238
 
149870
150239
  bool ConjunctionOrFilter::Equals(const TableFilter &other_p) const {
149871
- if (!TableFilter::Equals(other_p)) {
150240
+ if (!ConjunctionFilter::Equals(other_p)) {
149872
150241
  return false;
149873
150242
  }
149874
150243
  auto &other = (ConjunctionOrFilter &)other_p;
@@ -149883,11 +150252,11 @@ bool ConjunctionOrFilter::Equals(const TableFilter &other_p) const {
149883
150252
  return true;
149884
150253
  }
149885
150254
 
149886
- ConjunctionAndFilter::ConjunctionAndFilter() : TableFilter(TableFilterType::CONJUNCTION_AND) {
150255
+ ConjunctionAndFilter::ConjunctionAndFilter() : ConjunctionFilter(TableFilterType::CONJUNCTION_AND) {
149887
150256
  }
149888
150257
 
149889
150258
  FilterPropagateResult ConjunctionAndFilter::CheckStatistics(BaseStatistics &stats) {
149890
- // the OR filter is true if ALL of the children is true
150259
+ // the AND filter is true if ALL of the children is true
149891
150260
  D_ASSERT(!child_filters.empty());
149892
150261
  auto result = FilterPropagateResult::FILTER_ALWAYS_TRUE;
149893
150262
  for (auto &filter : child_filters) {
@@ -149913,7 +150282,7 @@ string ConjunctionAndFilter::ToString(const string &column_name) {
149913
150282
  }
149914
150283
 
149915
150284
  bool ConjunctionAndFilter::Equals(const TableFilter &other_p) const {
149916
- if (!TableFilter::Equals(other_p)) {
150285
+ if (!ConjunctionFilter::Equals(other_p)) {
149917
150286
  return false;
149918
150287
  }
149919
150288
  auto &other = (ConjunctionAndFilter &)other_p;
@@ -160130,6 +160499,14 @@ FilterPropagateResult NumericStatistics::CheckZonemap(ExpressionType comparison_
160130
160499
  } else {
160131
160500
  return FilterPropagateResult::FILTER_ALWAYS_FALSE;
160132
160501
  }
160502
+ case ExpressionType::COMPARE_NOTEQUAL:
160503
+ if (constant < min || constant > max) {
160504
+ return FilterPropagateResult::FILTER_ALWAYS_TRUE;
160505
+ } else if (min == max && min == constant) {
160506
+ // corner case of a cluster with one numeric equal to the target constant
160507
+ return FilterPropagateResult::FILTER_ALWAYS_FALSE;
160508
+ }
160509
+ return FilterPropagateResult::NO_PRUNING_POSSIBLE;
160133
160510
  case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
160134
160511
  // X >= C
160135
160512
  // this can be true only if max(X) >= C
@@ -160326,7 +160703,6 @@ unique_ptr<BaseStatistics> StringStatistics::Copy() {
160326
160703
  memcpy(stats->max, max, MAX_STRING_MINMAX_SIZE);
160327
160704
  stats->has_unicode = has_unicode;
160328
160705
  stats->max_string_length = max_string_length;
160329
- stats->max_string_length = max_string_length;
160330
160706
  if (validity_stats) {
160331
160707
  stats->validity_stats = validity_stats->Copy();
160332
160708
  }
@@ -160430,6 +160806,11 @@ FilterPropagateResult StringStatistics::CheckZonemap(ExpressionType comparison_t
160430
160806
  } else {
160431
160807
  return FilterPropagateResult::FILTER_ALWAYS_FALSE;
160432
160808
  }
160809
+ case ExpressionType::COMPARE_NOTEQUAL:
160810
+ if (min_comp < 0 || max_comp > 0) {
160811
+ return FilterPropagateResult::FILTER_ALWAYS_TRUE;
160812
+ }
160813
+ return FilterPropagateResult::NO_PRUNING_POSSIBLE;
160433
160814
  case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
160434
160815
  case ExpressionType::COMPARE_GREATERTHAN:
160435
160816
  if (max_comp <= 0) {
@@ -162553,6 +162934,16 @@ static void FilterSelectionSwitch(T *vec, T *predicate, SelectionVector &sel, id
162553
162934
  }
162554
162935
  break;
162555
162936
  }
162937
+ case ExpressionType::COMPARE_NOTEQUAL: {
162938
+ if (mask.AllValid()) {
162939
+ approved_tuple_count =
162940
+ TemplatedFilterSelection<T, NotEquals, false>(vec, predicate, sel, approved_tuple_count, mask, new_sel);
162941
+ } else {
162942
+ approved_tuple_count =
162943
+ TemplatedFilterSelection<T, NotEquals, true>(vec, predicate, sel, approved_tuple_count, mask, new_sel);
162944
+ }
162945
+ break;
162946
+ }
162556
162947
  case ExpressionType::COMPARE_LESSTHAN: {
162557
162948
  if (mask.AllValid()) {
162558
162949
  approved_tuple_count =
@@ -162622,15 +163013,44 @@ static idx_t TemplatedNullSelection(SelectionVector &sel, idx_t approved_tuple_c
162622
163013
  }
162623
163014
  }
162624
163015
 
162625
- void ColumnSegment::FilterSelection(SelectionVector &sel, Vector &result, const TableFilter &filter,
162626
- idx_t &approved_tuple_count, ValidityMask &mask) {
163016
+ idx_t ColumnSegment::FilterSelection(SelectionVector &sel, Vector &result, const TableFilter &filter,
163017
+ idx_t &approved_tuple_count, ValidityMask &mask) {
162627
163018
  switch (filter.filter_type) {
163019
+ case TableFilterType::CONJUNCTION_OR: {
163020
+ // similar to the CONJUNCTION_AND, but we need to take care of the SelectionVectors (OR all of them)
163021
+ idx_t count_total = 0;
163022
+ SelectionVector result_sel(approved_tuple_count);
163023
+ auto &conjunction_or = (ConjunctionOrFilter &)filter;
163024
+ for (auto &child_filter : conjunction_or.child_filters) {
163025
+ SelectionVector temp_sel;
163026
+ temp_sel.Initialize(sel);
163027
+ idx_t temp_tuple_count = approved_tuple_count;
163028
+ idx_t temp_count = FilterSelection(temp_sel, result, *child_filter, temp_tuple_count, mask);
163029
+ // tuples passed, move them into the actual result vector
163030
+ for (idx_t i = 0; i < temp_count; i++) {
163031
+ auto new_idx = temp_sel.get_index(i);
163032
+ bool is_new_idx = true;
163033
+ for (idx_t res_idx = 0; res_idx < count_total; res_idx++) {
163034
+ if (result_sel.get_index(res_idx) == new_idx) {
163035
+ is_new_idx = false;
163036
+ break;
163037
+ }
163038
+ }
163039
+ if (is_new_idx) {
163040
+ result_sel.set_index(count_total++, new_idx);
163041
+ }
163042
+ }
163043
+ }
163044
+ sel.Initialize(result_sel);
163045
+ approved_tuple_count = count_total;
163046
+ return approved_tuple_count;
163047
+ }
162628
163048
  case TableFilterType::CONJUNCTION_AND: {
162629
163049
  auto &conjunction_and = (ConjunctionAndFilter &)filter;
162630
163050
  for (auto &child_filter : conjunction_and.child_filters) {
162631
163051
  FilterSelection(sel, result, *child_filter, approved_tuple_count, mask);
162632
163052
  }
162633
- break;
163053
+ return approved_tuple_count;
162634
163054
  }
162635
163055
  case TableFilterType::CONSTANT_COMPARISON: {
162636
163056
  auto &constant_filter = (ConstantFilter &)filter;
@@ -162743,14 +163163,12 @@ void ColumnSegment::FilterSelection(SelectionVector &sel, Vector &result, const
162743
163163
  default:
162744
163164
  throw InvalidTypeException(result.GetType(), "Invalid type for filter pushed down to table comparison");
162745
163165
  }
162746
- break;
163166
+ return approved_tuple_count;
162747
163167
  }
162748
163168
  case TableFilterType::IS_NULL:
162749
- TemplatedNullSelection<true>(sel, approved_tuple_count, mask);
162750
- break;
163169
+ return TemplatedNullSelection<true>(sel, approved_tuple_count, mask);
162751
163170
  case TableFilterType::IS_NOT_NULL:
162752
- TemplatedNullSelection<false>(sel, approved_tuple_count, mask);
162753
- break;
163171
+ return TemplatedNullSelection<false>(sel, approved_tuple_count, mask);
162754
163172
  default:
162755
163173
  throw InternalException("FIXME: unsupported type for filter selection");
162756
163174
  }