You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2021/04/15 04:11:08 UTC

[calcite] branch master updated (0299697 -> 296b84c)

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

jhyde pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git.


    from 0299697  [CALCITE-4570] Always validate preconditions in Filter/Correlate/Snapshot expressions when assertions are enabled
     new 31bdc5a  Copy-paste error in Mappings.multiply
     new ac45431  Typo in file_adaper.md
     new 70d59fe  [CALCITE-4511] Distinct row count and population size for constant columns should be 1
     new 66c0d13  [CALCITE-4535] ServerDdlExecutor cannot execute DROP commands with qualified object names (Vladimir Ozerov)
     new 93c3050  [CALCITE-4515] Do not generate the new join tree from commute/associate rules if there are "always TRUE" conditions (Vladimir Ozerov)
     new 760714d  [CALCITE-4579] Piglet throws ClassCastException if Pig Latin script contains FLATTEN or STRSPLIT operators (Mahesh Kumar Behera)
     new 90530a0  [CALCITE-4572] Piglet fails if Pig Latin script contains RANK or FILTER operators (Mahesh Kumar Behera)
     new 296b84c  [CALCITE-4569] In piglet, allow creating a PigConverter with custom properties (Mahesh Kumar Behera)

The 8 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.


Summary of changes:
 .../rel/metadata/RelMdDistinctRowCount.java        |  15 +++
 .../calcite/rel/metadata/RelMdPopulationSize.java  |  15 +++
 .../calcite/rel/rules/JoinAssociateRule.java       |  44 +++++--
 .../apache/calcite/rel/rules/JoinCommuteRule.java  |  19 ++-
 .../main/java/org/apache/calcite/rex/RexUtil.java  |  23 ++++
 .../apache/calcite/util/mapping/MappingType.java   |   2 +-
 .../org/apache/calcite/util/mapping/Mappings.java  |   4 +-
 .../org/apache/calcite/test/RelMetadataTest.java   |  41 ++++++
 .../org/apache/calcite/test/RelOptRulesTest.java   | 138 +++++++++++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    |  67 +++++++++-
 .../org/apache/calcite/piglet/PigConverter.java    |  18 ++-
 .../calcite/piglet/PigRelOpInnerVisitor.java       |  18 ++-
 .../org/apache/calcite/piglet/PigRelOpVisitor.java |   4 +-
 .../java/org/apache/calcite/test/PigRelOpTest.java |  48 ++++++-
 .../apache/calcite/server/ServerDdlExecutor.java   |  73 +++++------
 .../java/org/apache/calcite/test/ServerTest.java   |  23 ++++
 site/_docs/file_adapter.md                         |   4 +-
 17 files changed, 478 insertions(+), 78 deletions(-)

[calcite] 04/08: [CALCITE-4535] ServerDdlExecutor cannot execute DROP commands with qualified object names (Vladimir Ozerov)

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

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 66c0d13a6b2fd4c04f049aace71a64d3d378b0dc
Author: devozerov <pp...@gmail.com>
AuthorDate: Sun Mar 14 11:02:59 2021 +0300

    [CALCITE-4535] ServerDdlExecutor cannot execute DROP commands with qualified object names (Vladimir Ozerov)
    
    Close apache/calcite#2371
---
 .../apache/calcite/server/ServerDdlExecutor.java   | 73 ++++++++++------------
 .../java/org/apache/calcite/test/ServerTest.java   | 23 +++++++
 2 files changed, 55 insertions(+), 41 deletions(-)

diff --git a/server/src/main/java/org/apache/calcite/server/ServerDdlExecutor.java b/server/src/main/java/org/apache/calcite/server/ServerDdlExecutor.java
index fd636d9..51c5b5f 100644
--- a/server/src/main/java/org/apache/calcite/server/ServerDdlExecutor.java
+++ b/server/src/main/java/org/apache/calcite/server/ServerDdlExecutor.java
@@ -47,6 +47,7 @@ import org.apache.calcite.schema.impl.ViewTableMacro;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlDataTypeSpec;
 import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
@@ -62,7 +63,6 @@ import org.apache.calcite.sql.ddl.SqlCreateSchema;
 import org.apache.calcite.sql.ddl.SqlCreateTable;
 import org.apache.calcite.sql.ddl.SqlCreateType;
 import org.apache.calcite.sql.ddl.SqlCreateView;
-import org.apache.calcite.sql.ddl.SqlDropMaterializedView;
 import org.apache.calcite.sql.ddl.SqlDropObject;
 import org.apache.calcite.sql.ddl.SqlDropSchema;
 import org.apache.calcite.sql.dialect.CalciteSqlDialect;
@@ -281,41 +281,54 @@ public class ServerDdlExecutor extends DdlExecutorImpl {
    * {@code DROP VIEW} commands. */
   public void execute(SqlDropObject drop,
       CalcitePrepare.Context context) {
-    final List<String> path = context.getDefaultSchemaPath();
-    CalciteSchema schema = context.getRootSchema();
-    for (String p : path) {
-      schema = schema.getSubSchema(p, true);
-    }
-    final boolean existed;
+    final Pair<CalciteSchema, String> pair = schema(context, false, drop.name);
+    CalciteSchema schema = pair.left;
+    String objectName = pair.right;
+    assert objectName != null;
+
+    boolean schemaExists = schema != null;
+
+    boolean existed;
     switch (drop.getKind()) {
     case DROP_TABLE:
     case DROP_MATERIALIZED_VIEW:
-      existed = schema.removeTable(drop.name.getSimple());
-      if (!existed && !drop.ifExists) {
+      Table materializedView = schemaExists && drop.getKind() == SqlKind.DROP_MATERIALIZED_VIEW
+          ? schema.plus().getTable(objectName) : null;
+
+      existed = schemaExists && schema.removeTable(objectName);
+      if (existed) {
+        if (materializedView instanceof Wrapper) {
+          ((Wrapper) materializedView).maybeUnwrap(MaterializationKey.class)
+              .ifPresent(materializationKey -> {
+                MaterializationService.instance()
+                    .removeMaterialization(materializationKey);
+              });
+        }
+      } else if (!drop.ifExists) {
         throw SqlUtil.newContextException(drop.name.getParserPosition(),
-            RESOURCE.tableNotFound(drop.name.getSimple()));
+            RESOURCE.tableNotFound(objectName));
       }
       break;
     case DROP_VIEW:
       // Not quite right: removes any other functions with the same name
-      existed = schema.removeFunction(drop.name.getSimple());
+      existed = schemaExists && schema.removeFunction(objectName);
       if (!existed && !drop.ifExists) {
         throw SqlUtil.newContextException(drop.name.getParserPosition(),
-            RESOURCE.viewNotFound(drop.name.getSimple()));
+            RESOURCE.viewNotFound(objectName));
       }
       break;
     case DROP_TYPE:
-      existed = schema.removeType(drop.name.getSimple());
+      existed = schemaExists && schema.removeType(objectName);
       if (!existed && !drop.ifExists) {
         throw SqlUtil.newContextException(drop.name.getParserPosition(),
-            RESOURCE.typeNotFound(drop.name.getSimple()));
+            RESOURCE.typeNotFound(objectName));
       }
       break;
     case DROP_FUNCTION:
-      existed = schema.removeFunction(drop.name.getSimple());
+      existed = schemaExists && schema.removeFunction(objectName);
       if (!existed && !drop.ifExists) {
         throw SqlUtil.newContextException(drop.name.getParserPosition(),
-            RESOURCE.functionNotFound(drop.name.getSimple()));
+            RESOURCE.functionNotFound(objectName));
       }
       break;
     case OTHER_DDL:
