| 264 | |
| 265 | template<int const JoinOp> |
| 266 | bool IR_ALWAYS_INLINE PartitionedHashJoinNode::NextProbeRow( |
| 267 | HashTableCtx* ht_ctx, RowBatch::Iterator* probe_batch_iterator, |
| 268 | int* remaining_capacity, Status* status) { |
| 269 | HashTableCtx::ExprValuesCache* expr_vals_cache = ht_ctx->expr_values_cache(); |
| 270 | while (!expr_vals_cache->AtEnd()) { |
| 271 | // Establish current_probe_row_ and find its corresponding partition. |
| 272 | DCHECK(!probe_batch_iterator->AtEnd()); |
| 273 | current_probe_row_ = probe_batch_iterator->Get(); |
| 274 | matched_probe_ = false; |
| 275 | |
| 276 | // True if the current row should be skipped for probing. |
| 277 | bool skip_row = false; |
| 278 | |
| 279 | // The hash of the expressions results for the current probe row. |
| 280 | uint32_t hash = expr_vals_cache->CurExprValuesHash(); |
| 281 | // Hoist the followings out of the else statement below to speed up non-null case. |
| 282 | const uint32_t partition_idx = hash >> (32 - NUM_PARTITIONING_BITS); |
| 283 | HashTable* hash_tbl = hash_tbls_[partition_idx]; |
| 284 | |
| 285 | // Fetch the hash and expr values' nullness for this row. |
| 286 | if (expr_vals_cache->IsRowNull()) { |
| 287 | if (JoinOp == TJoinOp::NULL_AWARE_LEFT_ANTI_JOIN |
| 288 | && build_hash_partitions_.non_empty_build) { |
| 289 | const int num_other_join_conjuncts = other_join_conjunct_evals_.size(); |
| 290 | // For NAAJ, we need to treat NULLs on the probe carefully. The logic is: |
| 291 | // 1. No build rows -> Return this row. The check for 'non_empty_build_' |
| 292 | // is for this case. |
| 293 | // 2. Has build rows & no other join predicates, skip row. |
| 294 | // 3. Has build rows & other join predicates, we need to evaluate against all |
| 295 | // build rows. First evaluate it against this partition, and if there is not |
| 296 | // a match, save it to evaluate against other partitions later. If there |
| 297 | // is a match, the row is skipped. |
| 298 | if (num_other_join_conjuncts == 0) { |
| 299 | // Condition 2 above. |
| 300 | skip_row = true; |
| 301 | } else { |
| 302 | // Condition 3 above. |
| 303 | if (UNLIKELY( |
| 304 | !AppendProbeRow(null_probe_rows_.get(), current_probe_row_, status))) { |
| 305 | DCHECK(!status->ok()); |
| 306 | return false; |
| 307 | } |
| 308 | matched_null_probe_.push_back(false); |
| 309 | skip_row = true; |
| 310 | } |
| 311 | } |
| 312 | } else { |
| 313 | // The build partition is in memory. Return this row for probing. |
| 314 | if (LIKELY(hash_tbl != NULL)) { |
| 315 | hash_tbl_iterator_ = hash_tbl->FindProbeRow(ht_ctx); |
| 316 | } else { |
| 317 | // The build partition is either empty or spilled. |
| 318 | PhjBuilderPartition* build_partition = |
| 319 | (*build_hash_partitions_.hash_partitions)[partition_idx].get(); |
| 320 | ProbePartition* probe_partition = probe_hash_partitions_[partition_idx].get(); |
| 321 | DCHECK((build_partition->IsClosed() && probe_partition == NULL) |
| 322 | || (build_partition->is_spilled() && probe_partition != NULL)); |
| 323 |
nothing calls this directly
no test coverage detected