zabetak commented on code in PR #2935:
URL: https://github.com/apache/calcite/pull/2935#discussion_r992121760


##########
core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java:
##########
@@ -540,4 +540,32 @@ public interface JoinRightEmptyRuleConfig extends 
PruneEmptyRule.Config {
       };
     }
   }
+
+
+  public static final RelOptRule EMPTY_TABLE =
+      ImmutableEmptyTableOptimizationConfig.of()
+          .withOperandSupplier(b0 -> {
+            return b0.operand(TableScan.class).noInputs();
+          })
+          .withDescription("ConvertEmptyTableToValues")

Review Comment:
   nit: To keep things uniform maybe rename to `"PruneZeroRowsTable"`



##########
core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java:
##########
@@ -540,4 +540,32 @@ public interface JoinRightEmptyRuleConfig extends 
PruneEmptyRule.Config {
       };
     }
   }
+
+
+  public static final RelOptRule EMPTY_TABLE =
+      ImmutableEmptyTableOptimizationConfig.of()
+          .withOperandSupplier(b0 -> {
+            return b0.operand(TableScan.class).noInputs();
+          })
+          .withDescription("ConvertEmptyTableToValues")
+          .toRule();
+
+  /** Configuration for rule that transforms an empty table into an empty 
values node.
+   * MaxRowCount is used as the stat to transform, hence Table implementer 
needs
+   * to supply this metadata if this optimization needs to be applied.*/
+  @Value.Immutable
+  public interface EmptyTableOptimizationConfig extends PruneEmptyRule.Config {
+
+    @Override default PruneEmptyRule toRule() {
+      return new PruneEmptyRule(this) {
+        @Override public void onMatch(RelOptRuleCall call) {
+          TableScan tableScan = call.rel(0);
+          Double maxRowCount = 
call.getMetadataQuery().getMaxRowCount(tableScan);
+          if (maxRowCount != null && maxRowCount == 0.0) {
+            call.transformTo(call.builder().push(tableScan).empty().build());

Review Comment:
   The effect of this rule is very similar to what `RemoveEmptySingleRule` is 
doing. The latter is also trying to conserve the traits so maybe it is a good 
idea to attemp to conserve the traits as well here.



##########
core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java:
##########
@@ -3413,6 +3413,54 @@ RelOptFixture checkDynamicFunctions(boolean 
treatDynamicCallsAsConstant) {
         .check();
   }
 
+  @Test void testEmptyTableProject() {
+    // table is transformed to empty values and extra project will be removed.
+    final String sql = "select * from EMPTY_PRODUCTS\n";
+    sql(sql)
+        .withRule(
+            PruneEmptyRules.EMPTY_TABLE,
+            PruneEmptyRules.PROJECT_INSTANCE)
+        .check();
+  }
+
+  @Test void testEmptyTableJoinLeft() {
+    // inner join is eliminated after the left table is transformed to empty 
values.
+    final String sql = "select * from EMPTY_PRODUCTS as e\n"
+        + ",products as d where e.PRODUCTID = d.PRODUCTID\n";
+    sql(sql)
+        .withRule(
+            PruneEmptyRules.EMPTY_TABLE,
+            PruneEmptyRules.JOIN_LEFT_INSTANCE)
+        .check();
+  }
+
+  @Test void testEmptyTableJoinRight() {
+    // inner join is eliminated after the right table is transformed to empty 
values.
+    final String sql = "select * from products as e\n"
+        + ",EMPTY_PRODUCTS as d where e.PRODUCTID = d.PRODUCTID\n";
+    sql(sql)
+        .withRule(
+            PruneEmptyRules.EMPTY_TABLE,
+            PruneEmptyRules.JOIN_RIGHT_INSTANCE)
+        .check();
+  }

Review Comment:
   I don't think need a test case for every possible combination of rules of 
`EMPTY_TABLE` with the others. I think we can keep just two:
   * `testEmptyTable` which just tests the new rule.
   * `testEmptyTableInComplexQuery` which exploits multiple pruning rules 
including `EMPTY_TABLE` to simplify a plan completely leaving only an empty 
`LogicalValues` at the end.



##########
core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java:
##########
@@ -540,4 +540,32 @@ public interface JoinRightEmptyRuleConfig extends 
PruneEmptyRule.Config {
       };
     }
   }
+
+
+  public static final RelOptRule EMPTY_TABLE =

Review Comment:
   I think it would be a good idea to add the new rule to 
`org.apache.calcite.plan.RelOptRules#ABSTRACT_RULES` list along with the other 
pruning rules.



##########
core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java:
##########
@@ -540,4 +540,32 @@ public interface JoinRightEmptyRuleConfig extends 
PruneEmptyRule.Config {
       };
     }
   }
+
+
+  public static final RelOptRule EMPTY_TABLE =
+      ImmutableEmptyTableOptimizationConfig.of()
+          .withOperandSupplier(b0 -> {
+            return b0.operand(TableScan.class).noInputs();
+          })
+          .withDescription("ConvertEmptyTableToValues")
+          .toRule();
+
+  /** Configuration for rule that transforms an empty table into an empty 
values node.
+   * MaxRowCount is used as the stat to transform, hence Table implementer 
needs
+   * to supply this metadata if this optimization needs to be applied.*/
+  @Value.Immutable
+  public interface EmptyTableOptimizationConfig extends PruneEmptyRule.Config {
+
+    @Override default PruneEmptyRule toRule() {
+      return new PruneEmptyRule(this) {
+        @Override public void onMatch(RelOptRuleCall call) {
+          TableScan tableScan = call.rel(0);
+          Double maxRowCount = 
call.getMetadataQuery().getMaxRowCount(tableScan);
+          if (maxRowCount != null && maxRowCount == 0.0) {

Review Comment:
   It is better to put the row count check in the `matches` method. When the 
condition is not satisfied the rule can be eliminated much earlier.



##########
testkit/src/main/java/org/apache/calcite/test/catalog/MockCatalogReader.java:
##########
@@ -618,6 +621,57 @@ public StructKind getKind() {
     }
   }
 
+  /**
+   * Mock implementation of
+   * {@link org.apache.calcite.prepare.Prepare.PreparingTable} which supplies 
MaxRow stat.
+   */
+  public static class MaxRowMockTable
+      extends MockTable implements BuiltInMetadata.MaxRowCount.Handler {

Review Comment:
   Maybe you can avoid introducing a new sub-class and make `MockTable` 
implement the `MaxRowCount.Handler` assuming that rowCount == maxRowCount at 
this point. If we need to differentiate in the future we can add or modify the 
constructors/factories in `MockTable`.



##########
core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java:
##########
@@ -469,7 +470,6 @@ public interface SortFetchZeroRuleConfig extends 
PruneEmptyRule.Config {
             call.transformTo(emptyValues);
           }
         }
-

Review Comment:
   nit: Please avoid unnecessary formatting changes.



##########
core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java:
##########
@@ -540,4 +540,32 @@ public interface JoinRightEmptyRuleConfig extends 
PruneEmptyRule.Config {
       };
     }
   }
+
+
+  public static final RelOptRule EMPTY_TABLE =
+      ImmutableEmptyTableOptimizationConfig.of()
+          .withOperandSupplier(b0 -> {
+            return b0.operand(TableScan.class).noInputs();
+          })
+          .withDescription("ConvertEmptyTableToValues")
+          .toRule();
+
+  /** Configuration for rule that transforms an empty table into an empty 
values node.
+   * MaxRowCount is used as the stat to transform, hence Table implementer 
needs
+   * to supply this metadata if this optimization needs to be applied.*/
+  @Value.Immutable
+  public interface EmptyTableOptimizationConfig extends PruneEmptyRule.Config {

Review Comment:
   A possibly better name would be `ZeroMaxRowsRuleConfig`.



##########
core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java:
##########
@@ -540,4 +540,32 @@ public interface JoinRightEmptyRuleConfig extends 
PruneEmptyRule.Config {
       };
     }
   }
+
+
+  public static final RelOptRule EMPTY_TABLE =
+      ImmutableEmptyTableOptimizationConfig.of()
+          .withOperandSupplier(b0 -> {
+            return b0.operand(TableScan.class).noInputs();
+          })

Review Comment:
   I think it can be simplified to `.withOperandSupplier(b0 -> 
b0.operand(TableScan.class).noInputs());`



##########
core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java:
##########
@@ -540,4 +540,32 @@ public interface JoinRightEmptyRuleConfig extends 
PruneEmptyRule.Config {
       };
     }
   }