@@ -356,24 +369,6 @@ public class ServerDdlExecutor extends DdlExecutorImpl {
             sql, schemaPath, pair.right, true, true);
   }
 
-  /** Executes a {@code DROP MATERIALIZED VIEW} command. */
-  public void execute(SqlDropMaterializedView drop,
-      CalcitePrepare.Context context) {
-    final Pair<CalciteSchema, String> pair = schema(context, true, drop.name);
-    final Table table = pair.left.plus().getTable(pair.right);
-    if (table != null) {
-      // Materialized view exists.
-      execute((SqlDropObject) drop, context);
-      if (table instanceof Wrapper) {
-        ((Wrapper) table).maybeUnwrap(MaterializationKey.class)
-            .ifPresent(materializationKey -> {
-              MaterializationService.instance()
-                  .removeMaterialization(materializationKey);
-            });
-      }
-    }
-  }
-
   /** Executes a {@code CREATE SCHEMA} command. */
   public void execute(SqlCreateSchema create,
       CalcitePrepare.Context context) {
@@ -395,15 +390,11 @@ public class ServerDdlExecutor extends DdlExecutorImpl {
   /** Executes a {@code DROP SCHEMA} command. */
   public void execute(SqlDropSchema drop,
       CalcitePrepare.Context context) {
-    final List<String> path = context.getDefaultSchemaPath();
-    CalciteSchema schema = context.getRootSchema();
-    for (String p : path) {
-      schema = schema.getSubSchema(p, true);
-    }
-    final boolean existed = schema.removeSubSchema(drop.name.getSimple());
+    final Pair<CalciteSchema, String> pair = schema(context, false, drop.name);
+    final boolean existed = pair.left != null && pair.left.removeSubSchema(pair.right);
     if (!existed && !drop.ifExists) {
       throw SqlUtil.newContextException(drop.name.getParserPosition(),
-          RESOURCE.schemaNotFound(drop.name.getSimple()));
+          RESOURCE.schemaNotFound(pair.right));
     }
   }
 
diff --git a/server/src/test/java/org/apache/calcite/test/ServerTest.java b/server/src/test/java/org/apache/calcite/test/ServerTest.java
index 559e949..43fa8c9 100644
--- a/server/src/test/java/org/apache/calcite/test/ServerTest.java
+++ b/server/src/test/java/org/apache/calcite/test/ServerTest.java
@@ -57,6 +57,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
@@ -532,4 +533,26 @@ class ServerTest {
       }
     }
   }
+
+  @Test public void testDropWithFullyQualifiedNameWhenSchemaDoesntExist() throws Exception {
+    try (Connection c = connect();
+         Statement s = c.createStatement()) {
+      checkDropWithFullyQualifiedNameWhenSchemaDoesntExist(s, "schema", "Schema");
+      checkDropWithFullyQualifiedNameWhenSchemaDoesntExist(s, "table", "Table");
+      checkDropWithFullyQualifiedNameWhenSchemaDoesntExist(s, "materialized view", "Table");
+      checkDropWithFullyQualifiedNameWhenSchemaDoesntExist(s, "view", "View");
+      checkDropWithFullyQualifiedNameWhenSchemaDoesntExist(s, "type", "Type");
+      checkDropWithFullyQualifiedNameWhenSchemaDoesntExist(s, "function", "Function");
+    }
+  }
+
+  private void checkDropWithFullyQualifiedNameWhenSchemaDoesntExist(
+      Statement statement, String objectType, String objectTypeInErrorMessage) throws Exception {
+    SQLException e = assertThrows(SQLException.class, () ->
+        statement.execute("drop " + objectType + " s.o"),
+        "expected error because the object doesn't exist");
+    assertThat(e.getMessage(), containsString(objectTypeInErrorMessage + " 'O' not found"));
+
+    statement.execute("drop " + objectType + " if exists s.o");
+  }
 }

[calcite] 08/08: [CALCITE-4569] In piglet, allow creating a PigConverter with custom properties (Mahesh Kumar Behera)

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

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 296b84cad4406be03f2db35ce6077ad8fed4fef6
Author: Mahesh Kumar Behera <ma...@apache.org>
AuthorDate: Fri Apr 9 18:03:04 2021 +0530

    [CALCITE-4569] In piglet, allow creating a PigConverter with custom properties (Mahesh Kumar Behera)
    
    Close apache/calcite#2391
---
 .../java/org/apache/calcite/piglet/PigConverter.java   | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/piglet/src/main/java/org/apache/calcite/piglet/PigConverter.java b/piglet/src/main/java/org/apache/calcite/piglet/PigConverter.java
index fdcc092..6219c96 100644
--- a/piglet/src/main/java/org/apache/calcite/piglet/PigConverter.java
+++ b/piglet/src/main/java/org/apache/calcite/piglet/PigConverter.java
@@ -40,6 +40,7 @@ import org.apache.calcite.tools.RuleSets;
 import org.apache.pig.ExecType;
 import org.apache.pig.PigServer;
 import org.apache.pig.impl.logicalLayer.FrontendException;
+import org.apache.pig.impl.util.PropertiesUtil;
 import org.apache.pig.newplan.logical.relational.LogicalPlan;
 
 import com.google.common.collect.ImmutableList;
