diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs index 0f04281aa23b..a92e64597e82 100644 --- a/datafusion/sql/src/planner.rs +++ b/datafusion/sql/src/planner.rs @@ -439,6 +439,25 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { } SQLDataType::Bytea => Ok(DataType::Binary), SQLDataType::Interval => Ok(DataType::Interval(IntervalUnit::MonthDayNano)), + SQLDataType::Struct(fields) => { + let fields = fields + .iter() + .enumerate() + .map(|(idx, field)| { + let data_type = self.convert_data_type(&field.field_type)?; + let field_name = match &field.field_name{ + Some(ident) => ident.clone(), + None => Ident::new(format!("c{idx}")) + }; + Ok(Arc::new(Field::new( + self.normalizer.normalize(field_name), + data_type, + true, + ))) + }) + .collect::>>()?; + Ok(DataType::Struct(Fields::from(fields))) + } // Explicitly list all other types so that if sqlparser // adds/changes the `SQLDataType` the compiler will tell us on upgrade // and avoid bugs like https://github.com/apache/datafusion/issues/3059 @@ -472,7 +491,6 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | SQLDataType::Bytes(_) | SQLDataType::Int64 | SQLDataType::Float64 - | SQLDataType::Struct(_) | SQLDataType::JSONB | SQLDataType::Unspecified => not_impl_err!( diff --git a/datafusion/sqllogictest/test_files/struct.slt b/datafusion/sqllogictest/test_files/struct.slt index 46a08709c3a3..749daa7e20e7 100644 --- a/datafusion/sqllogictest/test_files/struct.slt +++ b/datafusion/sqllogictest/test_files/struct.slt @@ -31,6 +31,33 @@ CREATE TABLE values( (3, 3.3, 'c', NULL) ; + +# named and named less struct fields +statement ok +CREATE TABLE struct_values ( + s1 struct, + s2 struct +) AS VALUES + (struct(1), struct(1, 'string1')), + (struct(2), struct(2, 'string2')), + (struct(3), struct(3, 'string3')) +; + +query ?? +select * from struct_values; +---- +{c0: 1} {a: 1, b: string1} +{c0: 2} {a: 2, b: string2} +{c0: 3} {a: 3, b: string3} + +query TT +select arrow_typeof(s1), arrow_typeof(s2) from struct_values; +---- +Struct([Field { name: "c0", data_type: Int32, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]) Struct([Field { name: "a", data_type: Int32, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: "b", data_type: Utf8, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]) +Struct([Field { name: "c0", data_type: Int32, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]) Struct([Field { name: "a", data_type: Int32, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: "b", data_type: Utf8, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]) +Struct([Field { name: "c0", data_type: Int32, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]) Struct([Field { name: "a", data_type: Int32, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: "b", data_type: Utf8, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]) + + # struct[i] query IRT select struct(1, 3.14, 'h')['c0'], struct(3, 2.55, 'b')['c1'], struct(2, 6.43, 'a')['c2'];