Skip to content

Commit 7910d6b

Browse files
committed
qgm: add RejectedNulls derived attribute tests
1 parent 794efab commit 7910d6b

File tree

1 file changed

+260
-0
lines changed

1 file changed

+260
-0
lines changed

src/sql/src/query_model/attribute/rejected_nulls.rs

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,263 @@ fn case_and(expr: &BoxScalarExpr) -> Option<(&BoxScalarExpr, &BoxScalarExpr)> {
278278

279279
None
280280
}
281+
282+
#[cfg(test)]
283+
mod tests {
284+
use super::*;
285+
use crate::query_model::model::*;
286+
use crate::query_model::test::util::*;
287+
288+
#[test]
289+
fn test_select_1() {
290+
let mut model = Model::new();
291+
let g_id = add_get(&mut model);
292+
let b_id = add_select(&mut model, g_id, |input| {
293+
vec![
294+
// P0: (#0 - #1) + (#2 - #3)
295+
exp::add(
296+
exp::sub(exp::cref(input, 0), exp::cref(input, 1)), // {#0, #1}
297+
exp::sub(exp::cref(input, 2), exp::cref(input, 3)), // {#2, #3}
298+
), // {#0, #1, #2, #3}
299+
]
300+
});
301+
302+
assert_derived_attribute(&mut model, b_id, |r#box| {
303+
HashSet::from([
304+
cref(input(&r#box, 0), 0),
305+
cref(input(&r#box, 0), 1),
306+
cref(input(&r#box, 0), 2),
307+
cref(input(&r#box, 0), 3),
308+
]) // {#0, #1, #2, #3}
309+
});
310+
}
311+
312+
#[test]
313+
fn test_select_2() {
314+
let mut model = Model::new();
315+
let g_id = add_get(&mut model);
316+
let b_id = add_select(&mut model, g_id, |input| {
317+
vec![
318+
// P0: (#0 > #1) || (#2 < #3)
319+
exp::and(
320+
exp::gt(exp::cref(input, 0), exp::cref(input, 1)), // {#0, #1}
321+
exp::lt(exp::cref(input, 2), exp::cref(input, 3)), // {#2, #3}
322+
), // {#0, #1, #2, #3}
323+
]
324+
});
325+
326+
assert_derived_attribute(&mut model, b_id, |r#box| {
327+
HashSet::from([
328+
cref(input(&r#box, 0), 0),
329+
cref(input(&r#box, 0), 1),
330+
cref(input(&r#box, 0), 2),
331+
cref(input(&r#box, 0), 3),
332+
]) // {#0, #1, #2, #3}
333+
});
334+
}
335+
336+
#[test]
337+
fn test_select_3() {
338+
let mut model = Model::new();
339+
let g_id = add_get(&mut model);
340+
let b_id = add_select(&mut model, g_id, |input| {
341+
vec![
342+
// P0: OR(NOT(OR(#0 < #1, #1 < #2)), AND(!isnull(#1), AND(#0 = #2, #2 = #3))
343+
exp::or(
344+
exp::not(exp::or(
345+
exp::lt(exp::cref(input, 0), exp::cref(input, 1)), // { #0, #1 }
346+
exp::lt(exp::cref(input, 1), exp::cref(input, 2)), // { #1, #2 }
347+
)), // { #0, #1, #2 }
348+
exp::and(
349+
exp::not(exp::isnull(exp::cref(input, 1))), // { #1 }
350+
exp::and(
351+
exp::eq(exp::cref(input, 0), exp::cref(input, 2)), // { #0, #2 }
352+
exp::eq(exp::cref(input, 2), exp::cref(input, 3)), // { #2, #3 }
353+
), // { #0, #2, #3 }
354+
), // { #0, #1, #2, #3 }
355+
), // { #0, #1, #2 }
356+
// P1: !isnull(#3)
357+
exp::not(exp::isnull(exp::cref(input, 3))), // { #3 }
358+
]
359+
});
360+
361+
assert_derived_attribute(&mut model, b_id, |r#box| {
362+
HashSet::from([
363+
cref(input(&r#box, 0), 0),
364+
cref(input(&r#box, 0), 1),
365+
cref(input(&r#box, 0), 2),
366+
cref(input(&r#box, 0), 3),
367+
]) // {#0, #1, #2, #3}
368+
});
369+
}
370+
371+
#[test]
372+
fn test_select_4() {
373+
let mut model = Model::new();
374+
let g_id = add_get(&mut model);
375+
let b_id = add_select(&mut model, g_id, |input| {
376+
vec![
377+
// P0: AND(NOT(AND(#0 < #1, #1 < #2)), OR(!isnull(#2), OR(#0 = #2, #2 = #3))
378+
exp::and(
379+
exp::not(exp::and(
380+
exp::lt(exp::cref(input, 0), exp::cref(input, 1)), // { #0, #1 }
381+
exp::lt(exp::cref(input, 1), exp::cref(input, 2)), // { #1, #2 }
382+
)), // { #1 }
383+
exp::or(
384+
exp::not(exp::isnull(exp::cref(input, 2))), // { #2 }
385+
exp::or(
386+
exp::eq(exp::cref(input, 0), exp::cref(input, 2)), // { #0, #2 }
387+
exp::eq(exp::cref(input, 2), exp::cref(input, 3)), // { #2, #3 }
388+
), // { #2 }
389+
), // { #2 }
390+
), // { #1, #2 }
391+
// P1: !isnull(#3)
392+
exp::not(exp::isnull(exp::cref(input, 3))), // { #3 }
393+
]
394+
});
395+
396+
assert_derived_attribute(&mut model, b_id, |r#box| {
397+
HashSet::from([
398+
cref(input(&r#box, 0), 1),
399+
cref(input(&r#box, 0), 2),
400+
cref(input(&r#box, 0), 3),
401+
]) // {#0, #2, #3}
402+
});
403+
}
404+
405+
#[test]
406+
fn test_left_outer_join_1() {
407+
let mut model = Model::new();
408+
let g_id = add_get(&mut model);
409+
let b_id = add_left_outer_join(&mut model, g_id, g_id, |lhs, rhs| {
410+
vec![
411+
// P0: (lhs.#0 > rhs.#0)
412+
exp::gt(exp::cref(lhs, 0), exp::cref(rhs, 0)),
413+
// P1: (lhs.#1 < rhs.#1)
414+
exp::lt(exp::cref(lhs, 1), exp::cref(rhs, 1)),
415+
// P2: (lhs.#2 == rhs.#2)
416+
exp::eq(exp::cref(lhs, 2), exp::cref(rhs, 2)),
417+
]
418+
});
419+
420+
assert_derived_attribute(&mut model, b_id, |r#box| {
421+
HashSet::from([
422+
cref(input(r#box, 1), 0),
423+
cref(input(r#box, 1), 1),
424+
cref(input(r#box, 1), 2),
425+
]) // {rhs.#0, rhs.#1, rhs.#2}
426+
});
427+
}
428+
429+
#[test]
430+
fn test_full_outer_join_1() {
431+
let mut model = Model::new();
432+
let g_id = add_get(&mut model);
433+
let b_id = add_full_outer_join(&mut model, g_id, g_id, |lhs, rhs| {
434+
vec![
435+
// P0: (lhs.#0 >= rhs.#0)
436+
exp::gte(exp::cref(lhs, 0), exp::cref(rhs, 0)),
437+
// P1: (lhs.#1 <= rhs.#1)
438+
exp::lte(exp::cref(lhs, 1), exp::cref(rhs, 1)),
439+
// P2: (lhs.#2 != rhs.#2)
440+
exp::not_eq(exp::cref(lhs, 2), exp::cref(rhs, 2)),
441+
]
442+
});
443+
444+
assert_derived_attribute(&mut model, b_id, |_| {
445+
HashSet::from([]) // {}
446+
});
447+
}
448+
449+
/// Adds a get box to the given model with a schema consisting of
450+
/// for 32-bit nullable integers.
451+
fn add_get(model: &mut Model) -> BoxId {
452+
let get_id = model.make_box(qgm::get(0).into());
453+
454+
let mut b = model.get_mut_box(get_id);
455+
b.add_column(exp::base(0, typ::int32(true)));
456+
b.add_column(exp::base(1, typ::int32(true)));
457+
b.add_column(exp::base(2, typ::int32(true)));
458+
b.add_column(exp::base(3, typ::int32(true)));
459+
460+
get_id
461+
}
462+
463+
/// Adds a select join to the model and attaches the given `predicates`.
464+
/// The select box has a single input connected to the `src_id` box.
465+
fn add_select<F>(model: &mut Model, src_id: BoxId, predicates: F) -> BoxId
466+
where
467+
F: FnOnce(QuantifierId) -> Vec<BoxScalarExpr>,
468+
{
469+
let tgt_id = model.make_box(Select::default().into());
470+
let inp_id = model.make_quantifier(QuantifierType::Foreach, src_id, tgt_id);
471+
472+
if let BoxType::Select(ref mut b) = model.get_mut_box(tgt_id).box_type {
473+
b.predicates.extend_from_slice(&predicates(inp_id));
474+
}
475+
476+
tgt_id
477+
}
478+
479+
/// Adds a full outer join to the model and attaches the given `predicates`.
480+
/// Both inputs are connected to the `lhs_id` and `rhs_id` boxes.
481+
fn add_full_outer_join<F>(
482+
model: &mut Model,
483+
lhs_id: BoxId,
484+
rhs_id: BoxId,
485+
predicates: F,
486+
) -> BoxId
487+
where
488+
F: FnOnce(QuantifierId, QuantifierId) -> Vec<BoxScalarExpr>,
489+
{
490+
let tgt_id = model.make_box(OuterJoin::default().into());
491+
let lhs_id = model.make_quantifier(QuantifierType::PreservedForeach, lhs_id, tgt_id);
492+
let rhs_id = model.make_quantifier(QuantifierType::PreservedForeach, rhs_id, tgt_id);
493+
494+
if let BoxType::OuterJoin(ref mut b) = model.get_mut_box(tgt_id).box_type {
495+
b.predicates.extend_from_slice(&predicates(lhs_id, rhs_id));
496+
}
497+
498+
tgt_id
499+
}
500+
501+
/// Adds a left outer join to the model and attaches the given `predicates`.
502+
/// Both inputs are connected to the `lhs_id` and `rhs_id` boxes.
503+
fn add_left_outer_join<F>(
504+
model: &mut Model,
505+
lhs_id: BoxId,
506+
rhs_id: BoxId,
507+
predicates: F,
508+
) -> BoxId
509+
where
510+
F: FnOnce(QuantifierId, QuantifierId) -> Vec<BoxScalarExpr>,
511+
{
512+
let tgt_id = model.make_box(OuterJoin::default().into());
513+
let lhs_id = model.make_quantifier(QuantifierType::PreservedForeach, lhs_id, tgt_id);
514+
let rhs_id = model.make_quantifier(QuantifierType::Foreach, rhs_id, tgt_id);
515+
516+
if let BoxType::OuterJoin(ref mut b) = model.get_mut_box(tgt_id).box_type {
517+
b.predicates.extend_from_slice(&predicates(lhs_id, rhs_id));
518+
}
519+
520+
tgt_id
521+
}
522+
523+
/// Derives the `RejectedNulls` for the given `b_id` and asserts its value.
524+
fn assert_derived_attribute<F>(model: &mut Model, b_id: BoxId, exp_value: F)
525+
where
526+
F: FnOnce(&QueryBox) -> HashSet<ColumnReference>,
527+
{
528+
RejectedNulls.derive(model, b_id);
529+
530+
let r#box = model.get_box(b_id);
531+
let act_value = r#box.attributes.get::<RejectedNulls>();
532+
let exp_value = &exp_value(&r#box);
533+
534+
assert_eq!(act_value, exp_value);
535+
}
536+
537+
fn input(b: &QueryBox, i: usize) -> QuantifierId {
538+
b.quantifiers.iter().nth(i).unwrap().clone()
539+
}
540+
}

0 commit comments

Comments
 (0)