Repository: calcite
Updated Branches:
  refs/heads/master c933c79f7 -> b4df7c97b


[CALCITE-1332] JDBC adapter for DB2 should always use aliases for tables: x.y.z 
AS z (Minji Kim)

Hold aliases in order-preserving Map rather than List<Pair>.

Close apache/calcite#261

fix up


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/b4df7c97
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/b4df7c97
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/b4df7c97

Branch: refs/heads/master
Commit: b4df7c97bb7905cb2c510a08830b8bd710107119
Parents: c933c79
Author: Minji Kim <[email protected]>
Authored: Wed Jul 27 11:37:45 2016 -0700
Committer: Julian Hyde <[email protected]>
Committed: Thu Jul 28 12:14:40 2016 -0700

----------------------------------------------------------------------
 .../calcite/adapter/jdbc/JdbcImplementor.java   |   4 +-
 .../calcite/adapter/jdbc/JdbcTableScan.java     |   5 +-
 .../calcite/rel/rel2sql/RelToSqlConverter.java  |  11 +-
 .../calcite/rel/rel2sql/SqlImplementor.java     |  90 +++++---
 .../java/org/apache/calcite/sql/SqlDialect.java |  31 +++
 .../rel/rel2sql/RelToSqlConverterTest.java      | 230 +++++++++++++++----
 6 files changed, 283 insertions(+), 88 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/b4df7c97/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java 
b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java
index e7da0ef..79ec62f 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java
@@ -22,7 +22,7 @@ import org.apache.calcite.rel.rel2sql.RelToSqlConverter;
 import org.apache.calcite.sql.SqlDialect;
 import org.apache.calcite.util.Util;
 
-import java.util.Collections;
+import com.google.common.collect.ImmutableList;
 
 /**
  * State for generating a SQL statement.
@@ -36,7 +36,7 @@ public class JdbcImplementor extends RelToSqlConverter {
   /** @see #dispatch */
   public Result visit(JdbcTableScan scan) {
     return result(scan.jdbcTable.tableName(),
-        Collections.singletonList(Clause.FROM), scan);
+        ImmutableList.of(Clause.FROM), scan, null);
   }
 
   public Result implement(RelNode node) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/b4df7c97/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java 
b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java
index 96cabc3..7ef8938 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java
@@ -22,7 +22,8 @@ import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.TableScan;
 
-import java.util.Collections;
+import com.google.common.collect.ImmutableList;
+
 import java.util.List;
 
 /**
@@ -49,7 +50,7 @@ public class JdbcTableScan extends TableScan implements 
JdbcRel {
 
   public JdbcImplementor.Result implement(JdbcImplementor implementor) {
     return implementor.result(jdbcTable.tableName(),
-        Collections.singletonList(JdbcImplementor.Clause.FROM), this);
+        ImmutableList.of(JdbcImplementor.Clause.FROM), this, null);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/b4df7c97/core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java 
b/core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java
index 4bfd402..04f3343 100644
--- a/core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java
+++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java
@@ -54,10 +54,11 @@ import org.apache.calcite.util.ReflectUtil;
 import org.apache.calcite.util.ReflectiveVisitor;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Utility to convert relational expressions to SQL abstract syntax tree.
@@ -177,7 +178,7 @@ public class RelToSqlConverter extends SqlImplementor
   public Result visit(TableScan e) {
     final SqlIdentifier identifier =
         new SqlIdentifier(e.getTable().getQualifiedName(), SqlParserPos.ZERO);
-    return result(identifier, Collections.singletonList(Clause.FROM), e);
+    return result(identifier, ImmutableList.of(Clause.FROM), e, null);
   }
 
   /** @see #dispatch */
@@ -228,8 +229,8 @@ public class RelToSqlConverter extends SqlImplementor
   /** @see #dispatch */
   public Result visit(Values e) {
     final List<String> fields = e.getRowType().getFieldNames();
-    final List<Clause> clauses = Collections.singletonList(Clause.SELECT);
-    final List<Pair<String, RelDataType>> pairs = ImmutableList.of();
+    final List<Clause> clauses = ImmutableList.of(Clause.SELECT);
+    final Map<String, RelDataType> pairs = ImmutableMap.of();
     final Context context = aliasContext(pairs, false);
     final List<SqlSelect> selects = new ArrayList<>();
     for (List<RexLiteral> tuple : e.getTuples()) {
@@ -255,7 +256,7 @@ public class RelToSqlConverter extends SqlImplementor
             select);
       }
     }
