You are viewing a plain text version of this content. The canonical link for it is here.
Posted to github@datafusion.apache.org by "adriangb (via GitHub)" <gi...@apache.org> on 2025/12/24 23:42:52 UTC

[PR] Demonstarte that Unparser inserts subquery which looses order [datafusion]

adriangb opened a new pull request, #19483:
URL: https://github.com/apache/datafusion/pull/19483

   (no comment)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] Preserve ORDER BY in Unparser for projection -> order by pattern [datafusion]

Posted by "kosiew (via GitHub)" <gi...@apache.org>.
kosiew merged PR #19483:
URL: https://github.com/apache/datafusion/pull/19483


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] Preserve ORDER BY in Unparser for projection -> order by pattern [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb commented on PR #19483:
URL: https://github.com/apache/datafusion/pull/19483#issuecomment-3691568793

   @alamb @goldmedal @y-f-u could you folks take a look at this since you originally added this bit of code in #11527? As far as I can tell this has kept all of those tests passing and only produced some formatting changes in one test's SQL, but I'm not familiar with the Unparser code in general so this needs some critical thought.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] Preserve ORDER BY in Unparser for projection -> order by pattern [datafusion]

Posted by "kosiew (via GitHub)" <gi...@apache.org>.
kosiew commented on code in PR #19483:
URL: https://github.com/apache/datafusion/pull/19483#discussion_r2649717267


##########
datafusion/core/tests/sql/unparser.rs:
##########
@@ -0,0 +1,467 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//! SQL Unparser Roundtrip Integration Tests
+//!
+//! This module tests the [`Unparser`] by running queries through a complete roundtrip:
+//! the original SQL is parsed into a logical plan, unparsed back to SQL, then that
+//! generated SQL is parsed and executed. The results are compared to verify semantic
+//! equivalence.
+//!
+//! ## Test Strategy
+//!
+//! Uses real-world benchmark queries (TPC-H and Clickbench) to validate that:
+//! 1. The unparser produces syntactically valid SQL
+//! 2. The unparsed SQL is semantically equivalent (produces identical results)
+//!
+//! ## Query Suites
+//!
+//! - **TPC-H**: Standard decision-support benchmark with 22 complex analytical queries
+//! - **Clickbench**: Web analytics benchmark with 43 queries against a denormalized schema
+//!
+//! [`Unparser`]: datafusion_sql::unparser::Unparser
+
+use std::fs::ReadDir;
+use std::future::Future;
+
+use arrow::array::RecordBatch;
+use datafusion::common::Result;
+use datafusion::prelude::{ParquetReadOptions, SessionContext};
+use datafusion_common::Column;
+use datafusion_expr::Expr;
+use datafusion_physical_plan::ExecutionPlanProperties;
+use datafusion_sql::unparser::Unparser;
+use datafusion_sql::unparser::dialect::DefaultDialect;
+use itertools::Itertools;
+
+/// Primary path to benchmark query files (when running from repo root).
+const BENCHMARKS_PATH_1: &str = "../../benchmarks/";
+
+/// Fallback path to benchmark query files (when running from different working directories).
+const BENCHMARKS_PATH_2: &str = "./benchmarks/";

Review Comment:
   `const BENCHMARK_PATHS: &[&str] = &["../../benchmarks/", "./benchmarks/"];`
   
   and you won't have to 
   `let paths = [BENCHMARKS_PATH_1, BENCHMARKS_PATH_2];`
   in `clickbench_queries`, `tpch_queries`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] Preserve ORDER BY in Unparser for projection -> order by pattern [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb commented on code in PR #19483:
URL: https://github.com/apache/datafusion/pull/19483#discussion_r2647569564


##########
datafusion/sql/tests/cases/plan_to_sql.rs:
##########
@@ -1984,7 +1984,7 @@ fn test_complex_order_by_with_grouping() -> Result<()> {
     }, {
         assert_snapshot!(
             sql,
-            @"SELECT j1.j1_id, j1.j1_string, lochierarchy FROM (SELECT j1.j1_id, j1.j1_string, (grouping(j1.j1_id) + grouping(j1.j1_string)) AS lochierarchy, grouping(j1.j1_string), grouping(j1.j1_id) FROM j1 GROUP BY ROLLUP (j1.j1_id, j1.j1_string) ORDER BY lochierarchy DESC NULLS FIRST, CASE WHEN ((grouping(j1.j1_id) + grouping(j1.j1_string)) = 0) THEN j1.j1_id END ASC NULLS LAST) LIMIT 100"
+            @r#"SELECT j1.j1_id, j1.j1_string, lochierarchy FROM (SELECT j1.j1_id, j1.j1_string, (grouping(j1.j1_id) + grouping(j1.j1_string)) AS lochierarchy, grouping(j1.j1_string), grouping(j1.j1_id) FROM j1 GROUP BY ROLLUP (j1.j1_id, j1.j1_string)) ORDER BY lochierarchy DESC NULLS FIRST, CASE WHEN (("grouping(j1.j1_id)" + "grouping(j1.j1_string)") = 0) THEN j1.j1_id END ASC NULLS LAST LIMIT 100"#

Review Comment:
   Formatted difference:
   
   ```diff
   - @"SELECT
   -   j1.j1_id,
   -   j1.j1_string,
   -   lochierarchy
   - FROM (
   -   SELECT
   -     j1.j1_id,
   -     j1.j1_string,
   -     (grouping(j1.j1_id) + grouping(j1.j1_string)) AS lochierarchy,
   -     grouping(j1.j1_string),
   -     grouping(j1.j1_id)
   -   FROM j1
   -   GROUP BY ROLLUP (j1.j1_id, j1.j1_string)
   -   ORDER BY
   -     lochierarchy DESC NULLS FIRST,
   -     CASE
   -       WHEN ((grouping(j1.j1_id) + grouping(j1.j1_string)) = 0) THEN j1.j1_id
   -     END ASC NULLS LAST
   - )
   - LIMIT 100"
   + @r#"SELECT
   +   j1.j1_id,
   +   j1.j1_string,
   +   lochierarchy
   + FROM (
   +   SELECT
   +     j1.j1_id,
   +     j1.j1_string,
   +     (grouping(j1.j1_id) + grouping(j1.j1_string)) AS lochierarchy,
   +     grouping(j1.j1_string),
   +     grouping(j1.j1_id)
   +   FROM j1
   +   GROUP BY ROLLUP (j1.j1_id, j1.j1_string)
   + )
   + ORDER BY
   +   lochierarchy DESC NULLS FIRST,
   +   CASE
   +     WHEN (("grouping(j1.j1_id)" + "grouping(j1.j1_string)") = 0) THEN j1.j1_id
   +   END ASC NULLS LAST
   + LIMIT 100"#
   ```
   
   As you can see the ORDER BY got moved outside of the subquery, which is what we want.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] Preserve ORDER BY in Unparser for projection -> order by pattern [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb commented on PR #19483:
URL: https://github.com/apache/datafusion/pull/19483#issuecomment-3692158283

   I've added a property based test that asserts the property that results should be the same after unparsing and re-parsing a query given the same input data*. I think this is a good test because:
   - It uses real world queries and data
   - It's a property based test on the thing users care about in general (correct results) instead of e.g. asserting the unparsed SQL matches some shape
   
   *: Not all queries have a deterministic sort order. I check if the *original* query has a known output ordering and if it doesn't I sort both outputs.
   
   These tests show that without these fixes there are two issues for ClickBench queries:
   - Column name quoting is missing for columns with uppercase letters
   - The ORDER BY bug
   
   Here is the failure output (also relevant to judge since the tests are being added):
   
   ```
   3 Clickbench test(s) failed:
   
   Results mismatch for q15.
   Original SQL:
   -- Must set for ClickBench hits_partitioned dataset. See https://github.com/apache/datafusion/issues/16591
   -- set datafusion.execution.parquet.binary_as_string = true
   
   SELECT "UserID", COUNT(*) FROM hits GROUP BY "UserID" ORDER BY COUNT(*) DESC LIMIT 10;
   
   Unparsed SQL:
   SELECT
     hits."UserID",
     "count(*)"
   FROM
     (
       SELECT
         hits."UserID",
         count(1) AS "count(*)",
         count(1)
       FROM
         hits
       GROUP BY
         hits."UserID" ORDER BY count(1) DESC NULLS FIRST
     ) LIMIT 10
   
   ---
   
   Results mismatch for q16.
   Original SQL:
   -- Must set for ClickBench hits_partitioned dataset. See https://github.com/apache/datafusion/issues/16591
   -- set datafusion.execution.parquet.binary_as_string = true
   
   SELECT "UserID", "SearchPhrase", COUNT(*) FROM hits GROUP BY "UserID", "SearchPhrase" ORDER BY COUNT(*) DESC LIMIT 10;
   
   Unparsed SQL:
   SELECT
     hits."UserID",
     hits."SearchPhrase",
     "count(*)"
   FROM
     (
       SELECT
         hits."UserID",
         hits."SearchPhrase",
         count(1) AS "count(*)",
         count(1)
       FROM
         hits
       GROUP BY
         hits."UserID", hits."SearchPhrase" ORDER BY count(1) DESC NULLS FIRST
     ) LIMIT 10
   
   ---
   
   Results mismatch for q18.
   Original SQL:
   -- Must set for ClickBench hits_partitioned dataset. See https://github.com/apache/datafusion/issues/16591
   -- set datafusion.execution.parquet.binary_as_string = true
   
   SELECT "UserID", extract(minute FROM to_timestamp_seconds("EventTime")) AS m, "SearchPhrase", COUNT(*) FROM hits GROUP BY "UserID", m, "SearchPhrase" ORDER BY COUNT(*) DESC LIMIT 10;
   
   Unparsed SQL:
   SELECT
     hits."UserID",
     m,
     hits."SearchPhrase",
     "count(*)"
   FROM
     (
       SELECT
         hits."UserID",
         date_part('MINUTE', to_timestamp_seconds(hits."EventTime")) AS m,
         hits."SearchPhrase",
         count(1) AS "count(*)",
         count(1)
       FROM
         hits
       GROUP BY
         hits."UserID", date_part('MINUTE', to_timestamp_seconds(hits."EventTime")), hits."SearchPhrase" ORDER BY count(1) DESC NULLS FIRST
     ) LIMIT 10
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] Preserve ORDER BY in Unparser for projection -> order by pattern [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb commented on code in PR #19483:
URL: https://github.com/apache/datafusion/pull/19483#discussion_r2647143472


##########
datafusion/core/tests/sql/orderby.rs:
##########
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use datafusion::catalog::MemTable;
+use datafusion::common::test_util::batches_to_string;
+use datafusion::sql::unparser::plan_to_sql;
+
+use super::*;
+
+#[tokio::test]
+async fn roundtrip_group_by_alias_with_execution() -> Result<()> {
+    let ctx = SessionContext::new();
+
+    // Create table schema
+    let t1_schema =
+        Arc::new(Schema::new(vec![Field::new("col", DataType::Int32, false)]));
+
+    // Create test data: rows (3), (2), (1)
+    let batch = RecordBatch::try_new(
+        t1_schema.clone(),
+        vec![Arc::new(Int32Array::from(vec![3, 2, 1]))],
+    )?;
+
+    // Register table with data
+    ctx.register_table(
+        "t1",
+        Arc::new(MemTable::try_new(t1_schema, vec![vec![batch]])?),
+    )?;
+
+    // Original query
+    let original_sql = r#"
+        SELECT
+          col * 2 as x_bucket,
+          count(*)
+        FROM t1
+        GROUP BY x_bucket
+        ORDER BY x_bucket, count(*)

Review Comment:
   We can probably move this to a test in `plan_to_sql.rs` but I struggled a bit translating it since there's limited functions available (e.g. `count(*)`). I do also think e2e tests with data are useful in that they don't require a specific SQL representation as long as query semantics are maintained. But I will try to port again once we get some initial feedback here.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] Preserve ORDER BY in Unparser for projection -> order by pattern [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb commented on code in PR #19483:
URL: https://github.com/apache/datafusion/pull/19483#discussion_r2647143472


##########
datafusion/core/tests/sql/orderby.rs:
##########
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use datafusion::catalog::MemTable;
+use datafusion::common::test_util::batches_to_string;
+use datafusion::sql::unparser::plan_to_sql;
+
+use super::*;
+
+#[tokio::test]
+async fn roundtrip_group_by_alias_with_execution() -> Result<()> {
+    let ctx = SessionContext::new();
+
+    // Create table schema
+    let t1_schema =
+        Arc::new(Schema::new(vec![Field::new("col", DataType::Int32, false)]));
+
+    // Create test data: rows (3), (2), (1)
+    let batch = RecordBatch::try_new(
+        t1_schema.clone(),
+        vec![Arc::new(Int32Array::from(vec![3, 2, 1]))],
+    )?;
+
+    // Register table with data
+    ctx.register_table(
+        "t1",
+        Arc::new(MemTable::try_new(t1_schema, vec![vec![batch]])?),
+    )?;
+
+    // Original query
+    let original_sql = r#"
+        SELECT
+          col * 2 as x_bucket,
+          count(*)
+        FROM t1
+        GROUP BY x_bucket
+        ORDER BY x_bucket, count(*)

Review Comment:
   We can probably move this to a test in `plan_to_sql.rs` but I struggled a bit translating it since there's limited functions available (e.g. `count(*)`). Will try again.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org