Repository: ignite
Updated Branches:
  refs/heads/master 04f074023 -> a6e97d146


IGNITE-9519: SQL: Allow complex object inline into indexes. This closes #4724.


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

Branch: refs/heads/master
Commit: a6e97d146db68dc510616ef4bd14281d3bba0a8e
Parents: 04f0740
Author: Stanislav Lukyanov <slukya...@gridgain.com>
Authored: Thu Sep 20 17:19:17 2018 +0300
Committer: devozerov <voze...@gridgain.com>
Committed: Thu Sep 20 17:19:17 2018 +0300

----------------------------------------------------------------------
 .../internal/binary/BinaryObjectImpl.java       |   2 +-
 .../query/h2/database/InlineIndexHelper.java    |  32 +-
 .../query/h2/opt/GridH2ValueCacheObject.java    |   6 +
 .../processors/cache/index/BasicIndexTest.java  | 820 +++++++++++++++++++
 .../h2/database/InlineIndexHelperTest.java      | 148 +++-
 .../IgniteCacheQuerySelfTestSuite.java          |   3 +
 6 files changed, 981 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/a6e97d14/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java
index 7ab8b35..65fb349 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java
@@ -205,7 +205,7 @@ public final class BinaryObjectImpl extends 
BinaryObjectExImpl implements Extern
     /**
      * @return Detached binary object.
      */
