Determines whether a pipeline must be split at a transform to fit into one SELECT statement. `following` contain names of following transforms in the pipeline.
(transform: &SqlTransform, following: &mut HashSet<String>)
| 308 | /// |
| 309 | /// `following` contain names of following transforms in the pipeline. |
| 310 | fn is_split_required(transform: &SqlTransform, following: &mut HashSet<String>) -> bool { |
| 311 | // Pipeline must be split when there is a transform that is out of order: |
| 312 | // - from (max 1x), |
| 313 | // - join (no limit), |
| 314 | // - filters (for WHERE) |
| 315 | // - aggregate (max 1x) |
| 316 | // - filters (for HAVING) |
| 317 | // - compute (no limit) |
| 318 | // - sort (no limit) |
| 319 | // - take (no limit) |
| 320 | // - distinct |
| 321 | // - append/except/intersect (no limit) |
| 322 | // - loop (max 1x) |
| 323 | // |
| 324 | // Select is not affected by the order. |
| 325 | use SqlTransform::Super; |
| 326 | use Transform::*; |
| 327 | |
| 328 | // Compute for aggregation does not count as a real compute, |
| 329 | // because it's done within the aggregation |
| 330 | if let Super(Compute(decl)) = transform { |
| 331 | if decl.is_aggregation { |
| 332 | return false; |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | fn contains_any<const C: usize>(set: &HashSet<String>, elements: [&'static str; C]) -> bool { |
| 337 | for t in elements { |
| 338 | if set.contains(t) { |
| 339 | return true; |
| 340 | } |
| 341 | } |
| 342 | false |
| 343 | } |
| 344 | |
| 345 | let split = match transform { |
| 346 | SqlTransform::From(_) => contains_any(following, ["From"]), |
| 347 | SqlTransform::Join { .. } => contains_any(following, ["From"]), |
| 348 | Super(Aggregate { .. }) => { |
| 349 | contains_any(following, ["From", "Join", "Aggregate", "Compute"]) |
| 350 | } |
| 351 | Super(Filter(_)) => contains_any(following, ["From", "Join"]), |
| 352 | Super(Compute(_)) => { |
| 353 | // Don't split between Compute and Filter when there's an Aggregate in following. |
| 354 | // Filter after Aggregate becomes HAVING in the same SELECT, so all preceding |
| 355 | // Computes (including those with aggregation functions like SUM) must stay |
| 356 | // with the Aggregate to get proper GROUP BY. |
| 357 | if following.contains("Aggregate") { |
| 358 | contains_any(following, ["From", "Join"]) |
| 359 | } else { |
| 360 | contains_any(following, ["From", "Join", /* "Aggregate" */ "Filter"]) |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | // Sort will be pushed down the CTEs, so there is no point in splitting for it. |
| 365 | // Super(Sort(_)) => contains_any(following, ["From", "Join", "Compute", "Aggregate"]), |
| 366 | Super(Take(_)) => contains_any( |
| 367 | following, |
no test coverage detected