1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::TransformArgs;
use expr::{func, AggregateExpr, AggregateFunc, MirRelationExpr, MirScalarExpr, UnaryFunc};
use repr::{Datum, RelationType, ScalarType};
#[derive(Debug)]
pub struct NonNullable;
impl crate::Transform for NonNullable {
fn transform(
&self,
relation: &mut MirRelationExpr,
_: TransformArgs,
) -> Result<(), crate::TransformError> {
relation.try_visit_mut_pre(&mut |e| self.action(e))
}
}
impl NonNullable {
pub fn action(&self, relation: &mut MirRelationExpr) -> Result<(), crate::TransformError> {
match relation {
MirRelationExpr::Map { input, scalars } => {
if scalars.iter().any(scalar_contains_isnull) {
let mut metadata = input.typ();
for scalar in scalars.iter_mut() {
scalar_nonnullable(scalar, &metadata);
let typ = scalar.typ(&metadata);
metadata.column_types.push(typ);
}
}
}
MirRelationExpr::Filter { input, predicates } => {
if predicates.iter().any(scalar_contains_isnull) {
let metadata = input.typ();
for predicate in predicates.iter_mut() {
scalar_nonnullable(predicate, &metadata);
}
}
}
MirRelationExpr::Reduce {
input,
group_key: _,
aggregates,
monotonic: _,
expected_group_size: _,
} => {
if aggregates.iter().any(|a| {
scalar_contains_isnull(&(a).expr) || matches!(&(a).func, AggregateFunc::Count)
}) {
let metadata = input.typ();
for aggregate in aggregates.iter_mut() {
scalar_nonnullable(&mut aggregate.expr, &metadata);
aggregate_nonnullable(aggregate, &metadata);
}
}
}
_ => {}
}
Ok(())
}
}
fn scalar_contains_isnull(expr: &MirScalarExpr) -> bool {
let mut result = false;
expr.visit_post(&mut |e| {
if let MirScalarExpr::CallUnary {
func: UnaryFunc::IsNull(func::IsNull),
..
} = e
{
result = true;
}
});
result
}
fn scalar_nonnullable(expr: &mut MirScalarExpr, metadata: &RelationType) {
expr.visit_mut_post(&mut |e| {
if let MirScalarExpr::CallUnary {
func: UnaryFunc::IsNull(func::IsNull),
expr,
} = e
{
if let MirScalarExpr::Column(c) = &**expr {
if !metadata.column_types[*c].nullable {
*e = MirScalarExpr::literal_ok(Datum::False, ScalarType::Bool);
}
}
}
})
}
fn aggregate_nonnullable(expr: &mut AggregateExpr, metadata: &RelationType) {
if let (AggregateFunc::Count, MirScalarExpr::Column(c)) = (&expr.func, &expr.expr) {
if !metadata.column_types[*c].nullable && !expr.distinct {
expr.expr = MirScalarExpr::literal_ok(Datum::True, ScalarType::Bool);
}
}
}