-    public BinaryObject detach() {
+    public BinaryObjectImpl detach() {
         if (!detachAllowed || detached())
             return this;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6e97d14/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java
index 05d5c46..0299033 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java
@@ -35,6 +35,7 @@ import org.h2.value.ValueDate;
 import org.h2.value.ValueDouble;
 import org.h2.value.ValueFloat;
 import org.h2.value.ValueInt;
+import org.h2.value.ValueJavaObject;
 import org.h2.value.ValueLong;
 import org.h2.value.ValueNull;
 import org.h2.value.ValueShort;
@@ -70,7 +71,8 @@ public class InlineIndexHelper {
         Value.STRING,
         Value.STRING_FIXED,
         Value.STRING_IGNORECASE,
-        Value.BYTES
+        Value.BYTES,
+        Value.JAVA_OBJECT
     );
 
     /** */
@@ -153,6 +155,7 @@ public class InlineIndexHelper {
             case Value.STRING_FIXED:
             case Value.STRING_IGNORECASE:
             case Value.BYTES:
+            case Value.JAVA_OBJECT:
                 this.size = -1;
                 break;
 
@@ -298,6 +301,9 @@ public class InlineIndexHelper {
             case Value.BYTES:
                 return ValueBytes.get(readBytes(pageAddr, off));
 
+            case Value.JAVA_OBJECT:
+                return ValueJavaObject.getNoCopy(null, readBytes(pageAddr, 
off), null);
+
             default:
                 throw new UnsupportedOperationException("no get operation for 
fast index type " + type);
         }
@@ -327,6 +333,7 @@ public class InlineIndexHelper {
             case Value.STRING_FIXED:
             case Value.STRING_IGNORECASE:
             case Value.BYTES:
+            case Value.JAVA_OBJECT:
                 return (PageUtils.getShort(pageAddr, off + 1) & 0x8000) == 0;
 
             default:
@@ -417,6 +424,7 @@ public class InlineIndexHelper {
                 return compareAsUUID(pageAddr, off, v, type);
 
             case Value.BYTES:
+            case Value.JAVA_OBJECT:
                 return compareAsBytes(pageAddr, off, v);
         }
 
@@ -900,23 +908,30 @@ public class InlineIndexHelper {
                 }
             }
 
-            case Value.BYTES: {
+            case Value.BYTES:
+            case Value.JAVA_OBJECT:
+             {
                 short size;
 
                 PageUtils.putByte(pageAddr, off, (byte)val.getType());
 
-                if (val.getBytes().length + 3 <= maxSize) {
-                    size = (short)val.getBytes().length;
+                 byte[] bytes = val.getBytes();
+
+                 if (bytes.length + 3 <= maxSize) {
+                    size = (short)bytes.length;
                     PageUtils.putShort(pageAddr, off + 1, size);
-                    PageUtils.putBytes(pageAddr, off + 3, val.getBytes());
+                    PageUtils.putBytes(pageAddr, off + 3, bytes);
+
+                    return size + 3;
                 }
                 else {
                     size = (short)((maxSize - 3) | 0x8000);
                     PageUtils.putShort(pageAddr, off + 1, size);
-                    PageUtils.putBytes(pageAddr, off + 3, 
Arrays.copyOfRange(val.getBytes(), 0, maxSize - 3));
+                    PageUtils.putBytes(pageAddr, off + 3, 
Arrays.copyOfRange(bytes, 0, maxSize - 3));
+
+                    return maxSize;
                 }
 
-                return size + 3;
             }
 
             default:
@@ -959,6 +974,7 @@ public class InlineIndexHelper {
             case Value.STRING_FIXED:
             case Value.STRING_IGNORECASE:
             case Value.BYTES:
+            case Value.JAVA_OBJECT:
                 if (shortVal.getType() == Value.NULL || v2.getType() == 
Value.NULL)
                     return true;
 
@@ -968,7 +984,7 @@ public class InlineIndexHelper {
                 int l1;
                 int l2;
 
-                if (type == Value.BYTES) {
+                if (type == Value.BYTES || type == Value.JAVA_OBJECT) {
                     l1 = shortVal.getBytes().length;
                     l2 = v2.getBytes().length;
                 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6e97d14/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ValueCacheObject.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ValueCacheObject.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ValueCacheObject.java
index d18668f..9b5f0d5 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ValueCacheObject.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ValueCacheObject.java
@@ -21,6 +21,7 @@ import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.sql.Types;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.binary.BinaryObjectImpl;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.CacheObjectValueContext;
 import org.h2.message.DbException;
@@ -49,6 +50,11 @@ public class GridH2ValueCacheObject extends Value {
     public GridH2ValueCacheObject(CacheObject obj, CacheObjectValueContext 
valCtx) {
         assert obj != null;
 
+        if (obj instanceof BinaryObjectImpl) {
+            ((BinaryObjectImpl)obj).detachAllowed(true);
+            obj = ((BinaryObjectImpl)obj).detach();
+        }
+
         this.obj = obj;
         this.valCtx = valCtx;
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6e97d14/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/BasicIndexTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/BasicIndexTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/BasicIndexTest.java
new file mode 100644
index 0000000..feb330b
--- /dev/null
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/BasicIndexTest.java
@@ -0,0 +1,820 @@
+/*
+ * 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.cache.index;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Objects;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.CacheKeyConfiguration;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
+import 
org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ * A set of basic tests for caches with indexes.
+ */
+public class BasicIndexTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new 
TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private Collection<QueryIndex> indexes;
+
+    /** */
+    private Integer inlineSize;
+
+    /** */
+    private Boolean isPersistenceEnabled;
+
+    /** */
+    private String affKeyFieldName;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String 
igniteInstanceName) throws Exception {
+        assertNotNull(indexes);
+
+        assertNotNull(inlineSize);
+
+        assertNotNull(isPersistenceEnabled);
+
+        for (QueryIndex index : indexes) {
+            index.setInlineSize(inlineSize);
+        }
+
+        IgniteConfiguration igniteCfg = 
super.getConfiguration(igniteInstanceName);
+
+        igniteCfg.setDiscoverySpi(
+            new TcpDiscoverySpi().setIpFinder(IP_FINDER)
+        );
+
+        LinkedHashMap<String, String> fields = new LinkedHashMap<>();
+        fields.put("keyStr", String.class.getName());
+        fields.put("keyLong", Long.class.getName());
+        fields.put("keyPojo", Pojo.class.getName());
+        fields.put("valStr", String.class.getName());
+        fields.put("valLong", Long.class.getName());
+        fields.put("valPojo", Pojo.class.getName());
+
+        CacheConfiguration<Key, Val> ccfg = new CacheConfiguration<Key, 
Val>(DEFAULT_CACHE_NAME)
+            .setQueryEntities(Collections.singleton(
+                new QueryEntity()
+                    .setKeyType(Key.class.getName())
+                    .setValueType(Val.class.getName())
+                    .setFields(fields)
+                    .setIndexes(indexes)
+            ))
+            .setSqlIndexMaxInlineSize(inlineSize);
+
+        if (affKeyFieldName != null) {
+            ccfg.setKeyConfiguration(new CacheKeyConfiguration()
+                .setTypeName(Key.class.getTypeName())
+                .setAffinityKeyFieldName(affKeyFieldName)
+            );
+        }
+
+        igniteCfg.setCacheConfiguration(ccfg);
+
+        if (isPersistenceEnabled) {
+            igniteCfg.setDataStorageConfiguration(new 
DataStorageConfiguration()
+                .setDefaultDataRegionConfiguration(
+                    new DataRegionConfiguration().setPersistenceEnabled(true)
+                )
+            );
+        }
+
+        return igniteCfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        stopAllGrids();
+
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+
+        indexes = null;
+
+        inlineSize = null;
+
+        isPersistenceEnabled = null;
+
+        affKeyFieldName = null;
+
+        super.afterTest();
+    }
+
+    /** */
+    public void testNoIndexesNoPersistence() throws Exception {
+        indexes = Collections.emptyList();
+
+        isPersistenceEnabled = false;
+
+        int[] inlineSizes = { 0, 10, 20, 50, 100 };
+
+        for (int i : inlineSizes) {
+            log().info("Checking inlineSize=" + i);
+
+            inlineSize = i;
+
+            startGrid();
+
+            populateCache();
+
+            checkAll();
+
+            stopGrid();
+        }
+    }
+
+    /** */
+    public void testAllIndexesNoPersistence() throws Exception {
+        indexes = Arrays.asList(
+            new QueryIndex("keyStr"),
+            new QueryIndex("keyLong"),
+            new QueryIndex("keyPojo"),
+            new QueryIndex("valStr"),
+            new QueryIndex("valLong"),
+            new QueryIndex("valPojo")
+        );
+
+        isPersistenceEnabled = false;
+
+        int[] inlineSizes = { 0, 10, 20, 50, 100 };
+
+        for (int i : inlineSizes) {
+            log().info("Checking inlineSize=" + i);
+
+            inlineSize = i;
+
+            startGrid();
+
+            populateCache();
+
+            checkAll();
+
+            stopGrid();
+        }
+    }
+
+    /** */
+    public void testDynamicIndexesNoPersistence() throws Exception {
+        indexes = Collections.emptyList();
+
+        isPersistenceEnabled = false;
+
+        int[] inlineSizes = { 0, 10, 20, 50, 100 };
+
+        for (int i : inlineSizes) {
+            log().info("Checking inlineSize=" + i);
+
+            inlineSize = i;
+
+            startGrid();
+
+            populateCache();
+
+            createDynamicIndexes(
+                "keyStr",
+                "keyLong",
+                "keyPojo",
+                "valStr",
+                "valLong",
+                "valPojo"
+            );
+
+            checkAll();
+
+            stopGrid();
+        }
+    }
+
+    /** */
+    public void testNoIndexesWithPersistence() throws Exception {
+        indexes = Collections.emptyList();
+
+        isPersistenceEnabled = true;
+
+        int[] inlineSizes = { 0, 10, 20, 50, 100 };
+
+        for (int i : inlineSizes) {
+            log().info("Checking inlineSize=" + i);
+
+            inlineSize = i;
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            populateCache();
+
+            checkAll();
+
+            stopGrid();
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            checkAll();
+
+            stopGrid();
+
+            cleanPersistenceDir();
+        }
+    }
+
+    /** */
+    public void testAllIndexesWithPersistence() throws Exception {
+        indexes = Arrays.asList(
+            new QueryIndex("keyStr"),
+            new QueryIndex("keyLong"),
+            new QueryIndex("keyPojo"),
+            new QueryIndex("valStr"),
+            new QueryIndex("valLong"),
+            new QueryIndex("valPojo")
+        );
+
+        isPersistenceEnabled = true;
+
+        int[] inlineSizes = { 0, 10, 20, 50, 100 };
+
+        for (int i : inlineSizes) {
+            log().info("Checking inlineSize=" + i);
+
+            inlineSize = i;
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            populateCache();
+
+            checkAll();
+
+            stopGrid();
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            checkAll();
+
+            stopGrid();
+
+            cleanPersistenceDir();
+        }
+    }
+
+    /** */
+    public void testDynamicIndexesWithPersistence() throws Exception {
+        indexes = Collections.emptyList();
+
+        isPersistenceEnabled = true;
+
+        int[] inlineSizes = { 0, 10, 20, 50, 100 };
+
+        for (int i : inlineSizes) {
+            log().info("Checking inlineSize=" + i);
+
+            inlineSize = i;
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            populateCache();
+
+            createDynamicIndexes(
+                "keyStr",
+                "keyLong",
+                "keyPojo",
+                "valStr",
+                "valLong",
+                "valPojo"
+            );
+
+            checkAll();
+
+            stopGrid();
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            checkAll();
+
+            stopGrid();
+
+            cleanPersistenceDir();
+        }
+    }
+
+    /** */
+    public void testNoIndexesWithPersistenceIndexRebuild() throws Exception {
+        indexes = Collections.emptyList();
+
+        isPersistenceEnabled = true;
+
+        int[] inlineSizes = { 0, 10, 20, 50, 100 };
+
+        for (int i : inlineSizes) {
+            log().info("Checking inlineSize=" + i);
+
+            inlineSize = i;
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            populateCache();
+
+            checkAll();
+
+            Path idxPath = getIndexBinPath();
+
+            // Shutdown gracefully to ensure there is a checkpoint with 
index.bin.
+            // Otherwise index.bin rebuilding may not work.
+            grid().cluster().active(false);
+
+            stopGrid();
+
+            assertTrue(U.delete(idxPath));
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            grid().cache(DEFAULT_CACHE_NAME).indexReadyFuture().get();
+
+            checkAll();
+
+            stopGrid();
+
+            cleanPersistenceDir();
+        }
+    }
+
+    /** */
+    public void testAllIndexesWithPersistenceIndexRebuild() throws Exception {
+        indexes = Arrays.asList(
+            new QueryIndex("keyStr"),
+            new QueryIndex("keyLong"),
+            new QueryIndex("keyPojo"),
+            new QueryIndex("valStr"),
+            new QueryIndex("valLong"),
+            new QueryIndex("valPojo")
+        );
+
+        isPersistenceEnabled = true;
+
+        int[] inlineSizes = { 0, 10, 20, 50, 100 };
+
+        for (int i : inlineSizes) {
+            log().info("Checking inlineSize=" + i);
+
+            inlineSize = i;
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            populateCache();
+
+            checkAll();
+
+            Path idxPath = getIndexBinPath();
+
+            // Shutdown gracefully to ensure there is a checkpoint with 
index.bin.
+            // Otherwise index.bin rebuilding may not work.
+            grid().cluster().active(false);
+
+            stopGrid();
+
+            assertTrue(U.delete(idxPath));
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            grid().cache(DEFAULT_CACHE_NAME).indexReadyFuture().get();
+
+            checkAll();
+
+            stopGrid();
+
+            cleanPersistenceDir();
+        }
+    }
+
+    /** */
+    public void testDynamicIndexesWithPersistenceIndexRebuild() throws 
Exception {
+        indexes = Collections.emptyList();
+
+        isPersistenceEnabled = true;
+
+        int[] inlineSizes = { 0, 10, 20, 50, 100 };
+
+        for (int i : inlineSizes) {
+            log().info("Checking inlineSize=" + i);
+
+            inlineSize = i;
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            populateCache();
+
+            createDynamicIndexes(
+                "keyStr",
+                "keyLong",
+                "keyPojo",
+                "valStr",
+                "valLong",
+                "valPojo"
+            );
+
+            checkAll();
+
+            Path idxPath = getIndexBinPath();
+
+            // Shutdown gracefully to ensure there is a checkpoint with 
index.bin.
+            // Otherwise index.bin rebuilding may not work.
+            grid().cluster().active(false);
+
+            stopGrid();
+
+            assertTrue(U.delete(idxPath));
+
+            startGrid();
+
+            grid().cluster().active(true);
+
+            grid().cache(DEFAULT_CACHE_NAME).indexReadyFuture().get();
+
+            checkAll();
+
+            stopGrid();
+
+            cleanPersistenceDir();
+        }
+    }
+
+    /** */
+    private void checkAll() {
+        IgniteCache<Key, Val> cache = grid().cache(DEFAULT_CACHE_NAME);
+
+        checkRemovePut(cache);
+
+        checkSelectAll(cache);
+
+        checkSelectStringEqual(cache);
+
+        checkSelectLongEqual(cache);
+
+        checkSelectStringRange(cache);
+
+        checkSelectLongRange(cache);
+    }
+
+    /** */
+    private void populateCache() {
+        IgniteCache<Key, Val> cache = grid().cache(DEFAULT_CACHE_NAME);
+
+        // Be paranoid and populate first even indexes in ascending order, 
then odd indexes in descending
+        // to check that inserting in the middle works.
+
+        for (int i = 0; i < 100; i += 2)
+            cache.put(key(i), val(i));
+
+        for (int i = 99; i > 0; i -= 2)
+            cache.put(key(i), val(i));
+
+        for (int i = 99; i > 0; i -= 2)
+            assertEquals(val(i), cache.get(key(i)));
+    }
+
+    /** */
+    private void checkRemovePut(IgniteCache<Key, Val> cache) {
+        final int INT = 24;
+
+        assertEquals(val(INT), cache.get(key(INT)));
+
+        cache.remove(key(INT));
+
+        assertNull(cache.get(key(INT)));
+
+        cache.put(key(INT), val(INT));
+
+        assertEquals(val(INT), cache.get(key(INT)));
+    }
+
+    /** */
+    private void checkSelectAll(IgniteCache<Key, Val> cache) {
+        List<List<?>> data = cache.query(new SqlFieldsQuery("select _key, _val 
from Val")).getAll();
+
+        assertEquals(100, data.size());
+
+        for (List<?> row : data) {
+            Key key = (Key)row.get(0);
+
+            Val val = (Val)row.get(1);
+
+            long i = key.keyLong;
+
+            assertEquals(key(i), key);
+
+            assertEquals(val(i), val);
+        }
+    }
+
+    /** */
+    private void checkSelectStringEqual(IgniteCache<Key, Val> cache) {
+        final String STR = "foo011";
+
+        final long LONG = 11;
+
+        List<List<?>> data = cache.query(new SqlFieldsQuery("select _key, _val 
from Val where keyStr = ?")
+            .setArgs(STR))
+            .getAll();
+
+        assertEquals(1, data.size());
+
+        List<?> row = data.get(0);
+
+        assertEquals(key(LONG), row.get(0));
+
+        assertEquals(val(LONG), row.get(1));
+    }
+
+    /** */
+    private void checkSelectLongEqual(IgniteCache<Key, Val> cache) {
+        final long LONG = 42;
+
+        List<List<?>> data = cache.query(new SqlFieldsQuery("select _key, _val 
from Val where valLong = ?")
+            .setArgs(LONG))
+            .getAll();
+
+        assertEquals(1, data.size());
+
+        List<?> row = data.get(0);
+
+        assertEquals(key(LONG), row.get(0));
+
+        assertEquals(val(LONG), row.get(1));
+    }
+
+    /** */
+    private void checkSelectStringRange(IgniteCache<Key, Val> cache) {
+        final String PREFIX = "foo06";
+
+        List<List<?>> data = cache.query(new SqlFieldsQuery("select _key, _val 
from Val where keyStr like ?")
+            .setArgs(PREFIX + "%"))
+            .getAll();
+
+        assertEquals(10, data.size());
+
+        for (List<?> row : data) {
+            Key key = (Key)row.get(0);
+
+            Val val = (Val)row.get(1);
+
+            long i = key.keyLong;
+
+            assertEquals(key(i), key);
+
+            assertEquals(val(i), val);
+
+            assertTrue(key.keyStr.startsWith(PREFIX));
+        }
+    }
+
+    /** */
+    private void checkSelectLongRange(IgniteCache<Key, Val> cache) {
+        final long RANGE_START = 70;
+
+        final long RANGE_END = 80;
+
+        List<List<?>> data = cache.query(
+            new SqlFieldsQuery("select _key, _val from Val where valLong >= ? 
and valLong < ?")
+                .setArgs(RANGE_START, RANGE_END))
+            .getAll();
+
+        assertEquals(10, data.size());
+
+        for (List<?> row : data) {
+            Key key = (Key)row.get(0);
+
+            Val val = (Val)row.get(1);
+
+            long i = key.keyLong;
+
+            assertEquals(key(i), key);
+
+            assertEquals(val(i), val);
+
+            assertTrue(i >= RANGE_START && i < RANGE_END);
+        }
+    }
+
+    /** Must be called when the grid is up. */
+    private Path getIndexBinPath() {
+        IgniteInternalCache<Object, Object> cachex = 
grid().cachex(DEFAULT_CACHE_NAME);
+
+        assertNotNull(cachex);
+
+        FilePageStoreManager pageStoreMgr = 
(FilePageStoreManager)cachex.context().shared().pageStore();
+
+        assertNotNull(pageStoreMgr);
+
+        File cacheWorkDir = pageStoreMgr.cacheWorkDir(cachex.configuration());
+
+        return cacheWorkDir.toPath().resolve("index.bin");
+    }
+
+    /** */
+    private void createDynamicIndexes(String... cols) {
+        IgniteCache<Key, Val> cache = grid().cache(DEFAULT_CACHE_NAME);
+
+        for (String col : cols) {
+            cache.query(new SqlFieldsQuery(
+                "create index on Val(" + col + ") INLINE_SIZE " + inlineSize
+            ));
+        }
+
+        cache.indexReadyFuture().get();
+    }
+
+    /** */
+    private static Key key(long i) {
+        return new Key(String.format("foo%03d", i), i, new Pojo(i));
+    }
+
+    /** */
+    private static Val val(long i) {
+        return new Val(String.format("bar%03d", i), i, new Pojo(i));
+    }
+
+    /** */
+    private static class Key {
+        /** */
+        private String keyStr;
+
+        /** */
+        private long keyLong;
+
+        /** */
+        private Pojo keyPojo;
+
+        /** */
+        private Key(String str, long aLong, Pojo pojo) {
+            keyStr = str;
+            keyLong = aLong;
+            keyPojo = pojo;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            Key key = (Key)o;
+
+            return keyLong == key.keyLong &&
+                Objects.equals(keyStr, key.keyStr) &&
+                Objects.equals(keyPojo, key.keyPojo);
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return Objects.hash(keyStr, keyLong, keyPojo);
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(Key.class, this);
+        }
+    }
+
+    /** */
+    private static class Val {
+        /** */
+        private String valStr;
+
+        /** */
+        private long valLong;
+
+        /** */
+        private Pojo valPojo;
+
+        /** */
+        private Val(String str, long aLong, Pojo pojo) {
+            valStr = str;
+            valLong = aLong;
+            valPojo = pojo;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            Val val = (Val)o;
+
+            return valLong == val.valLong &&
+                Objects.equals(valStr, val.valStr) &&
+                Objects.equals(valPojo, val.valPojo);
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return Objects.hash(valStr, valLong, valPojo);
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(Val.class, this);
+        }
+    }
+
+    /** */
+    private static class Pojo {
+        /** */
+        private long pojoLong;
+
+        /** */
+        private Pojo(long pojoLong) {
+            this.pojoLong = pojoLong;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            Pojo pojo = (Pojo)o;
+
+            return pojoLong == pojo.pojoLong;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return Objects.hash(pojoLong);
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(Pojo.class, this);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6e97d14/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java
index ea23483..4c64264 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java
@@ -1,3 +1,4 @@
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -42,6 +43,7 @@ import org.h2.value.ValueDate;
 import org.h2.value.ValueDouble;
 import org.h2.value.ValueFloat;
 import org.h2.value.ValueInt;
+import org.h2.value.ValueJavaObject;
 import org.h2.value.ValueLong;
 import org.h2.value.ValueNull;
 import org.h2.value.ValueShort;
@@ -49,6 +51,7 @@ import org.h2.value.ValueString;
 import org.h2.value.ValueTime;
 import org.h2.value.ValueTimestamp;
 import org.h2.value.ValueUuid;
+import org.springframework.util.SerializationUtils;
 
 /**
  * Simple tests for {@link InlineIndexHelper}.
@@ -169,7 +172,7 @@ public class InlineIndexHelperTest extends 
GridCommonAbstractTest {
             int i1 = rnd.nextInt(strings.length);
             int i2 = rnd.nextInt(strings.length);
 
-            assertEquals(Integer.compare(i1,i2), putAndCompare(strings[i1], 
strings[i2], inlineSize));
+            assertEquals(Integer.compare(i1, i2), putAndCompare(strings[i1], 
strings[i2], inlineSize));
         }
     }
 
@@ -185,12 +188,12 @@ public class InlineIndexHelperTest extends 
GridCommonAbstractTest {
             .setMaxSize(1024 * MB);
 
         PageMemory pageMem = new PageMemoryNoStoreImpl(log,
-                new UnsafeMemoryProvider(log),
-                null,
-                PAGE_SIZE,
-                plcCfg,
-                new DataRegionMetricsImpl(plcCfg),
-                false);
+            new UnsafeMemoryProvider(log),
+            null,
+            PAGE_SIZE,
+            plcCfg,
+            new DataRegionMetricsImpl(plcCfg),
+            false);
 
         pageMem.start();
 
@@ -209,7 +212,7 @@ public class InlineIndexHelperTest extends 
GridCommonAbstractTest {
 
             ih.put(pageAddr, off, v1 == null ? ValueNull.INSTANCE : 
ValueString.get(v1), maxSize);
 
-            return ih.compare(pageAddr, off, maxSize,  v2 == null ? 
ValueNull.INSTANCE : ValueString.get(v2), ALWAYS_FAILS_COMPARATOR);
+            return ih.compare(pageAddr, off, maxSize, v2 == null ? 
ValueNull.INSTANCE : ValueString.get(v2), ALWAYS_FAILS_COMPARATOR);
         }
         finally {
             if (page != 0L)
@@ -271,6 +274,30 @@ public class InlineIndexHelperTest extends 
GridCommonAbstractTest {
         assertTrue(getResBytes(ha, null, null));
     }
 
+    /** Test on Bytes values compare */
+    public void testRelyOnCompareJavaObject() {
+        InlineIndexHelper ha = new InlineIndexHelper(Value.JAVA_OBJECT, 0, 
SortOrder.ASCENDING,
+            CompareMode.getInstance(null, 0));
+
+        // different types
+        assertTrue(getResJavaObjects(ha, new String("1234"), new Integer(10)));
+
+        // the same types, but different values
+        assertTrue(getResJavaObjects(ha, new String("1234"), new 
String("123")));
+
+        // the same types and values
+        assertFalse(getResJavaObjects(ha, new String("1234"), new 
String("1234")));
+
+        // the same object
+        String key = "1";
+        assertFalse(getResJavaObjects(ha, key, key));
+
+        // one is null
+        assertTrue(getResJavaObjects(ha, key, null));
+        assertTrue(getResJavaObjects(ha, null, key));
+        assertTrue(getResJavaObjects(ha, null, null));
+    }
+
     /** */
     public void testStringTruncate() throws Exception {
         DataRegionConfiguration plcCfg = new 
DataRegionConfiguration().setInitialSize(1024 * MB)
@@ -350,17 +377,86 @@ public class InlineIndexHelperTest extends 
GridCommonAbstractTest {
             InlineIndexHelper ih = new InlineIndexHelper(Value.BYTES, 1, 0,
                 CompareMode.getInstance(null, 0));
 
-            ih.put(pageAddr, off, ValueBytes.get(new byte[] {1, 2, 3, 4, 5}), 
3 + 3);
+            int maxSize = 3 + 3;
+            int savedBytesCnt = ih.put(pageAddr, off, ValueBytes.get(new 
byte[] {1, 2, 3, 4, 5}), maxSize);
+
+            assertTrue(savedBytesCnt > 0);
+
+            assertTrue(savedBytesCnt <= maxSize);
+
+            assertFalse(ih.isValueFull(pageAddr, off));
+
+            maxSize = 3 + 5;
+
+            assertTrue(Arrays.equals(new byte[] {1, 2, 3}, ih.get(pageAddr, 
off, maxSize).getBytes()));
+
+            savedBytesCnt = ih.put(pageAddr, off, ValueBytes.get(new byte[] 
{1, 2, 3, 4, 5}), maxSize);
+
+            assertTrue(savedBytesCnt > 0);
+
+            assertTrue(savedBytesCnt <= maxSize);
+
+            assertTrue(ih.isValueFull(pageAddr, off));
+
+            assertTrue(Arrays.equals(new byte[] {1, 2, 3, 4, 5}, 
ih.get(pageAddr, off, maxSize).getBytes()));
+        }
+        finally {
+            if (page != 0L)
+                pageMem.releasePage(CACHE_ID, pageId, page);
+            pageMem.stop();
+        }
+    }
+
+    /** */
+    public void testJavaObject() throws Exception {
+        DataRegionConfiguration plcCfg = new 
DataRegionConfiguration().setInitialSize(1024 * MB)
+            .setMaxSize(1024 * MB);
+
+        PageMemory pageMem = new PageMemoryNoStoreImpl(log(),
+            new UnsafeMemoryProvider(log()),
+            null,
+            PAGE_SIZE,
+            plcCfg,
+            new DataRegionMetricsImpl(plcCfg),
+            false);
+
+        pageMem.start();
+
+        long pageId = 0L;
+        long page = 0L;
+
+        try {
+            pageId = pageMem.allocatePage(CACHE_ID, 1, 
PageIdAllocator.FLAG_DATA);
+            page = pageMem.acquirePage(CACHE_ID, pageId);
+            long pageAddr = pageMem.readLock(CACHE_ID, pageId, page);
+
+            int off = 0;
+
+            InlineIndexHelper ih = new InlineIndexHelper(Value.JAVA_OBJECT, 1, 
0,
+                CompareMode.getInstance(null, 0));
+
+            int maxSize = 3 + 3;
+            int savedBytesCnt = ih.put(pageAddr, off, 
ValueJavaObject.getNoCopy(null, new byte[] {1, 2, 3, 4, 5}, null), maxSize);
+
+            assertTrue(savedBytesCnt > 0);
+
+            assertTrue(savedBytesCnt <= maxSize);
 
             assertFalse(ih.isValueFull(pageAddr, off));
 
-            assertTrue(Arrays.equals(new byte[] {1, 2, 3}, ih.get(pageAddr, 
off, 3 + 5).getBytes()));
+            maxSize = 3 + 5;
+
+            assertTrue(Arrays.equals(new byte[] {1, 2, 3}, ih.get(pageAddr, 
off, maxSize).getBytes()));
 
-            ih.put(pageAddr, off, ValueBytes.get(new byte[] {1, 2, 3, 4, 5}), 
3 + 5);
+            savedBytesCnt = ih.put(pageAddr, off, 
ValueJavaObject.getNoCopy(null, new byte[] {1, 2, 3, 4, 5}, null), maxSize);
+
+            assertTrue(savedBytesCnt > 0);
+
+            assertTrue(savedBytesCnt <= maxSize);
 
             assertTrue(ih.isValueFull(pageAddr, off));
 
-            assertTrue(Arrays.equals(new byte[] {1, 2, 3, 4, 5}, 
ih.get(pageAddr, off, 3 + 5).getBytes()));
+            assertTrue(Arrays.equals(new byte[] {1, 2, 3, 4, 5}, 
ih.get(pageAddr, off, maxSize).getBytes()));
         }
         finally {
             if (page != 0L)
@@ -510,6 +606,16 @@ public class InlineIndexHelperTest extends 
GridCommonAbstractTest {
         return ha.canRelyOnCompare(c, v1, v2);
     }
 
+    /** */
+    private boolean getResJavaObjects(InlineIndexHelper ha, Object o1, Object 
o2) {
+        Value v1 = o1 == null ? ValueNull.INSTANCE : 
ValueJavaObject.getNoCopy(null, SerializationUtils.serialize(o1), null);
+        Value v2 = o2 == null ? ValueNull.INSTANCE : 
ValueJavaObject.getNoCopy(null, SerializationUtils.serialize(o2), null);
+
+        int c = v1.compareTypeSafe(v2, CompareMode.getInstance(null, 0));
+
+        return ha.canRelyOnCompare(c, v1, v2);
+    }
+
     /**
      * @param cnt String length.
      * @return Random string.
@@ -523,31 +629,31 @@ public class InlineIndexHelperTest extends 
GridCommonAbstractTest {
             char ch;
 
             if (rnd.nextInt(100) > 3)
-                ch = (char) (rnd.nextInt(95) + 32); // regular symbols
+                ch = (char)(rnd.nextInt(95) + 32); // regular symbols
             else
-                ch = (char) (rnd.nextInt(65407) + 127); // others symbols
+                ch = (char)(rnd.nextInt(65407) + 127); // others symbols
 
-            if(ch >= 56320 && ch <= 57343) {
-                if(cnt == 0)
+            if (ch >= 56320 && ch <= 57343) {
+                if (cnt == 0)
                     cnt++;
                 else {
                     // low surrogate, insert high surrogate after putting it in
                     buffer[cnt] = ch;
                     cnt--;
-                    buffer[cnt] = (char) (55296 + rnd.nextInt(128));
+                    buffer[cnt] = (char)(55296 + rnd.nextInt(128));
                 }
             }
-            else if(ch >= 55296 && ch <= 56191) {
-                if(cnt == 0)
+            else if (ch >= 55296 && ch <= 56191) {
+                if (cnt == 0)
                     cnt++;
                 else {
                     // high surrogate, insert low surrogate before putting it 
in
-                    buffer[cnt] = (char) (56320 + rnd.nextInt(128));
+                    buffer[cnt] = (char)(56320 + rnd.nextInt(128));
                     cnt--;
                     buffer[cnt] = ch;
                 }
             }
-            else if(ch >= 56192 && ch <= 56319)
+            else if (ch >= 56192 && ch <= 56319)
                 // private high surrogate, no effing clue, so skip it
                 cnt++;
             else

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6e97d14/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
index 7f67b35..1036eed 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
@@ -104,6 +104,7 @@ import 
org.apache.ignite.internal.processors.cache.distributed.replicated.Ignite
 import 
org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheReplicatedQueryEvtsDisabledSelfTest;
 import 
org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheReplicatedQueryP2PDisabledSelfTest;
 import 
org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheReplicatedQuerySelfTest;
+import org.apache.ignite.internal.processors.cache.index.BasicIndexTest;
 import 
org.apache.ignite.internal.processors.cache.index.DuplicateKeyValueClassesSelfTest;
 import 
org.apache.ignite.internal.processors.cache.index.DynamicIndexClientBasicSelfTest;
 import 
org.apache.ignite.internal.processors.cache.index.DynamicIndexServerBasicSelfTest;
@@ -225,6 +226,8 @@ public class IgniteCacheQuerySelfTestSuite extends 
TestSuite {
         suite.addTestSuite(SqlIllegalSchemaSelfTest.class);
         suite.addTestSuite(MultipleStatementsSqlQuerySelfTest.class);
 
+        suite.addTestSuite(BasicIndexTest.class);
+
         // Misc tests.
         // TODO: Enable when IGNITE-1094 is fixed.
         // suite.addTest(new TestSuite(QueryEntityValidationSelfTest.class));

Reply via email to