| 140 | } |
| 141 | |
| 142 | JoinResultPtr DirectKeyValueJoin::joinBlock(Block block) |
| 143 | { |
| 144 | const String & key_name = table_join->getOnlyClause().key_names_left[0]; |
| 145 | const ColumnWithTypeAndName & key_col = block.getByName(key_name); |
| 146 | if (!key_col.column) |
| 147 | return {}; |
| 148 | |
| 149 | Block original_right_block = originalRightBlock(right_sample_block, *table_join); |
| 150 | Block right_block_to_use = !right_sample_block_with_storage_column_names.empty() ? right_sample_block_with_storage_column_names : original_right_block; |
| 151 | const Names & attribute_names = right_block_to_use.getNames(); |
| 152 | |
| 153 | bool is_all_join = table_join->strictness() == JoinStrictness::All; |
| 154 | bool is_semi_join = table_join->strictness() == JoinStrictness::Semi; |
| 155 | bool is_anti_join = table_join->strictness() == JoinStrictness::Anti; |
| 156 | |
| 157 | NullMap null_map; |
| 158 | IColumn::Offsets offsets; |
| 159 | Chunk joined_chunk = storage->getByKeys({key_col}, attribute_names, null_map, offsets); |
| 160 | |
| 161 | /// Expected right block may differ from structure in storage, because of `join_use_nulls` or we just select not all joined attributes |
| 162 | Block sample_storage_block = storage->getSampleBlock(attribute_names); |
| 163 | MutableColumns result_columns = convertBlockStructure(sample_storage_block, right_block_to_use, joined_chunk.mutateColumns(), null_map); |
| 164 | |
| 165 | if (!offsets.empty()) |
| 166 | { |
| 167 | /// For ALL semantics with offsets, replicate left rows |
| 168 | if (is_all_join) |
| 169 | { |
| 170 | MutableColumns replicated_columns = block.mutateColumns(); |
| 171 | for (auto && col : replicated_columns) |
| 172 | col = IColumn::mutate(col->replicate(offsets)); |
| 173 | block.setColumns(std::move(replicated_columns)); |
| 174 | } |
| 175 | else |
| 176 | { |
| 177 | /// For ANY/ANTI/SEMI semantics right columns are not replicated |
| 178 | /// We need to 'unreplicate' them by keeping only the first match |
| 179 | selectFirstMatchForEachKey(offsets, result_columns, null_map); |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | for (size_t i = 0; i < result_columns.size(); ++i) |
| 184 | { |
| 185 | ColumnWithTypeAndName col = right_sample_block.getByPosition(i); |
| 186 | col.column = std::move(result_columns[i]); |
| 187 | block.insert(std::move(col)); |
| 188 | } |
| 189 | |
| 190 | if (is_anti_join) |
| 191 | { |
| 192 | /// invert null_map |
| 193 | for (auto & val : null_map) |
| 194 | val = !val; |
| 195 | } |
| 196 | |
| 197 | size_t non_null_rows = countBytesInFilter(null_map); |
| 198 | bool has_null_matches = non_null_rows < null_map.size(); |
| 199 | bool need_filtering = (isInner(table_join->kind()) || (isLeft(table_join->kind()) && (is_semi_join || is_anti_join))); |
nothing calls this directly
no test coverage detected