You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by ag...@apache.org on 2026/10/09 20:17:33 UTC
(datafusion-ballista) branch main updated: feat(core): support DESCRIBE table by planning it on the client (#2570)
This is an automated email from the ASF dual-hosted git repository.
andygrove pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-ballista.git
The following commit(s) were added to refs/heads/main by this push:
new 010b9598a feat(core): support DESCRIBE table by planning it on the client (#2570)
010b9598a is described below
commit 010b9598a86041e25ffeaf257bdac4d7934a5f3f
Author: Andy Grove <ag...@apache.org>
AuthorDate: Fri Oct 9 14:17:28 2026 -0600
feat(core): support DESCRIBE table by planning it on the client (#2570)
* feat(core): support DESCRIBE table by planning it on the client
* refactor(core): remove debug logging from DESCRIBE planning
---
ballista/client/tests/context_basic.rs | 20 +++++++++++++++++++
ballista/core/src/planner.rs | 35 ++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/ballista/client/tests/context_basic.rs b/ballista/client/tests/context_basic.rs
index 395f57031..651c20ec9 100644
--- a/ballista/client/tests/context_basic.rs
+++ b/ballista/client/tests/context_basic.rs
@@ -484,6 +484,26 @@ mod basic {
.collect::<Vec<&str>>()
);
}
+ #[tokio::test]
+ async fn test_describe_table() -> Result<()> {
+ let context = create_test_context().await;
+
+ let result = context.sql("DESCRIBE test").await?.collect().await?;
+
+ let output = pretty_format_batches(&result)?.to_string();
+ let header = output.lines().nth(1).expect("header line");
+ for column in ["column_name", "data_type", "is_nullable"] {
+ assert!(header.contains(column), "missing {column} in:\n{output}");
+ }
+ for column in ["id", "bool_col", "timestamp_col"] {
+ assert!(
+ output.contains(&format!("| {column} ")),
+ "missing row for {column} in:\n{output}"
+ );
+ }
+ Ok(())
+ }
+
async fn create_test_context() -> SessionContext {
let context = SessionContext::standalone().await.unwrap();
diff --git a/ballista/core/src/planner.rs b/ballista/core/src/planner.rs
index cb0a795ad..cf892abcb 100644
--- a/ballista/core/src/planner.rs
+++ b/ballista/core/src/planner.rs
@@ -125,6 +125,14 @@ impl<T: 'static + AsLogicalPlan> QueryPlanner for BallistaQueryPlanner<T> {
log::debug!("create_physical_plan - handling empty exec");
Ok(Arc::new(EmptyExec::new(Arc::new(Schema::empty()))))
}
+ LogicalPlan::DescribeTable(_) => {
+ // The plan already carries the table schema resolved from
+ // this context's catalog, and it cannot be serialized, so
+ // it is planned here rather than on the cluster.
+ self.local_planner
+ .create_physical_plan(logical_plan, session_state)
+ .await
+ }
LogicalPlan::Analyze(analyze) => {
log::debug!(
"create_physical_plan - handling explain analyze statement"
@@ -303,6 +311,33 @@ mod test {
Ok(())
}
+ #[tokio::test]
+ async fn should_plan_describe_table_locally() -> Result<()> {
+ let ctx = context();
+ ctx.sql("CREATE TABLE tt (c0 INT, c1 INT)")
+ .await?
+ .show()
+ .await?;
+ let describe_df = ctx.sql("DESCRIBE tt").await?;
+ let planner = BallistaQueryPlanner::<LogicalPlanNode>::new(
+ "http://localhost:50050".to_string(),
+ BallistaConfig::default(),
+ );
+ let plan = planner
+ .create_physical_plan(describe_df.logical_plan(), &ctx.state())
+ .await?;
+
+ assert!(matches!(
+ describe_df.logical_plan(),
+ LogicalPlan::DescribeTable(_)
+ ));
+ assert!(
+ plan.downcast_ref::<DistributedQueryExec<LogicalPlanNode>>()
+ .is_none()
+ );
+ Ok(())
+ }
+
#[tokio::test]
async fn should_create_distributed_explain_analyze_exec() -> Result<()> {
let ctx = context();
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org