You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by el...@apache.org on 2016/05/31 23:24:00 UTC

[02/14] calcite git commit: [CALCITE-1228] Bind parameters in INSERT

[CALCITE-1228] Bind parameters in INSERT

Deduce number and types of bind parameters for all DML statements, in
validator and in simple JDBC tests.

Also infer types of bind parameters in other kinds of query.


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

Branch: refs/heads/branch-avatica-1.8
Commit: f191a386aedaee05c6ffcc1d4b155193bfa4ca01
Parents: b0a996b
Author: Julian Hyde <jh...@apache.org>
Authored: Tue May 17 19:05:34 2016 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Sun May 22 12:46:46 2016 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/sql/SqlSelect.java  |  2 +-
 .../org/apache/calcite/sql/SqlSetOperator.java  |  2 +-
 .../java/org/apache/calcite/sql/SqlUpdate.java  |  5 +-
 .../calcite/sql/advise/SqlAdvisorValidator.java |  5 +-
 .../sql/type/ExplicitOperandTypeInference.java  |  7 +-
 .../calcite/sql/validate/AbstractNamespace.java | 11 ++-
 .../calcite/sql/validate/AliasNamespace.java    |  2 +-
 .../calcite/sql/validate/CollectNamespace.java  |  2 +-
 .../sql/validate/DelegatingNamespace.java       |  4 +-
 .../calcite/sql/validate/FieldNamespace.java    |  2 +-
 .../sql/validate/IdentifierNamespace.java       |  2 +-
 .../calcite/sql/validate/JoinNamespace.java     |  2 +-
 .../sql/validate/ParameterNamespace.java        |  2 +-
 .../sql/validate/ProcedureNamespace.java        |  2 +-
 .../calcite/sql/validate/SchemaNamespace.java   |  2 +-
 .../calcite/sql/validate/SelectNamespace.java   |  4 +-
 .../calcite/sql/validate/SetopNamespace.java    |  4 +-
 .../calcite/sql/validate/SqlValidator.java      |  5 +-
 .../calcite/sql/validate/SqlValidatorImpl.java  | 59 ++++++++-------
 .../sql/validate/SqlValidatorNamespace.java     |  9 ++-
 .../sql/validate/TableConstructorNamespace.java | 10 +--
 .../calcite/sql/validate/TableNamespace.java    |  2 +-
 .../calcite/sql/validate/UnnestNamespace.java   |  2 +-
 .../calcite/sql/validate/WithItemNamespace.java |  2 +-
 .../calcite/sql/validate/WithNamespace.java     |  4 +-
 .../calcite/sql/test/SqlOperatorBaseTest.java   | 21 ++---
 .../org/apache/calcite/sql/test/SqlTester.java  | 17 ++---
 .../apache/calcite/sql/test/SqlTesterImpl.java  | 33 ++++----
 .../org/apache/calcite/sql/test/SqlTests.java   | 10 +++
 .../calcite/test/JdbcFrontLinqBackTest.java     | 35 +++++++++
 .../apache/calcite/test/SqlValidatorTest.java   | 80 ++++++++++++++++----
 .../calcite/test/SqlValidatorTestCase.java      | 14 ++++
 32 files changed, 243 insertions(+), 120 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSelect.java b/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
