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

Function except

prqlc/prqlc/src/sql/pq/preprocess.rs:306–396  ·  view source on GitHub ↗

Creates [SqlTransform::Except] from [Transform::Join] and [Transform::Filter]

(
    pipeline: Vec<SqlTransform>,
    ctx: &mut Context,
)

Source from the content-addressed store, hash-verified

304
305/// Creates [SqlTransform::Except] from [Transform::Join] and [Transform::Filter]
306pub(in crate::sql) fn except(
307 pipeline: Vec<SqlTransform>,
308 ctx: &mut Context,
309) -> Result<Vec<SqlTransform>> {
310 use SqlTransform::*;
311
312 let output = ctx.anchor.determine_select_columns(&pipeline);
313 let output: HashSet<CId, RandomState> = HashSet::from_iter(output);
314
315 let mut res = Vec::with_capacity(pipeline.len());
316 for t in pipeline {
317 res.push(t);
318
319 if res.len() < 2 {
320 continue;
321 }
322 let SqlTransform::Join {
323 side: JoinSide::Left,
324 filter: join_cond,
325 with,
326 } = &res[res.len() - 2]
327 else {
328 continue;
329 };
330 let Super(Transform::Filter(filter)) = &res[res.len() - 1] else {
331 continue;
332 };
333
334 let with = ctx.anchor.relation_instances.get(with).unwrap();
335
336 let top = ctx.anchor.determine_select_columns(&res[0..res.len() - 2]);
337 let bottom = with.table_ref.columns.iter().map(|(_, c)| *c).collect_vec();
338
339 // join_cond must be a join over all columns
340 // (this could be loosened to check only the relation key)
341 let (join_left, join_right) = collect_equals(join_cond)?;
342 if !all_in(&top, join_left) || !all_in(&bottom, join_right) {
343 continue;
344 }
345
346 // filter has to check for nullability of bottom
347 // (this could be loosened to check only for nulls in a previously non-nullable column)
348 let (filter_left, filter_right) = collect_equals(filter)?;
349 if !(all_in(&bottom, filter_left) && all_null(filter_right)) {
350 continue;
351 }
352
353 // select must not contain things from bottom
354 if bottom.iter().any(|c| output.contains(c)) {
355 continue;
356 }
357
358 // determine DISTINCT
359 let mut distinct = false;
360 // EXCEPT ALL can become except EXCEPT DISTINCT, if top is DISTINCT.
361 // DISTINCT-ness of bottom has no effect on the output.
362 if res.len() >= 3 {
363 if let Distinct = &res[res.len() - 3] {

Callers 1

preprocessFunction · 0.85

Calls 13

collect_equalsFunction · 0.85
all_inFunction · 0.85
all_nullFunction · 0.85
lenMethod · 0.80
pushMethod · 0.80
mapMethod · 0.80
iterMethod · 0.80
contains_wildcardMethod · 0.80
push_hintMethod · 0.80
popMethod · 0.80
getMethod · 0.45

Tested by

no test coverage detected