-    return result(query, clauses, e);
+    return result(query, clauses, e, null);
   }
 
   /** @see #dispatch */

http://git-wip-us.apache.org/repos/asf/calcite/blob/b4df7c97/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java 
b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
index 1f116b2..3fc030f 100644
--- a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
+++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
@@ -59,11 +59,11 @@ import org.apache.calcite.sql.type.ReturnTypes;
 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.Pair;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
 import org.slf4j.Logger;
@@ -73,8 +73,8 @@ import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -233,7 +233,7 @@ public abstract class SqlImplementor {
     final SqlCall node = operator.createCall(new SqlNodeList(list, POS));
     final List<Clause> clauses =
         Expressions.list(Clause.SET_OP);
-    return result(node, clauses, rel);
+    return result(node, clauses, rel, null);
   }
 
   /**
@@ -382,25 +382,45 @@ public abstract class SqlImplementor {
   }
 
   /** Creates a result based on a single relational expression. */
-  public Result result(SqlNode node, Collection<Clause> clauses, RelNode rel) {
+  public Result result(SqlNode node, Collection<Clause> clauses,
+      RelNode rel, Map<String, RelDataType> aliases) {
+    assert aliases == null
+        || aliases.size() < 2
+        || aliases instanceof LinkedHashMap
+        || aliases instanceof ImmutableMap
+        : "must use a Map implementation that preserves order";
     final String alias2 = SqlValidatorUtil.getAlias(node, -1);
     final String alias3 = alias2 != null ? alias2 : "t";
     final String alias4 =
         SqlValidatorUtil.uniquify(
             alias3, aliasSet, SqlValidatorUtil.EXPR_SUGGESTER);
-    final String alias5 = alias2 == null || !alias2.equals(alias4) ? alias4
-        : null;
+    if (aliases != null
+        && !aliases.isEmpty()
+        && !dialect.hasImplicitTableAlias()) {
+      return new Result(node, clauses, alias4, aliases);
+    }
+
+    final String alias5;
+    if (alias2 == null
+        || !alias2.equals(alias4)
+        || !dialect.hasImplicitTableAlias()) {
+      alias5 = alias4;
+    } else {
+      alias5 = null;
+    }
     return new Result(node, clauses, alias5,
-        Collections.singletonList(Pair.of(alias4, rel.getRowType())));
+        ImmutableMap.of(alias4, rel.getRowType()));
   }
 
   /** Creates a result based on a join. (Each join could contain one or more
    * relational expressions.) */
   public Result result(SqlNode join, Result leftResult, Result rightResult) {
-    final List<Pair<String, RelDataType>> list = new ArrayList<>();
-    list.addAll(leftResult.aliases);
-    list.addAll(rightResult.aliases);
-    return new Result(join, Expressions.list(Clause.FROM), null, list);
+    final Map<String, RelDataType> aliases =
+        ImmutableMap.<String, RelDataType>builder()
+            .putAll(leftResult.aliases)
+            .putAll(rightResult.aliases)
+            .build();
+    return new Result(join, Expressions.list(Clause.FROM), null, aliases);
   }
 
   /** Wraps a node in a SELECT statement that has no clauses:
@@ -642,15 +662,15 @@ public abstract class SqlImplementor {
   }
 
   private static int computeFieldCount(
-      List<Pair<String, RelDataType>> aliases) {
+      Map<String, RelDataType> aliases) {
     int x = 0;
-    for (Pair<String, RelDataType> alias : aliases) {
-      x += alias.right.getFieldCount();
+    for (RelDataType type : aliases.values()) {
+      x += type.getFieldCount();
     }
     return x;
   }
 
-  public Context aliasContext(List<Pair<String, RelDataType>> aliases,
+  public Context aliasContext(Map<String, RelDataType> aliases,
       boolean qualified) {
     return new AliasContext(aliases, qualified);
   }
@@ -663,10 +683,10 @@ public abstract class SqlImplementor {
    * "table alias" based on the current sub-query's FROM clause. */
   public class AliasContext extends Context {
     private final boolean qualified;
-    private final List<Pair<String, RelDataType>> aliases;
+    private final Map<String, RelDataType> aliases;
 
-    /** Creates an AliasContext; use {@link #aliasContext(List, boolean)}. */
-    protected AliasContext(List<Pair<String, RelDataType>> aliases,
+    /** Creates an AliasContext; use {@link #aliasContext(Map, boolean)}. */
+    protected AliasContext(Map<String, RelDataType> aliases,
         boolean qualified) {
       super(computeFieldCount(aliases));
       this.aliases = aliases;
@@ -674,8 +694,8 @@ public abstract class SqlImplementor {
     }
 
     public SqlNode field(int ordinal) {
-      for (Pair<String, RelDataType> alias : aliases) {
-        final List<RelDataTypeField> fields = alias.right.getFieldList();
+      for (Map.Entry<String, RelDataType> alias : aliases.entrySet()) {
+        final List<RelDataTypeField> fields = alias.getValue().getFieldList();
         if (ordinal < fields.size()) {
           RelDataTypeField field = fields.get(ordinal);
           final SqlNode mappedSqlNode =
@@ -685,7 +705,7 @@ public abstract class SqlImplementor {
           }
           return new SqlIdentifier(!qualified
               ? ImmutableList.of(field.getName())
-              : ImmutableList.of(alias.left, field.getName()),
+              : ImmutableList.of(alias.getKey(), field.getName()),
               POS);
         }
         ordinal -= fields.size();
@@ -721,11 +741,11 @@ public abstract class SqlImplementor {
   public class Result {
     final SqlNode node;
     private final String neededAlias;
-    private final List<Pair<String, RelDataType>> aliases;
+    private final Map<String, RelDataType> aliases;
     final Expressions.FluentList<Clause> clauses;
 
     public Result(SqlNode node, Collection<Clause> clauses, String neededAlias,
-        List<Pair<String, RelDataType>> aliases) {
+        Map<String, RelDataType> aliases) {
       this.node = node;
       this.neededAlias = neededAlias;
       this.aliases = aliases;
@@ -744,7 +764,7 @@ public abstract class SqlImplementor {
      * <p>When you have called
      * {@link Builder#setSelect(SqlNodeList)},
      * {@link Builder#setWhere(SqlNode)} etc. call
-     * {@link Builder#result(SqlNode, Collection, RelNode)}
+     * {@link Builder#result(SqlNode, Collection, RelNode, Map)}
      * to fix the new query.
      *
      * @param rel Relational expression being implemented
@@ -787,9 +807,18 @@ public abstract class SqlImplementor {
           }
         };
       } else {
-        newContext = aliasContext(aliases, aliases.size() > 1);
+        boolean qualified =
+            !dialect.hasImplicitTableAlias() || aliases.size() > 1;
+        if (needNew) {
+          newContext =
+              aliasContext(ImmutableMap.of(neededAlias, rel.getRowType()),
+                  qualified);
+        } else {
+          newContext = aliasContext(aliases, qualified);
+        }
       }
-      return new Builder(rel, clauseList, select, newContext);
+      return new Builder(rel, clauseList, select, newContext,
+          needNew ? null : aliases);
     }
 
     // make private?
@@ -826,6 +855,9 @@ public abstract class SqlImplementor {
       if (node instanceof SqlSelect) {
         return (SqlSelect) node;
       }
+      if (!dialect.hasImplicitTableAlias()) {
+        return wrapSelect(asFrom());
+      }
       return wrapSelect(node);
     }
 
@@ -853,13 +885,15 @@ public abstract class SqlImplementor {
     final List<Clause> clauses;
     private final SqlSelect select;
     public final Context context;
+    private final Map<String, RelDataType> aliases;
 
     public Builder(RelNode rel, List<Clause> clauses, SqlSelect select,
-        Context context) {
+        Context context, Map<String, RelDataType> aliases) {
       this.rel = rel;
       this.clauses = clauses;
       this.select = select;
       this.context = context;
+      this.aliases = aliases;
     }
 
     public void setSelect(SqlNodeList nodeList) {
@@ -906,7 +940,7 @@ public abstract class SqlImplementor {
     }
 
     public Result result() {
-      return SqlImplementor.this.result(select, clauses, rel);
+      return SqlImplementor.this.result(select, clauses, rel, aliases);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/b4df7c97/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java 
b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
index fc04120..88e7f51 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
@@ -417,6 +417,37 @@ public class SqlDialect {
     return getDatabaseProduct() == DatabaseProduct.POSTGRESQL;
   }
 
+  /** Returns whether a qualified table in the FROM clause has an implicit 
alias
+   * which consists of just the table name.
+   *
+   * <p>For example, in {@link DatabaseProduct#ORACLE}
+   *
+   * <blockquote>SELECT * FROM sales.emp</blockquote>
+   *
+   * <p>is equivalent to
+   *
+   * <blockquote>SELECT * FROM sales.emp AS emp</blockquote>
+   *
+   * <p>and therefore
+   *
+   * <blockquote>SELECT emp.empno FROM sales.emp</blockquote>
+   *
+   * <p>is valid. But {@link DatabaseProduct#DB2} does not have an implicit
+   * alias, so the previous query it not valid; you need to write
+   *
+   * <blockquote>SELECT sales.emp.empno FROM sales.emp</blockquote>
+   *
+   * <p>Returns true for all databases except DB2.
+   */
+  public boolean hasImplicitTableAlias() {
+    switch (databaseProduct) {
+    case DB2:
+      return false;
+    default:
+      return true;
+    }
+  }
+
   /**
    * Converts a timestamp to a SQL timestamp literal, e.g.
    * {@code TIMESTAMP '2009-12-17 12:34:56'}.

http://git-wip-us.apache.org/repos/asf/calcite/blob/b4df7c97/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index 1d70131..85f4720 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -20,6 +20,7 @@ import org.apache.calcite.plan.RelTraitDef;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.sql.SqlDialect;
+import org.apache.calcite.sql.SqlDialect.DatabaseProduct;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.test.CalciteAssert;
@@ -83,16 +84,14 @@ public class RelToSqlConverterTest {
   @Test
   public void testSimpleSelectStarFromProductTable() {
     String query = "select * from \"product\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
-         "SELECT *\nFROM \"foodmart\".\"product\"");
+    checkRel2Sql(logicalPlanner, query,
+        "SELECT *\nFROM \"foodmart\".\"product\"");
   }
 
   @Test
   public void testSimpleSelectQueryFromProductTable() {
     String query = "select \"product_id\", \"product_class_id\" from 
\"product\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_id\", \"product_class_id\"\n"
             + "FROM \"foodmart\".\"product\"");
   }
@@ -103,8 +102,7 @@ public class RelToSqlConverterTest {
   public void testSelectQueryWithWhereClauseOfLessThan() {
     String query =
         "select \"product_id\", \"shelf_width\"  from \"product\" where 
\"product_id\" < 10";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_id\", \"shelf_width\"\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "WHERE \"product_id\" < 10");
@@ -115,8 +113,7 @@ public class RelToSqlConverterTest {
     String query = "select * from \"product\" "
         + "where (\"product_id\" = 10 OR \"product_id\" <= 5) "
         + "AND (80 >= \"shelf_width\" OR \"shelf_width\" > 30)";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT *\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "WHERE (\"product_id\" = 10 OR \"product_id\" <= 5) "
@@ -127,8 +124,7 @@ public class RelToSqlConverterTest {
   @Test
   public void testSelectQueryWithGroupBy() {
     String query = "select count(*) from \"product\" group by 
\"product_class_id\", \"product_id\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT COUNT(*)\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "GROUP BY \"product_class_id\", \"product_id\"");
@@ -137,8 +133,7 @@ public class RelToSqlConverterTest {
   @Test
   public void testSelectQueryWithMinAggregateFunction() {
     String query = "select min(\"net_weight\") from \"product\" group by 
\"product_class_id\" ";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT MIN(\"net_weight\")\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "GROUP BY \"product_class_id\"");
@@ -148,8 +143,7 @@ public class RelToSqlConverterTest {
   public void testSelectQueryWithMinAggregateFunction1() {
     String query = "select \"product_class_id\", min(\"net_weight\") from"
         + " \"product\" group by \"product_class_id\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_class_id\", MIN(\"net_weight\")\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "GROUP BY \"product_class_id\"");
@@ -159,8 +153,7 @@ public class RelToSqlConverterTest {
   public void testSelectQueryWithSumAggregateFunction() {
     String query =
         "select sum(\"net_weight\") from \"product\" group by 
\"product_class_id\" ";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT SUM(\"net_weight\")\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "GROUP BY \"product_class_id\"");
@@ -171,8 +164,7 @@ public class RelToSqlConverterTest {
     String query =
         "select sum(\"net_weight\"), min(\"low_fat\"), count(*)"
             + " from \"product\" group by \"product_class_id\" ";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT SUM(\"net_weight\"), MIN(\"low_fat\"), COUNT(*)\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "GROUP BY \"product_class_id\"");
@@ -183,8 +175,7 @@ public class RelToSqlConverterTest {
     String query =
         "select \"product_class_id\", sum(\"net_weight\"), min(\"low_fat\"), 
count(*)"
             + " from \"product\" group by \"product_class_id\" ";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_class_id\", SUM(\"net_weight\"), MIN(\"low_fat\"), 
COUNT(*)\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "GROUP BY \"product_class_id\"");
@@ -195,8 +186,7 @@ public class RelToSqlConverterTest {
     String query =
         "select \"product_class_id\", \"product_id\", count(*) from 
\"product\" group "
             + "by \"product_class_id\", \"product_id\"  ";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_class_id\", \"product_id\", COUNT(*)\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "GROUP BY \"product_class_id\", \"product_id\"");
@@ -206,8 +196,7 @@ public class RelToSqlConverterTest {
   public void testSelectQueryWithGroupByAndProjectList1() {
     String query =
         "select count(*)  from \"product\" group by \"product_class_id\", 
\"product_id\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT COUNT(*)\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "GROUP BY \"product_class_id\", \"product_id\"");
@@ -217,8 +206,7 @@ public class RelToSqlConverterTest {
   public void testSelectQueryWithGroupByHaving() {
     String query = "select count(*) from \"product\" group by 
\"product_class_id\","
         + " \"product_id\"  having \"product_id\"  > 10";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT COUNT(*)\n"
             + "FROM (SELECT \"product_class_id\", \"product_id\", COUNT(*)\n"
             + "FROM \"foodmart\".\"product\"\n"
@@ -229,8 +217,7 @@ public class RelToSqlConverterTest {
   @Test
   public void testSelectQueryWithOrderByClause() {
     String query = "select \"product_id\"  from \"product\" order by 
\"net_weight\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_id\", \"net_weight\"\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "ORDER BY \"net_weight\"");
@@ -240,8 +227,7 @@ public class RelToSqlConverterTest {
   public void testSelectQueryWithOrderByClause1() {
     String query =
         "select \"product_id\", \"net_weight\" from \"product\" order by 
\"net_weight\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_id\", \"net_weight\"\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "ORDER BY \"net_weight\"");
@@ -251,8 +237,7 @@ public class RelToSqlConverterTest {
   public void testSelectQueryWithTwoOrderByClause() {
     String query =
         "select \"product_id\"  from \"product\" order by \"net_weight\", 
\"gross_weight\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_id\", \"net_weight\", \"gross_weight\"\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "ORDER BY \"net_weight\", \"gross_weight\"");
@@ -263,8 +248,7 @@ public class RelToSqlConverterTest {
     String query =
         "select \"product_id\" from \"product\" order by \"net_weight\" asc, "
             + "\"gross_weight\" desc, \"low_fat\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_id\", \"net_weight\", \"gross_weight\", 
\"low_fat\"\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "ORDER BY \"net_weight\", \"gross_weight\" DESC, \"low_fat\"");
@@ -273,8 +257,7 @@ public class RelToSqlConverterTest {
   @Test
   public void testSelectQueryWithLimitClause() {
     String query = "select \"product_id\"  from \"product\" limit 100 offset 
10";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT product_id\n"
             + "FROM foodmart.product\n"
             + "LIMIT 100\nOFFSET 10",
@@ -284,8 +267,7 @@ public class RelToSqlConverterTest {
   @Test
   public void testSelectQueryWithLimitClauseWithoutOrder() {
     String query = "select \"product_id\"  from \"product\" limit 100 offset 
10";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_id\"\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "OFFSET 10 ROWS\n"
@@ -296,8 +278,7 @@ public class RelToSqlConverterTest {
   public void testSelectQueryWithLimitOffsetClause() {
     String query = "select \"product_id\"  from \"product\" order by 
\"net_weight\" asc"
         + " limit 100 offset 10";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_id\", \"net_weight\"\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "ORDER BY \"net_weight\"\n"
@@ -309,8 +290,7 @@ public class RelToSqlConverterTest {
   public void testSelectQueryWithFetchOffsetClause() {
     String query = "select \"product_id\"  from \"product\" order by 
\"product_id\""
         + " offset 10 rows fetch next 100 rows only";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"product_id\"\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "ORDER BY \"product_id\"\n"
@@ -323,8 +303,7 @@ public class RelToSqlConverterTest {
     String query =
         "select count(*), \"units_per_case\" from \"product\" where 
\"cases_per_pallet\" > 100 "
             + "group by \"product_id\", \"units_per_case\" order by 
\"units_per_case\" desc";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT COUNT(*), \"units_per_case\"\n"
             + "FROM \"foodmart\".\"product\"\n"
             + "WHERE \"cases_per_pallet\" > 100\n"
@@ -339,8 +318,7 @@ public class RelToSqlConverterTest {
             + "where \"hire_date\" > '2015-01-01' "
             + "and (\"position_title\" = 'SDE' or \"position_title\" = 'SDM') "
             + "group by \"store_id\", \"position_title\"";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT COUNT(*), SUM(\"employee_id\")\n"
             + "FROM \"foodmart\".\"reserve_employee\"\n"
             + "WHERE \"hire_date\" > '2015-01-01' "
@@ -357,8 +335,7 @@ public class RelToSqlConverterTest {
         + "  join \"product_class\" as pc using (\"product_class_id\")\n"
         + "where c.\"city\" = 'San Francisco'\n"
         + "and pc.\"product_department\" = 'Snacks'\n";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT *\nFROM \"foodmart\".\"sales_fact_1997\"\n"
             + "INNER JOIN \"foodmart\".\"customer\" "
             + "ON \"sales_fact_1997\".\"customer_id\" = 
\"customer\".\"customer_id\"\n"
@@ -374,14 +351,165 @@ public class RelToSqlConverterTest {
     String query = "select * from \"department\" where \"department_id\" in 
(\n"
         + "  select \"department_id\" from \"employee\"\n"
         + "  where \"store_id\" < 150)";
-    checkRel2Sql(this.logicalPlanner,
-        query,
+    checkRel2Sql(logicalPlanner, query,
         "SELECT \"department\".\"department_id\", 
\"department\".\"department_description\"\n"
             + "FROM \"foodmart\".\"department\"\nINNER JOIN "
             + "(SELECT \"department_id\"\nFROM \"foodmart\".\"employee\"\n"
             + "WHERE \"store_id\" < 150\nGROUP BY \"department_id\") AS \"t1\" 
"
             + "ON \"department\".\"department_id\" = 
\"t1\".\"department_id\"");
   }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-1332";>[CALCITE-1332]
+   * DB2 should always use aliases for tables: x.y.z AS z</a>. */
+  @Test public void testDb2DialectJoinStar() {
+    String query = "select * "
+        + "from \"foodmart\".\"employee\" A "
+        + "join \"foodmart\".\"department\" B\n"
+        + "on A.\"department_id\" = B.\"department_id\"";
+    final String expected = "SELECT *\n"
+        + "FROM foodmart.employee AS employee\n"
+        + "INNER JOIN foodmart.department AS department "
+        + "ON employee.department_id = department.department_id";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+  @Test public void testDb2DialectSelfJoinStar() {
+    String query = "select * "
+        + "from \"foodmart\".\"employee\" A join \"foodmart\".\"employee\" B\n"
+        + "on A.\"department_id\" = B.\"department_id\"";
+    final String expected = "SELECT *\n"
+        + "FROM foodmart.employee AS employee\n"
+        + "INNER JOIN foodmart.employee AS employee0 "
+        + "ON employee.department_id = employee0.department_id";
+    checkRel2Sql(logicalPlanner, query,
+        expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+  @Test public void testDb2DialectJoin() {
+    String query = "select A.\"employee_id\", B.\"department_id\" "
+        + "from \"foodmart\".\"employee\" A join \"foodmart\".\"department\" 
B\n"
+        + "on A.\"department_id\" = B.\"department_id\"";
+    final String expected = "SELECT"
+        + " employee.employee_id, department.department_id\n"
+        + "FROM foodmart.employee AS employee\n"
+        + "INNER JOIN foodmart.department AS department "
+        + "ON employee.department_id = department.department_id";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+  @Test public void testDb2DialectSelfJoin() {
+    String query = "select A.\"employee_id\", B.\"employee_id\" from "
+        + "\"foodmart\".\"employee\" A join \"foodmart\".\"employee\" B\n"
+        + "on A.\"department_id\" = B.\"department_id\"";
+    final String expected = "SELECT"
+        + " employee.employee_id, employee0.employee_id AS employee_id0\n"
+        + "FROM foodmart.employee AS employee\n"
+        + "INNER JOIN foodmart.employee AS employee0 "
+        + "ON employee.department_id = employee0.department_id";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+  @Test public void testDb2DialectWhere() {
+    String query = "select A.\"employee_id\" from "
+        + "\"foodmart\".\"employee\" A where A.\"department_id\" < 1000";
+    final String expected = "SELECT employee.employee_id\n"
+        + "FROM foodmart.employee AS employee\n"
+        + "WHERE employee.department_id < 1000";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+  @Test public void testDb2DialectJoinWhere() {
+    String query = "select A.\"employee_id\", B.\"department_id\" "
+        + "from \"foodmart\".\"employee\" A join \"foodmart\".\"department\" 
B\n"
+        + "on A.\"department_id\" = B.\"department_id\" "
+        + "where A.\"employee_id\" < 1000";
+    final String expected = "SELECT"
+        + " employee.employee_id, department.department_id\n"
+        + "FROM foodmart.employee AS employee\n"
+        + "INNER JOIN foodmart.department AS department "
+        + "ON employee.department_id = department.department_id\n"
+        + "WHERE employee.employee_id < 1000";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+  @Test public void testDb2DialectSelfJoinWhere() {
+    String query = "select A.\"employee_id\", B.\"employee_id\" from "
+        + "\"foodmart\".\"employee\" A join \"foodmart\".\"employee\" B\n"
+        + "on A.\"department_id\" = B.\"department_id\" "
+        + "where B.\"employee_id\" < 2000";
+    final String expected = "SELECT "
+        + "employee.employee_id, employee0.employee_id AS employee_id0\n"
+        + "FROM foodmart.employee AS employee\n"
+        + "INNER JOIN foodmart.employee AS employee0 "
+        + "ON employee.department_id = employee0.department_id\n"
+        + "WHERE employee0.employee_id < 2000";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+  @Test public void testDb2DialectCast() {
+    String query = "select \"hire_date\", cast(\"hire_date\" as varchar(10)) "
+        + "from \"foodmart\".\"reserve_employee\"";
+    final String expected = "SELECT reserve_employee.hire_date, "
+        + "CAST(reserve_employee.hire_date AS VARCHAR(10))\n"
+        + "FROM foodmart.reserve_employee AS reserve_employee";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+  @Test public void testDb2DialectSelectQueryWithGroupByHaving() {
+    String query = "select count(*) from \"product\" "
+        + "group by \"product_class_id\", \"product_id\" "
+        + "having \"product_id\"  > 10";
+    final String expected = "SELECT COUNT(*)\n"
+        + "FROM (SELECT product.product_class_id, product.product_id, COUNT"
+        + "(*)\n"
+        + "FROM foodmart.product AS product\n"
+        + "GROUP BY product.product_class_id, product.product_id) AS t0\n"
+        + "WHERE t0.product_id > 10";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+
+  @Test public void testDb2DialectSelectQueryComplex() {
+    String query = "select count(*), \"units_per_case\" "
+        + "from \"product\" where \"cases_per_pallet\" > 100 "
+        + "group by \"product_id\", \"units_per_case\" "
+        + "order by \"units_per_case\" desc";
+    final String expected = "SELECT COUNT(*), product.units_per_case\n"
+        + "FROM foodmart.product AS product\n"
+        + "WHERE product.cases_per_pallet > 100\n"
+        + "GROUP BY product.product_id, product.units_per_case\n"
+        + "ORDER BY product.units_per_case DESC";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
+  @Test public void testDb2DialectSelectQueryWithGroup() {
+    String query = "select count(*), sum(\"employee_id\") "
+        + "from \"reserve_employee\" "
+        + "where \"hire_date\" > '2015-01-01' "
+        + "and (\"position_title\" = 'SDE' or \"position_title\" = 'SDM') "
+        + "group by \"store_id\", \"position_title\"";
+    final String expected = "SELECT"
+        + " COUNT(*), SUM(reserve_employee.employee_id)\n"
+        + "FROM foodmart.reserve_employee AS reserve_employee\n"
+        + "WHERE reserve_employee.hire_date > '2015-01-01' "
+        + "AND (reserve_employee.position_title = 'SDE' OR "
+        + "reserve_employee.position_title = 'SDM')\n"
+        + "GROUP BY reserve_employee.store_id, 
reserve_employee.position_title";
+    checkRel2Sql(logicalPlanner, query, expected,
+        DatabaseProduct.DB2.getDialect());
+  }
+
 }
 
 // End RelToSqlConverterTest.java

Reply via email to