MCPcopy Create free account
hub / github.com/PRQL/prql / is_split_required

Function is_split_required

prqlc/prqlc/src/sql/pq/anchor.rs:310–418  ·  view source on GitHub ↗

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>)

Source from the content-addressed store, hash-verified

308///
309/// `following` contain names of following transforms in the pipeline.
310fn 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,

Callers 1

split_off_backFunction · 0.85

Calls 4

contains_anyFunction · 0.85
is_emptyMethod · 0.80
as_strMethod · 0.80
insertMethod · 0.45

Tested by

no test coverage detected