| 113 | |
| 114 | template<int const JoinOp> |
| 115 | bool IR_ALWAYS_INLINE PartitionedHashJoinNode::ProcessProbeRowLeftSemiJoins( |
| 116 | ScalarExprEvaluator* const* other_join_conjunct_evals, |
| 117 | int num_other_join_conjuncts, ScalarExprEvaluator* const* conjunct_evals, |
| 118 | int num_conjuncts, RowBatch::Iterator* out_batch_iterator, int* remaining_capacity, |
| 119 | Status* status) { |
| 120 | DCHECK(current_probe_row_ != NULL); |
| 121 | DCHECK(JoinOp == TJoinOp::LEFT_ANTI_JOIN || JoinOp == TJoinOp::LEFT_SEMI_JOIN || |
| 122 | JoinOp == TJoinOp::NULL_AWARE_LEFT_ANTI_JOIN); |
| 123 | TupleRow* out_row = out_batch_iterator->Get(); |
| 124 | for (; !hash_tbl_iterator_.AtEnd(); hash_tbl_iterator_.NextDuplicate()) { |
| 125 | TupleRow* matched_build_row = hash_tbl_iterator_.GetRow(); |
| 126 | DCHECK(matched_build_row != NULL); |
| 127 | |
| 128 | ClearExprResultsPool(num_conjuncts, num_other_join_conjuncts); |
| 129 | |
| 130 | // Evaluate the non-equi-join conjuncts against a temp row assembled from all |
| 131 | // build and probe tuples. |
| 132 | if (num_other_join_conjuncts > 0) { |
| 133 | CreateOutputRow(semi_join_staging_row_, current_probe_row_, matched_build_row); |
| 134 | if (!EvalOtherJoinConjuncts(other_join_conjunct_evals, |
| 135 | num_other_join_conjuncts, semi_join_staging_row_)) { |
| 136 | continue; |
| 137 | } |
| 138 | } |
| 139 | // Create output row assembled from probe tuples. |
| 140 | out_batch_iterator->parent()->CopyRow(current_probe_row_, out_row); |
| 141 | // A match is found in the hash table. The search is over for this probe row. |
| 142 | matched_probe_ = true; |
| 143 | hash_tbl_iterator_.SetAtEnd(); |
| 144 | // Append to output batch for left semi joins if the conjuncts are satisfied. |
| 145 | if (JoinOp == TJoinOp::LEFT_SEMI_JOIN && |
| 146 | ExecNode::EvalConjuncts(conjunct_evals, num_conjuncts, out_row)) { |
| 147 | --(*remaining_capacity); |
| 148 | if (*remaining_capacity == 0) return false; |
| 149 | out_row = out_batch_iterator->Next(); |
| 150 | } |
| 151 | // Done with this probe row. |
| 152 | return true; |
| 153 | } |
| 154 | |
| 155 | if (JoinOp != TJoinOp::LEFT_SEMI_JOIN && !matched_probe_) { |
| 156 | if (JoinOp == TJoinOp::NULL_AWARE_LEFT_ANTI_JOIN) { |
| 157 | // Null aware behavior. The probe row did not match in the hash table so we |
| 158 | // should interpret the hash table probe as "unknown" if there are nulls on the |
| 159 | // build side. For those rows, we need to process the remaining join |
| 160 | // predicates later. |
| 161 | if (builder_->null_aware_partition()->build_rows()->num_rows() != 0) { |
| 162 | if (num_other_join_conjuncts > 0 |
| 163 | && UNLIKELY(!AppendProbeRow(null_aware_probe_partition_->probe_rows(), |
| 164 | current_probe_row_, status))) { |
| 165 | DCHECK(!status->ok()); |
| 166 | return false; |
| 167 | } |
| 168 | return true; |
| 169 | } |
| 170 | } |
| 171 | // No match for this current_probe_row_, we need to output it. No need to |
| 172 | // evaluate the conjunct_evals since anti joins cannot have any. |
nothing calls this directly
no test coverage detected