Repository: calcite
Updated Branches:
  refs/heads/master 105bba1f8 -> 5be0f0b04


[CALCITE-1426] Support customized star expansion in Table


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

Branch: refs/heads/master
Commit: 5be0f0b046e36ea2ca3c052626599534dd8b0f71
Parents: 105bba1
Author: maryannxue <maryann....@gmail.com>
Authored: Tue Oct 18 15:44:02 2016 -0700
Committer: maryannxue <maryann....@gmail.com>
Committed: Tue Oct 18 15:44:02 2016 -0700

----------------------------------------------------------------------
 .../calcite/schema/CustomExpansionTable.java    |  42 ++++++
 .../org/apache/calcite/sql/SqlIdentifier.java   |  10 --
 .../java/org/apache/calcite/sql/SqlInsert.java  |   4 +
 .../calcite/sql/advise/SqlAdvisorValidator.java |   7 +
 .../calcite/sql/validate/SqlValidator.java      |   7 +
 .../calcite/sql/validate/SqlValidatorImpl.java  | 127 +++++++++++--------
 .../apache/calcite/test/MockCatalogReader.java  |  75 +++++++++--
 .../calcite/test/SqlToRelConverterTest.java     |   6 +
 .../apache/calcite/test/SqlValidatorTest.java   |   6 +
 .../org/apache/calcite/test/RelOptRulesTest.xml |  12 +-
 .../calcite/test/SqlToRelConverterTest.xml      |  18 ++-
 11 files changed, 236 insertions(+), 78 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/main/java/org/apache/calcite/schema/CustomExpansionTable.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/schema/CustomExpansionTable.java 
b/core/src/main/java/org/apache/calcite/schema/CustomExpansionTable.java
new file mode 100644
index 0000000..21ac696
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/schema/CustomExpansionTable.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.schema;
+
+import java.util.List;
+
+/**
+ * Extension to {@link Table} that specifies a list of column names for
+ * custom star expansion. The columns specified in the list can be any
+ * top-level column from the Table or any field or nested field under a
+ * top-level column, thus each column name is returned as a list of String
+ * objects representing the full name of the column or field. This expansion
+ * list will also be used as target columns in INSERT if the original target
+ * column list is not present.
+ *
+ * <p>It is optional for a Table to implement this interface. If Table does
+ * not implement this interface, star expansion will be performed in the
+ * default way according to the Table's row type.</p>
+ *
+ * <p><strong>NOTE: This class is experimental and subject to
+ * change/removal without notice</strong>.</p>
+ */
+public interface CustomExpansionTable extends Table {
+  /** Returns a list of column names for custom star expansion. */
+  List<List<String>> getCustomStarExpansion();
+}
+
+// End CustomExpansionTable.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java 
b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
index 7e2294c..d070150 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
@@ -258,16 +258,6 @@ public class SqlIdentifier extends SqlNode {
     return new SqlIdentifier(names, collation, pos2, componentPositions);
   }
 
-  /**
-   * Creates an identifier that consists of this identifier plus a wildcard 
star.
-   * Does not modify this identifier.
-   */
-  public SqlIdentifier plusStar() {
-    final SqlIdentifier id = this.plus("*", SqlParserPos.ZERO);
-    return new SqlIdentifier(Lists.transform(id.names, STAR_TO_EMPTY), null, 
id.pos,
-        id.componentPositions);
-  }
-
   /** Creates an identifier that consists of all but the last {@code n}
    * name segments of this one. */
   public SqlIdentifier skipLast(int n) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/main/java/org/apache/calcite/sql/SqlInsert.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlInsert.java 
b/core/src/main/java/org/apache/calcite/sql/SqlInsert.java
index 19472a7..1c9030e 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlInsert.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlInsert.java
@@ -120,6 +120,10 @@ public class SqlInsert extends SqlCall {
     return columnList;
   }
 
