This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new e52b5e581b fix: Ignore nullability in Substrait structs (#11130)
e52b5e581b is described below

commit e52b5e581b9f98337451cbc7dca90a0d0a711b96
Author: Arttu <[email protected]>
AuthorDate: Sun Jun 30 12:39:54 2024 +0200

    fix: Ignore nullability in Substrait structs (#11130)
    
    Similar to https://github.com/apache/datafusion/pull/10874/files
    
    Arrow requires schema to match exactly to literals.
    Substrait contains nullability separate in literals and types,
    and the nullability of a literal may vary
    row-by-row.
    The only reliable way is to either not use nullability at all (this PR),
    or alternatively pass the expected type into from_substrait_literal
    so that it can use the expected nullability.
---
 datafusion/substrait/src/logical_plan/consumer.rs | 48 ++---------------------
 datafusion/substrait/src/logical_plan/producer.rs |  6 +--
 2 files changed, 7 insertions(+), 47 deletions(-)

diff --git a/datafusion/substrait/src/logical_plan/consumer.rs 
b/datafusion/substrait/src/logical_plan/consumer.rs
index 9bc842a12a..f7a64bd90c 100644
--- a/datafusion/substrait/src/logical_plan/consumer.rs
+++ b/datafusion/substrait/src/logical_plan/consumer.rs
@@ -1529,7 +1529,7 @@ fn from_substrait_struct_type(
         let field = Field::new(
             next_struct_field_name(i, dfs_names, name_idx)?,
             from_substrait_type(f, dfs_names, name_idx)?,
-            is_substrait_type_nullable(f)?,
+            true, // We assume everything to be nullable since that's easier 
than ensuring it matches
         );
         fields.push(field);
     }
@@ -1573,47 +1573,6 @@ fn from_substrait_named_struct(base_schema: 
&NamedStruct) -> Result<DFSchemaRef>
     Ok(DFSchemaRef::new(DFSchema::try_from(Schema::new(fields?))?))
 }
 
-fn is_substrait_type_nullable(dtype: &Type) -> Result<bool> {
-    fn is_nullable(nullability: i32) -> bool {
-        nullability != substrait::proto::r#type::Nullability::Required as i32
-    }
-
-    let nullable = match dtype
-        .kind
-        .as_ref()
-        .ok_or_else(|| substrait_datafusion_err!("Type must contain Kind"))?
-    {
-        r#type::Kind::Bool(val) => is_nullable(val.nullability),
-        r#type::Kind::I8(val) => is_nullable(val.nullability),
-        r#type::Kind::I16(val) => is_nullable(val.nullability),
-        r#type::Kind::I32(val) => is_nullable(val.nullability),
-        r#type::Kind::I64(val) => is_nullable(val.nullability),
-        r#type::Kind::Fp32(val) => is_nullable(val.nullability),
-        r#type::Kind::Fp64(val) => is_nullable(val.nullability),
-        r#type::Kind::String(val) => is_nullable(val.nullability),
-        r#type::Kind::Binary(val) => is_nullable(val.nullability),
-        r#type::Kind::Timestamp(val) => is_nullable(val.nullability),
-        r#type::Kind::Date(val) => is_nullable(val.nullability),
-        r#type::Kind::Time(val) => is_nullable(val.nullability),
-        r#type::Kind::IntervalYear(val) => is_nullable(val.nullability),
-        r#type::Kind::IntervalDay(val) => is_nullable(val.nullability),
-        r#type::Kind::TimestampTz(val) => is_nullable(val.nullability),
-        r#type::Kind::Uuid(val) => is_nullable(val.nullability),
-        r#type::Kind::FixedChar(val) => is_nullable(val.nullability),
-        r#type::Kind::Varchar(val) => is_nullable(val.nullability),
-        r#type::Kind::FixedBinary(val) => is_nullable(val.nullability),
-        r#type::Kind::Decimal(val) => is_nullable(val.nullability),
-        r#type::Kind::PrecisionTimestamp(val) => is_nullable(val.nullability),
-        r#type::Kind::PrecisionTimestampTz(val) => 
is_nullable(val.nullability),
-        r#type::Kind::Struct(val) => is_nullable(val.nullability),
-        r#type::Kind::List(val) => is_nullable(val.nullability),
-        r#type::Kind::Map(val) => is_nullable(val.nullability),
-        r#type::Kind::UserDefined(val) => is_nullable(val.nullability),
-        r#type::Kind::UserDefinedTypeReference(_) => true, // not implemented, 
assume nullable
-    };
-    Ok(nullable)
-}
-
 fn from_substrait_bound(
     bound: &Option<Bound>,
     is_lower: bool,
@@ -1793,8 +1752,9 @@ fn from_substrait_literal(
             for (i, field) in s.fields.iter().enumerate() {
                 let name = next_struct_field_name(i, dfs_names, name_idx)?;
                 let sv = from_substrait_literal(field, dfs_names, name_idx)?;
-                builder = builder
-                    .with_scalar(Field::new(name, sv.data_type(), 
field.nullable), sv);
+                // We assume everything to be nullable, since Arrow's strict 
about things matching
+                // and it's hard to match otherwise.
+                builder = builder.with_scalar(Field::new(name, sv.data_type(), 
true), sv);
             }
             builder.build()?
         }
diff --git a/datafusion/substrait/src/logical_plan/producer.rs 
b/datafusion/substrait/src/logical_plan/producer.rs
index 302f38606b..c3bef1689d 100644
--- a/datafusion/substrait/src/logical_plan/producer.rs
+++ b/datafusion/substrait/src/logical_plan/producer.rs
@@ -2289,8 +2289,8 @@ mod test {
             ),
         )))?;
 
-        let c0 = Field::new("c0", DataType::Boolean, false);
-        let c1 = Field::new("c1", DataType::Int32, false);
+        let c0 = Field::new("c0", DataType::Boolean, true);
+        let c1 = Field::new("c1", DataType::Int32, true);
         let c2 = Field::new("c2", DataType::Utf8, true);
         round_trip_literal(
             ScalarStructBuilder::new()
@@ -2363,7 +2363,7 @@ mod test {
         round_trip_type(DataType::Struct(
             vec![
                 Field::new("c0", DataType::Int32, true),
-                Field::new("c1", DataType::Utf8, false),
+                Field::new("c1", DataType::Utf8, true),
             ]
             .into(),
         ))?;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to