+
+
+  public static final RelOptRule EMPTY_TABLE =
+      ImmutableEmptyTableOptimizationConfig.of()
+          .withOperandSupplier(b0 -> {
+            return b0.operand(TableScan.class).noInputs();
+          })
+          .withDescription("ConvertEmptyTableToValues")
+          .toRule();
+
+  /** Configuration for rule that transforms an empty table into an empty 
values node.
+   * MaxRowCount is used as the stat to transform, hence Table implementer 
needs
+   * to supply this metadata if this optimization needs to be applied.*/
+  @Value.Immutable
+  public interface EmptyTableOptimizationConfig extends PruneEmptyRule.Config {
+
+    @Override default PruneEmptyRule toRule() {
+      return new PruneEmptyRule(this) {
+        @Override public void onMatch(RelOptRuleCall call) {
+          TableScan tableScan = call.rel(0);

Review Comment:
   It is better to be more general here (use `RelNode` here instead of 
`TableScan`); the rule will still work correctly and if people want to reduce 
or enlarge the scope they can do it by changing the matching operands of the 
configuration.



##########
core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java:
##########
@@ -540,4 +540,32 @@ public interface JoinRightEmptyRuleConfig extends 
PruneEmptyRule.Config {
       };
     }
   }
+
+
+  public static final RelOptRule EMPTY_TABLE =

Review Comment:
   All other rules in this class are suffixed with `INSTANCE`. To keep things 
uniform I would suggest one of the following:
   * `EMPTY_TABLE_INSTANCE`
   * `TABLE_ZERO_ROWS_INSTANCE`
   * `ZERO_ROWS_TABLE_INSTANCE`



-- 
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: commits-unsubscr...@calcite.apache.org

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

Reply via email to