Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e_test/batch/types/map.slt.part
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ db error: ERROR: Failed to run the query
Caused by these errors (recent errors listed first):
1: Failed to bind expression: map_from_entries(ARRAY[ROW('a', 1, 2)])
2: Expr error
3: the underlying struct for map must have exactly two fields, got: StructType { fields: [("f1", Varchar), ("f2", Int32), ("f3", Int32)] }
3: the underlying struct for map must have exactly two fields, got: Varchar, Int32, Int32


query error
Expand Down
46 changes: 35 additions & 11 deletions src/common/src/types/struct_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,42 @@ pub struct StructType(Arc<StructTypeInner>);

impl Debug for StructType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let alternate = f.alternate();

let mut d = f.debug_struct("StructType");
d.field("fields", &self.0.fields);
if let Some(ids) = &self.0.field_ids
// TODO: This is for making `EXPLAIN` output more concise, but it hurts the readability
// for testing and debugging. Avoid using `Debug` repr in `EXPLAIN` output instead.
&& alternate
{
d.field("field_ids", ids);
// `DataType` derives `Debug`, so `StructType`'s `Debug` representation frequently appears
// in `EXPLAIN` and planner test outputs. Prefer a compact single-line format for `{:?}`,
// while keeping the detailed `StructType { fields: ..., field_ids: ... }` for `{:#?}`.
if f.alternate() {
let mut d = f.debug_struct("StructType");
d.field("fields", &self.0.fields);
if let Some(ids) = &self.0.field_ids {
d.field("field_ids", ids);
}
d.finish()
} else {
// Many internal composite types use synthetic field names like `f1`, `f2`, ...
// Treat them as unnamed to keep `EXPLAIN` output concise.
let omit_names = self.is_unnamed()
|| self
.0
.fields
.iter()
.enumerate()
.all(|(i, (name, _))| name == &format!("f{}", i + 1));
let mut first = true;
for (name, ty) in self.iter() {
if !first {
write!(f, ", ")?;
}
first = false;
if omit_names {
// Unnamed struct comes from `ROW(...)` expressions and prints as `Struct(t1, t2, ...)`.
write!(f, "{:?}", ty)?;
} else {
// Quote the identifier when needed (e.g. reserved keywords or special chars).
write!(f, "{}:{:?}", QuoteIdent(name), ty)?;
}
}
Ok(())
}
d.finish()
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/frontend/planner_test/tests/testdata/output/agg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2265,7 +2265,7 @@
FROM with_0
WHERE false;
logical_plan: |-
LogicalProject { exprs: [null:Struct(StructType { fields: [("a", Int16), ("b", Float64), ("c", Time)] }), 995:Int32, '-168:00:00':Interval, 294:Float64] }
LogicalProject { exprs: [null:Struct(a:Int16, b:Float64, c:Time), 995:Int32, '-168:00:00':Interval, 294:Float64] }
└─LogicalFilter { predicate: false:Boolean }
└─LogicalShare { id: 7 }
└─LogicalProject { exprs: [true:Boolean, -2147483600:Float32, -10773:Int16] }
Expand All @@ -2278,6 +2278,6 @@
batch_plan: 'BatchValues { rows: [] }'
stream_plan: |-
StreamMaterialize { columns: [col_0, col_1, col_2, col_3, _row_id(hidden)], stream_key: [_row_id], pk_columns: [_row_id], pk_conflict: NoCheck }
└─StreamProject { exprs: [null:Struct(StructType { fields: [("a", Int16), ("b", Float64), ("c", Time)] }), 995:Int32, '-168:00:00':Interval, 294:Float64, _row_id] }
└─StreamProject { exprs: [null:Struct(a:Int16, b:Float64, c:Time), 995:Int32, '-168:00:00':Interval, 294:Float64, _row_id] }
└─StreamFilter { predicate: false:Boolean }
└─StreamValues { rows: [[0:Int64]] }
4 changes: 2 additions & 2 deletions src/frontend/planner_test/tests/testdata/output/array.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@
logical_plan: |-
LogicalProject { exprs: [Array as $expr1] }
└─LogicalValues { rows: [[]], schema: Schema { fields: [] } }
batch_plan: 'BatchValues { rows: [[ARRAY[]:List(Struct(StructType { fields: [("f1", Int32)] }))]] }'
batch_plan: 'BatchValues { rows: [[ARRAY[]:List(Struct(Int32))]] }'
stream_plan: |-
StreamMaterialize { columns: [array, _row_id(hidden)], stream_key: [_row_id], pk_columns: [_row_id], pk_conflict: NoCheck }
└─StreamValues { rows: [[ARRAY[]:List(Struct(StructType { fields: [("f1", Int32)] })), 0:Int64]] }
└─StreamValues { rows: [[ARRAY[]:List(Struct(Int32)), 0:Int64]] }
- sql: |
select array_cat(array[66], array[123]);
logical_plan: |-
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/planner_test/tests/testdata/output/expr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@
├─BatchExchange { order: [], dist: HashShard(t.j) }
│ └─BatchScan { table: t, columns: [t.k, t.j], distribution: SomeShard }
└─BatchExchange { order: [], dist: HashShard(t.j) }
└─BatchProject { exprs: [t.j, JsonbPopulateRecord(null:Struct(StructType { fields: [("a", Int32), ("b", Int32)] }), t.j) as $expr1] }
└─BatchProject { exprs: [t.j, JsonbPopulateRecord(null:Struct(a:Int32, b:Int32), t.j) as $expr1] }
└─BatchNestedLoopJoin { type: Inner, predicate: true, output: all }
├─BatchExchange { order: [], dist: Single }
│ └─BatchHashAgg { group_key: [t.j], aggs: [] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,27 @@
select * from t where (v1,v3) > (2,3);
batch_plan: |-
BatchExchange { order: [], dist: Single }
└─BatchFilter { predicate: (Row(t.v1, t.v3) > '(2,3)':Struct(StructType { fields: [("f1", Int32), ("f2", Int32)] })) }
└─BatchFilter { predicate: (Row(t.v1, t.v3) > '(2,3)':Struct(Int32, Int32)) }
└─BatchScan { table: t, columns: [t.v1, t.v2, t.v3], scan_ranges: [t.v1 >= Int32(2)], distribution: UpstreamHashShard(t.v1, t.v2, t.v3) }
- sql: |
create table t(v1 int, v2 int, v3 int, primary key(v1,v2,v3));
select * from t where (v3,v2,v1) > (1,2,3);
batch_plan: |-
BatchExchange { order: [], dist: Single }
└─BatchFilter { predicate: (Row(t.v3, t.v2, t.v1) > '(1,2,3)':Struct(StructType { fields: [("f1", Int32), ("f2", Int32), ("f3", Int32)] })) }
└─BatchFilter { predicate: (Row(t.v3, t.v2, t.v1) > '(1,2,3)':Struct(Int32, Int32, Int32)) }
└─BatchScan { table: t, columns: [t.v1, t.v2, t.v3], distribution: UpstreamHashShard(t.v1, t.v2, t.v3) }
- sql: |
create table t(v1 int, v2 int, v3 int, primary key(v1,v2,v3));
select * from t where (v1,v2,v1) > (1,2,3);
batch_plan: |-
BatchExchange { order: [], dist: Single }
└─BatchFilter { predicate: (Row(t.v1, t.v2, t.v1) > '(1,2,3)':Struct(StructType { fields: [("f1", Int32), ("f2", Int32), ("f3", Int32)] })) }
└─BatchFilter { predicate: (Row(t.v1, t.v2, t.v1) > '(1,2,3)':Struct(Int32, Int32, Int32)) }
└─BatchScan { table: t, columns: [t.v1, t.v2, t.v3], scan_ranges: [(t.v1, t.v2) >= (Int32(1), Int32(2))], distribution: UpstreamHashShard(t.v1, t.v2, t.v3) }
- sql: |
create table t1(v1 int, v2 int, v3 int);
create materialized view mv1 as select * from t1 order by v1 asc, v2 asc, v3 desc;
select * from mv1 where (v1,v2,v3) > (1,3,1);
batch_plan: |-
BatchExchange { order: [], dist: Single }
└─BatchFilter { predicate: (Row(mv1.v1, mv1.v2, mv1.v3) > '(1,3,1)':Struct(StructType { fields: [("f1", Int32), ("f2", Int32), ("f3", Int32)] })) }
└─BatchFilter { predicate: (Row(mv1.v1, mv1.v2, mv1.v3) > '(1,3,1)':Struct(Int32, Int32, Int32)) }
└─BatchScan { table: mv1, columns: [mv1.v1, mv1.v2, mv1.v3], scan_ranges: [(mv1.v1, mv1.v2) >= (Int32(1), Int32(3))], distribution: SomeShard }
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@
insert into s values (1,2,(1,2,(1,2,null)));
logical_plan: |-
LogicalInsert { table: s, mapping: [0:0, 1:1, 2:2] }
└─LogicalValues { rows: [[1:Int32, 2:Int32, Row(1:Int32, 2:Int32, Row(1:Int32, 2:Int32, null:Int32))]], schema: Schema { fields: [*VALUES*_0.column_0:Int32, *VALUES*_0.column_1:Int32, *VALUES*_0.column_2:Struct(StructType { fields: [("v1", Int32), ("v2", Int32), ("v3", Struct(StructType { fields: [("v1", Int32), ("v2", Int32), ("v3", Int32)] }))] })] } }
└─LogicalValues { rows: [[1:Int32, 2:Int32, Row(1:Int32, 2:Int32, Row(1:Int32, 2:Int32, null:Int32))]], schema: Schema { fields: [*VALUES*_0.column_0:Int32, *VALUES*_0.column_1:Int32, *VALUES*_0.column_2:Struct(v1:Int32, v2:Int32, v3:Struct(v1:Int32, v2:Int32, v3:Int32))] } }
create_table_with_connector:
format: plain
encode: protobuf
Expand Down
4 changes: 2 additions & 2 deletions src/frontend/planner_test/tests/testdata/output/update.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@
batch_plan: |-
BatchExchange { order: [], dist: Single }
└─BatchUpdate { table: t, exprs: [Field($4, 0:Int32), Field($4, 1:Int32), $2] }
└─BatchProject { exprs: [t.v1, t.v2, t._row_id, t._rw_timestamp, $expr10011::Struct(StructType { fields: [("v1", Int32), ("v2", Int32)] }) as $expr1] }
└─BatchProject { exprs: [t.v1, t.v2, t._row_id, t._rw_timestamp, $expr10011::Struct(v1:Int32, v2:Int32) as $expr1] }
└─BatchNestedLoopJoin { type: LeftOuter, predicate: true, output: all }
├─BatchExchange { order: [], dist: Single }
│ └─BatchScan { table: t, columns: [t.v1, t.v2, t._row_id, t._rw_timestamp], distribution: UpstreamHashShard(t._row_id) }
└─BatchValues { rows: [['(666.66,777)':Struct(StructType { fields: [("f1", Decimal), ("f2", Int32)] })]] }
└─BatchValues { rows: [['(666.66,777)':Struct(Decimal, Int32)]] }
Loading
Loading