Returns the nullability of the expression based on [ExprSchema]. Note: [`DFSchema`] implements [ExprSchema]. [`DFSchema`]: datafusion_common::DFSchema # Errors This function errors when it is not possible to compute its nullability. This happens when the expression refers to a column that does not exist in the schema.
(&self, input_schema: &dyn ExprSchema)
| 246 | /// nullability. This happens when the expression refers to a |
| 247 | /// column that does not exist in the schema. |
| 248 | fn nullable(&self, input_schema: &dyn ExprSchema) -> Result<bool> { |
| 249 | match self { |
| 250 | Expr::Alias(Alias { expr, .. }) | Expr::Not(expr) | Expr::Negative(expr) => { |
| 251 | expr.nullable(input_schema) |
| 252 | } |
| 253 | |
| 254 | Expr::InList(InList { expr, list, .. }) => { |
| 255 | // Avoid inspecting too many expressions. |
| 256 | const MAX_INSPECT_LIMIT: usize = 6; |
| 257 | // Stop if a nullable expression is found or an error occurs. |
| 258 | let has_nullable = std::iter::once(expr.as_ref()) |
| 259 | .chain(list) |
| 260 | .take(MAX_INSPECT_LIMIT) |
| 261 | .find_map(|e| { |
| 262 | e.nullable(input_schema) |
| 263 | .map(|nullable| if nullable { Some(()) } else { None }) |
| 264 | .transpose() |
| 265 | }) |
| 266 | .transpose()?; |
| 267 | Ok(match has_nullable { |
| 268 | // If a nullable subexpression is found, the result may also be nullable. |
| 269 | Some(_) => true, |
| 270 | // If the list is too long, we assume it is nullable. |
| 271 | None if list.len() + 1 > MAX_INSPECT_LIMIT => true, |
| 272 | // All the subexpressions are non-nullable, so the result must be non-nullable. |
| 273 | _ => false, |
| 274 | }) |
| 275 | } |
| 276 | |
| 277 | Expr::Between(Between { |
| 278 | expr, low, high, .. |
| 279 | }) => Ok(expr.nullable(input_schema)? |
| 280 | || low.nullable(input_schema)? |
| 281 | || high.nullable(input_schema)?), |
| 282 | |
| 283 | Expr::Column(c) => input_schema.nullable(c), |
| 284 | Expr::OuterReferenceColumn(field, _) => Ok(field.is_nullable()), |
| 285 | Expr::Literal(value, _) => Ok(value.is_null()), |
| 286 | Expr::Case(case) => { |
| 287 | let nullable_then = case |
| 288 | .when_then_expr |
| 289 | .iter() |
| 290 | .filter_map(|(w, t)| { |
| 291 | let is_nullable = match t.nullable(input_schema) { |
| 292 | Err(e) => return Some(Err(e)), |
| 293 | Ok(n) => n, |
| 294 | }; |
| 295 | |
| 296 | // Branches with a then expression that is not nullable do not impact the |
| 297 | // nullability of the case expression. |
| 298 | if !is_nullable { |
| 299 | return None; |
| 300 | } |
| 301 | |
| 302 | // For case-with-expression assume all 'then' expressions are reachable |
| 303 | if case.expr.is_some() { |
| 304 | return Some(Ok(())); |
| 305 | } |
no test coverage detected