@@ -49,6 +50,7 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 
 /**
  * Extension from PigServer to convert Pig scripts into logical relational
@@ -98,14 +100,22 @@ public class PigConverter extends PigServer {
 
   private final PigRelBuilder builder;
 
-  private PigConverter(FrameworkConfig config, ExecType execType)
-      throws Exception {
-    super(execType);
+  /** Private constructor. */
+  private PigConverter(FrameworkConfig config, ExecType execType,
+      Properties properties) throws Exception {
+    super(execType, properties);
     this.builder = PigRelBuilder.create(config);
   }
 
+  /** Creates a PigConverter using the given property settings. */
+  public static PigConverter create(FrameworkConfig config,
+      Properties properties) throws Exception {
+    return new PigConverter(config, ExecType.LOCAL, properties);
+  }
+
+  /** Creates a PigConverter using default property settings. */
   public static PigConverter create(FrameworkConfig config) throws Exception {
-    return new PigConverter(config, ExecType.LOCAL);
+    return create(config, PropertiesUtil.loadDefaultProperties());
   }
 
   public PigRelBuilder getBuilder() {

[calcite] 01/08: Copy-paste error in Mappings.multiply

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

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 31bdc5a7c4b66a37162511045215ebb27dc95712
Author: Viliam Durina <vi...@users.noreply.github.com>
AuthorDate: Fri Mar 26 16:49:53 2021 +0100

    Copy-paste error in Mappings.multiply
    
    Close apache/calcite#2383
---
 core/src/main/java/org/apache/calcite/util/mapping/MappingType.java | 2 +-
 core/src/main/java/org/apache/calcite/util/mapping/Mappings.java    | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/util/mapping/MappingType.java b/core/src/main/java/org/apache/calcite/util/mapping/MappingType.java
index 010f547..3235192 100644
--- a/core/src/main/java/org/apache/calcite/util/mapping/MappingType.java
+++ b/core/src/main/java/org/apache/calcite/util/mapping/MappingType.java
@@ -19,7 +19,7 @@ package org.apache.calcite.util.mapping;
 /**
  * Describes the type of a mapping, from the most general
  * {@link #MULTI_FUNCTION} (every element in the source and target domain can
- * participate in many mappings) to the most retricted {@link #BIJECTION} (every
+ * participate in many mappings) to the most restricted {@link #BIJECTION} (every
  * element in the source and target domain must be paired with precisely one
  * element in the other domain).
  *
diff --git a/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java b/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java
index a218e95..ebad6bb 100644
--- a/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java
+++ b/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java
@@ -145,8 +145,8 @@ public abstract class Mappings {
   /**
    * Multiplies one mapping by another.
    *
-   * <p>{@code divide(A, B)} returns a mapping C such that B . C (the mapping
-   * B followed by the mapping C) is equivalent to A.
+   * <p>{@code multiply(A, B)} returns a mapping C such that A . B (the mapping
+   * A followed by the mapping B) is equivalent to C.
    *
    * @param mapping1 First mapping
    * @param mapping2 Second mapping

[calcite] 03/08: [CALCITE-4511] Distinct row count and population size for constant columns should be 1

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

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 70d59fedfdb9fc956f3b1d1764833cbded7ae44d
Author: liyafan82 <fa...@foxmail.com>
AuthorDate: Tue Feb 23 13:52:16 2021 +0800

    [CALCITE-4511] Distinct row count and population size for constant columns should be 1
    
    Close apache/calcite#2355
---
 .../rel/metadata/RelMdDistinctRowCount.java        | 15 ++++++++
 .../calcite/rel/metadata/RelMdPopulationSize.java  | 15 ++++++++
 .../main/java/org/apache/calcite/rex/RexUtil.java  | 23 ++++++++++++
 .../org/apache/calcite/test/RelMetadataTest.java   | 41 ++++++++++++++++++++++
 4 files changed, 94 insertions(+)

diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
index 9596342..a8b42cf 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
@@ -227,6 +227,21 @@ public class RelMdDistinctRowCount
         return 1D;
       }
     }
+
+    // try to remove const columns from the group keys, as they do not
+    // affect the distinct row count
+    ImmutableBitSet nonConstCols = RexUtil.getNonConstColumns(groupKey, rel.getProjects());
+    if (nonConstCols.cardinality() == 0) {
+      // all columns are constants, the distinct row count should be 1
+      return 1D;
+    }
+
+    if (nonConstCols.cardinality() < groupKey.cardinality()) {
+      // some const columns can be removed, call the method recursively
+      // with the trimmed columns
+      return getDistinctRowCount(rel, mq, nonConstCols, predicate);
+    }
+
     ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder();
     ImmutableBitSet.Builder projCols = ImmutableBitSet.builder();
     List<RexNode> projExprs = rel.getProjects();
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
index ca39cc8..7c34639 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
@@ -27,6 +27,7 @@ import org.apache.calcite.rel.core.TableModify;
 import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ImmutableBitSet;
 
@@ -107,6 +108,20 @@ public class RelMdPopulationSize
 
   public @Nullable Double getPopulationSize(Project rel, RelMetadataQuery mq,
       ImmutableBitSet groupKey) {
+    // try to remove const columns from the group keys, as they do not
+    // affect the population size
+    ImmutableBitSet nonConstCols = RexUtil.getNonConstColumns(groupKey, rel.getProjects());
+    if (nonConstCols.cardinality() == 0) {
+      // all columns are constants, the population size should be 1
+      return 1D;
+    }
+
+    if (nonConstCols.cardinality() < groupKey.cardinality()) {
+      // some const columns can be removed, call the method recursively
+      // with the trimmed columns
+      return getPopulationSize(rel, mq, nonConstCols);
+    }
+
     ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder();
     ImmutableBitSet.Builder projCols = ImmutableBitSet.builder();
     List<RexNode> projExprs = rel.getProjects();
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index cfe0a8f..4870a82 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -40,6 +40,7 @@ import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.util.ControlFlowException;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.RangeSets;
@@ -2332,6 +2333,28 @@ public class RexUtil {
     return occurrences;
   }
 
+  /**
+   * Given some expressions, gets the indices of the non-constant ones.
+   */
+  public static ImmutableBitSet getNonConstColumns(List<RexNode> expressions) {
+    ImmutableBitSet cols = ImmutableBitSet.range(0, expressions.size());
+    return getNonConstColumns(cols, expressions);
+  }
+
+  /**
+   * Given some expressions and columns, gets the indices of the non-constant ones.
+   */
+  public static ImmutableBitSet getNonConstColumns(
+      ImmutableBitSet columns, List<RexNode> expressions) {
+    ImmutableBitSet.Builder nonConstCols = ImmutableBitSet.builder();
+    for (int col : columns) {
+      if (!isLiteral(expressions.get(col), true)) {
+        nonConstCols.set(col);
+      }
+    }
+    return nonConstCols.build();
+  }
+
   //~ Inner Classes ----------------------------------------------------------
 
   /**
diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
index 7d84dbb..55b2217 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -92,6 +92,7 @@ import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexTableInputRef;
 import org.apache.calcite.rex.RexTableInputRef.RelTableRef;
+import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.runtime.SqlFunctions;
 import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.sql.SqlKind;
@@ -3240,6 +3241,46 @@ public class RelMetadataTest extends SqlToRelTestBase {
     checkNodeTypeCount(sql, expected);
   }
 
+  @Test void testConstColumnsNdv() {
+    final String sql = "select ename, 100, 200 from emp";
+    final RelNode rel = convertSql(sql);
+    RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
+
+    assertThat(rel, instanceOf(Project.class));
+
+    Project project = (Project) rel;
+    assertThat(project.getProjects().size(), is(3));
+
+    // a non-const column, followed by two constant columns.
+    assertThat(RexUtil.isLiteral(project.getProjects().get(0), true), is(false));
+    assertThat(RexUtil.isLiteral(project.getProjects().get(1), true), is(true));
+    assertThat(RexUtil.isLiteral(project.getProjects().get(2), true), is(true));
+
+    // the distinct row count of const columns should be 1
+    assertThat(mq.getDistinctRowCount(rel, ImmutableBitSet.of(), null), is(1.0));
+    assertThat(mq.getDistinctRowCount(rel, ImmutableBitSet.of(1), null), is(1.0));
+    assertThat(mq.getDistinctRowCount(rel, ImmutableBitSet.of(1, 2), null), is(1.0));
+
+    // the population size of const columns should be 1
+    assertThat(mq.getPopulationSize(rel, ImmutableBitSet.of()), is(1.0));
+    assertThat(mq.getPopulationSize(rel, ImmutableBitSet.of(1)), is(1.0));
+    assertThat(mq.getPopulationSize(rel, ImmutableBitSet.of(1, 2)), is(1.0));
+
+    // the distinct row count of mixed columns depends on the distinct row
+    // count of non-const columns
+    assertThat(mq.getDistinctRowCount(rel, ImmutableBitSet.of(0, 1), null),
+        is(mq.getDistinctRowCount(rel, ImmutableBitSet.of(0), null)));
+    assertThat(mq.getDistinctRowCount(rel, ImmutableBitSet.of(0, 1, 2), null),
+        is(mq.getDistinctRowCount(rel, ImmutableBitSet.of(0), null)));
+
+    // the population size of mixed columns depends on the population size of
+    // non-const columns
+    assertThat(mq.getPopulationSize(rel, ImmutableBitSet.of(0, 1)),
+        is(mq.getPopulationSize(rel, ImmutableBitSet.of(0))));
+    assertThat(mq.getPopulationSize(rel, ImmutableBitSet.of(0, 1, 2)),
+        is(mq.getPopulationSize(rel, ImmutableBitSet.of(0))));
+  }
+
   private static final SqlOperator NONDETERMINISTIC_OP = new SqlSpecialOperator(
           "NDC",
           SqlKind.OTHER_FUNCTION,

[calcite] 07/08: [CALCITE-4572] Piglet fails if Pig Latin script contains RANK or FILTER operators (Mahesh Kumar Behera)

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

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 90530a0a0571513d5358a0dd16197390f492633d
Author: Mahesh Kumar Behera <ma...@apache.org>
AuthorDate: Sat Apr 10 11:03:00 2021 +0530

    [CALCITE-4572] Piglet fails if Pig Latin script contains RANK or FILTER operators (Mahesh Kumar Behera)
    
    Close apache/calcite#2394
---
 .../org/apache/calcite/piglet/PigRelOpVisitor.java |  4 +--
 .../java/org/apache/calcite/test/PigRelOpTest.java | 34 ++++++++++++++++++----
 2 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpVisitor.java b/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpVisitor.java
index ecbb81a..7d0dc71 100644
--- a/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpVisitor.java
+++ b/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpVisitor.java
@@ -84,8 +84,6 @@ import java.util.Set;
  * algebra plans.
  */
 class PigRelOpVisitor extends PigRelOpWalker.PlanPreVisitor {
-  private static final String RANK_PREFIX = "rank_";
-
   // The relational algebra builder customized for Pig
   protected final PigRelBuilder builder;
   private Operator currentRoot;
@@ -648,7 +646,7 @@ class PigRelOpVisitor extends PigRelOpWalker.PlanPreVisitor {
     List<String> fieldNames = new ArrayList<>();
 
     projectedFields.add(rankField);
-    fieldNames.add(RANK_PREFIX + loRank.getAlias()); // alias of the rank field
+    fieldNames.add(loRank.getSchema().getField(0).alias); // alias of the rank field
     for (int i = 0; i < inputRowType.getFieldCount(); i++) {
       projectedFields.add(builder.field(i));
       fieldNames.add(inputRowType.getFieldNames().get(i));
diff --git a/piglet/src/test/java/org/apache/calcite/test/PigRelOpTest.java b/piglet/src/test/java/org/apache/calcite/test/PigRelOpTest.java
index de14526..959949d 100644
--- a/piglet/src/test/java/org/apache/calcite/test/PigRelOpTest.java
+++ b/piglet/src/test/java/org/apache/calcite/test/PigRelOpTest.java
@@ -1142,7 +1142,7 @@ class PigRelOpTest extends PigRelTestBase {
         + "  LogicalProject(EMPNO=[$0], JOB=[$2], DEPTNO=[$7])\n"
         + "    LogicalTableScan(table=[[scott, EMP]])\n";
     final String optimizedPlan = ""
-        + "LogicalProject(rank_C=[$3], EMPNO=[$0], JOB=[$1], DEPTNO=[$2])\n"
+        + "LogicalProject(rank_B=[$3], EMPNO=[$0], JOB=[$1], DEPTNO=[$2])\n"
         + "  LogicalWindow(window#0=[window(order by [2, 1 DESC] "
         + "aggs [RANK()])])\n"
         + "    LogicalProject(EMPNO=[$0], JOB=[$2], DEPTNO=[$7])\n"
@@ -1150,7 +1150,7 @@ class PigRelOpTest extends PigRelTestBase {
 
     final String script = base + "C = RANK B BY DEPTNO ASC, JOB DESC;\n";
     final String plan = ""
-        + "LogicalProject(rank_C=[RANK() OVER (ORDER BY $2, $1 DESC)], "
+        + "LogicalProject(rank_B=[RANK() OVER (ORDER BY $2, $1 DESC)], "
         + "EMPNO=[$0], JOB=[$1], DEPTNO=[$2])\n"
         + basePlan;
     final String result = ""
@@ -1170,7 +1170,7 @@ class PigRelOpTest extends PigRelTestBase {
         + "(14,7900,CLERK,30)\n";
     final String sql = ""
         + "SELECT RANK() OVER (ORDER BY DEPTNO, JOB DESC RANGE BETWEEN "
-        + "UNBOUNDED PRECEDING AND CURRENT ROW) AS rank_C, EMPNO, JOB, DEPTNO\n"
+        + "UNBOUNDED PRECEDING AND CURRENT ROW) AS rank_B, EMPNO, JOB, DEPTNO\n"
         + "FROM scott.EMP";
     pig(script).assertRel(hasTree(plan))
         .assertOptimizedRel(hasTree(optimizedPlan))
@@ -1179,14 +1179,14 @@ class PigRelOpTest extends PigRelTestBase {
 
     final String script2 = base + "C = RANK B BY DEPTNO ASC, JOB DESC DENSE;\n";
     final String optimizedPlan2 = ""
-        + "LogicalProject(rank_C=[$3], EMPNO=[$0], JOB=[$1], DEPTNO=[$2])\n"
+        + "LogicalProject(rank_B=[$3], EMPNO=[$0], JOB=[$1], DEPTNO=[$2])\n"
         + "  LogicalWindow(window#0=[window(order by [2, 1 DESC] "
         + "aggs [DENSE_RANK()])"
         + "])\n"
         + "    LogicalProject(EMPNO=[$0], JOB=[$2], DEPTNO=[$7])\n"
         + "      LogicalTableScan(table=[[scott, EMP]])\n";
     final String plan2 = ""
-        + "LogicalProject(rank_C=[DENSE_RANK() OVER (ORDER BY $2, $1 DESC)], "
+        + "LogicalProject(rank_B=[DENSE_RANK() OVER (ORDER BY $2, $1 DESC)], "
         + "EMPNO=[$0], JOB=[$1], DEPTNO=[$2])\n"
         + basePlan;
     final String result2 = ""
@@ -1206,7 +1206,7 @@ class PigRelOpTest extends PigRelTestBase {
         + "(9,7900,CLERK,30)\n";
     final String sql2 = ""
         + "SELECT DENSE_RANK() OVER (ORDER BY DEPTNO, JOB DESC RANGE BETWEEN "
-        + "UNBOUNDED PRECEDING AND CURRENT ROW) AS rank_C, EMPNO, JOB, DEPTNO\n"
+        + "UNBOUNDED PRECEDING AND CURRENT ROW) AS rank_B, EMPNO, JOB, DEPTNO\n"
         + "FROM scott.EMP";
     pig(script2).assertRel(hasTree(plan2))
         .assertOptimizedRel(hasTree(optimizedPlan2))
@@ -1621,4 +1621,26 @@ class PigRelOpTest extends PigRelTestBase {
     pig(script).assertRel(hasTree(plan))
         .assertSql(is(sql));
   }
+
+  @Test void testRankAndFilter() {
+    final String script = ""
+        + "A = LOAD 'emp1' USING PigStorage(',')  as ("
+        + "    id:int, name:chararray, age:int, city:chararray);\n"
+        + "B = rank A;\n"
+        + "C = FILTER B by ($0 > 1);";
+
+    final String plan = ""
+        + "LogicalFilter(condition=[>($0, 1)])\n"
+        + "  LogicalProject(rank_A=[RANK() OVER ()], id=[$0],"
+        + " name=[$1], age=[$2], city=[$3])\n"
+        + "    LogicalTableScan(table=[[emp1]])\n";
+
+    final String sql = "SELECT w0$o0 AS rank_A, id, name, age, city\n"
+        + "FROM (SELECT id, name, age, city, RANK() OVER (RANGE BETWEEN "
+        + "UNBOUNDED PRECEDING AND CURRENT ROW)\n"
+        + "    FROM emp1) AS t\n"
+        + "WHERE w0$o0 > 1";
+    pig(script).assertRel(hasTree(plan))
+        .assertSql(is(sql));
+  }
 }

[calcite] 06/08: [CALCITE-4579] Piglet throws ClassCastException if Pig Latin script contains FLATTEN or STRSPLIT operators (Mahesh Kumar Behera)

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

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 760714d9ed4a1323d59b4bb2bf2887f030500019
Author: Mahesh Kumar Behera <ma...@apache.org>
AuthorDate: Mon Apr 12 07:47:22 2021 +0530

    [CALCITE-4579] Piglet throws ClassCastException if Pig Latin script contains FLATTEN or STRSPLIT operators (Mahesh Kumar Behera)
    
    Close apache/calcite#2396
---
 .../apache/calcite/piglet/PigRelOpInnerVisitor.java    | 18 ++++++++++++++----
 .../java/org/apache/calcite/test/PigRelOpTest.java     | 14 ++++++++++++++
 2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpInnerVisitor.java b/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpInnerVisitor.java
index 5d62668..727a187 100644
--- a/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpInnerVisitor.java
+++ b/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpInnerVisitor.java
@@ -23,6 +23,7 @@ import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.logical.LogicalValues;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.MultisetSqlType;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
@@ -172,10 +173,19 @@ class PigRelOpInnerVisitor extends PigRelOpVisitor {
               && (dataType.getFieldCount() > 0 || dataType instanceof DynamicTupleRecordType)) {
         if (dataType instanceof DynamicTupleRecordType) {
           ((DynamicTupleRecordType) dataType).resize(outputFieldSchema.size());
-        }
-        for (int j = 0; j < dataType.getFieldCount(); j++) {
-          innerCols.add(builder.dot(rexNode, j));
-          fieldAlias.add(outputFieldSchema.getField(j).alias);
+          for (int j = 0; j < outputFieldSchema.size(); j++) {
+            final RelDataType scriptType = PigTypes.convertSchemaField(
+                outputFieldSchema.getField(j));
+            RexNode exp = builder.call(
+                SqlStdOperatorTable.ITEM, rexNode, builder.literal(j + 1));
+            innerCols.add(builder.getRexBuilder().makeCast(scriptType, exp));
+            fieldAlias.add(outputFieldSchema.getField(j).alias);
+          }
+        } else {
+          for (int j = 0; j < dataType.getFieldCount(); j++) {
+            innerCols.add(builder.dot(rexNode, j));
+            fieldAlias.add(outputFieldSchema.getField(j).alias);
+          }
         }
       } else {
         innerCols.add(rexNode);
diff --git a/piglet/src/test/java/org/apache/calcite/test/PigRelOpTest.java b/piglet/src/test/java/org/apache/calcite/test/PigRelOpTest.java
index 5c1a5b2..de14526 100644
--- a/piglet/src/test/java/org/apache/calcite/test/PigRelOpTest.java
+++ b/piglet/src/test/java/org/apache/calcite/test/PigRelOpTest.java
@@ -1607,4 +1607,18 @@ class PigRelOpTest extends PigRelTestBase {
         .assertResult(is(result))
         .assertSql(is(sql));
   }
+
+  @Test void testFlattenStrSplit() {
+    final String script = ""
+        + "A = LOAD 'scott.DEPT' as (DEPTNO:int, DNAME:chararray, LOC:CHARARRAY);\n"
+        + "B = FOREACH A GENERATE FLATTEN(STRSPLIT(DNAME, ',')) as NAMES;\n";
+    final String plan = ""
+        + "LogicalProject(NAMES=[CAST(ITEM(STRSPLIT(PIG_TUPLE($1, ',')), 1)):BINARY(1)])\n"
+        + "  LogicalTableScan(table=[[scott, DEPT]])\n";
+    final String sql = ""
+        + "SELECT CAST(STRSPLIT(PIG_TUPLE(DNAME, ','))[1] AS BINARY(1)) AS NAMES\n"
+        + "FROM scott.DEPT";
+    pig(script).assertRel(hasTree(plan))
+        .assertSql(is(sql));
+  }
 }

[calcite] 05/08: [CALCITE-4515] Do not generate the new join tree from commute/associate rules if there are "always TRUE" conditions (Vladimir Ozerov)

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

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 93c305031fb6c152c118390647f2b9b0979109c2
Author: devozerov <pp...@gmail.com>
AuthorDate: Fri Feb 26 14:38:30 2021 +0300

    [CALCITE-4515] Do not generate the new join tree from commute/associate rules if there are "always TRUE" conditions (Vladimir Ozerov)
---
 .../calcite/rel/rules/JoinAssociateRule.java       |  44 +++++--
 .../apache/calcite/rel/rules/JoinCommuteRule.java  |  19 ++-
 .../org/apache/calcite/test/RelOptRulesTest.java   | 138 +++++++++++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    |  67 +++++++++-
 4 files changed, 253 insertions(+), 15 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
index a4eb516..d65dfa3 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
@@ -19,7 +19,6 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelRule;
-import org.apache.calcite.plan.volcano.RelSubset;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinRelType;
@@ -28,6 +27,7 @@ import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexPermuteInputsShuttle;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.tools.RelBuilderFactory;
+import org.apache.calcite.util.ImmutableBeans;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.mapping.Mappings;
 
@@ -68,7 +68,7 @@ public class JoinAssociateRule
     final Join bottomJoin = call.rel(1);
     final RelNode relA = bottomJoin.getLeft();
     final RelNode relB = bottomJoin.getRight();
-    final RelSubset relC = call.rel(2);
+    final RelNode relC = call.rel(2);
     final RelOptCluster cluster = topJoin.getCluster();
     final RexBuilder rexBuilder = cluster.getRexBuilder();
 
@@ -120,6 +120,11 @@ public class JoinAssociateRule
     JoinPushThroughJoinRule.split(bottomJoin.getCondition(), aBitSet, top,
         bottom);
 
+    final boolean allowAlwaysTrueCondition = config.isAllowAlwaysTrueCondition();
+    if (!allowAlwaysTrueCondition && (top.isEmpty() || bottom.isEmpty())) {
+      return;
+    }
+
     // Mapping for moving conditions from topJoin or bottomJoin to
     // newBottomJoin.
     // target: | B | C      |
@@ -132,16 +137,23 @@ public class JoinAssociateRule
     final List<RexNode> newBottomList =
         new RexPermuteInputsShuttle(bottomMapping, relB, relC)
             .visitList(bottom);
-    RexNode newBottomCondition =
-        RexUtil.composeConjunction(rexBuilder, newBottomList);
 
-    final Join newBottomJoin =
-        bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relB,
-            relC, JoinRelType.INNER, false);
+    RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList);
+    if (!allowAlwaysTrueCondition && newBottomCondition.isAlwaysTrue()) {
+      return;
+    }
 
     // Condition for newTopJoin consists of pieces from bottomJoin and topJoin.
     // Field ordinals do not need to be changed.
     RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, top);
+    if (!allowAlwaysTrueCondition && newTopCondition.isAlwaysTrue()) {
+      return;
+    }
+
+    final Join newBottomJoin =
+        bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relB,
+            relC, JoinRelType.INNER, false);
+
     @SuppressWarnings("SuspiciousNameCombination")
     final Join newTopJoin =
         topJoin.copy(topJoin.getTraitSet(), newTopCondition, relA,
@@ -153,19 +165,29 @@ public class JoinAssociateRule
   /** Rule configuration. */
   public interface Config extends RelRule.Config {
     Config DEFAULT = EMPTY.as(Config.class)
-        .withOperandFor(Join.class, RelSubset.class);
+        .withOperandFor(Join.class);
 
     @Override default JoinAssociateRule toRule() {
       return new JoinAssociateRule(this);
     }
 
+    /**
+     * Whether to emit the new join tree if the new top or bottom join has a condition which
+     * is always {@code TRUE}.
+     */
+    @ImmutableBeans.Property
+    @ImmutableBeans.BooleanDefault(true)
+    boolean isAllowAlwaysTrueCondition();
+
+    /** Sets {@link #isAllowAlwaysTrueCondition()}. */
+    Config withAllowAlwaysTrueCondition(boolean allowAlwaysTrueCondition);
+
     /** Defines an operand tree for the given classes. */
-    default Config withOperandFor(Class<? extends Join> joinClass,
-        Class<? extends RelSubset> relSubsetClass) {
+    default Config withOperandFor(Class<? extends Join> joinClass) {
       return withOperandSupplier(b0 ->
           b0.operand(joinClass).inputs(
               b1 -> b1.operand(joinClass).anyInputs(),
-              b2 -> b2.operand(relSubsetClass).anyInputs()))
+              b2 -> b2.operand(RelNode.class).anyInputs()))
           .as(Config.class);
     }
   }
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
index ee4752e..c38be27 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
@@ -139,7 +139,13 @@ public class JoinCommuteRule
   @Override public boolean matches(RelOptRuleCall call) {
     Join join = call.rel(0);
     // SEMI and ANTI join cannot be swapped.
-    return join.getJoinType().projectsRight();
+    if (!join.getJoinType().projectsRight()) {
+      return false;
+    }
+
+    // Suppress join with "true" condition (that is, cartesian joins).
+    return config.isAllowAlwaysTrueCondition()
+        || !join.getCondition().isAlwaysTrue();
   }
 
   @Override public void onMatch(final RelOptRuleCall call) {
@@ -241,12 +247,21 @@ public class JoinCommuteRule
           .as(Config.class);
     }
 
-    /** Whether to swap outer joins. */
+    /** Whether to swap outer joins; default false. */
     @ImmutableBeans.Property
     @ImmutableBeans.BooleanDefault(false)
     boolean isSwapOuter();
 
     /** Sets {@link #isSwapOuter()}. */
     Config withSwapOuter(boolean swapOuter);
+
+    /** Whether to emit the new join tree if the join condition is {@code TRUE}
+     * (that is, cartesian joins); default true. */
+    @ImmutableBeans.Property
+    @ImmutableBeans.BooleanDefault(true)
+    boolean isAllowAlwaysTrueCondition();
+
+    /** Sets {@link #isAllowAlwaysTrueCondition()}. */
+    Config withAllowAlwaysTrueCondition(boolean allowAlwaysTrueCondition);
   }
 }
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 449914b..6ef31a5 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -71,6 +71,8 @@ import org.apache.calcite.rel.rules.DateRangeRules;
 import org.apache.calcite.rel.rules.FilterJoinRule;
 import org.apache.calcite.rel.rules.FilterMultiJoinMergeRule;
 import org.apache.calcite.rel.rules.FilterProjectTransposeRule;
+import org.apache.calcite.rel.rules.JoinAssociateRule;
+import org.apache.calcite.rel.rules.JoinCommuteRule;
 import org.apache.calcite.rel.rules.MultiJoin;
 import org.apache.calcite.rel.rules.ProjectCorrelateTransposeRule;
 import org.apache.calcite.rel.rules.ProjectFilterTransposeRule;
@@ -6981,4 +6983,140 @@ class RelOptRulesTest extends RelOptTestBase {
         .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS)
         .checkUnchanged();
   }
+
+  @Test void testJoinCommuteRuleWithAlwaysTrueConditionAllowed() {
+    checkJoinCommuteRuleWithAlwaysTrueConditionDisallowed(true);
+  }
+
+  @Test void testJoinCommuteRuleWithAlwaysTrueConditionDisallowed() {
+    checkJoinCommuteRuleWithAlwaysTrueConditionDisallowed(false);
+  }
+
+  private void checkJoinCommuteRuleWithAlwaysTrueConditionDisallowed(boolean allowAlwaysTrue) {
+    final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
+
+    RelNode left = relBuilder.scan("EMP").build();
+    RelNode right = relBuilder.scan("DEPT").build();
+
+    RelNode relNode = relBuilder.push(left)
+        .push(right)
+        .join(JoinRelType.INNER,
+            relBuilder.literal(true))
+        .build();
+
+    JoinCommuteRule.Config ruleConfig = JoinCommuteRule.Config.DEFAULT;
+    if (!allowAlwaysTrue) {
+      ruleConfig = ruleConfig.withAllowAlwaysTrueCondition(false);
+    }
+
+    HepProgram program = new HepProgramBuilder()
+        .addMatchLimit(1)
+        .addRuleInstance(ruleConfig.toRule())
+        .build();
+
+    HepPlanner hepPlanner = new HepPlanner(program);
+    hepPlanner.setRoot(relNode);
+    RelNode output = hepPlanner.findBestExp();
+
+    final String planAfter = NL + RelOptUtil.toString(output);
+    final DiffRepository diffRepos = getDiffRepos();
+    diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+    SqlToRelTestBase.assertValid(output);
+  }
+
+  @Test void testJoinAssociateRuleWithBottomAlwaysTrueConditionAllowed() {
+    checkJoinAssociateRuleWithBottomAlwaysTrueCondition(true);
+  }
+
+  @Test void testJoinAssociateRuleWithBottomAlwaysTrueConditionDisallowed() {
+    checkJoinAssociateRuleWithBottomAlwaysTrueCondition(false);
+  }
+
+  private void checkJoinAssociateRuleWithBottomAlwaysTrueCondition(boolean allowAlwaysTrue) {
+    final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
+
+    RelNode bottomLeft = relBuilder.scan("EMP").build();
+    RelNode bottomRight = relBuilder.scan("DEPT").build();
+    RelNode top = relBuilder.scan("BONUS").build();
+
+    RelNode relNode = relBuilder.push(bottomLeft)
+        .push(bottomRight)
+        .join(JoinRelType.INNER,
+            relBuilder.call(SqlStdOperatorTable.EQUALS,
+                relBuilder.field(2, 0, "DEPTNO"),
+                relBuilder.field(2, 1, "DEPTNO")))
+        .push(top)
+        .join(JoinRelType.INNER,
+            relBuilder.call(SqlStdOperatorTable.EQUALS,
+                relBuilder.field(2, 0, "JOB"),
+                relBuilder.field(2, 1, "JOB")))
+        .build();
+
+    JoinAssociateRule.Config ruleConfig = JoinAssociateRule.Config.DEFAULT;
+    if (!allowAlwaysTrue) {
+      ruleConfig = ruleConfig.withAllowAlwaysTrueCondition(false);
+    }
+
+    HepProgram program = new HepProgramBuilder()
+        .addMatchLimit(1)
+        .addMatchOrder(HepMatchOrder.TOP_DOWN)
+        .addRuleInstance(ruleConfig.toRule())
+        .build();
+
+    HepPlanner hepPlanner = new HepPlanner(program);
+    hepPlanner.setRoot(relNode);
+    RelNode output = hepPlanner.findBestExp();
+
+    final String planAfter = NL + RelOptUtil.toString(output);
+    final DiffRepository diffRepos = getDiffRepos();
+    diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+    SqlToRelTestBase.assertValid(output);
+  }
+
+  @Test void testJoinAssociateRuleWithTopAlwaysTrueConditionAllowed() {
+    checkJoinAssociateRuleWithTopAlwaysTrueCondition(true);
+  }
+
+  @Test void testJoinAssociateRuleWithTopAlwaysTrueConditionDisallowed() {
+    checkJoinAssociateRuleWithTopAlwaysTrueCondition(false);
+  }
+
+  private void checkJoinAssociateRuleWithTopAlwaysTrueCondition(boolean allowAlwaysTrue) {
+    final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
+
+    RelNode bottomLeft = relBuilder.scan("EMP").build();
+    RelNode bottomRight = relBuilder.scan("BONUS").build();
+    RelNode top = relBuilder.scan("DEPT").build();
+
+    RelNode relNode = relBuilder.push(bottomLeft)
+        .push(bottomRight)
+        .join(JoinRelType.INNER,
+            relBuilder.literal(true))
+        .push(top)
+        .join(JoinRelType.INNER,
+            relBuilder.call(SqlStdOperatorTable.EQUALS,
+                relBuilder.field(2, 0, "DEPTNO"),
+                relBuilder.field(2, 1, "DEPTNO")))
+        .build();
+
+    JoinAssociateRule.Config ruleConfig = JoinAssociateRule.Config.DEFAULT;
+    if (!allowAlwaysTrue) {
+      ruleConfig = ruleConfig.withAllowAlwaysTrueCondition(false);
+    }
+
+    HepProgram program = new HepProgramBuilder()
+        .addMatchLimit(1)
+        .addMatchOrder(HepMatchOrder.TOP_DOWN)
+        .addRuleInstance(ruleConfig.toRule())
+        .build();
+
+    HepPlanner hepPlanner = new HepPlanner(program);
+    hepPlanner.setRoot(relNode);
+    RelNode output = hepPlanner.findBestExp();
+
+    final String planAfter = NL + RelOptUtil.toString(output);
+    final DiffRepository diffRepos = getDiffRepos();
+    diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+    SqlToRelTestBase.assertValid(output);
+  }
 }
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 8346c92..3dc6ad2 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3718,6 +3718,69 @@ LogicalIntersect(all=[true])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testJoinAssociateRuleWithBottomAlwaysTrueConditionAllowed">
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalJoin(condition=[AND(=($2, $12), =($7, $8))], joinType=[inner])
+  LogicalTableScan(table=[[scott, EMP]])
+  LogicalJoin(condition=[true], joinType=[inner])
+    LogicalTableScan(table=[[scott, DEPT]])
+    LogicalTableScan(table=[[scott, BONUS]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testJoinAssociateRuleWithBottomAlwaysTrueConditionDisallowed">
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalJoin(condition=[=($2, $12)], joinType=[inner])
+  LogicalJoin(condition=[=($7, $8)], joinType=[inner])
+    LogicalTableScan(table=[[scott, EMP]])
+    LogicalTableScan(table=[[scott, DEPT]])
+  LogicalTableScan(table=[[scott, BONUS]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testJoinAssociateRuleWithTopAlwaysTrueConditionAllowed">
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalJoin(condition=[=($7, $12)], joinType=[inner])
+  LogicalTableScan(table=[[scott, EMP]])
+  LogicalJoin(condition=[true], joinType=[inner])
+    LogicalTableScan(table=[[scott, BONUS]])
+    LogicalTableScan(table=[[scott, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testJoinAssociateRuleWithTopAlwaysTrueConditionDisallowed">
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalJoin(condition=[=($7, $12)], joinType=[inner])
+  LogicalJoin(condition=[true], joinType=[inner])
+    LogicalTableScan(table=[[scott, EMP]])
+    LogicalTableScan(table=[[scott, BONUS]])
+  LogicalTableScan(table=[[scott, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testJoinCommuteRuleWithAlwaysTrueConditionAllowed">
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(EMPNO=[$3], ENAME=[$4], JOB=[$5], MGR=[$6], HIREDATE=[$7], SAL=[$8], COMM=[$9], DEPTNO=[$10], DEPTNO0=[$0], DNAME=[$1], LOC=[$2])
+  LogicalJoin(condition=[true], joinType=[inner])
+    LogicalTableScan(table=[[scott, DEPT]])
+    LogicalTableScan(table=[[scott, EMP]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testJoinCommuteRuleWithAlwaysTrueConditionDisallowed">
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalJoin(condition=[true], joinType=[inner])
+  LogicalTableScan(table=[[scott, EMP]])
+  LogicalTableScan(table=[[scott, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testJoinProjectTransposeWindow">
         <Resource name="sql">
             <![CDATA[select *
@@ -8227,7 +8290,7 @@ LogicalAggregate(group=[{}], EXPR$0=[SUM($0)])
     </TestCase>
     <TestCase name="testPushAggregateThroughJoin7">
         <Resource name="sql">
-            <![CDATA[select any_value(B.sal)
+            <![CDATA[select any_value(distinct B.sal)
 from sales.emp as A
 join (select distinct sal from sales.emp) as B
 on A.sal=B.sal
@@ -8255,7 +8318,7 @@ LogicalAggregate(group=[{}], EXPR$0=[ANY_VALUE($1)])
     </TestCase>
     <TestCase name="testPushAggregateThroughJoin8">
         <Resource name="sql">
-            <![CDATA[select single_value(B.sal)
+            <![CDATA[select single_value(distinct B.sal)
 from sales.emp as A
 join (select distinct sal from sales.emp) as B
 on A.sal=B.sal

[calcite] 02/08: Typo in file_adaper.md

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

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit ac454315ea81af0eed1a2a9dca3d70ac729e6b28
Author: dugenkui <du...@kuaishou.com>
AuthorDate: Fri Apr 9 21:06:40 2021 +0800

    Typo in file_adaper.md
    
    Close apache/calcite#2392
---
 site/_docs/file_adapter.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/site/_docs/file_adapter.md b/site/_docs/file_adapter.md
index c955e09..0518133 100644
--- a/site/_docs/file_adapter.md
+++ b/site/_docs/file_adapter.md
@@ -76,11 +76,11 @@ as follows.
         "name": "EMPS",
         "url": "file:file/src/test/resources/sales/EMPS.html"
       }, {
-        "name": "DEPTS"
+        "name": "DEPTS",
         "url": "file:file/src/test/resources/sales/DEPTS.html"
       } ]
     }
-  ]
+  } ]
 }
 {% endhighlight %}