You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by ab...@apache.org on 2025/05/12 19:28:46 UTC

(druid) branch pivot_col_name_null_fix created (now eb74217ffa1)

This is an automated email from the ASF dual-hosted git repository.

abhishekrb pushed a change to branch pivot_col_name_null_fix
in repository https://gitbox.apache.org/repos/asf/druid.git


      at eb74217ffa1 Preserve column names as-is for unnest queries in the decoupled planner mode.

This branch includes the following new commits:

     new eb74217ffa1 Preserve column names as-is for unnest queries in the decoupled planner mode.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


(druid) 01/01: Preserve column names as-is for unnest queries in the decoupled planner mode.

Posted by ab...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

abhishekrb pushed a commit to branch pivot_col_name_null_fix
in repository https://gitbox.apache.org/repos/asf/druid.git

commit eb74217ffa1f257496e9e90cc6a6036f59a85bcc
Author: Abhishek Balaji Radhakrishnan <ab...@gmail.com>
AuthorDate: Mon May 12 12:22:11 2025 -0700

    Preserve column names as-is for unnest queries in the decoupled planner mode.
    
    Unnest queries in the decoupled planner mode adds a suffix "_null" for some
    cases. Currently the PlannerResult is based on the built query's output type rather
    than the planned output type (which shouldn't contain the "_null" suffix). This is the
    same for "coupled" planner.
    
    The planner result is used for populating things in the sql direct statement. The sql row
    transformer depends on the planner result, so this PR fixes that by aligning with the planned
    output type.
---
 .../druid/sql/calcite/planner/QueryHandler.java    |   7 +-
 .../org/apache/druid/sql/http/SqlResourceTest.java | 103 +++++++++++++++++++++
 2 files changed, 106 insertions(+), 4 deletions(-)

diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/QueryHandler.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/QueryHandler.java
index 0f2f25ef6d3..9e608f7616a 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/QueryHandler.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/QueryHandler.java
@@ -540,6 +540,8 @@ public abstract class QueryHandler extends SqlStatementHandler.BaseStatementHand
     QueryValidations.validateLogicalQueryForDruid(handlerContext.plannerContext(), parameterized);
     CalcitePlanner planner = handlerContext.planner();
 
+    final RelDataType rowType = prepareResult.getReturnedRowType();
+
     if (plannerContext.getPlannerConfig()
                       .getNativeQuerySqlPlanningMode()
                       .equals(QueryContexts.NATIVE_QUERY_SQL_PLANNING_MODE_DECOUPLED)
@@ -574,7 +576,7 @@ public abstract class QueryHandler extends SqlStatementHandler.BaseStatementHand
         return planExplanation(possiblyLimitedRoot, newRoot, true);
       }
 
-      return new PlannerResult(resultsSupplier, finalBaseQuery.getOutputRowType());
+      return new PlannerResult(resultsSupplier, rowType);
     } else {
       final DruidRel<?> druidRel = (DruidRel<?>) planner.transform(
           CalciteRulesManager.DRUID_CONVENTION_RULES,
@@ -591,9 +593,6 @@ public abstract class QueryHandler extends SqlStatementHandler.BaseStatementHand
       if (explain != null) {
         return planExplanation(possiblyLimitedRoot, druidRel, true);
       } else {
-        // Compute row type.
-        final RelDataType rowType = prepareResult.getReturnedRowType();
-
         // sanity check
         final Set<ResourceAction> readResourceActions =
             plannerContext.getResourceActions()
diff --git a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
index 8b767de3b5a..f18873668ea 100644
--- a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
@@ -634,6 +634,109 @@ public class SqlResourceTest extends CalciteTestBase
     );
   }
 
+
+  @Test
+  public void testPivotRowTypePreservedInDecoupledPlanner() throws Exception
+  {
+    final List<Map<String, Object>> rows = doPost(
+            new SqlQuery(
+                    "SET plannerStrategy='DECOUPLED';" +
+                            " WITH t1 AS (\n" +
+                            "  SELECT *\n" +
+                            "  FROM (\n" +
+                            "    VALUES\n" +
+                            "    ('18-19', 'female', 84),\n" +
+                            "    ('18-19', 'male', 217),\n" +
+                            "    ('20-29', 'female', 321),\n" +
+                            "    ('20-29', 'male', 820),\n" +
+                            "    ('30-39', 'female', 63),\n" +
+                            "    ('30-39', 'male', 449),\n" +
+                            "    ('40-49', 'female', 10),\n" +
+                            "    ('40-49', 'male', 83),\n" +
+                            "    ('50-59', 'female', 2),\n" +
+                            "    ('50-59', 'male', 13)\n" +
+                            "  ) AS data(Age, Gender, Visitors)\n" +
+                            "),\n" +
+                            "t2 AS (\n" +
+                            "  SELECT Age, Gender, CAST(SUM(Visitors) AS double) / (SELECT SUM(Visitors) FROM t1) AS Share\n" +
+                            "  FROM t1\n" +
+                            "  GROUP BY 1, 2\n" +
+                            ")\n" +
+                            "SELECT *\n" +
+                            "FROM t2\n" +
+                            "PIVOT (MAX(Share) FOR Gender IN ('female' AS Women, 'male' AS Men));",
+                    ResultFormat.OBJECT,
+                    false,
+                    false,
+                    false,
+                    null,
+                    null
+            )
+    ).rhs;
+
+    Assert.assertEquals(
+            ImmutableList.of(
+                    ImmutableMap.of("Age", "18-19", "Women", 0.040737148399612025, "Men", 0.1052376333656644),
+                    ImmutableMap.of("Age", "20-29", "Women", 0.1556741028128031, "Men", 0.3976721629485936),
+                    ImmutableMap.of("Age", "30-39", "Women", 0.030552861299709022, "Men", 0.2177497575169738),
+                    ImmutableMap.of("Age", "40-49", "Women", 0.004849660523763337, "Men", 0.040252182347235696),
+                    ImmutableMap.of("Age", "50-59", "Women", 0.0009699321047526673, "Men", 0.006304558680892337)
+            ),
+            rows
+    );
+  }
+
+  @Test
+  public void testPivotRowTypePreservedInCoupledPlanner() throws Exception
+  {
+    final List<Map<String, Object>> rows = doPost(
+            new SqlQuery(
+                    "SET plannerStrategy='COUPLED';" +
+                            " WITH t1 AS (\n" +
+                            "  SELECT *\n" +
+                            "  FROM (\n" +
+                            "    VALUES\n" +
+                            "    ('18-19', 'female', 84),\n" +
+                            "    ('18-19', 'male', 217),\n" +
+                            "    ('20-29', 'female', 321),\n" +
+                            "    ('20-29', 'male', 820),\n" +
+                            "    ('30-39', 'female', 63),\n" +
+                            "    ('30-39', 'male', 449),\n" +
+                            "    ('40-49', 'female', 10),\n" +
+                            "    ('40-49', 'male', 83),\n" +
+                            "    ('50-59', 'female', 2),\n" +
+                            "    ('50-59', 'male', 13)\n" +
+                            "  ) AS data(Age, Gender, Visitors)\n" +
+                            "),\n" +
+                            "t2 AS (\n" +
+                            "  SELECT Age, Gender, CAST(SUM(Visitors) AS double) / (SELECT SUM(Visitors) FROM t1) AS Share\n" +
+                            "  FROM t1\n" +
+                            "  GROUP BY 1, 2\n" +
+                            ")\n" +
+                            "SELECT *\n" +
+                            "FROM t2\n" +
+                            "PIVOT (MAX(Share) FOR Gender IN ('female' AS Women, 'male' AS Men));",
+                    ResultFormat.OBJECT,
+                    false,
+                    false,
+                    false,
+                    null,
+                    null
+            )
+    ).rhs;
+
+    Assert.assertEquals(
+            ImmutableList.of(
+                    ImmutableMap.of("Age", "18-19", "Women", 0.040737148399612025, "Men", 0.1052376333656644),
+                    ImmutableMap.of("Age", "20-29", "Women", 0.1556741028128031, "Men", 0.3976721629485936),
+                    ImmutableMap.of("Age", "30-39", "Women", 0.030552861299709022, "Men", 0.2177497575169738),
+                    ImmutableMap.of("Age", "40-49", "Women", 0.004849660523763337, "Men", 0.040252182347235696),
+                    ImmutableMap.of("Age", "50-59", "Women", 0.0009699321047526673, "Men", 0.006304558680892337)
+            ),
+            rows
+    );
+  }
+
   @Test
   public void testArrayResultFormat() throws Exception
   {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org