index d1cb249..c054763 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
@@ -205,7 +205,7 @@ public class SqlSelect extends SqlCall {
   }
 
   public void validate(SqlValidator validator, SqlValidatorScope scope) {
-    validator.validateQuery(this, scope);
+    validator.validateQuery(this, scope, validator.getUnknownType());
   }
 
   // Override SqlCall, to introduce a subquery frame.

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/SqlSetOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSetOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlSetOperator.java
index d4699f3..d6e128a 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlSetOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlSetOperator.java
@@ -87,7 +87,7 @@ public class SqlSetOperator extends SqlBinaryOperator {
       SqlValidator validator,
       SqlValidatorScope scope,
       SqlValidatorScope operandScope) {
-    validator.validateQuery(call, operandScope);
+    validator.validateQuery(call, operandScope, validator.getUnknownType());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java b/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java
index 5d8ebfa..475d00d 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java
@@ -71,13 +71,14 @@ public class SqlUpdate extends SqlCall {
 
   public List<SqlNode> getOperandList() {
     return ImmutableNullableList.of(targetTable, targetColumnList,
-        sourceExpressionList, condition, sourceSelect, alias);
+        sourceExpressionList, condition, alias);
   }
 
   @Override public void setOperand(int i, SqlNode operand) {
     switch (i) {
     case 0:
-      targetTable = (SqlIdentifier) operand;
+      assert operand instanceof SqlIdentifier;
+      targetTable = operand;
       break;
     case 1:
       targetColumnList = (SqlNodeList) operand;

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/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 a7228af..4d07e79 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
@@ -185,11 +185,12 @@ public class SqlAdvisorValidator extends SqlValidatorImpl {
     }
   }
 
-  protected void validateNamespace(final SqlValidatorNamespace namespace) {
+  protected void validateNamespace(final SqlValidatorNamespace namespace,
+      RelDataType targetRowType) {
     // Only attempt to validate each namespace once. Otherwise if
     // validation fails, we may end up cycling.
     if (activeNamespaces.add(namespace)) {
-      super.validateNamespace(namespace);
+      super.validateNamespace(namespace, targetRowType);
     } else {
       namespace.setType(emptyStructType);
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/type/ExplicitOperandTypeInference.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/ExplicitOperandTypeInference.java b/core/src/main/java/org/apache/calcite/sql/type/ExplicitOperandTypeInference.java
index 684388e..64b1025 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/ExplicitOperandTypeInference.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/ExplicitOperandTypeInference.java
@@ -44,7 +44,12 @@ public class ExplicitOperandTypeInference implements SqlOperandTypeInference {
       SqlCallBinding callBinding,
       RelDataType returnType,
       RelDataType[] operandTypes) {
-    assert operandTypes.length == paramTypes.size();
+    if (operandTypes.length != paramTypes.size()) {
+      // This call does not match the inference strategy.
+      // It's likely that we're just about to give a validation error.
+      // Don't make a fuss, just give up.
+      return;
+    }
     paramTypes.toArray(operandTypes);
   }
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java
index c0c1971..9ddf257 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java
@@ -75,7 +75,7 @@ abstract class AbstractNamespace implements SqlValidatorNamespace {
     return validator;
   }
 
-  public final void validate() {
+  public final void validate(RelDataType targetRowType) {
     switch (status) {
     case UNVALIDATED:
       try {
@@ -83,7 +83,7 @@ abstract class AbstractNamespace implements SqlValidatorNamespace {
         Util.permAssert(
             rowType == null,
             "Namespace.rowType must be null before validate has been called");
-        RelDataType type = validateImpl();
+        RelDataType type = validateImpl(targetRowType);
         Util.permAssert(
             type != null,
             "validateImpl() returned null");
@@ -116,12 +116,15 @@ abstract class AbstractNamespace implements SqlValidatorNamespace {
    * {@link #status} field to protect against cycles.
    *
    * @return record data type, never null
+   *
+   * @param targetRowType Desired row type, must not be null, may be the data
+   *                      type 'unknown'.
    */
-  protected abstract RelDataType validateImpl();
+  protected abstract RelDataType validateImpl(RelDataType targetRowType);
 
   public RelDataType getRowType() {
     if (rowType == null) {
-      validator.validateNamespace(this);
+      validator.validateNamespace(this, validator.unknownType);
       Util.permAssert(rowType != null, "validate must set rowType");
     }
     return rowType;

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/AliasNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AliasNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/AliasNamespace.java
index d425ceb..a2192c9 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/AliasNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/AliasNamespace.java
@@ -63,7 +63,7 @@ public class AliasNamespace extends AbstractNamespace {
 
   //~ Methods ----------------------------------------------------------------
 
-  protected RelDataType validateImpl() {
+  protected RelDataType validateImpl(RelDataType targetRowType) {
     final List<String> nameList = new ArrayList<String>();
     final List<SqlNode> operands = call.getOperandList();
     final SqlValidatorNamespace childNs =

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/CollectNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/CollectNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/CollectNamespace.java
index f076358..e06a945 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/CollectNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/CollectNamespace.java
@@ -64,7 +64,7 @@ public class CollectNamespace extends AbstractNamespace {
 
   //~ Methods ----------------------------------------------------------------
 
-  protected RelDataType validateImpl() {
+  protected RelDataType validateImpl(RelDataType targetRowType) {
     return child.getOperator().deriveType(validator, scope, child);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java
index 6dfb3fd..7794002 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java
@@ -68,8 +68,8 @@ public abstract class DelegatingNamespace implements SqlValidatorNamespace {
     return namespace.getType();
   }
 
-  public void validate() {
-    namespace.validate();
+  public void validate(RelDataType targetRowType) {
+    namespace.validate(targetRowType);
   }
 
   public SqlNode getNode() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/FieldNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/FieldNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/FieldNamespace.java
index bf6fcbe..f685d37 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/FieldNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/FieldNamespace.java
@@ -49,7 +49,7 @@ class FieldNamespace extends AbstractNamespace {
     throw new UnsupportedOperationException();
   }
 
-  protected RelDataType validateImpl() {
+  protected RelDataType validateImpl(RelDataType targetRowType) {
     return rowType;
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
index 7b46690..5133f50 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
@@ -100,7 +100,7 @@ public class IdentifierNamespace extends AbstractNamespace {
     }
   }
 
-  public RelDataType validateImpl() {
+  public RelDataType validateImpl(RelDataType targetRowType) {
     resolvedNamespace = parentScope.getTableNamespace(id.names);
     if (resolvedNamespace == null) {
       throw validator.newValidationError(id,

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java
index 464d84c..ded36b0 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java
@@ -38,7 +38,7 @@ class JoinNamespace extends AbstractNamespace {
 
   //~ Methods ----------------------------------------------------------------
 
-  protected RelDataType validateImpl() {
+  protected RelDataType validateImpl(RelDataType targetRowType) {
     RelDataType leftType =
         validator.getNamespace(join.getLeft()).getRowType();
     RelDataType rightType =

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/ParameterNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/ParameterNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/ParameterNamespace.java
index 9d9d8ba..5fb41cf 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/ParameterNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/ParameterNamespace.java
@@ -42,7 +42,7 @@ class ParameterNamespace extends AbstractNamespace {
     return null;
   }
 
-  public RelDataType validateImpl() {
+  public RelDataType validateImpl(RelDataType targetRowType) {
     return type;
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/ProcedureNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/ProcedureNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/ProcedureNamespace.java
index e436527..1b226a7 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/ProcedureNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/ProcedureNamespace.java
@@ -48,7 +48,7 @@ public class ProcedureNamespace extends AbstractNamespace {
 
   //~ Methods ----------------------------------------------------------------
 
-  public RelDataType validateImpl() {
+  public RelDataType validateImpl(RelDataType targetRowType) {
     validator.inferUnknownTypes(validator.unknownType, scope, call);
     final RelDataType type = validator.deriveTypeImpl(scope, call);
     final SqlOperator operator = call.getOperator();

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/SchemaNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SchemaNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/SchemaNamespace.java
index e8347c4..49e21f3 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SchemaNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SchemaNamespace.java
@@ -40,7 +40,7 @@ class SchemaNamespace extends AbstractNamespace {
     this.names = Preconditions.checkNotNull(names);
   }
 
-  protected RelDataType validateImpl() {
+  protected RelDataType validateImpl(RelDataType targetRowType) {
     final RelDataTypeFactory.FieldInfoBuilder builder =
         validator.getTypeFactory().builder();
     for (SqlMoniker moniker

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java
index 48a45c1..c0a2dec 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java
@@ -56,8 +56,8 @@ public class SelectNamespace extends AbstractNamespace {
     return select;
   }
 
-  public RelDataType validateImpl() {
-    validator.validateSelect(select, validator.unknownType);
+  public RelDataType validateImpl(RelDataType targetRowType) {
+    validator.validateSelect(select, targetRowType);
     return rowType;
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/SetopNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SetopNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/SetopNamespace.java
index c2ec583..adc6e6d 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SetopNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SetopNamespace.java
@@ -89,7 +89,7 @@ public class SetopNamespace extends AbstractNamespace {
     return SqlMonotonicity.NOT_MONOTONIC;
   }
 
-  public RelDataType validateImpl() {
+  public RelDataType validateImpl(RelDataType targetRowType) {
     switch (call.getKind()) {
     case UNION:
     case INTERSECT:
@@ -100,7 +100,7 @@ public class SetopNamespace extends AbstractNamespace {
           throw validator.newValidationError(operand,
               RESOURCE.needQueryOp(operand.toString()));
         }
-        validator.validateQuery(operand, scope);
+        validator.validateQuery(operand, scope, targetRowType);
       }
       return call.getOperator().deriveType(
           validator,

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/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 1adc9d8..605c665 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
@@ -166,9 +166,12 @@ public interface SqlValidator {
    *
    * @param node  Query node
    * @param scope Scope in which the query occurs
+   * @param targetRowType Desired row type, must not be null, may be the data
+   *                      type 'unknown'.
    * @throws RuntimeException if the query is not valid
    */
-  void validateQuery(SqlNode node, SqlValidatorScope scope);
+  void validateQuery(SqlNode node, SqlValidatorScope scope,
+      RelDataType targetRowType);
 
   /**
    * Returns the type assigned to a node by validation.

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/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 df95dd6..9551a16 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
@@ -335,6 +335,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       expandSelectItem(
           selectItem,
           select,
+          unknownType,
           list,
           new LinkedHashSet<String>(),
           types,
@@ -399,6 +400,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
   private boolean expandSelectItem(
       final SqlNode selectItem,
       SqlSelect select,
+      RelDataType targetType,
       List<SqlNode> selectItems,
       Set<String> aliases,
       List<Map.Entry<String, RelDataType>> types,
@@ -438,6 +440,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     selectItems.add(expanded);
     aliases.add(alias);
 
+    inferUnknownTypes(targetType, scope, expanded);
     final RelDataType type = deriveType(selectScope, expanded);
     setValidatedNodeTypeImpl(expanded, type);
     types.add(Pair.of(alias, type));
@@ -847,7 +850,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     return outermostNode;
   }
 
-  public void validateQuery(SqlNode node, SqlValidatorScope scope) {
+  public void validateQuery(SqlNode node, SqlValidatorScope scope,
+      RelDataType targetRowType) {
     final SqlValidatorNamespace ns = getNamespace(node, scope);
     if (node.getKind() == SqlKind.TABLESAMPLE) {
       List<SqlNode> operands = ((SqlCall) node).getOperandList();
@@ -861,7 +865,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       }
     }
 
-    validateNamespace(ns);
+    validateNamespace(ns, targetRowType);
     if (node == top) {
       validateModality(node);
     }
@@ -873,9 +877,14 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
 
   /**
    * Validates a namespace.
+   *
+   * @param namespace Namespace
+   * @param targetRowType Desired row type, must not be null, may be the data
+   *                      type 'unknown'.
    */
-  protected void validateNamespace(final SqlValidatorNamespace namespace) {
-    namespace.validate();
+  protected void validateNamespace(final SqlValidatorNamespace namespace,
+      RelDataType targetRowType) {
+    namespace.validate(targetRowType);
     if (namespace.getNode() != null) {
       setValidatedNodeType(namespace.getNode(), namespace.getType());
     }
@@ -1629,25 +1638,19 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
         inferUnknownTypes(type, scope, child);
       }
     } else if (node instanceof SqlCase) {
-      // REVIEW wael: can this be done in a paramtypeinference strategy
-      // object?
-      SqlCase caseCall = (SqlCase) node;
-      RelDataType returnType = deriveType(scope, node);
+      final SqlCase caseCall = (SqlCase) node;
 
-      SqlNodeList whenList = caseCall.getWhenOperands();
-      for (int i = 0; i < whenList.size(); i++) {
-        SqlNode sqlNode = whenList.get(i);
-        inferUnknownTypes(unknownType, scope, sqlNode);
+      final RelDataType whenType =
+          caseCall.getValueOperand() == null ? booleanType : unknownType;
+      for (SqlNode sqlNode : caseCall.getWhenOperands().getList()) {
+        inferUnknownTypes(whenType, scope, sqlNode);
       }
-      SqlNodeList thenList = caseCall.getThenOperands();
-      for (int i = 0; i < thenList.size(); i++) {
-        SqlNode sqlNode = thenList.get(i);
+      RelDataType returnType = deriveType(scope, node);
+      for (SqlNode sqlNode : caseCall.getThenOperands().getList()) {
         inferUnknownTypes(returnType, scope, sqlNode);
       }
 
-      if (!SqlUtil.isNullLiteral(
-          caseCall.getElseOperand(),
-          false)) {
+      if (!SqlUtil.isNullLiteral(caseCall.getElseOperand(), false)) {
         inferUnknownTypes(
             returnType,
             scope,
@@ -2787,13 +2790,13 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       validateOver((SqlCall) node, scope);
       break;
     default:
-      validateQuery(node, scope);
+      validateQuery(node, scope, targetRowType);
       break;
     }
 
     // Validate the namespace representation of the node, just in case the
     // validation did not occur implicitly.
-    getNamespace(node, scope).validate();
+    getNamespace(node, scope).validate(targetRowType);
   }
 
   protected void validateOver(SqlCall call, SqlValidatorScope scope) {
@@ -3220,7 +3223,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
 
   public void validateWith(SqlWith with, SqlValidatorScope scope) {
     final SqlValidatorNamespace namespace = getNamespace(with);
-    validateNamespace(namespace);
+    validateNamespace(namespace, unknownType);
   }
 
   public void validateWithItem(SqlWithItem withItem) {
@@ -3499,6 +3502,10 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
         expandSelectItem(
             selectItem,
             select,
+            targetRowType.isStruct()
+                && targetRowType.getFieldCount() >= i
+                ? targetRowType.getFieldList().get(i).getType()
+                : unknownType,
             expandedSelectItems,
             aliases,
             fieldList,
@@ -3656,7 +3663,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
 
   public void validateInsert(SqlInsert insert) {
     SqlValidatorNamespace targetNamespace = getNamespace(insert);
-    validateNamespace(targetNamespace);
+    validateNamespace(targetNamespace, unknownType);
     SqlValidatorTable table = targetNamespace.getTable();
 
     // INSERT has an optional column name list.  If present then
@@ -3674,7 +3681,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       validateSelect(sqlSelect, targetRowType);
     } else {
       SqlValidatorScope scope = scopes.get(source);
-      validateQuery(source, scope);
+      validateQuery(source, scope, targetRowType);
     }
 
     // REVIEW jvs 4-Dec-2008: In FRG-365, this namespace row type is
@@ -3813,7 +3820,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     IdentifierNamespace targetNamespace =
         getNamespace(call.getTargetTable()).unwrap(
             IdentifierNamespace.class);
-    validateNamespace(targetNamespace);
+    validateNamespace(targetNamespace, unknownType);
     SqlValidatorTable table = targetNamespace.getTable();
 
     validateAccess(call.getTargetTable(), table, SqlAccessEnum.DELETE);
@@ -3823,7 +3830,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     IdentifierNamespace targetNamespace =
         getNamespace(call.getTargetTable()).unwrap(
             IdentifierNamespace.class);
-    validateNamespace(targetNamespace);
+    validateNamespace(targetNamespace, unknownType);
     SqlValidatorTable table = targetNamespace.getTable();
 
     RelDataType targetRowType =
@@ -3857,7 +3864,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     // Let's use the update/insert targetRowType when available.
     IdentifierNamespace targetNamespace =
         (IdentifierNamespace) getNamespace(call.getTargetTable());
-    validateNamespace(targetNamespace);
+    validateNamespace(targetNamespace, unknownType);
 
     SqlValidatorTable table = targetNamespace.getTable();
     validateAccess(call.getTargetTable(), table, SqlAccessEnum.UPDATE);

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java
index 007028d..db9fd3a 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java
@@ -83,7 +83,7 @@ public interface SqlValidatorNamespace {
    * Sets the type of this namespace.
    *
    * <p>Allows the type for the namespace to be explicitly set, but usually is
-   * called during {@link #validate()}.</p>
+   * called during {@link #validate(RelDataType)}.</p>
    *
    * <p>Implicitly also sets the row type. If the type is not a struct, then
    * the row type is the type wrapped as a struct with a single column,
@@ -105,8 +105,11 @@ public interface SqlValidatorNamespace {
    *
    * <p>Please call {@link SqlValidatorImpl#validateNamespace} rather than
    * calling this method directly.</p>
+   *
+   * @param targetRowType Desired row type, must not be null, may be the data
+   *                      type 'unknown'.
    */
-  void validate();
+  void validate(RelDataType targetRowType);
 
   /**
    * Returns the parse tree node at the root of this namespace.
@@ -192,7 +195,7 @@ public interface SqlValidatorNamespace {
    * (the body of the with-item). An {@link IdentifierNamespace} typically
    * resolves to a {@link TableNamespace}.</p>
    *
-   * <p>You must not call this method before {@link #validate()} has
+   * <p>You must not call this method before {@link #validate(RelDataType)} has
    * completed.</p> */
   SqlValidatorNamespace resolve();
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/TableConstructorNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/TableConstructorNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/TableConstructorNamespace.java
index da8a22f..b590f61 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/TableConstructorNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/TableConstructorNamespace.java
@@ -18,7 +18,6 @@ package org.apache.calcite.sql.validate;
 
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.sql.SqlCall;
-import org.apache.calcite.sql.SqlInsert;
 import org.apache.calcite.sql.SqlNode;
 
 import static org.apache.calcite.util.Static.RESOURCE;
@@ -54,16 +53,9 @@ public class TableConstructorNamespace extends AbstractNamespace {
 
   //~ Methods ----------------------------------------------------------------
 
-  protected RelDataType validateImpl() {
+  protected RelDataType validateImpl(RelDataType targetRowType) {
     // First, validate the VALUES. If VALUES is inside INSERT, infers
     // the type of NULL values based on the types of target columns.
-    final RelDataType targetRowType;
-    if (enclosingNode instanceof SqlInsert) {
-      SqlInsert node = (SqlInsert) enclosingNode;
-      targetRowType = validator.getValidatedNodeType(node);
-    } else {
-      targetRowType = validator.getUnknownType();
-    }
     validator.validateValues(values, targetRowType, scope);
     final RelDataType tableConstructorRowType =
         validator.getTableConstructorRowType(values, scope);

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/TableNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/TableNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/TableNamespace.java
index 044d41b..d354c5d 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/TableNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/TableNamespace.java
@@ -44,7 +44,7 @@ class TableNamespace extends AbstractNamespace {
     this(validator, table, ImmutableList.<RelDataTypeField>of());
   }
 
-  protected RelDataType validateImpl() {
+  protected RelDataType validateImpl(RelDataType targetRowType) {
     if (extendedFields.isEmpty()) {
       return table.getRowType();
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java
index 68c1108..3eee0a8 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java
@@ -47,7 +47,7 @@ class UnnestNamespace extends AbstractNamespace {
 
   //~ Methods ----------------------------------------------------------------
 
-  protected RelDataType validateImpl() {
+  protected RelDataType validateImpl(RelDataType targetRowType) {
     // Validate the call and its arguments, and infer the return type.
     validator.validateCall(unnest, scope);
     RelDataType type =

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/WithItemNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/WithItemNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/WithItemNamespace.java
index 040f080..8173349 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/WithItemNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/WithItemNamespace.java
@@ -34,7 +34,7 @@ class WithItemNamespace extends AbstractNamespace {
     this.withItem = withItem;
   }
 
-  @Override protected RelDataType validateImpl() {
+  @Override protected RelDataType validateImpl(RelDataType targetRowType) {
     final SqlValidatorNamespace childNs =
         validator.getNamespace(withItem.query);
     final RelDataType rowType = childNs.getRowTypeSansSystemColumns();

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java
index d3cfb9a..e02e794 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java
@@ -48,13 +48,13 @@ public class WithNamespace extends AbstractNamespace {
 
   //~ Methods ----------------------------------------------------------------
 
-  protected RelDataType validateImpl() {
+  protected RelDataType validateImpl(RelDataType targetRowType) {
     for (SqlNode withItem : with.withList) {
       validator.validateWithItem((SqlWithItem) withItem);
     }
     final SqlValidatorScope scope2 =
         validator.getWithScope(Util.last(with.withList.getList()));
-    validator.validateQuery(with.body, scope2);
+    validator.validateQuery(with.body, scope2, targetRowType);
     final RelDataType rowType = validator.getValidatedNodeType(with.body);
     validator.setValidatedNodeType(with, rowType);
     return rowType;

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 6c24eee..a9ab66f 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -1880,7 +1880,7 @@ public abstract class SqlOperatorBaseTest {
     // both are valid
     tester.check(
         "values 1 > 2 and sqrt(-4) = -2",
-        SqlTests.BOOLEAN_TYPE_CHECKER,
+        SqlTests.BOOLEAN_TYPE_CHECKER, SqlTests.ANY_PARAMETER_CHECKER,
         new ValueOrExceptionResultChecker(
             Boolean.FALSE, INVALID_ARG_FOR_POWER, CODE_2201F));
   }
@@ -2759,7 +2759,7 @@ public abstract class SqlOperatorBaseTest {
     // get error
     tester.check(
         "values 1 < cast(null as integer) or sqrt(-4) = -2",
-        SqlTests.BOOLEAN_TYPE_CHECKER,
+        SqlTests.BOOLEAN_TYPE_CHECKER, SqlTests.ANY_PARAMETER_CHECKER,
         new ValueOrExceptionResultChecker(
             null, INVALID_ARG_FOR_POWER, CODE_2201F));
 
@@ -2769,7 +2769,7 @@ public abstract class SqlOperatorBaseTest {
     // both are valid.
     tester.check(
         "values 1 < 2 or sqrt(-4) = -2",
-        SqlTests.BOOLEAN_TYPE_CHECKER,
+        SqlTests.BOOLEAN_TYPE_CHECKER, SqlTests.ANY_PARAMETER_CHECKER,
         new ValueOrExceptionResultChecker(
             Boolean.TRUE, INVALID_ARG_FOR_POWER, CODE_2201F));
 
@@ -2779,7 +2779,7 @@ public abstract class SqlOperatorBaseTest {
     // both are valid.
     tester.check(
         "values 1 < cast(null as integer) or sqrt(4) = -2",
-        SqlTests.BOOLEAN_TYPE_CHECKER,
+        SqlTests.BOOLEAN_TYPE_CHECKER, SqlTests.ANY_PARAMETER_CHECKER,
         new ValueOrExceptionResultChecker(
             null, INVALID_ARG_FOR_POWER, CODE_2201F));
 
@@ -5419,7 +5419,7 @@ public abstract class SqlOperatorBaseTest {
                 query = SqlTesterImpl.buildQuery(s);
               }
               tester.check(query, SqlTests.ANY_TYPE_CHECKER,
-                  SqlTests.ANY_RESULT_CHECKER);
+                  SqlTests.ANY_PARAMETER_CHECKER, SqlTests.ANY_RESULT_CHECKER);
             }
           } catch (Error e) {
             System.out.println(s + ": " + e.getMessage());
@@ -5558,14 +5558,9 @@ public abstract class SqlOperatorBaseTest {
       super(testFactory);
     }
 
-    @Override public void check(
-        String query,
-        TypeChecker typeChecker,
-        ResultChecker resultChecker) {
-      super.check(
-          query,
-          typeChecker,
-          resultChecker);
+    @Override public void check(String query, TypeChecker typeChecker,
+        ParameterChecker parameterChecker, ResultChecker resultChecker) {
+      super.check(query, typeChecker, parameterChecker, resultChecker);
       //noinspection unchecked
       final CalciteAssert.ConnectionFactory connectionFactory =
           (CalciteAssert.ConnectionFactory)

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/test/java/org/apache/calcite/sql/test/SqlTester.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlTester.java b/core/src/test/java/org/apache/calcite/sql/test/SqlTester.java
index 2873c6d..95a02d4 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlTester.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlTester.java
@@ -269,12 +269,15 @@ public interface SqlTester extends AutoCloseable, SqlValidatorTestCase.Tester {
    * @param query         SQL query
    * @param typeChecker   Checks whether the result is the expected type; must
    *                      not be null
+   * @param parameterChecker Checks whether the parameters are of expected
+   *                      types
    * @param resultChecker Checks whether the result has the expected value;
    *                      must not be null
    */
   void check(
       String query,
       TypeChecker typeChecker,
+      ParameterChecker parameterChecker,
       ResultChecker resultChecker);
 
   /**
@@ -297,15 +300,6 @@ public interface SqlTester extends AutoCloseable, SqlValidatorTestCase.Tester {
       VmName... unimplementedVmNames);
 
   /**
-   * Checks to see if this tester is for the given VmName. Return false if
-   * no vm associated with this tester.
-   *
-   * @param vmName VmName to check for.
-   * @return whether or not this tester is for the given VmName.
-   */
-  boolean isVm(VmName vmName);
-
-  /**
    * Checks that an aggregate expression returns the expected result.
    *
    * <p>For example, <code>checkAgg("AVG(DISTINCT x)", new String[] {"2", "3",
@@ -383,6 +377,11 @@ public interface SqlTester extends AutoCloseable, SqlValidatorTestCase.Tester {
     void checkType(RelDataType type);
   }
 
+  /** Parameter checker. */
+  interface ParameterChecker {
+    void checkParameters(RelDataType parameterRowType);
+  }
+
   /** Result checker. */
   interface ResultChecker {
     void checkResult(ResultSet result) throws Exception;

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java b/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
index 4770344..f9f1bd1 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
@@ -440,25 +440,31 @@ public class SqlTesterImpl implements SqlTester {
       TypeChecker typeChecker,
       Object result,
       double delta) {
-    check(
-        query,
-        typeChecker,
+    check(query, typeChecker, SqlTests.ANY_PARAMETER_CHECKER,
         SqlTests.createChecker(result, delta));
   }
 
-  public void check(
-      String query,
-      TypeChecker typeChecker,
-      ResultChecker resultChecker) {
+  public void check(String query, TypeChecker typeChecker,
+      ParameterChecker parameterChecker, ResultChecker resultChecker) {
     // This implementation does NOT check the result!
-    // (It can't because we're pure Java.)
     // All it does is check the return type.
 
-    // Parse and validate. There should be no errors.
-    RelDataType actualType = getColumnType(query);
+    if (typeChecker == null) {
+      // Parse and validate. There should be no errors.
+      Util.discard(getResultType(query));
+    } else {
+      // Parse and validate. There should be no errors.
+      // There must be 1 column. Get its type.
+      RelDataType actualType = getColumnType(query);
+
+      // Check result type.
+      typeChecker.checkType(actualType);
+    }
 
-    // Check result type.
-    typeChecker.checkType(actualType);
+    SqlValidator validator = getValidator();
+    SqlNode n = parseAndValidate(validator, query);
+    final RelDataType parameterRowType = validator.getParameterRowType(n);
+    parameterChecker.checkParameters(parameterRowType);
   }
 
   public void checkMonotonic(String query,
@@ -681,9 +687,6 @@ public class SqlTesterImpl implements SqlTester {
     };
   }
 
-  public boolean isVm(VmName vmName) {
-    return false;
-  }
 }
 
 // End SqlTesterImpl.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java b/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
index d5889fb..ea4091b 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
@@ -27,6 +27,7 @@ import java.util.HashSet;
 import java.util.Set;
 import java.util.regex.Pattern;
 
+import static org.apache.calcite.sql.test.SqlTester.ParameterChecker;
 import static org.apache.calcite.sql.test.SqlTester.ResultChecker;
 import static org.apache.calcite.sql.test.SqlTester.TypeChecker;
 
@@ -58,6 +59,15 @@ public abstract class SqlTests {
       };
 
   /**
+   * Checker that allows any number or type of parameters.
+   */
+  public static final ParameterChecker ANY_PARAMETER_CHECKER =
+      new ParameterChecker() {
+        public void checkParameters(RelDataType parameterRowType) {
+        }
+      };
+
+  /**
    * Helper function to get the string representation of a RelDataType
    * (include precision/scale but no charset or collation)
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java b/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
index c09fb0b..58c7783 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
@@ -30,6 +30,9 @@ import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.schema.impl.AbstractTableQueryable;
 
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -48,7 +51,9 @@ import java.util.Properties;
 import static org.apache.calcite.test.CalciteAssert.hr;
 import static org.apache.calcite.test.CalciteAssert.that;
 
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -239,6 +244,36 @@ public class JdbcFrontLinqBackTest {
             "name=Sebastian; C=2");
   }
 
+  @Test public void testInsertBind() throws Exception {
+    final List<JdbcTest.Employee> employees = new ArrayList<>();
+    CalciteAssert.AssertThat with = mutable(employees);
+    with.query("select count(*) as c from \"foo\".\"bar\"")
+        .returns("C=1\n");
+    with.doWithConnection(
+        new Function<CalciteConnection, Object>() {
+          public Object apply(CalciteConnection c) {
+            try {
+              final String sql = "insert into \"foo\".\"bar\"\n"
+                  + "values (?, 0, ?, 10.0, null)";
+              try (PreparedStatement p = c.prepareStatement(sql)) {
+                p.setInt(1, 1);
+                p.setString(2, "foo");
+                final int count = p.executeUpdate();
+                assertThat(count, is(1));
+              }
+              return null;
+            } catch (SQLException e) {
+              throw Throwables.propagate(e);
+            }
+          }
+        });
+    with.query("select count(*) as c from \"foo\".\"bar\"")
+        .returns("C=2\n");
+    with.query("select * from \"foo\".\"bar\"")
+        .returnsUnordered("empid=0; deptno=0; name=first; salary=0.0; commission=null",
+            "empid=1; deptno=0; name=foo; salary=10.0; commission=null");
+  }
+
   /**
    * Creates the post processor routine to be applied against a Connection.
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/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 bc8c5e4..4a29961 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -70,7 +70,6 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
    * yellow in Intellij and maybe someone will fix them.
    */
   protected static final boolean TODO = false;
-  public static final boolean TODO_TYPE_INFERENCE = false;
   private static final String ANY = "(?s).*";
 
   protected static final Logger LOGGER =
@@ -6560,19 +6559,21 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
   }
 
   @Test public void testBind() {
-    check("select * from emp where deptno = ?");
-    check("select * from emp where deptno = ? and sal < 100000");
-    if (TODO_TYPE_INFERENCE) {
-      check("select case when deptno = ? then 1 else 2 end from emp");
-    }
-    if (TODO_TYPE_INFERENCE) {
-      check("select deptno from emp group by substring(name from ? for ?)");
-    }
-    if (TODO_TYPE_INFERENCE) {
-      check("select deptno from emp\n"
-          + "group by case when deptno = ? then 1 else 2 end");
-    }
-    check("select 1 from emp having sum(sal) < ?");
+    sql("select * from emp where deptno = ?").ok();
+    sql("select * from emp where deptno = ? and sal < 100000").ok();
+    sql("select case when deptno = ? then 1 else 2 end from emp").ok();
+    // It is not possible to infer type of ?, because SUBSTRING is overloaded
+    sql("select deptno from emp group by substring(name from ^?^ for ?)")
+        .fails("Illegal use of dynamic parameter");
+    // In principle we could infer that ? should be a VARCHAR
+    sql("select count(*) from emp group by position(^?^ in ename)")
+        .fails("Illegal use of dynamic parameter");
+    sql("select ^deptno^ from emp\n"
+        + "group by case when deptno = ? then 1 else 2 end")
+        .fails("Expression 'DEPTNO' is not being grouped");
+    sql("select deptno from emp\n"
+        + "group by deptno, case when deptno = ? then 1 else 2 end").ok();
+    sql("select 1 from emp having sum(sal) < ?").ok();
   }
 
   @Test public void testUnnest() {
@@ -7451,6 +7452,57 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
         + "select 1, 1 from (values 'a')");
   }
 
+  @Test public void testInsertBind() {
+    // VALUES
+    sql("insert into emp (empno, deptno) values (?, ?)")
+        .ok()
+        .bindType("RecordType(INTEGER ?0, INTEGER ?1)");
+
+    // multiple VALUES
+    sql("insert into emp (empno, deptno) values (?, 1), (2, ?), (3, null)")
+        .ok()
+        .bindType("RecordType(INTEGER ?0, INTEGER ?1)");
+
+    // VALUES with expression
+    sql("insert into emp (ename, deptno) values (?, ? + 1)")
+        .ok()
+        .bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
+
+    // SELECT
+    sql("insert into emp (ename, deptno) select ?, ? from (values (1))")
+        .ok()
+        .bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
+
+    // WITH
+    final String sql = "insert into emp (ename, deptno)\n"
+        + "with v as (values ('a'))\n"
+        + "select ?, ? from (values (1))";
+    sql(sql).ok().bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
+
+    // UNION
+    final String sql2 = "insert into emp (ename, deptno)\n"
+        + "select ?, ? from (values (1))\n"
+        + "union all\n"
+        + "select ?, ? from (values (time '1:2:3'))";
+    final String expected2 = "RecordType(VARCHAR(20) ?0, INTEGER ?1,"
+        + " VARCHAR(20) ?2, INTEGER ?3)";
+    sql(sql2).ok().bindType(expected2);
+  }
+
+  @Test public void testUpdateBind() {
+    final String sql = "update emp\n"
+        + "set ename = ?\n"
+        + "where deptno = ?";
+    sql(sql).ok().bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
+  }
+
+  @Test public void testDeleteBind() {
+    final String sql = "delete from emp\n"
+        + "where deptno = ?\n"
+        + "or ename = ?";
+    sql(sql).ok().bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1)");
+  }
+
   @Test public void testStream() {
     sql("select stream * from orders").ok();
     sql("select stream * from ^emp^")

http://git-wip-us.apache.org/repos/asf/calcite/blob/f191a386/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
index 6860851..025de3a 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
@@ -25,6 +25,7 @@ import org.apache.calcite.sql.parser.SqlParserUtil;
 import org.apache.calcite.sql.test.DefaultSqlTestFactory;
 import org.apache.calcite.sql.test.SqlTester;
 import org.apache.calcite.sql.test.SqlTesterImpl;
+import org.apache.calcite.sql.test.SqlTests;
 import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
@@ -35,6 +36,8 @@ import java.nio.charset.Charset;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
@@ -566,6 +569,17 @@ public class SqlValidatorTestCase {
       tester.checkMonotonic(sql, expectedMonotonicity);
       return this;
     }
+
+    public Sql bindType(final String bindType) {
+      tester.check(sql, null,
+          new SqlTester.ParameterChecker() {
+            public void checkParameters(RelDataType parameterRowType) {
+              assertThat(parameterRowType.toString(), is(bindType));
+            }
+          },
+          SqlTests.ANY_RESULT_CHECKER);
+      return this;
+    }
   }
 }