+  public void setTargetColumnList(SqlNodeList columnList) {
+    this.columnList = columnList;
+  }
+
   public final SqlNode getModifierNode(SqlInsertKeyword modifier) {
     for (SqlNode keyword : keywords) {
       SqlInsertKeyword keyword2 =

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java 
b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
index 4d07e79..90f68cc 100644
--- a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
+++ b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
@@ -201,6 +201,13 @@ public class SqlAdvisorValidator extends SqlValidatorImpl {
     return true;
   }
 
+  public boolean shouldUseCustomStarExpansion() {
+    // Disable custom star expansion otherwise SqlValidatorNamespace.getTable()
+    // could be called on a SqlValidatorNamespace that was not successfully
+    // validated.
+    return false;
+  }
+
   protected boolean shouldAllowOverRelation() {
     return true; // no reason not to be lenient
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
index 215b96c..cc14c36 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
@@ -617,6 +617,13 @@ public interface SqlValidator {
   boolean shouldExpandIdentifiers();
 
   /**
+   * Returns whether to use a Table's custom star expansion.
+   *
+   * @return true if custom star expansion should be used; false otherwise.
+   */
+  boolean shouldUseCustomStarExpansion();
+
+  /**
    * Enables or disables rewrite of "macro-like" calls such as COALESCE.
    *
    * @param rewriteCalls new setting

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index bc630a9..b2dada1 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -19,6 +19,7 @@ package org.apache.calcite.sql.validate;
 import org.apache.calcite.config.NullCollation;
 import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.rel.type.DynamicRecordType;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -29,6 +30,7 @@ import org.apache.calcite.runtime.CalciteContextException;
 import org.apache.calcite.runtime.CalciteException;
 import org.apache.calcite.runtime.Feature;
 import org.apache.calcite.runtime.Resources;
+import org.apache.calcite.schema.CustomExpansionTable;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.sql.JoinConditionType;
 import org.apache.calcite.sql.JoinType;
@@ -460,26 +462,42 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
                scope,
                includeSystemVars);
         } else {
-          final SqlNode from = p.right.getNode();
-          final SqlValidatorNamespace fromNs = getNamespace(from, scope);
-          assert fromNs != null;
-          final RelDataType rowType = fromNs.getRowType();
-          for (RelDataTypeField field : rowType.getFieldList()) {
-            String columnName = field.getName();
-
-            // TODO: do real implicit collation here
-            final SqlIdentifier exp =
-                new SqlIdentifier(
-                    ImmutableList.of(p.left, columnName),
-                    startPosition);
-            addOrExpandField(
-                selectItems,
-                aliases,
-                types,
-                includeSystemVars,
-                scope,
-                exp,
-                field);
+          final List<List<String>> customStarExpansion =
+              getCustomStarExpansion(p.right);
+          if (customStarExpansion != null) {
+            for (List<String> names : customStarExpansion) {
+              SqlIdentifier exp = new SqlIdentifier(
+                  Lists.asList(p.left, names.toArray(new 
String[names.size()])),
+                  startPosition);
+              addToSelectList(
+                  selectItems,
+                  aliases,
+                  types,
+                  exp,
+                  scope,
+                  includeSystemVars);
+            }
+          } else {
+            final SqlNode from = p.right.getNode();
+            final SqlValidatorNamespace fromNs = getNamespace(from, scope);
+            assert fromNs != null;
+            final RelDataType rowType = fromNs.getRowType();
+            for (RelDataTypeField field : rowType.getFieldList()) {
+              String columnName = field.getName();
+
+              // TODO: do real implicit collation here
+              final SqlNode exp =
+                  new SqlIdentifier(
+                      ImmutableList.of(p.left, columnName),
+                      startPosition);
+              addToSelectList(
+                  selectItems,
+                  aliases,
+                  types,
+                  exp,
+                  scope,
+                  includeSystemVars);
+            }
           }
         }
       }
@@ -512,14 +530,13 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
           String columnName = field.getName();
 
           // TODO: do real implicit collation here
-          addOrExpandField(
+          addToSelectList(
               selectItems,
               aliases,
               types,
-              includeSystemVars,
-              scope,
               prefixId.plus(columnName, startPosition),
-              field);
+              scope,
+              includeSystemVars);
         }
       } else {
         throw newValidationError(prefixId, RESOURCE.starRequiresRecordType());
@@ -528,33 +545,18 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     }
   }
 
-  private boolean addOrExpandField(List<SqlNode> selectItems, Set<String> 
aliases,
-      List<Map.Entry<String, RelDataType>> types, boolean includeSystemVars,
-      SelectScope scope, SqlIdentifier id, RelDataTypeField field) {
-    switch (field.getType().getStructKind()) {
-    case PEEK_FIELDS:
-    case PEEK_FIELDS_DEFAULT:
-      final SqlNode starExp = id.plusStar();
-      expandStar(
-          selectItems,
-          aliases,
-          types,
-          includeSystemVars,
-          scope,
-          starExp);
-      return true;
-
-    default:
-      addToSelectList(
-          selectItems,
-          aliases,
-          types,
-          id,
-          scope,
-          includeSystemVars);
+  private List<List<String>> getCustomStarExpansion(SqlValidatorNamespace ns) {
+    if (!shouldUseCustomStarExpansion()) {
+      return null;
     }
-
-    return false;
+    final SqlValidatorTable table = ns.getTable();
+    if (table instanceof Prepare.PreparingTable) {
+      Table t = ((Prepare.PreparingTable) table).unwrap(Table.class);
+      if (t instanceof CustomExpansionTable) {
+        return ((CustomExpansionTable) t).getCustomStarExpansion();
+      }
+    }
+    return null;
   }
 
   public SqlNode validate(SqlNode topNode) {
@@ -1759,6 +1761,10 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     return expandIdentifiers;
   }
 
+  public boolean shouldUseCustomStarExpansion() {
+    return true;
+  }
+
   protected boolean shouldAllowIntermediateOrderBy() {
     return true;
   }
@@ -3734,6 +3740,11 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     validateNamespace(targetNamespace, unknownType);
     SqlValidatorTable table = targetNamespace.getTable();
 
+    // If the INSERT does not have a target column list and the target
+    // table specifies a custom star expansion list, we will set the new
+    // target column list as the star expansion list.
+    rewriteTargetColumnList(insert, targetNamespace);
+
     // INSERT has an optional column name list.  If present then
     // reduce the rowtype to the columns specified.  If not present
     // then the entire target rowtype is used.
@@ -3771,6 +3782,22 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     validateAccess(insert.getTargetTable(), table, SqlAccessEnum.INSERT);
   }
 
+  private void rewriteTargetColumnList(
+      SqlInsert insert, SqlValidatorNamespace ns) {
+    final List<List<String>> customStarExpansion = getCustomStarExpansion(ns);
+    if (customStarExpansion == null) {
+      return;
+    }
+
+    final List<SqlNode> targetColumnList = new ArrayList<>();
+    final SqlParserPos startPosition = insert.getParserPosition();
+    for (List<String> names : customStarExpansion) {
+      targetColumnList.add(new SqlIdentifier(names, startPosition));
+    }
+    insert.setTargetColumnList(
+        new SqlNodeList(targetColumnList, startPosition));
+  }
+
   private void checkFieldCount(
       SqlNode node,
       RelDataType logicalSourceRowType,

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java 
b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
index 3912880..3e5246a 100644
--- a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
+++ b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
@@ -48,6 +48,7 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.schema.CustomExpansionTable;
 import org.apache.calcite.schema.ModifiableView;
 import org.apache.calcite.schema.Path;
 import org.apache.calcite.schema.Schema;
@@ -356,7 +357,7 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
     //   FROM EMP
     //   WHERE DEPTNO = 20 AND SAL > 1000
     MockTable emp20View = new MockViewTable(this, salesSchema.getCatalogName(),
-        salesSchema.name, "EMP_20", false, 600, empTable,
+        salesSchema.name, "EMP_20", false, 600, empTable, null,
         ImmutableIntList.of(0, 1, 2, 3, 4, 5, 6, 8)) {
 
       @Override public RexNode getConstraint(RexBuilder rexBuilder,
@@ -392,8 +393,19 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
 
     MockSchema structTypeSchema = new MockSchema("STRUCT");
     registerSchema(structTypeSchema);
-    final MockTable structTypeTable = MockTable.create(this, structTypeSchema,
-        "T", false, 100);
+    MockTable structTypeTable = new MockTable(this,
+        structTypeSchema.getCatalogName(), structTypeSchema.name,
+        "T", false, 100,
+        ImmutableList.<List<String>>of(
+            ImmutableList.of("K0"),
+            ImmutableList.of("C1"),
+            ImmutableList.of("F1", "A0"),
+            ImmutableList.of("F2", "A0"),
+            ImmutableList.of("F0", "C0"),
+            ImmutableList.of("F1", "C0"),
+            ImmutableList.of("F0", "C1"),
+            ImmutableList.of("F1", "C2"),
+            ImmutableList.of("F2", "C3")));
     structTypeTable.addColumn("K0", varchar20Type);
     structTypeTable.addColumn("C1", varchar20Type);
     final RelDataType f0Type = typeFactory.builder()
@@ -427,7 +439,7 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
     MockTable struct10View = new MockViewTable(this,
         structTypeSchema.getCatalogName(),
         structTypeSchema.name, "T_10", false, 20,
-        structTypeTable, ImmutableIntList.of(0, 1, 2, 3, 4)) {
+        structTypeTable, null, ImmutableIntList.of(0, 1, 2, 3, 4)) {
 
       @Override public RexNode getConstraint(RexBuilder rexBuilder,
           RelDataType tableRowType) {
@@ -451,6 +463,19 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
     struct10View.addColumn("F1", f1Type);
     struct10View.addColumn("F2", f2Type);
     registerTable(struct10View);
+
+    // TODO Remove this table and use STRUCT.T instead after
+    // CALCITE-1425 is done.
+    MockTable simpleTable = new MockTable(this,
+        structTypeSchema.getCatalogName(), structTypeSchema.name,
+        "SIMPLE", false, 100,
+        ImmutableList.<List<String>>of(
+            ImmutableList.of("K2"),
+            ImmutableList.of("K0")));
+    simpleTable.addColumn("K0", varchar20Type);
+    simpleTable.addColumn("K1", intTypeNull);
+    simpleTable.addColumn("K2", timestampType);
+    registerTable(simpleTable);
     return this;
   }
 
@@ -636,20 +661,42 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
     protected final List<String> names;
     private final Set<String> monotonicColumnSet = Sets.newHashSet();
     private StructKind kind = StructKind.FULLY_QUALIFIED;
+    protected final List<List<String>> customExpansionList;
 
     public MockTable(MockCatalogReader catalogReader, String catalogName,
-        String schemaName, String name, boolean stream, double rowCount) {
+        String schemaName, String name, boolean stream, double rowCount,
+        List<List<String>> customExpansionList) {
       this.catalogReader = catalogReader;
       this.stream = stream;
       this.rowCount = rowCount;
       this.names = ImmutableList.of(catalogName, schemaName, name);
+      this.customExpansionList = customExpansionList;
+    }
+
+    /**
+     * Subclass of AbstractModifiableTable that also implements
+     * CustomExpansionTable.
+     */
+    private abstract class AbstractModifiableTableWithCustomExpansion
+        extends JdbcTest.AbstractModifiableTable
+        implements CustomExpansionTable {
+
+      protected AbstractModifiableTableWithCustomExpansion(String tableName) {
+        super(tableName);
+      }
     }
 
     public static MockTable create(MockCatalogReader catalogReader,
         MockSchema schema, String name, boolean stream, double rowCount) {
+      return create(catalogReader, schema, name, stream, rowCount, null);
+    }
+
+    public static MockTable create(MockCatalogReader catalogReader,
+        MockSchema schema, String name, boolean stream, double rowCount,
+        List<List<String>> customExpansionList) {
       MockTable table =
           new MockTable(catalogReader, schema.getCatalogName(), schema.name,
-              name, stream, rowCount);
+              name, stream, rowCount, customExpansionList);
       schema.addTable(name);
       return table;
     }
@@ -660,7 +707,7 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
       }
       if (clazz.isAssignableFrom(Table.class)) {
         return clazz.cast(
-            new JdbcTest.AbstractModifiableTable(Util.last(names)) {
+            new AbstractModifiableTableWithCustomExpansion(Util.last(names)) {
               @Override public RelDataType
               getRowType(RelDataTypeFactory typeFactory) {
                 return typeFactory.createStructType(rowType.getFieldList());
@@ -684,6 +731,10 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
                   String tableName, Class clazz) {
                 return null;
               }
+
+              @Override public List<List<String>> getCustomStarExpansion() {
+                return customExpansionList;
+              }
             });
       }
       return null;
@@ -756,7 +807,7 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
 
     public RelOptTable extend(List<RelDataTypeField> extendedFields) {
       final MockTable table = new MockTable(catalogReader, names.get(0),
-          names.get(1), names.get(2), stream, rowCount);
+          names.get(1), names.get(2), stream, rowCount, customExpansionList);
       table.columnList.addAll(columnList);
       table.columnList.addAll(extendedFields);
       table.onRegister(catalogReader.typeFactory);
@@ -783,8 +834,10 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
 
     MockViewTable(MockCatalogReader catalogReader, String catalogName,
         String schemaName, String name, boolean stream, double rowCount,
-        MockTable fromTable, ImmutableIntList mapping) {
-      super(catalogReader, catalogName, schemaName, name, stream, rowCount);
+        MockTable fromTable, List<List<String>> customExpansionList,
+        ImmutableIntList mapping) {
+      super(catalogReader, catalogName, schemaName, name, stream, rowCount,
+          customExpansionList);
       this.fromTable = fromTable;
       this.table = fromTable.unwrap(Table.class);
       this.mapping = mapping;
@@ -875,7 +928,7 @@ public class MockCatalogReader implements 
Prepare.CatalogReader {
   public static class MockDynamicTable extends MockTable {
     MockDynamicTable(MockCatalogReader catalogReader, String catalogName,
         String schemaName, String name, boolean stream, double rowCount) {
-      super(catalogReader, catalogName, schemaName, name, stream, rowCount);
+      super(catalogReader, catalogName, schemaName, name, stream, rowCount, 
null);
     }
 
     public void onRegister(RelDataTypeFactory typeFactory) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index c32e751..c50b301 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -1745,6 +1745,12 @@ public class SqlToRelConverterTest extends 
SqlToRelTestBase {
     sql(sql).ok();
   }
 
+  @Test public void testStructTypeWithSelectStar2() {
+    final String sql = "select * from struct.t t1 join struct.t t2\n"
+        + "on t1.k0 = t2.k0";
+    sql(sql).ok();
+  }
+
   @Test public void testStructTypeWithSelectFieldNameDotStar() {
     final String sql = "select f1.* from struct.t";
     sql(sql).ok();

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index caee32f..83125ba 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -7972,6 +7972,12 @@ public class SqlValidatorTest extends 
SqlValidatorTestCase {
     sql(sql2).ok().bindType(expected2);
   }
 
+  @Test public void testInsertBindWithCustomStarExpansion() {
+    sql("insert into struct.simple values (?, ?)")
+        .ok()
+        .bindType("RecordType(TIMESTAMP(0) ?0, VARCHAR(20) ?1)");
+  }
+
   @Test public void testUpdateBind() {
     final String sql = "update emp\n"
         + "set ename = ?\n"

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
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 d830b95..e773160 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1134,7 +1134,7 @@ where c0 in (
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
-LogicalProject(K0=[$0], C1=[$1], C0=[$2], C10=[$3], C00=[$4], C2=[$5], 
A0=[$6], C3=[$7], A00=[$8])
+LogicalProject(K0=[$0], C1=[$1], A0=[$6], A00=[$8], C0=[$2], C00=[$4], 
C10=[$3], C2=[$5], C3=[$7])
   LogicalFilter(condition=[IN($2, {
 LogicalProject(C0=[$4])
   LogicalProject(K0=[$0], C1=[$1], C0=[$2.C0], C13=[$2.C1], C04=[$3.C0], 
C2=[$3.C2], A0=[$3.A0], C3=[$4.C3], A08=[$4.A0])
@@ -1146,7 +1146,7 @@ LogicalProject(C0=[$4])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(K0=[$0], C1=[$1], C0=[$2], C10=[$3], C00=[$4], C2=[$5], 
A0=[$6], C3=[$7], A00=[$8])
+LogicalProject(K0=[$0], C1=[$1], A0=[$6], A00=[$8], C0=[$2], C00=[$4], 
C10=[$3], C2=[$5], C3=[$7])
   LogicalProject(K0=[$0], C1=[$1], C0=[$2], C13=[$3], C04=[$4], C2=[$5], 
A0=[$6], C3=[$7], A08=[$8])
     LogicalJoin(condition=[=($2, $9)], joinType=[inner])
       LogicalProject(K0=[$0], C1=[$1], C0=[$2.C0], C13=[$2.C1], C04=[$3.C0], 
C2=[$3.C2], A0=[$3.A0], C3=[$4.C3], A08=[$4.A0])
@@ -1167,7 +1167,7 @@ where c0 = (
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
-LogicalProject(K0=[$0], C1=[$1], C0=[$2], C10=[$3], C00=[$4], C2=[$5], 
A0=[$6], C3=[$7], A00=[$8])
+LogicalProject(K0=[$0], C1=[$1], A0=[$6], A00=[$8], C0=[$2], C00=[$4], 
C10=[$3], C2=[$5], C3=[$7])
   LogicalFilter(condition=[=($2, $SCALAR_QUERY({
 LogicalAggregate(group=[{}], EXPR$0=[MAX($0)])
   LogicalProject($f0=[$4])
@@ -1181,7 +1181,7 @@ LogicalAggregate(group=[{}], EXPR$0=[MAX($0)])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(K0=[$0], C1=[$1], C0=[$2], C10=[$3], C00=[$4], C2=[$5], 
A0=[$6], C3=[$7], A00=[$8])
+LogicalProject(K0=[$0], C1=[$1], A0=[$6], A00=[$8], C0=[$2], C00=[$4], 
C10=[$3], C2=[$5], C3=[$7])
   LogicalProject(K0=[$0], C1=[$1], C0=[$2], C13=[$3], C04=[$4], C2=[$5], 
A0=[$6], C3=[$7], A08=[$8])
     LogicalFilter(condition=[=($2, $9)])
       LogicalCorrelate(correlation=[$cor0], joinType=[LEFT], 
requiredColumns=[{0}])
@@ -1204,7 +1204,7 @@ where c0 in (
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
-LogicalProject(K0=[$0], C1=[$1], C0=[$2], C10=[$3], C00=[$4], C2=[$5], 
A0=[$6], C3=[$7], A00=[$8])
+LogicalProject(K0=[$0], C1=[$1], A0=[$6], A00=[$8], C0=[$2], C00=[$4], 
C10=[$3], C2=[$5], C3=[$7])
   LogicalFilter(condition=[IN($2, {
 LogicalProject(C0=[$4])
   LogicalFilter(condition=[=($cor0.C2_5, $5)])
@@ -1217,7 +1217,7 @@ LogicalProject(C0=[$4])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(K0=[$0], C1=[$1], C0=[$2], C10=[$3], C00=[$4], C2=[$5], 
A0=[$6], C3=[$7], A00=[$8])
+LogicalProject(K0=[$0], C1=[$1], A0=[$6], A00=[$8], C0=[$2], C00=[$4], 
C10=[$3], C2=[$5], C3=[$7])
   LogicalProject(K0=[$0], C1=[$1], C0=[$2], C13=[$3], C04=[$4], C2=[$5], 
A0=[$6], C3=[$7], A08=[$8])
     LogicalFilter(condition=[=($2, $9)])
       LogicalCorrelate(correlation=[$cor0], joinType=[INNER], 
requiredColumns=[{5}])

http://git-wip-us.apache.org/repos/asf/calcite/blob/5be0f0b0/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git 
a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml 
b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index 371c20c..500ee91 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -2584,12 +2584,28 @@ LogicalProject(F1=[$0])
         </Resource>
         <Resource name="plan">
             <![CDATA[
-LogicalProject(K0=[$0], C1=[$1], C0=[$2], C10=[$3], C00=[$4], C2=[$5], 
A0=[$6], C3=[$7], A00=[$8])
+LogicalProject(K0=[$0], C1=[$1], A0=[$6], A00=[$8], C0=[$2], C00=[$4], 
C10=[$3], C2=[$5], C3=[$7])
   LogicalProject(K0=[$0], C1=[$1], C0=[$2.C0], C13=[$2.C1], C04=[$3.C0], 
C2=[$3.C2], A0=[$3.A0], C3=[$4.C3], A08=[$4.A0])
     LogicalTableScan(table=[[CATALOG, STRUCT, T]])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testStructTypeWithSelectStar2">
+        <Resource name="sql">
+            <![CDATA[select * from struct.t t1 join struct.t t2
+on t1.k0 = t2.k0]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalProject(K0=[$0], C1=[$1], A0=[$6], A00=[$8], C0=[$2], C00=[$4], 
C10=[$3], C2=[$5], C3=[$7], K00=[$9], C11=[$10], A01=[$15], A02=[$17], 
C01=[$11], C02=[$13], C12=[$12], C20=[$14], C30=[$16])
+  LogicalJoin(condition=[=($0, $9)], joinType=[inner])
+    LogicalProject(K0=[$0], C1=[$1], C0=[$2.C0], C13=[$2.C1], C04=[$3.C0], 
C2=[$3.C2], A0=[$3.A0], C3=[$4.C3], A08=[$4.A0])
+      LogicalTableScan(table=[[CATALOG, STRUCT, T]])
+    LogicalProject(K0=[$0], C1=[$1], C0=[$2.C0], C13=[$2.C1], C04=[$3.C0], 
C2=[$3.C2], A0=[$3.A0], C3=[$4.C3], A08=[$4.A0])
+      LogicalTableScan(table=[[CATALOG, STRUCT, T]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testStructTypeWithSelectFieldNameDotStar">
         <Resource name="sql">
             <![CDATA[select f1.* from struct.t]]>

Reply via email to