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