You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2019/02/07 13:46:35 UTC
[ignite] branch master updated: IGNITE-11118: SQL: Type conversions
for thin client partition pruning. This closes #6016.
This is an automated email from the ASF dual-hosted git repository.
vozerov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 3524eb9 IGNITE-11118: SQL: Type conversions for thin client partition pruning. This closes #6016.
3524eb9 is described below
commit 3524eb9d42bd865d28326c4f82070928c5e5fd75
Author: sanpwc <la...@gmail.com>
AuthorDate: Thu Feb 7 16:46:27 2019 +0300
IGNITE-11118: SQL: Type conversions for thin client partition pruning. This closes #6016.
---
.../sql/optimizer/affinity/PartitionAllNode.java | 2 +-
...onResolver.java => PartitionClientContext.java} | 19 +-
.../optimizer/affinity/PartitionCompositeNode.java | 27 +-
.../optimizer/affinity/PartitionConstantNode.java | 2 +-
.../optimizer/affinity/PartitionDataTypeUtils.java | 528 +++++++++++++++++++++
.../sql/optimizer/affinity/PartitionGroupNode.java | 13 +-
.../sql/optimizer/affinity/PartitionNode.java | 4 +-
.../sql/optimizer/affinity/PartitionNoneNode.java | 2 +-
.../optimizer/affinity/PartitionParameterNode.java | 36 +-
...onResolver.java => PartitionParameterType.java} | 45 +-
.../sql/optimizer/affinity/PartitionResolver.java | 1 +
.../optimizer/affinity/PartitionSingleNode.java | 14 +-
.../processors/query/h2/IgniteH2Indexing.java | 6 +-
.../query/h2/affinity/PartitionExtractor.java | 69 ++-
.../h2/twostep/SqlDataTypeConversionTest.java | 372 +++++++++++++++
.../IgniteBinaryCacheQueryTestSuite.java | 5 +-
16 files changed, 1079 insertions(+), 66 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionAllNode.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionAllNode.java
index c625089..cb9500d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionAllNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionAllNode.java
@@ -36,7 +36,7 @@ public class PartitionAllNode implements PartitionNode {
}
/** {@inheritDoc} */
- @Override public Collection<Integer> apply(Object... args) {
+ @Override public Collection<Integer> apply(PartitionClientContext cliCtx, Object... args) {
return null;
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionClientContext.java
similarity index 66%
copy from modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java
copy to modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionClientContext.java
index e606200..1d7594f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionClientContext.java
@@ -14,23 +14,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.ignite.internal.sql.optimizer.affinity;
-import org.apache.ignite.IgniteCheckedException;
+import org.jetbrains.annotations.Nullable;
/**
- * Partition resolver interface. Takes argument, data type and cache name, returns partition.
+ * Client context. Passed to partition resolver on thin clients.
*/
-public interface PartitionResolver {
+public class PartitionClientContext {
/**
* Resolve partition.
*
* @param arg Argument.
- * @param dataType Data type.
+ * @param typ Type.
* @param cacheName Cache name.
- * @return Partition.
- * @throws IgniteCheckedException If failed.
+ * @return Partition or {@code null} if cannot be resolved.
*/
- int partition(Object arg, int dataType, String cacheName) throws IgniteCheckedException;
+ @Nullable public Integer partition(Object arg, @Nullable PartitionParameterType typ, String cacheName) {
+ PartitionDataTypeUtils.convert(arg, typ);
+
+ // TODO: IGNITE-10308: Implement partition resolution logic.
+ return null;
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionCompositeNode.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionCompositeNode.java
index d724cf8..1235e6a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionCompositeNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionCompositeNode.java
@@ -56,14 +56,21 @@ public class PartitionCompositeNode implements PartitionNode {
}
/** {@inheritDoc} */
- @Override public Collection<Integer> apply(Object... args) throws IgniteCheckedException {
- Collection<Integer> leftParts = left.apply(args);
- Collection<Integer> rightParts = right.apply(args);
+ @Override public Collection<Integer> apply(PartitionClientContext cliCtx, Object... args)
+ throws IgniteCheckedException {
+ Collection<Integer> leftParts = left.apply(cliCtx, args);
+ Collection<Integer> rightParts = right.apply(cliCtx, args);
+
+ // Failed to resolve partitions on both sides, return.
+ if (leftParts == null && rightParts == null)
+ return null;
if (op == PartitionCompositeNodeOperator.AND) {
- // () and (...) -> ()
- if (leftParts == null || rightParts == null)
- return null;
+ // (ALL) and (...) -> (...)
+ if (leftParts == null)
+ return rightParts;
+ else if (rightParts == null)
+ return leftParts;
// (A, B) and (B, C) -> (B)
leftParts = new HashSet<>(leftParts);
@@ -73,11 +80,9 @@ public class PartitionCompositeNode implements PartitionNode {
else {
assert op == PartitionCompositeNodeOperator.OR;
- // () or (...) -> (...)
- if (leftParts == null)
- return rightParts;
- else if (rightParts == null)
- return leftParts;
+ // (ALL) or (...) -> (ALL)
+ if (leftParts == null || rightParts == null)
+ return null;
// (A, B) or (B, C) -> (A, B, C)
leftParts = new HashSet<>(leftParts);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionConstantNode.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionConstantNode.java
index da9dca2..24037bd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionConstantNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionConstantNode.java
@@ -39,7 +39,7 @@ public class PartitionConstantNode extends PartitionSingleNode {
}
/** {@inheritDoc} */
- @Override public int applySingle(Object... args) {
+ @Override public Integer applySingle(PartitionClientContext cliCtx, Object... args) {
return part;
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionDataTypeUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionDataTypeUtils.java
new file mode 100644
index 0000000..cbb9810
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionDataTypeUtils.java
@@ -0,0 +1,528 @@
+/*
+ * 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.ignite.internal.sql.optimizer.affinity;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Utility methods for partition extractor.
+ */
+public class PartitionDataTypeUtils {
+ /** Decimal representation of maximum long value. */
+ private static final BigDecimal MAX_LONG_DECIMAL = BigDecimal.valueOf(Long.MAX_VALUE);
+
+ /** Decimal representation of minimum long value. */
+ private static final BigDecimal MIN_LONG_DECIMAL = BigDecimal.valueOf(Long.MIN_VALUE);
+
+ /** Decimal representation of maximum int value. */
+ private static final BigDecimal MAX_INTEGER_DECIMAL = new BigDecimal(Integer.MAX_VALUE);
+
+ /** Decimal representation of minimum int value. */
+ private static final BigDecimal MIN_INTEGER_DECIMAL = new BigDecimal(Integer.MIN_VALUE);
+
+ /** Decimal representation of maximum short value. */
+ private static final BigDecimal MAX_SHORT_DECIMAL = new BigDecimal(Short.MAX_VALUE);
+
+ /** Decimal representation of minimum short value. */
+ private static final BigDecimal MIN_SHORT_DECIMAL = new BigDecimal(Short.MIN_VALUE);
+
+ /** Decimal representation of maximum byte value. */
+ private static final BigDecimal MAX_BYTE_DECIMAL = new BigDecimal(Byte.MAX_VALUE);
+
+ /** Decimal representation of minimum byte value. */
+ private static final BigDecimal MIN_BYTE_DECIMAL = new BigDecimal(Byte.MIN_VALUE);
+
+ /** Convertation failure marker. */
+ public static final Object CONVERTATION_FAILURE = new Object();
+
+ /**
+ * Convert argument to the given type.
+ *
+ * @param arg Argument.
+ * @param targetType Type.
+ * @return Converted argument or <code>CONVERTATION_FAILURE</code> if convertation failed.
+ */
+ public static Object convert(Object arg, PartitionParameterType targetType) {
+ assert targetType != null;
+
+ if (arg == null)
+ return null;
+
+ PartitionParameterType argType = typeFromClass(arg.getClass());
+
+ if (argType == null)
+ return CONVERTATION_FAILURE;
+
+ if (argType == targetType)
+ return arg;
+
+ try {
+ switch (targetType) {
+ case BOOLEAN:
+ return getBoolean(arg, argType);
+
+ case BYTE:
+ return getIntegerNumeric(
+ arg,
+ argType,
+ Byte.MIN_VALUE,
+ Byte.MAX_VALUE,
+ MIN_BYTE_DECIMAL,
+ MAX_BYTE_DECIMAL,
+ PartitionParameterType.BYTE
+ );
+
+ case SHORT:
+ return getIntegerNumeric(
+ arg,
+ argType,
+ Short.MIN_VALUE,
+ Short.MAX_VALUE,
+ MIN_SHORT_DECIMAL,
+ MAX_SHORT_DECIMAL,
+ PartitionParameterType.SHORT
+ );
+
+ case INT:
+ return getIntegerNumeric(
+ arg,
+ argType,
+ Integer.MIN_VALUE,
+ Integer.MAX_VALUE,
+ MIN_INTEGER_DECIMAL,
+ MAX_INTEGER_DECIMAL,
+ PartitionParameterType.INT
+ );
+
+ case LONG:
+ return getIntegerNumeric(
+ arg,
+ argType,
+ Long.MIN_VALUE,
+ Long.MAX_VALUE, MIN_LONG_DECIMAL,
+ MAX_LONG_DECIMAL,
+ PartitionParameterType.LONG
+ );
+
+ case FLOAT:
+ return getFloat(arg, argType);
+
+ case DOUBLE:
+ return getDouble(arg, argType);
+
+ case DECIMAL:
+ return getDecimal(arg, argType);
+
+ case STRING:
+ return getString(arg, argType);
+
+ case UUID:
+ return getUUID(arg, argType);
+
+ default:
+ return CONVERTATION_FAILURE;
+ }
+ }
+ catch (NumberFormatException e) {
+ return CONVERTATION_FAILURE;
+ }
+ }
+
+ /**
+ * Convert argument to <code>UUID</code>.
+ *
+ * @param arg Argument to convert.
+ * @param argType Argument type.
+ * @return Converted value or <code>CONVERTATION_FAILURE</code> if convertation failed.
+ */
+ @NotNull private static Object getUUID(Object arg, PartitionParameterType argType) {
+ switch (argType) {
+ case STRING:
+ return stringToUUID((String)arg);
+
+ default:
+ return CONVERTATION_FAILURE;
+ }
+ }
+
+ /**
+ * Convert argument to <code>String</code>.
+ *
+ * @param arg Argument to convert.
+ * @param argType Argument type.
+ * @return Converted value or <code>CONVERTATION_FAILURE</code> if convertation failed.
+ */
+ private static Object getString(Object arg, PartitionParameterType argType) {
+ switch (argType) {
+ case BOOLEAN:
+ return (Boolean)arg ? "TRUE" : "FALSE";
+
+ case BYTE:
+ case SHORT:
+ case INT:
+ case LONG:
+ case DOUBLE:
+ case FLOAT:
+ return String.valueOf(arg);
+
+ case DECIMAL: {
+ // We had to use such kind of convertation instead of common arg.toString() in order to match
+ // H2 convertation results. In case of using arg.toString() we will have inconsistant convertation
+ // results for values similar to BigDecimal.valueOf(12334535345456700.12345634534534578901).
+ // Main difference between toPlainString() and toString() is that toPlainString()
+ // returns a string representation of a {@code BigDecimal} without an exponent field.
+ String p = ((BigDecimal)arg).toPlainString();
+
+ return p.length() < 40 ? p : arg.toString();
+ }
+
+ case UUID:
+ return arg.toString();
+
+ default:
+ return CONVERTATION_FAILURE;
+ }
+ }
+
+ /**
+ * Convert argument to <code>Float</code>.
+ *
+ * @param arg Argument to convert.
+ * @param argType Argument type.
+ * @return Converted value or <code>CONVERTATION_FAILURE</code> if convertation failed.
+ */
+ @NotNull private static Object getFloat(Object arg, PartitionParameterType argType) {
+ switch (argType) {
+ case BOOLEAN:
+ return arg.equals(Boolean.TRUE) ? (float)1 : (float)0;
+
+ case BYTE:
+ case SHORT:
+ case INT:
+ case LONG:
+ case DECIMAL:
+ case DOUBLE:
+ return ((Number)arg).floatValue();
+
+ case STRING:
+ return Float.parseFloat(((String)arg).trim());
+
+ default:
+ return CONVERTATION_FAILURE;
+ }
+ }
+
+ /**
+ * Convert argument to <code>Double</code>.
+ *
+ * @param arg Argument to convert.
+ * @param argType Argument type.
+ * @return Converted value or <code>CONVERTATION_FAILURE</code> if convertation failed.
+ */
+ @NotNull private static Object getDouble(Object arg, PartitionParameterType argType) {
+ switch (argType) {
+ case BOOLEAN:
+ return arg.equals(Boolean.TRUE) ? (double)1 : (double)0;
+
+ case BYTE:
+ case SHORT:
+ case INT:
+ case LONG:
+ case DECIMAL:
+ case FLOAT:
+ return ((Number)arg).doubleValue();
+
+ case STRING:
+ return Double.parseDouble(((String)arg).trim());
+
+ default:
+ return CONVERTATION_FAILURE;
+ }
+ }
+
+ /**
+ * Convert argument to <code>Decimal</code>.
+ *
+ * @param arg Argument to convert.
+ * @param argType Argument type.
+ * @return Converted value or <code>CONVERTATION_FAILURE</code> if convertation failed.
+ */
+ @NotNull private static Object getDecimal(Object arg, PartitionParameterType argType) {
+ switch (argType) {
+ case BOOLEAN:
+ return arg.equals(Boolean.TRUE) ? BigDecimal.ONE : BigDecimal.ZERO;
+
+ case BYTE:
+ case SHORT:
+ case INT:
+ case LONG:
+ return BigDecimal.valueOf(((Number)arg).longValue());
+
+ case DOUBLE: {
+ double d = (double)arg;
+
+ if (Double.isInfinite(d) || Double.isNaN(d))
+ return CONVERTATION_FAILURE;
+
+ return BigDecimal.valueOf(d);
+ }
+ case FLOAT: {
+ float f = (float)arg;
+
+ if (Float.isInfinite(f) || Float.isNaN(f))
+ return CONVERTATION_FAILURE;
+
+ return new BigDecimal(Float.toString(f));
+ }
+
+ case STRING:
+ return new BigDecimal(((String)arg).trim());
+
+ default:
+ return CONVERTATION_FAILURE;
+ }
+ }
+
+ /**
+ * Convert argument to integer numeric: byte, short, int, long.
+ *
+ * @param arg Argument to convert.
+ * @param argType Argument type.
+ * @return Converted value or <code>CONVERTATION_FAILURE</code> if convertation failed.
+ */
+ @SuppressWarnings("EnumSwitchStatementWhichMissesCases")
+ @NotNull private static Object getIntegerNumeric(
+ Object arg,
+ PartitionParameterType argType,
+ long minVal,
+ long maxVal,
+ BigDecimal minValDecimal,
+ BigDecimal maxValDecimal,
+ PartitionParameterType targetType
+ ) {
+ assert targetType == PartitionParameterType.BYTE || targetType == PartitionParameterType.SHORT ||
+ targetType == PartitionParameterType.INT || targetType == PartitionParameterType.LONG;
+
+ long res;
+
+ switch (argType) {
+ case BOOLEAN:
+ res = arg.equals(Boolean.TRUE) ? 1L : 0L;
+
+ break;
+
+ case BYTE:
+ case SHORT:
+ case INT:
+ case LONG: {
+ res = ((Number)arg).longValue();
+
+ if (res > maxVal || res < minVal)
+ return CONVERTATION_FAILURE;
+
+ break;
+ }
+ case DECIMAL: {
+ BigDecimal d = (BigDecimal)arg;
+
+ if (d.compareTo(maxValDecimal) > 0 || d.compareTo(minValDecimal) < 0)
+ return CONVERTATION_FAILURE;
+ else
+ res = d.setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
+
+ break;
+ }
+
+ case DOUBLE: {
+ Double d = (Double)arg;
+
+ if (d > maxVal || d < minVal)
+ return CONVERTATION_FAILURE;
+ else
+ res = Math.round(d);
+
+ break;
+ }
+
+ case FLOAT: {
+ Float f = (Float)arg;
+
+ if (f > maxVal || f < minVal)
+ return CONVERTATION_FAILURE;
+ else
+ res = Math.round(f);
+
+ break;
+ }
+
+ case STRING: {
+ res = Long.parseLong(((String)arg).trim());
+
+ if (res > maxVal || res < minVal)
+ return CONVERTATION_FAILURE;
+
+ break;
+ }
+
+ default:
+ return CONVERTATION_FAILURE;
+ }
+
+ switch (targetType) {
+ case BYTE:
+ return (byte)res;
+ case SHORT:
+ return (short)res;
+ case INT:
+ return (int)res;
+ case LONG:
+ return res;
+ }
+
+ return CONVERTATION_FAILURE;
+ }
+
+ /**
+ * Convert argument to <code>Boolean</code>.
+ *
+ * @param arg Argument to convert.
+ * @param argType Argument type.
+ * @return Converted value or <code>CONVERTATION_FAILURE</code> if convertation failed.
+ */
+ @NotNull private static Object getBoolean(Object arg, PartitionParameterType argType) {
+ switch (argType) {
+ case BYTE:
+ return (Byte)arg != 0;
+
+ case SHORT:
+ return (Short)arg != 0;
+
+ case INT:
+ return (Integer)arg != 0;
+
+ case LONG:
+ return (Long)arg != 0;
+
+ case DECIMAL:
+ return !arg.equals(BigDecimal.ZERO);
+
+ case DOUBLE:
+ return Math.signum((Double)arg) != 0;
+
+ case FLOAT:
+ return Math.signum((Float)arg) != 0;
+
+ case STRING: {
+ String sVal = (String)arg;
+
+ if ("true".equalsIgnoreCase(sVal) ||
+ "t".equalsIgnoreCase(sVal) ||
+ "yes".equalsIgnoreCase(sVal) ||
+ "y".equalsIgnoreCase(sVal) ||
+ "1".equals(sVal))
+ return Boolean.TRUE;
+ else if ("false".equalsIgnoreCase(sVal) ||
+ "f".equalsIgnoreCase(sVal) ||
+ "no".equalsIgnoreCase(sVal) ||
+ "n".equalsIgnoreCase(sVal) ||
+ "0".equals(sVal))
+ return Boolean.FALSE;
+ }
+ default:
+ return CONVERTATION_FAILURE;
+ }
+ }
+
+ /**
+ * Get the <code>PartitionParameterType</code> type for the given Java class.
+ *
+ * @param c The Java class.
+ * @return The <code>PartitionParameterType</code> type.
+ */
+ private static PartitionParameterType typeFromClass(Class<?> c) {
+ assert c != null;
+
+ if (String.class == c)
+ return PartitionParameterType.STRING;
+ else if (Integer.class == c)
+ return PartitionParameterType.INT;
+ else if (Long.class == c)
+ return PartitionParameterType.LONG;
+ else if (Boolean.class == c)
+ return PartitionParameterType.BOOLEAN;
+ else if (Double.class == c)
+ return PartitionParameterType.DOUBLE;
+ else if (Byte.class == c)
+ return PartitionParameterType.BYTE;
+ else if (Short.class == c)
+ return PartitionParameterType.SHORT;
+ else if (Float.class == c)
+ return PartitionParameterType.FLOAT;
+ else if (UUID.class == c)
+ return PartitionParameterType.UUID;
+ else if (BigDecimal.class == c)
+ return PartitionParameterType.DECIMAL;
+ else
+ return null;
+ }
+
+ /**
+ * Utility method that helps to convert String to UUID. Given method is more fault tolerant than more common
+ * <code>UUID.fromString()</code>. For example it supports String represendation of UUID-without-hyphens
+ * conversion, that is not supported by mentioned above <code>UUID.fromString()</code>.
+ *
+ * @param s String to
+ * @return UUID or <code>CONVERTATION_FAILURE</code> if convertation failed.
+ */
+ public static Object stringToUUID(String s) {
+ long low = 0, high = 0;
+ for (int i = 0, j = 0, len = s.length(); i < len; i++) {
+ char c = s.charAt(i);
+
+ if (c >= '0' && c <= '9')
+ low = (low << 4) | (c - '0');
+ else if (c >= 'a' && c <= 'f')
+ low = (low << 4) | (c - 'a' + 0xa);
+ else if (c == '-')
+ continue;
+ else if (c >= 'A' && c <= 'F')
+ low = (low << 4) | (c - 'A' + 0xa);
+ else if (c <= ' ')
+ continue;
+ else
+ return CONVERTATION_FAILURE;
+
+ if (j++ == 15) {
+ high = low;
+
+ low = 0;
+ }
+ }
+
+ return new UUID(high, low);
+ }
+
+ /**
+ * Private constructor.
+ */
+ private PartitionDataTypeUtils() {
+ // No-op.
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionGroupNode.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionGroupNode.java
index b7106a7..8a3c5d1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionGroupNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionGroupNode.java
@@ -46,12 +46,19 @@ public class PartitionGroupNode implements PartitionNode {
}
/** {@inheritDoc} */
- @Override public Collection<Integer> apply(Object... args) throws IgniteCheckedException {
+ @Override public Collection<Integer> apply(PartitionClientContext ctx, Object... args)
+ throws IgniteCheckedException {
// Deduplicate same partitions which may appear during resolution.
HashSet<Integer> res = new HashSet<>(siblings.size());
- for (PartitionSingleNode sibling : siblings)
- res.add(sibling.applySingle(args));
+ for (PartitionSingleNode sibling : siblings) {
+ Integer part = sibling.applySingle(ctx, args);
+
+ if (part == null)
+ return null;
+
+ res.add(part);
+ }
return res;
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionNode.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionNode.java
index c8c354c..57936b1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionNode.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.sql.optimizer.affinity;
import org.apache.ignite.IgniteCheckedException;
+import org.jetbrains.annotations.Nullable;
import java.util.Collection;
@@ -28,11 +29,12 @@ public interface PartitionNode {
/**
* Get partitions.
*
+ * @param cliCtx Thin client context (optional).
* @param args Query arguments.
* @return Partitions.
* @throws IgniteCheckedException If failed.
*/
- Collection<Integer> apply(Object... args) throws IgniteCheckedException;
+ Collection<Integer> apply(@Nullable PartitionClientContext cliCtx, Object... args) throws IgniteCheckedException;
/**
* @return Join group for the given node.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionNoneNode.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionNoneNode.java
index f136fc9..361b3e0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionNoneNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionNoneNode.java
@@ -37,7 +37,7 @@ public class PartitionNoneNode implements PartitionNode {
}
/** {@inheritDoc} */
- @Override public Collection<Integer> apply(Object... args) {
+ @Override public Collection<Integer> apply(PartitionClientContext cliCtx, Object... args) {
return Collections.emptySet();
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionParameterNode.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionParameterNode.java
index 6219c30..c909a23 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionParameterNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionParameterNode.java
@@ -32,8 +32,11 @@ public class PartitionParameterNode extends PartitionSingleNode {
/** Index. */
private final int idx;
- /** Data type. */
- private final int dataType;
+ /** Parameter data type. */
+ private final int type;
+
+ /** Mapped parameter type. */
+ private final PartitionParameterType mappedType;
/**
* Constructor.
@@ -41,26 +44,37 @@ public class PartitionParameterNode extends PartitionSingleNode {
* @param tbl Table descriptor.
* @param partResolver Partition resolver.
* @param idx Parameter index.
- * @param dataType Parameter data type.
+ * @param type Parameter data type.
+ * @param mappedType Mapped parameter type to be used by thin clients.
*/
- public PartitionParameterNode(PartitionTable tbl, PartitionResolver partResolver, int idx, int dataType) {
+ public PartitionParameterNode(PartitionTable tbl, PartitionResolver partResolver, int idx, int type,
+ PartitionParameterType mappedType) {
super(tbl);
this.partResolver = partResolver;
this.idx = idx;
- this.dataType = dataType;
+ this.type = type;
+ this.mappedType = mappedType;
}
/** {@inheritDoc} */
- @Override public int applySingle(Object... args) throws IgniteCheckedException {
+ @Override public Integer applySingle(PartitionClientContext cliCtx, Object... args) throws IgniteCheckedException {
assert args != null;
assert idx < args.length;
- return partResolver.partition(
- args[idx],
- dataType,
- tbl.cacheName()
- );
+ Object arg = args[idx];
+
+ if (cliCtx != null)
+ return cliCtx.partition(arg, mappedType, tbl.cacheName());
+ else {
+ assert partResolver != null;
+
+ return partResolver.partition(
+ arg,
+ type,
+ tbl.cacheName()
+ );
+ }
}
/** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionParameterType.java
similarity index 63%
copy from modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java
copy to modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionParameterType.java
index e606200..ff0943b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionParameterType.java
@@ -17,20 +17,37 @@
package org.apache.ignite.internal.sql.optimizer.affinity;
-import org.apache.ignite.IgniteCheckedException;
-
/**
- * Partition resolver interface. Takes argument, data type and cache name, returns partition.
+ * Partition argument type.
*/
-public interface PartitionResolver {
- /**
- * Resolve partition.
- *
- * @param arg Argument.
- * @param dataType Data type.
- * @param cacheName Cache name.
- * @return Partition.
- * @throws IgniteCheckedException If failed.
- */
- int partition(Object arg, int dataType, String cacheName) throws IgniteCheckedException;
+public enum PartitionParameterType {
+ /** Boolean. */
+ BOOLEAN,
+
+ /** Byte. */
+ BYTE,
+
+ /** Short. */
+ SHORT,
+
+ /** Int. */
+ INT,
+
+ /** Long. */
+ LONG,
+
+ /** Float. */
+ FLOAT,
+
+ /** Double. */
+ DOUBLE,
+
+ /** String. */
+ STRING,
+
+ /** Decimal. */
+ DECIMAL,
+
+ /** UUID. */
+ UUID
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java
index e606200..4d25bef 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionResolver.java
@@ -21,6 +21,7 @@ import org.apache.ignite.IgniteCheckedException;
/**
* Partition resolver interface. Takes argument, data type and cache name, returns partition.
+ * The only purpose of this methods is to allow partition pruning classes to be located in core module.
*/
public interface PartitionResolver {
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionSingleNode.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionSingleNode.java
index 466e1c6..33f61d0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionSingleNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/optimizer/affinity/PartitionSingleNode.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.sql.optimizer.affinity;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.F;
+import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
@@ -42,17 +43,22 @@ public abstract class PartitionSingleNode implements PartitionNode {
}
/** {@inheritDoc} */
- @Override public Collection<Integer> apply(Object... args) throws IgniteCheckedException {
- return Collections.singletonList(applySingle(args));
+ @Override public Collection<Integer> apply(PartitionClientContext cliCtx, Object... args)
+ throws IgniteCheckedException {
+ Integer part = applySingle(cliCtx, args);
+
+ return part != null ? Collections.singletonList(part) : null;
}
/**
* Apply arguments and get single partition.
*
+ * @param cliCtx Client context.
* @param args Arguments.
- * @return Partition.
+ * @return Partition or {@code null} if failed.
*/
- public abstract int applySingle(Object... args) throws IgniteCheckedException;
+ public abstract Integer applySingle(@Nullable PartitionClientContext cliCtx, Object... args)
+ throws IgniteCheckedException;
/**
* @return {@code True} if constant, {@code false} if argument.
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
index 9ee056f..f5b013f 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
@@ -2103,9 +2103,11 @@ public class IgniteH2Indexing implements GridQueryIndexing {
return explicitParts;
else if (derivedParts != null) {
try {
- Collection<Integer> realParts = derivedParts.tree().apply(args);
+ Collection<Integer> realParts = derivedParts.tree().apply(null, args);
- if (F.isEmpty(realParts))
+ if (realParts == null)
+ return null;
+ else if (realParts.isEmpty())
return IgniteUtils.EMPTY_INTS;
else {
int[] realParts0 = new int[realParts.size()];
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/affinity/PartitionExtractor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/affinity/PartitionExtractor.java
index f82be53..996a3b2 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/affinity/PartitionExtractor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/affinity/PartitionExtractor.java
@@ -17,6 +17,11 @@
package org.apache.ignite.internal.processors.query.h2.affinity;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteSystemProperties;
import org.apache.ignite.cache.CacheMode;
@@ -46,6 +51,7 @@ import org.apache.ignite.internal.sql.optimizer.affinity.PartitionJoinCondition;
import org.apache.ignite.internal.sql.optimizer.affinity.PartitionNode;
import org.apache.ignite.internal.sql.optimizer.affinity.PartitionNoneNode;
import org.apache.ignite.internal.sql.optimizer.affinity.PartitionParameterNode;
+import org.apache.ignite.internal.sql.optimizer.affinity.PartitionParameterType;
import org.apache.ignite.internal.sql.optimizer.affinity.PartitionResult;
import org.apache.ignite.internal.sql.optimizer.affinity.PartitionSingleNode;
import org.apache.ignite.internal.sql.optimizer.affinity.PartitionTable;
@@ -56,12 +62,6 @@ import org.h2.table.Column;
import org.h2.value.Value;
import org.jetbrains.annotations.Nullable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
/**
* Partition tree extractor.
*/
@@ -623,13 +623,66 @@ public class PartitionExtractor {
return new PartitionConstantNode(tbl0, part);
}
- else if (rightParam != null)
- return new PartitionParameterNode(tbl0, partResolver, rightParam.index(), leftCol0.getType());
+ else if (rightParam != null) {
+ int colType = leftCol0.getType();
+
+ return new PartitionParameterNode(
+ tbl0,
+ partResolver,
+ rightParam.index(),
+ leftCol0.getType(),
+ mappedType(colType)
+ );
+ }
else
return null;
}
/**
+ * Mapped Ignite type for H2 type.
+ *
+ * @param type H2 type.
+ * @return ignite type.
+ */
+ @Nullable private static PartitionParameterType mappedType(int type) {
+ // Try map if possible.
+ switch (type) {
+ case Value.BOOLEAN:
+ return PartitionParameterType.BOOLEAN;
+
+ case Value.BYTE:
+ return PartitionParameterType.BYTE;
+
+ case Value.SHORT:
+ return PartitionParameterType.SHORT;
+
+ case Value.INT:
+ return PartitionParameterType.INT;
+
+ case Value.LONG:
+ return PartitionParameterType.LONG;
+
+ case Value.FLOAT:
+ return PartitionParameterType.FLOAT;
+
+ case Value.DOUBLE:
+ return PartitionParameterType.DOUBLE;
+
+ case Value.STRING:
+ return PartitionParameterType.STRING;
+
+ case Value.DECIMAL:
+ return PartitionParameterType.DECIMAL;
+
+ case Value.UUID:
+ return PartitionParameterType.UUID;
+ }
+
+ // Otherwise we do not support it.
+ return null;
+ }
+
+ /**
* Unwrap constant if possible.
*
* @param ast AST.
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/SqlDataTypeConversionTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/SqlDataTypeConversionTest.java
new file mode 100644
index 0000000..3e62d5d
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/SqlDataTypeConversionTest.java
@@ -0,0 +1,372 @@
+/*
+ * 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.ignite.internal.processors.query.h2.twostep;
+
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.ignite.internal.processors.query.h2.H2Utils;
+import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
+import org.apache.ignite.internal.sql.optimizer.affinity.PartitionDataTypeUtils;
+import org.apache.ignite.internal.sql.optimizer.affinity.PartitionParameterType;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.h2.value.Value;
+import org.junit.Test;
+
+/**
+ * Data conversion tests.
+ */
+public class SqlDataTypeConversionTest extends GridCommonAbstractTest {
+ /** Map to convert <code>PartitionParameterType</code> instances to correspondig java classes. */
+ private static final Map<PartitionParameterType, Class<?>> PARAMETER_TYPE_TO_JAVA_CLASS;
+
+ /** Map to convert <code>PartitionParameterType</code> instances to correspondig H2 data types. */
+ private static final Map<PartitionParameterType, Integer> IGNITE_PARAMETER_TYPE_TO_H2_PARAMETER_TYPE;
+
+ /** Ignite H2 Indexing. */
+ private static IgniteH2Indexing idx;
+
+ static {
+ Map<PartitionParameterType, Class<?>> paramTypeToJavaCls = new EnumMap<>(PartitionParameterType.class);
+
+ paramTypeToJavaCls.put(PartitionParameterType.BOOLEAN, Boolean.class);
+ paramTypeToJavaCls.put(PartitionParameterType.BYTE, Byte.class);
+ paramTypeToJavaCls.put(PartitionParameterType.SHORT, Short.class);
+ paramTypeToJavaCls.put(PartitionParameterType.INT, Integer.class);
+ paramTypeToJavaCls.put(PartitionParameterType.LONG, Long.class);
+ paramTypeToJavaCls.put(PartitionParameterType.FLOAT, Float.class);
+ paramTypeToJavaCls.put(PartitionParameterType.DOUBLE, Double.class);
+ paramTypeToJavaCls.put(PartitionParameterType.STRING, String.class);
+ paramTypeToJavaCls.put(PartitionParameterType.DECIMAL, BigDecimal.class);
+ paramTypeToJavaCls.put(PartitionParameterType.UUID, UUID.class);
+
+ PARAMETER_TYPE_TO_JAVA_CLASS = Collections.unmodifiableMap(paramTypeToJavaCls);
+
+ Map<PartitionParameterType, Integer> igniteParamTypeToH2ParamType = new EnumMap<>(PartitionParameterType.class);
+
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.BOOLEAN, Value.BOOLEAN);
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.BYTE, Value.BYTE);
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.SHORT, Value.SHORT);
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.INT, Value.INT);
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.LONG, Value.LONG);
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.FLOAT, Value.FLOAT);
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.DOUBLE, Value.DOUBLE);
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.STRING, Value.STRING);
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.DECIMAL, Value.DECIMAL);
+ igniteParamTypeToH2ParamType.put(PartitionParameterType.UUID, Value.UUID);
+
+ IGNITE_PARAMETER_TYPE_TO_H2_PARAMETER_TYPE = Collections.unmodifiableMap(igniteParamTypeToH2ParamType);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ idx = (IgniteH2Indexing)startGrid(0).context().query().getIndexing();
+ }
+
+ /**
+ * Test null value conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertNull() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(null);
+ }
+
+ /**
+ * Test boolean conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertBoolean() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Boolean.TRUE);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Boolean.FALSE);
+ }
+
+ /**
+ * Test byte conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertByte() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2((byte)42, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2((byte)0, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Byte.MIN_VALUE, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Byte.MAX_VALUE, PartitionParameterType.UUID);
+
+ assertEquals(PartitionDataTypeUtils.CONVERTATION_FAILURE,
+ PartitionDataTypeUtils.convert((byte)42, PartitionParameterType.UUID));
+ }
+
+ /**
+ * Test short conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertShort() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2((short)42, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2((short)0, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Short.MIN_VALUE, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Short.MAX_VALUE, PartitionParameterType.UUID);
+
+ assertEquals(PartitionDataTypeUtils.CONVERTATION_FAILURE,
+ PartitionDataTypeUtils.convert((short)42, PartitionParameterType.UUID));
+ }
+
+ /**
+ * Test int conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertInteger() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(42, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(0, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Integer.MIN_VALUE, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Integer.MAX_VALUE, PartitionParameterType.UUID);
+
+ assertEquals(PartitionDataTypeUtils.CONVERTATION_FAILURE,
+ PartitionDataTypeUtils.convert(42, PartitionParameterType.UUID));
+ }
+
+ /**
+ * Test long conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertLong() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(42L, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(0L, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Long.MIN_VALUE, PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Long.MAX_VALUE, PartitionParameterType.UUID);
+
+ assertEquals(PartitionDataTypeUtils.CONVERTATION_FAILURE,
+ PartitionDataTypeUtils.convert(42L, PartitionParameterType.UUID));
+ }
+
+ /**
+ * Test float conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertFloat() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(42.1f);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(0.1f);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(0f);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(1.2345678E7f);
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Float.POSITIVE_INFINITY);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Float.NEGATIVE_INFINITY);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Float.NaN);
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Float.MIN_VALUE);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Float.MAX_VALUE);
+ }
+
+ /**
+ * Test double conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertDouble() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(42.2d);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(0.2d);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(0d);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(1.2345678E7d);
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Double.POSITIVE_INFINITY);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Double.NEGATIVE_INFINITY);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Double.NaN);
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Double.MIN_VALUE);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(Double.MAX_VALUE);
+ }
+
+ /**
+ * Test string conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertString() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("42", PartitionParameterType.BOOLEAN);
+
+ assertEquals(PartitionDataTypeUtils.CONVERTATION_FAILURE,
+ PartitionDataTypeUtils.convert("42", PartitionParameterType.BOOLEAN));
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("0");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("1");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("42.3", PartitionParameterType.BOOLEAN);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("0.3", PartitionParameterType.BOOLEAN);
+
+ assertEquals(PartitionDataTypeUtils.CONVERTATION_FAILURE,
+ PartitionDataTypeUtils.convert("0.3", PartitionParameterType.BOOLEAN));
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("42.4f");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("0.4d");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("12345678901234567890.123456789012345678901d");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("04d17cf3-bc20-4e3d-9ff7-72437cdae227");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("04d17cf3bc204e3d9ff772437cdae227");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("a");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("aaa",
+ PartitionParameterType.BOOLEAN);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(" aaa ");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("true");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("t");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("yes");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("y");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("false");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("f");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("no");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("n");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(" true ");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("null");
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("NULL");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("2000-01-02");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("10:00:00");
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2("2001-01-01 23:59:59.123456");
+ }
+
+ /**
+ * Test decimal conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertDecimal() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(new BigDecimal(42.5d), PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(new BigDecimal(0.5d), PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(new BigDecimal(0), PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(new BigDecimal(1.2345678E7),
+ PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(BigDecimal.valueOf(12334535345456700.12345634534534578901),
+ PartitionParameterType.UUID);
+
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(new BigDecimal(Double.MIN_VALUE),
+ PartitionParameterType.UUID);
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(new BigDecimal(Double.MAX_VALUE),
+ PartitionParameterType.UUID);
+
+ assertEquals(PartitionDataTypeUtils.CONVERTATION_FAILURE,
+ PartitionDataTypeUtils.convert(new BigDecimal(42.5d), PartitionParameterType.UUID));
+ }
+
+ /**
+ * Test uuid conversion.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void convertUUID() throws Exception {
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(UUID.randomUUID());
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(UUID.fromString("00000000-0000-0000-0000-00000000000a"));
+ makeSureThatConvertationResultsExactTheSameAsWithinH2(new UUID(0L, 1L));
+ }
+
+ /**
+ * Test string to uuid conversion with different combinations of upper and lower case letters and with/without
+ * hyphens.
+ */
+ @Test
+ public void stringToUUIDConvertation() {
+ UUID expUuid = UUID.fromString("273ded0d-86de-432e-b252-54c06ec22927");
+
+ // Lower case and hyphens.
+ assertEquals(expUuid, PartitionDataTypeUtils.stringToUUID("273ded0d-86de-432e-b252-54c06ec22927"));
+
+ // Lower case without hyphens.
+ assertEquals(expUuid, PartitionDataTypeUtils.stringToUUID("273ded0d86de432eb25254c06ec22927"));
+
+ // Lower case without few hyphens.
+ assertEquals(expUuid, PartitionDataTypeUtils.stringToUUID("273ded0d86de432e-b25254c06ec22927"));
+
+ // Upper case and hyphens.
+ assertEquals(expUuid, PartitionDataTypeUtils.stringToUUID("273dED0D-86DE-432E-B25254C06EC22927"));
+
+ // Upper case without few hyphens.
+ assertEquals(expUuid, PartitionDataTypeUtils.stringToUUID("273dED0D86DE432Eb252-54c06ec22927"));
+ }
+
+ /**
+ * Actual conversial check logic.
+ *
+ * @param arg Argument to convert.
+ * @param excludedTargetTypesFromCheck <@code>PartitionParameterType</code> instances to exclude from check.
+ * @throws Exception If failed.
+ */
+ private void makeSureThatConvertationResultsExactTheSameAsWithinH2(Object arg,
+ PartitionParameterType ... excludedTargetTypesFromCheck) throws Exception {
+
+ Iterable<PartitionParameterType> targetTypes = excludedTargetTypesFromCheck.length > 0 ?
+ EnumSet.complementOf(EnumSet.of(excludedTargetTypesFromCheck[0], excludedTargetTypesFromCheck)):
+ EnumSet.allOf(PartitionParameterType.class);
+
+ for (PartitionParameterType targetType : targetTypes) {
+ Object convertationRes = PartitionDataTypeUtils.convert(arg, targetType);
+
+ if (PartitionDataTypeUtils.CONVERTATION_FAILURE == convertationRes) {
+ try {
+ H2Utils.convert(arg, idx, IGNITE_PARAMETER_TYPE_TO_H2_PARAMETER_TYPE.get(targetType));
+
+ fail("Data conversion failed in Ignite but not in H2.");
+ }
+ catch (org.h2.message.DbException h2Exception) {
+ assertTrue(h2Exception.getMessage().contains("Numeric value out of range") ||
+ h2Exception.getMessage().contains("Data conversion error"));
+ }
+ }
+ else {
+ Object convertationH2Res = H2Utils.convert(arg, idx,
+ IGNITE_PARAMETER_TYPE_TO_H2_PARAMETER_TYPE.get(targetType));
+
+ if (convertationRes == null)
+ assertNull(convertationH2Res);
+ else {
+ assertEquals(PARAMETER_TYPE_TO_JAVA_CLASS.get(targetType), convertationRes.getClass());
+ assertEquals(convertationH2Res.getClass(), convertationRes.getClass());
+ assertEquals(convertationH2Res, convertationRes);
+ }
+ }
+ }
+ }
+}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite.java
index 4482b612c..a275ac6 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite.java
@@ -82,8 +82,8 @@ import org.apache.ignite.internal.processors.cache.IgniteCachePrimitiveFieldsQue
import org.apache.ignite.internal.processors.cache.IgniteCacheQueryH2IndexingLeakTest;
import org.apache.ignite.internal.processors.cache.IgniteCacheQueryIndexSelfTest;
import org.apache.ignite.internal.processors.cache.IgniteCacheQueryLoadSelfTest;
-import org.apache.ignite.internal.processors.cache.IgniteCacheSqlInsertValidationSelfTest;
import org.apache.ignite.internal.processors.cache.IgniteCacheSqlDmlErrorSelfTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheSqlInsertValidationSelfTest;
import org.apache.ignite.internal.processors.cache.IgniteCacheSqlQueryErrorSelfTest;
import org.apache.ignite.internal.processors.cache.IgniteCacheUnionDuplicatesTest;
import org.apache.ignite.internal.processors.cache.IgniteCacheUpdateSqlQuerySelfTest;
@@ -223,6 +223,7 @@ import org.apache.ignite.internal.processors.query.h2.twostep.BetweenOperationEx
import org.apache.ignite.internal.processors.query.h2.twostep.DmlSelectPartitionPruningSelfTest;
import org.apache.ignite.internal.processors.query.h2.twostep.InOperationExtractPartitionSelfTest;
import org.apache.ignite.internal.processors.query.h2.twostep.JoinPartitionPruningSelfTest;
+import org.apache.ignite.internal.processors.query.h2.twostep.SqlDataTypeConversionTest;
import org.apache.ignite.internal.processors.sql.IgniteCachePartitionedAtomicColumnConstraintsTest;
import org.apache.ignite.internal.processors.sql.IgniteCachePartitionedTransactionalColumnConstraintsTest;
import org.apache.ignite.internal.processors.sql.IgniteCachePartitionedTransactionalSnapshotColumnConstraintTest;
@@ -545,6 +546,8 @@ import org.junit.runners.Suite;
GridCacheDynamicLoadOnClientTest.class,
GridCacheDynamicLoadOnClientPersistentTest.class,
+ SqlDataTypeConversionTest.class,
+
//Query history.
SqlQueryHistorySelfTest.class,
SqlQueryHistoryFromClientSelfTest.class,