Function sql::query_model::attribute::rejected_nulls::rejected_nulls [−][src]
pub(crate) fn rejected_nulls(
expr: &BoxScalarExpr,
set: &mut HashSet<ColumnReference>
)
Expand description
Returns all columns that must be non-NULL for the boolean expr
to be NULL
or FALSE
.
An expression expr
rejects nulls in a set of column references
C
if it evaluates to either FALSE
or NULL
whenever some
c
in C
is null.
An expression expr
propagates nulls in a set of column references
C
if it evaluates to NULL
whenever some c
in C
is null.
Consequently, results returned by propagated_nulls
must be
included in rejected_nulls
.
Unfortuantely, boolean functions such as “and” and “or” are not propagating nulls in their inputs, but we still need to handle them here, as they are used quite frequently in predicates. The procedure for doing this is derived below.
Observe the truth values for the following terms:
For AND(A, B)
:
F | N | T | |
---|---|---|---|
F | F | F | F |
N | F | N | N |
T | F | N | T |
For OR(A, B)
:
F | N | T | |
---|---|---|---|
F | F | N | T |
N | N | N | T |
T | T | T | T |
For NOT(AND(A, B))
:
F | N | T | |
---|---|---|---|
F | T | T | T |
N | T | N | N |
T | T | N | F |
For NOT(OR(A, B))
:
F | N | T | |
---|---|---|---|
F | T | N | F |
N | N | N | F |
T | F | F | F |
Based on the above truth tables, we can establish the following statements are always true:
- If either
A
orB
rejects nulls inC
, thenAND(A, B)
rejects nulls inC
. - If both
A
andB
reject nulls inC
, thenOR(A, B)
rejects nulls inC
. - If both
A
andB
propagate nulls inC
, thenNOT(AND(A, B))
rejects nulls inC
. - If either
A
orB
propagates nulls inC
, thenNOT(OR(A, B))
rejects nulls inC
.
Based on the above statements, the algorithm implemented by this function can be described by the following pseudo-code:
def rejected_nulls(expr: Expr, sign: bool = true) -> Set[Expr]:
match expr:
case NOT(ISNULL(c)):
{ c }
case NOT(expr):
rejected_nulls(expr, !sign)
case AND(lhs, rhs):
if sign > 0:
rejected_nulls(lhs, sign) ∪ rejected_nulls(rhs, sign)
else:
propagated_nulls(lhs) ∩ propagated_nulls(rhs)
case OR(lhs, rhs):
if sign > 0:
rejected_nulls(lhs, sign) ∩ rejected_nulls(rhs, sign)
else:
propagated_nulls(lhs) ∪ propagated_nulls(rhs)
case expr:
propagated_nulls(expr)