| 1 | #include "duckdb/storage/table/column_segment.hpp" |
| 2 | #include "duckdb/common/limits.hpp" |
| 3 | #include "duckdb/storage/table/update_segment.hpp" |
| 4 | #include "duckdb/common/types/null_value.hpp" |
| 5 | #include "duckdb/common/types/vector.hpp" |
| 6 | #include "duckdb/storage/table/append_state.hpp" |
| 7 | #include "duckdb/storage/storage_manager.hpp" |
| 8 | #include "duckdb/planner/filter/conjunction_filter.hpp" |
| 9 | #include "duckdb/planner/filter/constant_filter.hpp" |
| 10 | #include "duckdb/main/config.hpp" |
| 11 | #include "duckdb/storage/table/scan_state.hpp" |
| 12 | |
| 13 | #include <cstring> |
| 14 | |
| 15 | namespace duckdb { |
| 16 | |
| 17 | unique_ptr<ColumnSegment> ColumnSegment::CreatePersistentSegment(DatabaseInstance &db, BlockManager &block_manager, |
| 18 | block_id_t block_id, idx_t offset, |
| 19 | const LogicalType &type, idx_t start, idx_t count, |
| 20 | CompressionType compression_type, |
| 21 | BaseStatistics statistics) { |
| 22 | auto &config = DBConfig::GetConfig(db); |
| 23 | optional_ptr<CompressionFunction> function; |
| 24 | shared_ptr<BlockHandle> block; |
| 25 | if (block_id == INVALID_BLOCK) { |
| 26 | // constant segment, no need to allocate an actual block |
| 27 | function = config.GetCompressionFunction(type: CompressionType::COMPRESSION_CONSTANT, data_type: type.InternalType()); |
| 28 | } else { |
| 29 | function = config.GetCompressionFunction(type: compression_type, data_type: type.InternalType()); |
| 30 | block = block_manager.RegisterBlock(block_id); |
| 31 | } |
| 32 | auto segment_size = Storage::BLOCK_SIZE; |
| 33 | return make_uniq<ColumnSegment>(args&: db, args: std::move(block), args: type, args: ColumnSegmentType::PERSISTENT, args&: start, args&: count, args&: *function, |
| 34 | args: std::move(statistics), args&: block_id, args&: offset, args&: segment_size); |
| 35 | } |
| 36 | |
| 37 | unique_ptr<ColumnSegment> ColumnSegment::CreateTransientSegment(DatabaseInstance &db, const LogicalType &type, |
| 38 | idx_t start, idx_t segment_size) { |
| 39 | auto &config = DBConfig::GetConfig(db); |
| 40 | auto function = config.GetCompressionFunction(type: CompressionType::COMPRESSION_UNCOMPRESSED, data_type: type.InternalType()); |
| 41 | auto &buffer_manager = BufferManager::GetBufferManager(db); |
| 42 | shared_ptr<BlockHandle> block; |
| 43 | // transient: allocate a buffer for the uncompressed segment |
| 44 | if (segment_size < Storage::BLOCK_SIZE) { |
| 45 | block = buffer_manager.RegisterSmallMemory(block_size: segment_size); |
| 46 | } else { |
| 47 | buffer_manager.Allocate(block_size: segment_size, can_destroy: false, block: &block); |
| 48 | } |
| 49 | return make_uniq<ColumnSegment>(args&: db, args: std::move(block), args: type, args: ColumnSegmentType::TRANSIENT, args&: start, args: 0, args&: *function, |
| 50 | args: BaseStatistics::CreateEmpty(type), INVALID_BLOCK, args: 0, args&: segment_size); |
| 51 | } |
| 52 | |
| 53 | unique_ptr<ColumnSegment> ColumnSegment::CreateSegment(ColumnSegment &other, idx_t start) { |
| 54 | return make_uniq<ColumnSegment>(args&: other, args&: start); |
| 55 | } |
| 56 | |
| 57 | ColumnSegment::ColumnSegment(DatabaseInstance &db, shared_ptr<BlockHandle> block, LogicalType type_p, |
| 58 | ColumnSegmentType segment_type, idx_t start, idx_t count, CompressionFunction &function_p, |
| 59 | BaseStatistics statistics, block_id_t block_id_p, idx_t offset_p, idx_t segment_size_p) |
| 60 | : SegmentBase<ColumnSegment>(start, count), db(db), type(std::move(type_p)), |
| 61 | type_size(GetTypeIdSize(type: type.InternalType())), segment_type(segment_type), function(function_p), |
| 62 | stats(std::move(statistics)), block(std::move(block)), block_id(block_id_p), offset(offset_p), |
| 63 | segment_size(segment_size_p) { |
| 64 | if (function.get().init_segment) { |
| 65 | segment_state = function.get().init_segment(*this, block_id); |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | ColumnSegment::ColumnSegment(ColumnSegment &other, idx_t start) |
| 70 | : SegmentBase<ColumnSegment>(start, other.count.load()), db(other.db), type(std::move(other.type)), |
| 71 | type_size(other.type_size), segment_type(other.segment_type), function(other.function), |
| 72 | stats(std::move(other.stats)), block(std::move(other.block)), block_id(other.block_id), offset(other.offset), |
| 73 | segment_size(other.segment_size), segment_state(std::move(other.segment_state)) { |
| 74 | } |
| 75 | |
| 76 | ColumnSegment::~ColumnSegment() { |
| 77 | } |
| 78 | |
| 79 | //===--------------------------------------------------------------------===// |
| 80 | // Scan |
| 81 | //===--------------------------------------------------------------------===// |
| 82 | void ColumnSegment::InitializeScan(ColumnScanState &state) { |
| 83 | state.scan_state = function.get().init_scan(*this); |
| 84 | } |
| 85 | |
| 86 | void ColumnSegment::Scan(ColumnScanState &state, idx_t scan_count, Vector &result, idx_t result_offset, |
| 87 | bool entire_vector) { |
| 88 | if (entire_vector) { |
| 89 | D_ASSERT(result_offset == 0); |
| 90 | Scan(state, scan_count, result); |
| 91 | } else { |
| 92 | D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); |
| 93 | ScanPartial(state, scan_count, result, result_offset); |
| 94 | D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | void ColumnSegment::Skip(ColumnScanState &state) { |
| 99 | function.get().skip(*this, state, state.row_index - state.internal_index); |
| 100 | state.internal_index = state.row_index; |
| 101 | } |
| 102 | |
| 103 | void ColumnSegment::Scan(ColumnScanState &state, idx_t scan_count, Vector &result) { |
| 104 | function.get().scan_vector(*this, state, scan_count, result); |
| 105 | } |
| 106 | |
| 107 | void ColumnSegment::ScanPartial(ColumnScanState &state, idx_t scan_count, Vector &result, idx_t result_offset) { |
| 108 | function.get().scan_partial(*this, state, scan_count, result, result_offset); |
| 109 | } |
| 110 | |
| 111 | //===--------------------------------------------------------------------===// |
| 112 | // Fetch |
| 113 | //===--------------------------------------------------------------------===// |
| 114 | void ColumnSegment::FetchRow(ColumnFetchState &state, row_t row_id, Vector &result, idx_t result_idx) { |
| 115 | function.get().fetch_row(*this, state, row_id - this->start, result, result_idx); |
| 116 | } |
| 117 | |
| 118 | //===--------------------------------------------------------------------===// |
| 119 | // Append |
| 120 | //===--------------------------------------------------------------------===// |
| 121 | idx_t ColumnSegment::SegmentSize() const { |
| 122 | return segment_size; |
| 123 | } |
| 124 | |
| 125 | void ColumnSegment::Resize(idx_t new_size) { |
| 126 | D_ASSERT(new_size > this->segment_size); |
| 127 | D_ASSERT(offset == 0); |
| 128 | auto &buffer_manager = BufferManager::GetBufferManager(db); |
| 129 | auto old_handle = buffer_manager.Pin(handle&: block); |
| 130 | shared_ptr<BlockHandle> new_block; |
| 131 | auto new_handle = buffer_manager.Allocate(block_size: Storage::BLOCK_SIZE, can_destroy: false, block: &new_block); |
| 132 | memcpy(dest: new_handle.Ptr(), src: old_handle.Ptr(), n: segment_size); |
| 133 | this->block_id = new_block->BlockId(); |
| 134 | this->block = std::move(new_block); |
| 135 | this->segment_size = new_size; |
| 136 | } |
| 137 | |
| 138 | void ColumnSegment::InitializeAppend(ColumnAppendState &state) { |
| 139 | D_ASSERT(segment_type == ColumnSegmentType::TRANSIENT); |
| 140 | if (!function.get().init_append) { |
| 141 | throw InternalException("Attempting to init append to a segment without init_append method" ); |
| 142 | } |
| 143 | state.append_state = function.get().init_append(*this); |
| 144 | } |
| 145 | |
| 146 | idx_t ColumnSegment::Append(ColumnAppendState &state, UnifiedVectorFormat &append_data, idx_t offset, idx_t count) { |
| 147 | D_ASSERT(segment_type == ColumnSegmentType::TRANSIENT); |
| 148 | if (!function.get().append) { |
| 149 | throw InternalException("Attempting to append to a segment without append method" ); |
| 150 | } |
| 151 | return function.get().append(*state.append_state, *this, stats, append_data, offset, count); |
| 152 | } |
| 153 | |
| 154 | idx_t ColumnSegment::FinalizeAppend(ColumnAppendState &state) { |
| 155 | D_ASSERT(segment_type == ColumnSegmentType::TRANSIENT); |
| 156 | if (!function.get().finalize_append) { |
| 157 | throw InternalException("Attempting to call FinalizeAppend on a segment without a finalize_append method" ); |
| 158 | } |
| 159 | auto result_count = function.get().finalize_append(*this, stats); |
| 160 | state.append_state.reset(); |
| 161 | return result_count; |
| 162 | } |
| 163 | |
| 164 | void ColumnSegment::RevertAppend(idx_t start_row) { |
| 165 | D_ASSERT(segment_type == ColumnSegmentType::TRANSIENT); |
| 166 | if (function.get().revert_append) { |
| 167 | function.get().revert_append(*this, start_row); |
| 168 | } |
| 169 | this->count = start_row - this->start; |
| 170 | } |
| 171 | |
| 172 | //===--------------------------------------------------------------------===// |
| 173 | // Convert To Persistent |
| 174 | //===--------------------------------------------------------------------===// |
| 175 | void ColumnSegment::ConvertToPersistent(optional_ptr<BlockManager> block_manager, block_id_t block_id_p) { |
| 176 | D_ASSERT(segment_type == ColumnSegmentType::TRANSIENT); |
| 177 | segment_type = ColumnSegmentType::PERSISTENT; |
| 178 | |
| 179 | block_id = block_id_p; |
| 180 | offset = 0; |
| 181 | |
| 182 | if (block_id == INVALID_BLOCK) { |
| 183 | // constant block: reset the block buffer |
| 184 | D_ASSERT(stats.statistics.IsConstant()); |
| 185 | block.reset(); |
| 186 | } else { |
| 187 | D_ASSERT(!stats.statistics.IsConstant()); |
| 188 | // non-constant block: write the block to disk |
| 189 | // the data for the block already exists in-memory of our block |
| 190 | // instead of copying the data we alter some metadata so the buffer points to an on-disk block |
| 191 | block = block_manager->ConvertToPersistent(block_id, old_block: std::move(block)); |
| 192 | } |
| 193 | |
| 194 | segment_state.reset(); |
| 195 | if (function.get().init_segment) { |
| 196 | segment_state = function.get().init_segment(*this, block_id); |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | void ColumnSegment::MarkAsPersistent(shared_ptr<BlockHandle> block_p, uint32_t offset_p) { |
| 201 | D_ASSERT(segment_type == ColumnSegmentType::TRANSIENT); |
| 202 | segment_type = ColumnSegmentType::PERSISTENT; |
| 203 | |
| 204 | block_id = block_p->BlockId(); |
| 205 | offset = offset_p; |
| 206 | block = std::move(block_p); |
| 207 | |
| 208 | segment_state.reset(); |
| 209 | if (function.get().init_segment) { |
| 210 | segment_state = function.get().init_segment(*this, block_id); |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | //===--------------------------------------------------------------------===// |
| 215 | // Filter Selection |
| 216 | //===--------------------------------------------------------------------===// |
| 217 | template <class T, class OP, bool HAS_NULL> |
| 218 | static idx_t TemplatedFilterSelection(T *vec, T predicate, SelectionVector &sel, idx_t approved_tuple_count, |
| 219 | ValidityMask &mask, SelectionVector &result_sel) { |
| 220 | idx_t result_count = 0; |
| 221 | for (idx_t i = 0; i < approved_tuple_count; i++) { |
| 222 | auto idx = sel.get_index(idx: i); |
| 223 | if ((!HAS_NULL || mask.RowIsValid(row_idx: idx)) && OP::Operation(vec[idx], predicate)) { |
| 224 | result_sel.set_index(idx: result_count++, loc: idx); |
| 225 | } |
| 226 | } |
| 227 | return result_count; |
| 228 | } |
| 229 | |
| 230 | template <class T> |
| 231 | static void FilterSelectionSwitch(T *vec, T predicate, SelectionVector &sel, idx_t &approved_tuple_count, |
| 232 | ExpressionType comparison_type, ValidityMask &mask) { |
| 233 | SelectionVector new_sel(approved_tuple_count); |
| 234 | // the inplace loops take the result as the last parameter |
| 235 | switch (comparison_type) { |
| 236 | case ExpressionType::COMPARE_EQUAL: { |
| 237 | if (mask.AllValid()) { |
| 238 | approved_tuple_count = |
| 239 | TemplatedFilterSelection<T, Equals, false>(vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 240 | } else { |
| 241 | approved_tuple_count = |
| 242 | TemplatedFilterSelection<T, Equals, true>(vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 243 | } |
| 244 | break; |
| 245 | } |
| 246 | case ExpressionType::COMPARE_NOTEQUAL: { |
| 247 | if (mask.AllValid()) { |
| 248 | approved_tuple_count = |
| 249 | TemplatedFilterSelection<T, NotEquals, false>(vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 250 | } else { |
| 251 | approved_tuple_count = |
| 252 | TemplatedFilterSelection<T, NotEquals, true>(vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 253 | } |
| 254 | break; |
| 255 | } |
| 256 | case ExpressionType::COMPARE_LESSTHAN: { |
| 257 | if (mask.AllValid()) { |
| 258 | approved_tuple_count = |
| 259 | TemplatedFilterSelection<T, LessThan, false>(vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 260 | } else { |
| 261 | approved_tuple_count = |
| 262 | TemplatedFilterSelection<T, LessThan, true>(vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 263 | } |
| 264 | break; |
| 265 | } |
| 266 | case ExpressionType::COMPARE_GREATERTHAN: { |
| 267 | if (mask.AllValid()) { |
| 268 | approved_tuple_count = TemplatedFilterSelection<T, GreaterThan, false>(vec, predicate, sel, |
| 269 | approved_tuple_count, mask, new_sel); |
| 270 | } else { |
| 271 | approved_tuple_count = TemplatedFilterSelection<T, GreaterThan, true>(vec, predicate, sel, |
| 272 | approved_tuple_count, mask, new_sel); |
| 273 | } |
| 274 | break; |
| 275 | } |
| 276 | case ExpressionType::COMPARE_LESSTHANOREQUALTO: { |
| 277 | if (mask.AllValid()) { |
| 278 | approved_tuple_count = TemplatedFilterSelection<T, LessThanEquals, false>( |
| 279 | vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 280 | } else { |
| 281 | approved_tuple_count = TemplatedFilterSelection<T, LessThanEquals, true>( |
| 282 | vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 283 | } |
| 284 | break; |
| 285 | } |
| 286 | case ExpressionType::COMPARE_GREATERTHANOREQUALTO: { |
| 287 | if (mask.AllValid()) { |
| 288 | approved_tuple_count = TemplatedFilterSelection<T, GreaterThanEquals, false>( |
| 289 | vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 290 | } else { |
| 291 | approved_tuple_count = TemplatedFilterSelection<T, GreaterThanEquals, true>( |
| 292 | vec, predicate, sel, approved_tuple_count, mask, new_sel); |
| 293 | } |
| 294 | break; |
| 295 | } |
| 296 | default: |
| 297 | throw NotImplementedException("Unknown comparison type for filter pushed down to table!" ); |
| 298 | } |
| 299 | sel.Initialize(other: new_sel); |
| 300 | } |
| 301 | |
| 302 | template <bool IS_NULL> |
| 303 | static idx_t TemplatedNullSelection(SelectionVector &sel, idx_t &approved_tuple_count, ValidityMask &mask) { |
| 304 | if (mask.AllValid()) { |
| 305 | // no NULL values |
| 306 | if (IS_NULL) { |
| 307 | approved_tuple_count = 0; |
| 308 | return 0; |
| 309 | } else { |
| 310 | return approved_tuple_count; |
| 311 | } |
| 312 | } else { |
| 313 | SelectionVector result_sel(approved_tuple_count); |
| 314 | idx_t result_count = 0; |
| 315 | for (idx_t i = 0; i < approved_tuple_count; i++) { |
| 316 | auto idx = sel.get_index(idx: i); |
| 317 | if (mask.RowIsValid(row_idx: idx) != IS_NULL) { |
| 318 | result_sel.set_index(idx: result_count++, loc: idx); |
| 319 | } |
| 320 | } |
| 321 | sel.Initialize(other: result_sel); |
| 322 | approved_tuple_count = result_count; |
| 323 | return result_count; |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | idx_t ColumnSegment::FilterSelection(SelectionVector &sel, Vector &result, const TableFilter &filter, |
| 328 | idx_t &approved_tuple_count, ValidityMask &mask) { |
| 329 | switch (filter.filter_type) { |
| 330 | case TableFilterType::CONJUNCTION_OR: { |
| 331 | // similar to the CONJUNCTION_AND, but we need to take care of the SelectionVectors (OR all of them) |
| 332 | idx_t count_total = 0; |
| 333 | SelectionVector result_sel(approved_tuple_count); |
| 334 | auto &conjunction_or = filter.Cast<ConjunctionOrFilter>(); |
| 335 | for (auto &child_filter : conjunction_or.child_filters) { |
| 336 | SelectionVector temp_sel; |
| 337 | temp_sel.Initialize(other: sel); |
| 338 | idx_t temp_tuple_count = approved_tuple_count; |
| 339 | idx_t temp_count = FilterSelection(sel&: temp_sel, result, filter: *child_filter, approved_tuple_count&: temp_tuple_count, mask); |
| 340 | // tuples passed, move them into the actual result vector |
| 341 | for (idx_t i = 0; i < temp_count; i++) { |
| 342 | auto new_idx = temp_sel.get_index(idx: i); |
| 343 | bool is_new_idx = true; |
| 344 | for (idx_t res_idx = 0; res_idx < count_total; res_idx++) { |
| 345 | if (result_sel.get_index(idx: res_idx) == new_idx) { |
| 346 | is_new_idx = false; |
| 347 | break; |
| 348 | } |
| 349 | } |
| 350 | if (is_new_idx) { |
| 351 | result_sel.set_index(idx: count_total++, loc: new_idx); |
| 352 | } |
| 353 | } |
| 354 | } |
| 355 | sel.Initialize(other: result_sel); |
| 356 | approved_tuple_count = count_total; |
| 357 | return approved_tuple_count; |
| 358 | } |
| 359 | case TableFilterType::CONJUNCTION_AND: { |
| 360 | auto &conjunction_and = filter.Cast<ConjunctionAndFilter>(); |
| 361 | for (auto &child_filter : conjunction_and.child_filters) { |
| 362 | FilterSelection(sel, result, filter: *child_filter, approved_tuple_count, mask); |
| 363 | } |
| 364 | return approved_tuple_count; |
| 365 | } |
| 366 | case TableFilterType::CONSTANT_COMPARISON: { |
| 367 | auto &constant_filter = filter.Cast<ConstantFilter>(); |
| 368 | // the inplace loops take the result as the last parameter |
| 369 | switch (result.GetType().InternalType()) { |
| 370 | case PhysicalType::UINT8: { |
| 371 | auto result_flat = FlatVector::GetData<uint8_t>(vector&: result); |
| 372 | auto predicate = UTinyIntValue::Get(value: constant_filter.constant); |
| 373 | FilterSelectionSwitch<uint8_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 374 | comparison_type: constant_filter.comparison_type, mask); |
| 375 | break; |
| 376 | } |
| 377 | case PhysicalType::UINT16: { |
| 378 | auto result_flat = FlatVector::GetData<uint16_t>(vector&: result); |
| 379 | auto predicate = USmallIntValue::Get(value: constant_filter.constant); |
| 380 | FilterSelectionSwitch<uint16_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 381 | comparison_type: constant_filter.comparison_type, mask); |
| 382 | break; |
| 383 | } |
| 384 | case PhysicalType::UINT32: { |
| 385 | auto result_flat = FlatVector::GetData<uint32_t>(vector&: result); |
| 386 | auto predicate = UIntegerValue::Get(value: constant_filter.constant); |
| 387 | FilterSelectionSwitch<uint32_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 388 | comparison_type: constant_filter.comparison_type, mask); |
| 389 | break; |
| 390 | } |
| 391 | case PhysicalType::UINT64: { |
| 392 | auto result_flat = FlatVector::GetData<uint64_t>(vector&: result); |
| 393 | auto predicate = UBigIntValue::Get(value: constant_filter.constant); |
| 394 | FilterSelectionSwitch<uint64_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 395 | comparison_type: constant_filter.comparison_type, mask); |
| 396 | break; |
| 397 | } |
| 398 | case PhysicalType::INT8: { |
| 399 | auto result_flat = FlatVector::GetData<int8_t>(vector&: result); |
| 400 | auto predicate = TinyIntValue::Get(value: constant_filter.constant); |
| 401 | FilterSelectionSwitch<int8_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 402 | comparison_type: constant_filter.comparison_type, mask); |
| 403 | break; |
| 404 | } |
| 405 | case PhysicalType::INT16: { |
| 406 | auto result_flat = FlatVector::GetData<int16_t>(vector&: result); |
| 407 | auto predicate = SmallIntValue::Get(value: constant_filter.constant); |
| 408 | FilterSelectionSwitch<int16_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 409 | comparison_type: constant_filter.comparison_type, mask); |
| 410 | break; |
| 411 | } |
| 412 | case PhysicalType::INT32: { |
| 413 | auto result_flat = FlatVector::GetData<int32_t>(vector&: result); |
| 414 | auto predicate = IntegerValue::Get(value: constant_filter.constant); |
| 415 | FilterSelectionSwitch<int32_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 416 | comparison_type: constant_filter.comparison_type, mask); |
| 417 | break; |
| 418 | } |
| 419 | case PhysicalType::INT64: { |
| 420 | auto result_flat = FlatVector::GetData<int64_t>(vector&: result); |
| 421 | auto predicate = BigIntValue::Get(value: constant_filter.constant); |
| 422 | FilterSelectionSwitch<int64_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 423 | comparison_type: constant_filter.comparison_type, mask); |
| 424 | break; |
| 425 | } |
| 426 | case PhysicalType::INT128: { |
| 427 | auto result_flat = FlatVector::GetData<hugeint_t>(vector&: result); |
| 428 | auto predicate = HugeIntValue::Get(value: constant_filter.constant); |
| 429 | FilterSelectionSwitch<hugeint_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 430 | comparison_type: constant_filter.comparison_type, mask); |
| 431 | break; |
| 432 | } |
| 433 | case PhysicalType::FLOAT: { |
| 434 | auto result_flat = FlatVector::GetData<float>(vector&: result); |
| 435 | auto predicate = FloatValue::Get(value: constant_filter.constant); |
| 436 | FilterSelectionSwitch<float>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 437 | comparison_type: constant_filter.comparison_type, mask); |
| 438 | break; |
| 439 | } |
| 440 | case PhysicalType::DOUBLE: { |
| 441 | auto result_flat = FlatVector::GetData<double>(vector&: result); |
| 442 | auto predicate = DoubleValue::Get(value: constant_filter.constant); |
| 443 | FilterSelectionSwitch<double>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 444 | comparison_type: constant_filter.comparison_type, mask); |
| 445 | break; |
| 446 | } |
| 447 | case PhysicalType::VARCHAR: { |
| 448 | auto result_flat = FlatVector::GetData<string_t>(vector&: result); |
| 449 | auto predicate = string_t(StringValue::Get(value: constant_filter.constant)); |
| 450 | FilterSelectionSwitch<string_t>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 451 | comparison_type: constant_filter.comparison_type, mask); |
| 452 | break; |
| 453 | } |
| 454 | case PhysicalType::BOOL: { |
| 455 | auto result_flat = FlatVector::GetData<bool>(vector&: result); |
| 456 | auto predicate = BooleanValue::Get(value: constant_filter.constant); |
| 457 | FilterSelectionSwitch<bool>(vec: result_flat, predicate, sel, approved_tuple_count, |
| 458 | comparison_type: constant_filter.comparison_type, mask); |
| 459 | break; |
| 460 | } |
| 461 | default: |
| 462 | throw InvalidTypeException(result.GetType(), "Invalid type for filter pushed down to table comparison" ); |
| 463 | } |
| 464 | return approved_tuple_count; |
| 465 | } |
| 466 | case TableFilterType::IS_NULL: |
| 467 | return TemplatedNullSelection<true>(sel, approved_tuple_count, mask); |
| 468 | case TableFilterType::IS_NOT_NULL: |
| 469 | return TemplatedNullSelection<false>(sel, approved_tuple_count, mask); |
| 470 | default: |
| 471 | throw InternalException("FIXME: unsupported type for filter selection" ); |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | } // namespace duckdb |
| 476 | |