| 152 | |
| 153 | |
| 154 | void AddingDefaultsTransform::transform(Chunk & chunk) |
| 155 | { |
| 156 | if (column_defaults.empty()) |
| 157 | return; |
| 158 | |
| 159 | const auto * block_missing_values = input_format.getMissingValues(); |
| 160 | if (!block_missing_values) |
| 161 | return; |
| 162 | |
| 163 | const auto & header = getOutputPort().getHeader(); |
| 164 | size_t num_rows = chunk.getNumRows(); |
| 165 | auto res = header.cloneWithColumns(chunk.detachColumns()); |
| 166 | |
| 167 | /// Identify columns that need defaults computed |
| 168 | std::vector<std::pair<String, size_t>> columns_needing_defaults; |
| 169 | for (const auto & [col_name, col_default] : column_defaults) |
| 170 | { |
| 171 | if (!res.has(col_name)) |
| 172 | continue; |
| 173 | size_t column_idx = res.getPositionByName(col_name); |
| 174 | if (block_missing_values->hasDefaultBits(column_idx)) |
| 175 | columns_needing_defaults.emplace_back(col_name, column_idx); |
| 176 | } |
| 177 | |
| 178 | if (columns_needing_defaults.empty()) |
| 179 | { |
| 180 | chunk.setColumns(res.getColumns(), num_rows); |
| 181 | return; |
| 182 | } |
| 183 | |
| 184 | /// Build dependency graph: for each column needing defaults, find which other |
| 185 | /// columns (that also need defaults) its default expression depends on. |
| 186 | /// This is needed because if column `s` has DEFAULT concat('test', CAST(n, 'String')) |
| 187 | /// and column `n` has DEFAULT 42, when inserting {"n": 2} we need to first compute |
| 188 | /// n's defaults (for rows where n is missing), mix them into the block, and only |
| 189 | /// then compute s's defaults so that s can see the correct values of n. |
| 190 | std::unordered_map<String, NameSet> dependencies; |
| 191 | std::unordered_set<String> columns_needing_defaults_set; |
| 192 | for (const auto & [col_name, col_idx] : columns_needing_defaults) |
| 193 | columns_needing_defaults_set.insert(col_name); |
| 194 | |
| 195 | for (const auto & [col_name, col_idx] : columns_needing_defaults) |
| 196 | { |
| 197 | const auto & col_default = column_defaults.at(col_name); |
| 198 | RequiredSourceColumnsVisitor::Data columns_context; |
| 199 | auto expr_clone = col_default.expression->clone(); |
| 200 | RequiredSourceColumnsVisitor(columns_context).visit(expr_clone); |
| 201 | NameSet required = columns_context.requiredColumns(); |
| 202 | |
| 203 | NameSet deps; |
| 204 | for (const auto & req : required) |
| 205 | { |
| 206 | if (columns_needing_defaults_set.contains(req)) |
| 207 | deps.insert(req); |
| 208 | } |
| 209 | dependencies[col_name] = std::move(deps); |
| 210 | } |
| 211 |
nothing calls this directly
no test coverage detected