diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java index 91fe45db4b382..9bf66bd52574a 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java @@ -105,6 +105,9 @@ public class IgniteSqlValidator extends SqlValidatorImpl { /** Dynamic parameters. */ @Nullable private final Object[] parameters; + /** */ + private final RelDataType nullType; + /** * Creates a validator. * @@ -124,6 +127,8 @@ public IgniteSqlValidator( super(opTab, catalogReader, typeFactory, cfg); this.parameters = parameters; + + nullType = typeFactory.createSqlType(SqlTypeName.NULL); } /** {@inheritDoc} */ @@ -543,7 +548,7 @@ private boolean isSystemFieldName(String alias) { /** {@inheritDoc} */ @Override public RelDataType deriveType(SqlValidatorScope scope, SqlNode expr) { if (expr instanceof SqlDynamicParam) { - RelDataType type = deriveDynamicParameterType((SqlDynamicParam)expr); + RelDataType type = deriveDynamicParameterType((SqlDynamicParam)expr, nullType); if (type != null) return type; @@ -553,23 +558,23 @@ private boolean isSystemFieldName(String alias) { } /** @return A derived type or {@code null} if unable to determine. */ - @Nullable private RelDataType deriveDynamicParameterType(SqlDynamicParam node) { + @Nullable private RelDataType deriveDynamicParameterType(SqlDynamicParam node, RelDataType nullValType) { + if (parameters == null || node.getIndex() >= parameters.length) + return null; + RelDataType type = getValidatedNodeTypeIfKnown(node); // Do not clarify the widest type for any value. if (type instanceof OtherType) return type; - if (parameters == null || node.getIndex() >= parameters.length) - return null; + if (type == nullType) + return nullValType; Object val = parameters[node.getIndex()]; - if (val == null && type != null) - return type; - type = val == null - ? typeFactory.createSqlType(SqlTypeName.NULL) + ? nullValType : typeFactory().createTypeWithNullability(typeFactory().toSql(typeFactory().createType(val.getClass())), true); setValidatedNodeType(node, type); @@ -579,8 +584,8 @@ private boolean isSystemFieldName(String alias) { /** {@inheritDoc} */ @Override protected void inferUnknownTypes(RelDataType inferredType, SqlValidatorScope scope, SqlNode node) { - if (node instanceof SqlDynamicParam && unknownType.equals(inferredType) - && deriveDynamicParameterType((SqlDynamicParam)node) != null) + if (node instanceof SqlDynamicParam && !(inferredType instanceof OtherType) + && deriveDynamicParameterType((SqlDynamicParam)node, unknownType.equals(inferredType) ? nullType : inferredType) != null) return; if (node instanceof SqlCall) { diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DynamicParametersIntegrationTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DynamicParametersIntegrationTest.java index cbfc657123ecb..af3f92dd25b89 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DynamicParametersIntegrationTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DynamicParametersIntegrationTest.java @@ -105,6 +105,15 @@ public void testCasts() { /** */ @Test public void testDynamicParameters() { + assertQuery("select 1 + ?").withParams(1).returns(2).check(); + assertQuery("select ? + 1").withParams(1).returns(2).check(); + assertQuery("select 1 + CAST(? AS INTEGER)").withParams(2L).returns(3).check(); + assertQuery("select CAST(? AS INTEGER) + 1").withParams(2L).returns(3).check(); + assertQuery("select 1 + ?").withParams(1L).returns(2L).check(); + assertQuery("select ? + 1").withParams(1L).returns(2L).check(); + assertQuery("select 1 + ?").withParams(new BigDecimal("2")).returns(new BigDecimal(3)).check(); + assertQuery("select ? + 1").withParams(new BigDecimal("2")).returns(new BigDecimal(3)).check(); + assertQuery("SELECT COALESCE(?, ?)").withParams("a", 10).returns("a").check(); assertQuery("SELECT COALESCE(null, ?)").withParams(13).returns(13).check(); assertQuery("SELECT LOWER(?)").withParams("ASD").returns("asd").check(); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java index ec08ff5dac1b2..71f290d54cf41 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java @@ -145,6 +145,9 @@ public void testParseSelectAndUnion() throws Exception { checkQuery("select (select 1)"); checkQuery("select (select 1, select ?)"); checkQuery("select ((select 1), select ? + ?)"); + checkQuery("select 1 + ?"); + checkQuery("select ? + 1"); + checkQuery("select ? + ?"); checkQuery("select CURRENT_DATE"); checkQuery("select CURRENT_DATE()");