xiedeyantu commented on code in PR #4544:
URL: https://github.com/apache/calcite/pull/4544#discussion_r2358676334


##########
core/src/test/java/org/apache/calcite/test/RelBuilderTest.java:
##########
@@ -5585,6 +5590,284 @@ private static RelNode 
buildCorrelateWithJoin(JoinRelType type, RelBuilder build
     assertThat(root, hasTree(expected));
   }
 
+
+  @Test void testCombine() {
+    // Create two separate queries
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode scan1 = builder.scan("EMP")
+        .filter(builder.equals(builder.field("DEPTNO"), builder.literal(10)))
+        .project(builder.field("ENAME"))
+        .build();
+    RelNode scan2 = builder.scan("EMP")
+        .filter(builder.equals(builder.field("DEPTNO"), builder.literal(20)))
+        .project(builder.field("SAL"))
+        .build();
+
+    // Test combine with varargs
+    RelNode combine1 = builder.combine(scan1, scan2).build();
+    assertThat(combine1, instanceOf(Combine.class));
+    assertThat(combine1.getInputs(), hasSize(2));
+
+    // Test combine with Iterable
+    RelNode combine2 = builder.combine(Arrays.asList(scan1, scan2)).build();
+    assertThat(combine2, instanceOf(Combine.class));
+    assertThat(combine2.getInputs(), hasSize(2));
+
+    // Test combine with stack
+    builder.push(scan1)
+        .push(scan2);
+    RelNode combine3 = builder.combine(2).build();
+    assertThat(combine3, instanceOf(Combine.class));
+    assertThat(((Combine) combine3).getInputs(), hasSize(2));
+
+    // Test combine with all stack
+    builder.clear();
+    builder.push(scan1)
+        .push(scan2);
+    RelNode combine4 = builder.combine().build();
+    assertThat(combine4, instanceOf(Combine.class));
+    assertThat(combine4.getInputs(), hasSize(2));
+  }
+
+  @Test void testCombineWithSharedSubexpression() {
+    // Test that demonstrates how Combine can optimize queries with shared 
subexpressions
+    final RelBuilder builder = RelBuilder.create(config().build());
+
+    // Create a common subexpression - employees with salary > 1000
+    builder.scan("EMP")
+        .filter(
+            builder.call(SqlStdOperatorTable.GREATER_THAN,
+            builder.field("SAL"), builder.literal(1000)));
+    RelNode commonSubexpr = builder.build();
+
+    // Query 1: Count high earners by department
+    RelNode query1 = builder.push(commonSubexpr)
+        .aggregate(builder.groupKey("DEPTNO"), builder.count())
+        .build();
+
+    // Query 2: Get names of high earners
+    RelNode query2 = builder.push(commonSubexpr)
+        .project(builder.field("ENAME"), builder.field("SAL"))
+        .build();
+
+    // Combine both queries - planner can recognize shared subexpression
+    RelNode combined = builder.combine(query1, query2).build();
+
+    assertThat(combined, instanceOf(Combine.class));
+    assertThat(combined.getInputs(), hasSize(2));
+    // Both queries share the same filter as their base

Review Comment:
   @asolimando 's question is also what I want to know, but I still have some 
additional questions.
   I found that currently we need to explicitly create Combine operators to 
form shared operators. If I have multiple plans, how can I send multiple plans 
into the volcano planner simultaneously? Should I wrap multiple RelRoots with 
Combine?
   Because I understand this capability is only available in the volcano 
planner and not really necessary in the Hep planner. If we're in the volcano 
planner, can we automatically add Combine operators using passThrough and 
derive capabilities? Similar to how we add Exchange or Sort operators.



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to