Skip to content

Commit 138fdfe

Browse files
committed
Differentiate 0-row and 1-row EmptyRelation in EXPLAIN
The `LogicalPlan::EmptyRelation` can produce no rows or exactly 1 null (placeholder) row of the requested schema. When viewing EXPLAIN output of a LogicalPlan it's good to know which one is the case.
1 parent 7d52145 commit 138fdfe

31 files changed

+320
-321
lines changed

datafusion-cli/tests/snapshots/cli_quick_test@can_see_indent_format.snap

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ info:
55
args:
66
- "--command"
77
- EXPLAIN FORMAT indent SELECT 123
8-
snapshot_kind: text
98
---
109
success: true
1110
exit_code: 0
@@ -15,7 +14,7 @@ exit_code: 0
1514
| plan_type | plan |
1615
+---------------+------------------------------------------+
1716
| logical_plan | Projection: Int64(123) |
18-
| | EmptyRelation |
17+
| | EmptyRelation: rows=1 |
1918
| physical_plan | ProjectionExec: expr=[123 as Int64(123)] |
2019
| | PlaceholderRowExec |
2120
| | |

datafusion/core/tests/dataframe/mod.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,7 +1213,7 @@ async fn join_on_filter_datatype() -> Result<()> {
12131213
JoinType::Inner,
12141214
Some(Expr::Literal(ScalarValue::Null, None)),
12151215
)?;
1216-
assert_snapshot!(join.into_optimized_plan().unwrap(), @"EmptyRelation");
1216+
assert_snapshot!(join.into_optimized_plan().unwrap(), @"EmptyRelation: rows=0");
12171217

12181218
// JOIN ON expression must be boolean type
12191219
let join = left.join_on(right, JoinType::Inner, Some(lit("TRUE")))?;
@@ -4940,11 +4940,11 @@ async fn test_dataframe_placeholder_missing_param_values() -> Result<()> {
49404940

49414941
assert_snapshot!(
49424942
actual,
4943-
@r###"
4943+
@r"
49444944
Filter: a = $0 [a:Int32]
49454945
Projection: Int32(1) AS a [a:Int32]
4946-
EmptyRelation []
4947-
"###
4946+
EmptyRelation: rows=1 []
4947+
"
49484948
);
49494949

49504950
// Executing LogicalPlans with placeholders that don't have bound values
@@ -4973,11 +4973,11 @@ async fn test_dataframe_placeholder_missing_param_values() -> Result<()> {
49734973

49744974
assert_snapshot!(
49754975
actual,
4976-
@r###"
4976+
@r"
49774977
Filter: a = Int32(3) [a:Int32]
49784978
Projection: Int32(1) AS a [a:Int32]
4979-
EmptyRelation []
4980-
"###
4979+
EmptyRelation: rows=1 []
4980+
"
49814981
);
49824982

49834983
// N.B., the test is basically `SELECT 1 as a WHERE a = 3;` which returns no results.
@@ -5004,10 +5004,10 @@ async fn test_dataframe_placeholder_column_parameter() -> Result<()> {
50045004

50055005
assert_snapshot!(
50065006
actual,
5007-
@r###"
5007+
@r"
50085008
Projection: $1 [$1:Null;N]
5009-
EmptyRelation []
5010-
"###
5009+
EmptyRelation: rows=1 []
5010+
"
50115011
);
50125012

50135013
// Executing LogicalPlans with placeholders that don't have bound values
@@ -5034,10 +5034,10 @@ async fn test_dataframe_placeholder_column_parameter() -> Result<()> {
50345034

50355035
assert_snapshot!(
50365036
actual,
5037-
@r###"
5037+
@r"
50385038
Projection: Int32(3) AS $1 [$1:Null;N]
5039-
EmptyRelation []
5040-
"###
5039+
EmptyRelation: rows=1 []
5040+
"
50415041
);
50425042

50435043
assert_snapshot!(
@@ -5073,11 +5073,11 @@ async fn test_dataframe_placeholder_like_expression() -> Result<()> {
50735073

50745074
assert_snapshot!(
50755075
actual,
5076-
@r###"
5076+
@r#"
50775077
Filter: a LIKE $1 [a:Utf8]
50785078
Projection: Utf8("foo") AS a [a:Utf8]
5079-
EmptyRelation []
5080-
"###
5079+
EmptyRelation: rows=1 []
5080+
"#
50815081
);
50825082

50835083
// Executing LogicalPlans with placeholders that don't have bound values
@@ -5106,11 +5106,11 @@ async fn test_dataframe_placeholder_like_expression() -> Result<()> {
51065106

51075107
assert_snapshot!(
51085108
actual,
5109-
@r###"
5109+
@r#"
51105110
Filter: a LIKE Utf8("f%") [a:Utf8]
51115111
Projection: Utf8("foo") AS a [a:Utf8]
5112-
EmptyRelation []
5113-
"###
5112+
EmptyRelation: rows=1 []
5113+
"#
51145114
);
51155115

51165116
assert_snapshot!(

datafusion/core/tests/execution/logical_plan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ fn inline_scan_projection_test() -> Result<()> {
128128
@r"
129129
SubqueryAlias: ?table?
130130
Projection: a
131-
EmptyRelation
131+
EmptyRelation: rows=0
132132
"
133133
);
134134

datafusion/core/tests/optimizer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fn select_arrow_cast() {
6262
plan,
6363
@r#"
6464
Projection: Float64(1234) AS f64, LargeUtf8("foo") AS large
65-
EmptyRelation
65+
EmptyRelation: rows=1
6666
"#
6767
);
6868
}

datafusion/expr/src/logical_plan/plan.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1720,7 +1720,10 @@ impl LogicalPlan {
17201720
impl Display for Wrapper<'_> {
17211721
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
17221722
match self.0 {
1723-
LogicalPlan::EmptyRelation(_) => write!(f, "EmptyRelation"),
1723+
LogicalPlan::EmptyRelation(EmptyRelation { produce_one_row, schema: _ }) => {
1724+
let rows = if *produce_one_row { 1 } else { 0 };
1725+
write!(f, "EmptyRelation: rows={rows}")
1726+
},
17241727
LogicalPlan::RecursiveQuery(RecursiveQuery {
17251728
is_distinct, ..
17261729
}) => {

0 commit comments

Comments
 (0)