http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
----------------------------------------------------------------------
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 937363a..e726857 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
@@ -62,6 +62,7 @@ import 
org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheObjectValueContext;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture;
@@ -73,7 +74,6 @@ import 
org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccUtils;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
-import org.apache.ignite.internal.processors.query.h2.affinity.PartitionInfo;
 import org.apache.ignite.internal.processors.cache.query.GridCacheQueryManager;
 import 
org.apache.ignite.internal.processors.cache.query.GridCacheQueryMarshallable;
 import org.apache.ignite.internal.processors.cache.query.GridCacheTwoStepQuery;
@@ -100,7 +100,9 @@ import 
org.apache.ignite.internal.processors.query.QueryIndexDescriptorImpl;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.processors.query.SqlClientContext;
 import org.apache.ignite.internal.processors.query.UpdateSourceIterator;
+import org.apache.ignite.internal.processors.query.h2.affinity.PartitionInfo;
 import org.apache.ignite.internal.processors.query.h2.database.H2RowFactory;
+import 
org.apache.ignite.internal.processors.query.h2.database.H2TreeClientIndex;
 import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
 import 
org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasInnerIO;
 import 
org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasLeafIO;
@@ -751,16 +753,20 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
     GridH2IndexBase createSortedIndex(String name, GridH2Table tbl, boolean 
pk, boolean affinityKey,
         List<IndexColumn> unwrappedCols, List<IndexColumn> wrappedCols, int 
inlineSize) {
         try {
-            GridCacheContext cctx = tbl.cache();
+            GridCacheContextInfo cacheInfo = tbl.cacheInfo();
 
             if (log.isDebugEnabled())
-                log.debug("Creating cache index [cacheId=" + cctx.cacheId() + 
", idxName=" + name + ']');
+                log.debug("Creating cache index [cacheId=" + 
cacheInfo.cacheId() + ", idxName=" + name + ']');
 
-            final int segments = 
tbl.rowDescriptor().context().config().getQueryParallelism();
+            if (cacheInfo.affinityNode()) {
+                final int segments = 
tbl.rowDescriptor().context().config().getQueryParallelism();
 
-            H2RowCache cache = rowCache.forGroup(cctx.groupId());
+                H2RowCache cache = rowCache.forGroup(cacheInfo.groupId());
 
-            return new H2TreeIndex(cctx, cache, tbl, name, pk, affinityKey, 
unwrappedCols, wrappedCols, inlineSize, segments);
+                return new H2TreeIndex(cacheInfo.gridCacheContext(), cache, 
tbl, name, pk, affinityKey, unwrappedCols, wrappedCols, inlineSize, segments);
+            }
+            else
+                return new H2TreeClientIndex(tbl, name, pk, unwrappedCols);
         }
         catch (IgniteCheckedException e) {
             throw new IgniteException(e);
@@ -1379,7 +1385,7 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
             if (o instanceof GridSqlAlias)
                 o = GridSqlAlias.unwrap((GridSqlAst) o);
             if (o instanceof GridSqlTable && ((GridSqlTable) o).dataTable() != 
null) {
-                GridCacheContext cctx = ((GridSqlTable) o).dataTable().cache();
+                GridCacheContext cctx = 
((GridSqlTable)o).dataTable().cacheContext();
 
                 if (mvccEnabled == null) {
                     mvccEnabled = cctx.mvccEnabled();
@@ -2335,31 +2341,12 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
      * @return H2 prepared statement.
      */
     private PreparedStatement prepareStatementAndCaches(Connection c, String 
sqlQry) {
-        boolean cachesCreated = false;
-
-        while (true) {
-            try {
-                return prepareStatement(c, sqlQry, true);
-            }
-            catch (SQLException e) {
-                if (!cachesCreated && (
-                        e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 ||
-                            e.getErrorCode() == 
ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 ||
-                            e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1)
-                        ) {
-                    try {
-                        ctx.cache().createMissingQueryCaches();
-                    }
-                    catch (IgniteCheckedException ignored) {
-                        throw new CacheException("Failed to create missing 
caches.", e);
-                    }
-
-                    cachesCreated = true;
-                }
-                else
-                    throw new IgniteSQLException("Failed to parse query. " + 
e.getMessage(),
-                        IgniteQueryErrorCode.PARSING, e);
-            }
+        try {
+            return prepareStatement(c, sqlQry, true);
+        }
+        catch (SQLException e) {
+            throw new IgniteSQLException("Failed to parse query. " + 
e.getMessage(),
+                IgniteQueryErrorCode.PARSING, e);
         }
     }
 
@@ -2445,19 +2432,20 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
      *
      * This implementation doesn't support type reregistration.
      *
+     * @param cacheInfo Cache context info.
      * @param type Type description.
      * @param isSql {@code true} in case table has been created from SQL.
      * @throws IgniteCheckedException In case of error.
      */
-    @Override public boolean registerType(GridCacheContext cctx, 
GridQueryTypeDescriptor type, boolean isSql)
+    @Override public boolean registerType(GridCacheContextInfo cacheInfo, 
GridQueryTypeDescriptor type, boolean isSql)
         throws IgniteCheckedException {
         validateTypeDescriptor(type);
 
-        String schemaName = schema(cctx.name());
+        String schemaName = schema(cacheInfo.name());
 
         H2Schema schema = schemas.get(schemaName);
 
-        H2TableDescriptor tbl = new H2TableDescriptor(this, schema, type, 
cctx, isSql);
+        H2TableDescriptor tbl = new H2TableDescriptor(this, schema, type, 
cacheInfo, isSql);
 
         try {
             Connection conn = connMgr.connectionForThread(schemaName);
@@ -2596,6 +2584,16 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
         dataTables.remove(h2Tbl.identifier(), h2Tbl);
     }
 
+    /** {@inheritDoc} */
+    public GridCacheContextInfo registeredCacheInfo(String cacheName) {
+        for (GridH2Table value : dataTables.values()) {
+            if (value.cacheName().equals(cacheName))
+                return value.cacheInfo();
+        }
+
+        return null;
+    }
+
     /**
      * Find table for index.
      *
@@ -2675,7 +2673,7 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
         List<H2TableDescriptor> tbls = new ArrayList<>();
 
         for (H2TableDescriptor tbl : s.tables()) {
-            if (F.eq(tbl.cache().name(), cacheName))
+            if (F.eq(tbl.cacheName(), cacheName))
                 tbls.add(tbl);
         }
 
@@ -3044,9 +3042,25 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
     }
 
     /** {@inheritDoc} */
-    @Override public void registerCache(String cacheName, String schemaName, 
GridCacheContext<?, ?> cctx)
+    @Override public boolean initCacheContext(GridCacheContext cacheCtx) {
+        GridCacheContextInfo cacheInfo = registeredCacheInfo(cacheCtx.name());
+
+        if (cacheInfo != null) {
+            assert !cacheInfo.isCacheContextInited() : cacheInfo.name();
+            assert cacheInfo.name().equals(cacheCtx.name()) : cacheInfo.name() 
+ " != " + cacheCtx.name();
+
+            cacheInfo.initCacheContext(cacheCtx);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void registerCache(String cacheName, String schemaName, 
GridCacheContextInfo<?, ?> cacheInfo)
         throws IgniteCheckedException {
-        rowCache.onCacheRegistered(cctx);
+        rowCache.onCacheRegistered(cacheInfo);
 
         synchronized (schemaMux) {
             createSchemaIfNeeded(schemaName, false);
@@ -3054,14 +3068,14 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
 
         cacheName2schema.put(cacheName, schemaName);
 
-        createSqlFunctions(schemaName, cctx.config().getSqlFunctionClasses());
+        createSqlFunctions(schemaName, 
cacheInfo.config().getSqlFunctionClasses());
     }
 
     /** {@inheritDoc} */
-    @Override public void unregisterCache(GridCacheContext cctx, boolean 
rmvIdx) {
-        rowCache.onCacheUnregistered(cctx);
+    @Override public void unregisterCache(GridCacheContextInfo cacheInfo, 
boolean rmvIdx) {
+        rowCache.onCacheUnregistered(cacheInfo);
 
-        String cacheName = cctx.name();
+        String cacheName = cacheInfo.name();
 
         String schemaName = schema(cacheName);
 
@@ -3078,7 +3092,7 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
             Collection<H2TableDescriptor> rmvTbls = new HashSet<>();
 
             for (H2TableDescriptor tbl : schema.tables()) {
-                if (F.eq(tbl.cache().name(), cacheName)) {
+                if (F.eq(tbl.cacheName(), cacheName)) {
                     try {
                         tbl.table().setRemoveIndexOnDestroy(rmvIdx);
 
@@ -3297,6 +3311,8 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
                 GridH2Table tbl = dataTable(tblKey);
 
                 if (tbl != null) {
+                    H2Utils.checkAndStartNotStartedCache(tbl);
+
                     int cacheId = tbl.cacheId();
 
                     caches0.add(cacheId);

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeClientIndex.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeClientIndex.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeClientIndex.java
new file mode 100644
index 0000000..a0bab43
--- /dev/null
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeClientIndex.java
@@ -0,0 +1,114 @@
+/*
+ * 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.database;
+
+import java.util.List;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
+import org.h2.engine.Session;
+import org.h2.index.Cursor;
+import org.h2.index.IndexType;
+import org.h2.result.SearchRow;
+import org.h2.table.IndexColumn;
+
+/**
+ * We need indexes on an not affinity nodes. The index shouldn't contains any 
data.
+ */
+public class H2TreeClientIndex extends H2TreeIndexBase {
+
+    /**
+     *
+     */
+    public static final IgniteSQLException SHOULDNT_BE_INVOKED_EXCEPTION = new 
IgniteSQLException("Shouldn't be invoked, due to it's not affinity node");
+
+    /**
+     * @param tbl Table.
+     * @param name Index name.
+     * @param pk Primary key.
+     * @param colsList Index columns.
+     */
+    public H2TreeClientIndex(
+        GridH2Table tbl,
+        String name,
+        boolean pk,
+        List<IndexColumn> colsList
+    ) {
+        IndexColumn[] cols = colsList.toArray(new 
IndexColumn[colsList.size()]);
+
+        IndexColumn.mapColumns(cols, tbl);
+
+        initBaseIndex(tbl, 0, name, cols,
+            pk ? IndexType.createPrimaryKey(false, false) : 
IndexType.createNonUnique(false, false, false));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void refreshColumnIds() {
+        //do nothing.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void destroy(boolean rmvIndex) {
+        //do nothing.
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int segmentsCount() {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Cursor find(Session ses, SearchRow lower, SearchRow 
upper) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public GridH2Row put(GridH2Row row) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean putx(GridH2Row row) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public GridH2Row remove(SearchRow row) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean removex(SearchRow row) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getRowCount(Session ses) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Cursor findFirstOrLast(Session session, boolean b) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected H2Tree treeForRead(int segment) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
index b7179b7..2c0a9d8 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal.processors.query.h2.database;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.IgniteCheckedException;
@@ -35,7 +34,6 @@ import 
org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.h2.H2Cursor;
 import org.apache.ignite.internal.processors.query.h2.H2RowCache;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Cursor;
-import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryContext;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
@@ -52,10 +50,7 @@ import org.h2.index.IndexType;
 import org.h2.index.SingleRowCursor;
 import org.h2.message.DbException;
 import org.h2.result.SearchRow;
-import org.h2.result.SortOrder;
-import org.h2.table.Column;
 import org.h2.table.IndexColumn;
-import org.h2.table.TableFilter;
 import org.h2.value.Value;
 import org.jetbrains.annotations.Nullable;
 
@@ -63,7 +58,7 @@ import org.jetbrains.annotations.Nullable;
  * H2 Index over {@link BPlusTree}.
  */
 @SuppressWarnings({"TypeMayBeWeakened", "unchecked"})
-public class H2TreeIndex extends GridH2IndexBase {
+public class H2TreeIndex extends H2TreeIndexBase {
     /** Default value for {@code IGNITE_MAX_INDEX_PAYLOAD_SIZE} */
     public static final int IGNITE_MAX_INDEX_PAYLOAD_SIZE_DEFAULT = 10;
 
@@ -145,66 +140,59 @@ public class H2TreeIndex extends GridH2IndexBase {
 
         IndexColumn[] cols;
 
-        if (cctx.affinityNode()) {
-            segments = new H2Tree[segmentsCnt];
-
-            IgniteCacheDatabaseSharedManager db = cctx.shared().database();
-
-            AtomicInteger maxCalculatedInlineSize = new AtomicInteger();
-
-            for (int i = 0; i < segments.length; i++) {
-                db.checkpointReadLock();
-
-                try {
-                    RootPage page = getMetaPage(treeName, i);
-
-                    segments[i] = new H2Tree(
-                        treeName,
-                        idxName,
-                        tblName,
-                        tbl.cacheName(),
-                        cctx.offheap().reuseListForIndex(treeName),
-                        cctx.groupId(),
-                        cctx.dataRegion().pageMemory(),
-                        cctx.shared().wal(),
-                        cctx.offheap().globalRemoveId(),
-                        tbl.rowFactory(),
-                        page.pageId().pageId(),
-                        page.isAllocated(),
-                        unwrappedColsInfo,
-                        wrappedColsInfo,
-                        maxCalculatedInlineSize,
-                        pk,
-                        affinityKey,
-                        cctx.mvccEnabled(),
-                        rowCache,
-                        cctx.kernalContext().failure(),
-                        log) {
-                        @Override public int compareValues(Value v1, Value v2) 
{
-                            return v1 == v2 ? 0 : table.compareTypeSafe(v1, 
v2);
-                        }
-                    };
-                }
-                finally {
-                    db.checkpointReadUnlock();
-                }
+        assert cctx.affinityNode();
+
+        segments = new H2Tree[segmentsCnt];
+
+        IgniteCacheDatabaseSharedManager db = cctx.shared().database();
+
+        AtomicInteger maxCalculatedInlineSize = new AtomicInteger();
+
+        for (int i = 0; i < segments.length; i++) {
+            db.checkpointReadLock();
+
+            try {
+                RootPage page = getMetaPage(treeName, i);
+
+                segments[i] = new H2Tree(
+                    treeName,
+                    idxName,
+                    tblName,
+                    tbl.cacheName(),
+                    cctx.offheap().reuseListForIndex(treeName),
+                    cctx.groupId(),
+                    cctx.dataRegion().pageMemory(),
+                    cctx.shared().wal(),
+                    cctx.offheap().globalRemoveId(),
+                    tbl.rowFactory(),
+                    page.pageId().pageId(),
+                    page.isAllocated(),
+                    unwrappedColsInfo,
+                    wrappedColsInfo,
+                    maxCalculatedInlineSize,
+                    pk,
+                    affinityKey,
+                    cctx.mvccEnabled(),
+                    rowCache,
+                    cctx.kernalContext().failure(),
+                    log) {
+                    @Override public int compareValues(Value v1, Value v2) {
+                        return v1 == v2 ? 0 : table.compareTypeSafe(v1, v2);
+                    }
+                };
             }
+            finally {
+                db.checkpointReadUnlock();
+            }
+        }
 
-            boolean useUnwrappedCols = segments[0].unwrappedPk();
-
-            IndexColumnsInfo colsInfo = useUnwrappedCols ? unwrappedColsInfo : 
wrappedColsInfo;
+        boolean useUnwrappedCols = segments[0].unwrappedPk();
 
-            cols = colsInfo.cols();
+        IndexColumnsInfo colsInfo = useUnwrappedCols ? unwrappedColsInfo : 
wrappedColsInfo;
 
-            inlineIdxs = colsInfo.inlineIdx();
-        }
-        else {
-            // We need indexes on the client node, but index will not contain 
any data.
-            segments = null;
-            inlineIdxs = null;
+        cols = colsInfo.cols();
 
-            cols = unwrappedColsInfo.cols();
-        }
+        inlineIdxs = colsInfo.inlineIdx();
 
         IndexColumn.mapColumns(cols, tbl);
 
@@ -371,17 +359,6 @@ public class H2TreeIndex extends GridH2IndexBase {
     }
 
     /** {@inheritDoc} */
-    @Override public double getCost(Session ses, int[] masks, TableFilter[] 
filters, int filter, SortOrder sortOrder, HashSet<Column> allColumnsSet) {
-        long rowCnt = getRowCountApproximation();
-
-        double baseCost = getCostRangeIndex(masks, rowCnt, filters, filter, 
sortOrder, false, allColumnsSet);
-
-        int mul = getDistributedMultiplier(ses, filters, filter);
-
-        return mul * baseCost;
-    }
-
-    /** {@inheritDoc} */
     @Override public long getRowCount(Session ses) {
         try {
             int seg = threadLocalSegment();
@@ -398,16 +375,6 @@ public class H2TreeIndex extends GridH2IndexBase {
     }
 
     /** {@inheritDoc} */
-    @Override public long getRowCountApproximation() {
-        return 10_000; // TODO
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean canGetFirstOrLast() {
-        return true;
-    }
-
-    /** {@inheritDoc} */
     @Override public Cursor findFirstOrLast(Session session, boolean b) {
         try {
             H2Tree tree = treeForRead(threadLocalSegment());

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java
new file mode 100644
index 0000000..e6dda14
--- /dev/null
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java
@@ -0,0 +1,53 @@
+/*
+ * 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.database;
+
+import java.util.HashSet;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
+import org.h2.engine.Session;
+import org.h2.result.SortOrder;
+import org.h2.table.Column;
+import org.h2.table.TableFilter;
+
+/**
+ * H2 tree index base.
+ */
+public abstract class H2TreeIndexBase extends GridH2IndexBase {
+    /** {@inheritDoc} */
+    @Override public double getCost(Session ses, int[] masks, TableFilter[] 
filters, int filter, SortOrder sortOrder,
+        HashSet<Column> allColumnsSet) {
+        long rowCnt = getRowCountApproximation();
+
+        double baseCost = getCostRangeIndex(masks, rowCnt, filters, filter, 
sortOrder, false, allColumnsSet);
+
+        int mul = getDistributedMultiplier(ses, filters, filter);
+
+        return mul * baseCost;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean canGetFirstOrLast() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getRowCountApproximation() {
+        return 10_000; // TODO
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
index b99d7dc..6308eab 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
@@ -129,7 +129,7 @@ public class DdlStatementsProcessor {
             if (cmd instanceof SqlCreateIndexCommand) {
                 SqlCreateIndexCommand cmd0 = (SqlCreateIndexCommand)cmd;
 
-                GridH2Table tbl = dataTableWithRetry(cmd0.schemaName(), 
cmd0.tableName());
+                GridH2Table tbl = idx.dataTable(cmd0.schemaName(), 
cmd0.tableName());
 
                 if (tbl == null)
                     throw new 
SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND, 
cmd0.tableName());
@@ -167,7 +167,7 @@ public class DdlStatementsProcessor {
             else if (cmd instanceof SqlDropIndexCommand) {
                 SqlDropIndexCommand cmd0 = (SqlDropIndexCommand)cmd;
 
-                GridH2Table tbl = 
dataTableForIndexWithRetry(cmd0.schemaName(), cmd0.indexName());
+                GridH2Table tbl = idx.dataTableForIndex(cmd0.schemaName(), 
cmd0.indexName());
 
                 if (tbl != null) {
                     isDdlSupported(tbl);
@@ -186,7 +186,7 @@ public class DdlStatementsProcessor {
             else if (cmd instanceof SqlAlterTableCommand) {
                 SqlAlterTableCommand cmd0 = (SqlAlterTableCommand)cmd;
 
-                GridH2Table tbl = dataTableWithRetry(cmd0.schemaName(), 
cmd0.tableName());
+                GridH2Table tbl = idx.dataTable(cmd0.schemaName(), 
cmd0.tableName());
 
                 if (tbl == null) {
                     throw new 
SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND,
@@ -270,7 +270,7 @@ public class DdlStatementsProcessor {
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), 
cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), 
cmd.tableName());
 
                 if (tbl == null)
                     throw new 
SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND, 
cmd.tableName());
@@ -309,7 +309,7 @@ public class DdlStatementsProcessor {
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableForIndexWithRetry(cmd.schemaName(), 
cmd.indexName());
+                GridH2Table tbl = idx.dataTableForIndex(cmd.schemaName(), 
cmd.indexName());
 
                 if (tbl != null) {
                     isDdlSupported(tbl);
@@ -332,7 +332,7 @@ public class DdlStatementsProcessor {
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), 
cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), 
cmd.tableName());
 
                 if (tbl != null) {
                     if (!cmd.ifNotExists())
@@ -365,7 +365,7 @@ public class DdlStatementsProcessor {
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), 
cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), 
cmd.tableName());
 
                 if (tbl == null) {
                     if (!cmd.ifExists())
@@ -380,7 +380,7 @@ public class DdlStatementsProcessor {
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), 
cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), 
cmd.tableName());
 
                 if (tbl == null) {
                     if (!cmd.ifTableExists())
@@ -423,7 +423,7 @@ public class DdlStatementsProcessor {
                         assert tbl.rowDescriptor() != null;
 
                         if (!allFieldsNullable)
-                            
QueryUtils.checkNotNullAllowed(tbl.cache().config());
+                            
QueryUtils.checkNotNullAllowed(tbl.cacheContext().config());
 
                         fut = ctx.query().dynamicColumnAdd(tbl.cacheName(), 
cmd.schemaName(),
                             tbl.rowDescriptor().type().tableName(), cols, 
cmd.ifTableExists(), cmd.ifNotExists());
@@ -435,7 +435,7 @@ public class DdlStatementsProcessor {
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), 
cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), 
cmd.tableName());
 
                 if (tbl == null) {
                     if (!cmd.ifTableExists())
@@ -445,7 +445,7 @@ public class DdlStatementsProcessor {
                 else {
                     assert tbl.rowDescriptor() != null;
 
-                    if (tbl.cache().mvccEnabled())
+                    if (tbl.cacheContext().mvccEnabled())
                         throw new IgniteSQLException("Cannot drop column(s) 
with enabled MVCC. " +
                             "Operation is unsupported at the moment.", 
IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
 
@@ -511,46 +511,6 @@ public class DdlStatementsProcessor {
     }
 
     /**
-     * Get table by name optionally creating missing query caches.
-     *
-     * @param schemaName Schema name.
-     * @param tableName Table name.
-     * @return Table or {@code null} if none found.
-     * @throws IgniteCheckedException If failed.
-     */
-    private GridH2Table dataTableWithRetry(String schemaName, String 
tableName) throws IgniteCheckedException {
-        GridH2Table tbl = idx.dataTable(schemaName, tableName);
-
-        if (tbl == null) {
-            ctx.cache().createMissingQueryCaches();
-
-            tbl = idx.dataTable(schemaName, tableName);
-        }
-
-        return tbl;
-    }
-
-    /**
-     * Get table by name optionally creating missing query caches.
-     *
-     * @param schemaName Schema name.
-     * @param indexName Index name.
-     * @return Table or {@code null} if none found.
-     * @throws IgniteCheckedException If failed.
-     */
-    private GridH2Table dataTableForIndexWithRetry(String schemaName, String 
indexName) throws IgniteCheckedException {
-        GridH2Table tbl = idx.dataTableForIndex(schemaName, indexName);
-
-        if (tbl == null) {
-            ctx.cache().createMissingQueryCaches();
-
-            tbl = idx.dataTableForIndex(schemaName, indexName);
-        }
-
-        return tbl;
-    }
-
-    /**
      * Check if schema supports DDL statement.
      *
      * @param schemaName Schema name.
@@ -567,7 +527,7 @@ public class DdlStatementsProcessor {
      * @param tbl Table.
      */
     private static void isDdlSupported(GridH2Table tbl) {
-        GridCacheContext cctx = tbl.cache();
+        GridCacheContext cctx = tbl.cacheContext();
 
         assert cctx != null;
 
@@ -683,11 +643,10 @@ public class DdlStatementsProcessor {
                 scale.put(e.getKey(), col.getScale());
             }
 
-            if (col.getType() == Value.STRING || 
-                col.getType() == Value.STRING_FIXED || 
-                col.getType() == Value.STRING_IGNORECASE) {
+            if (col.getType() == Value.STRING ||
+                col.getType() == Value.STRING_FIXED ||
+                col.getType() == Value.STRING_IGNORECASE)
                 precision.put(e.getKey(), (int)col.getPrecision());
-            }
         }
 
         if (!F.isEmpty(dfltValues))

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
index 0f8b6d8..fc3514b 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
@@ -535,7 +535,7 @@ public final class UpdatePlan {
      * @return Cache context.
      */
     public GridCacheContext cacheContext() {
-        return tbl.cache();
+        return tbl.cacheContext();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
index 477f22a..f1826a1 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
@@ -22,6 +22,7 @@ import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -39,6 +40,7 @@ import 
org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.processors.query.h2.DmlStatementsProcessor;
+import org.apache.ignite.internal.processors.query.h2.H2Utils;
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
@@ -93,6 +95,7 @@ public final class UpdatePlanBuilder {
      * @param fieldsQry Original query.
      * @return Update plan.
      */
+    @SuppressWarnings("ConstantConditions")
     public static UpdatePlan planForStatement(Prepared prepared, boolean loc, 
IgniteH2Indexing idx,
         @Nullable Connection conn, @Nullable SqlFieldsQuery fieldsQry, 
@Nullable Integer errKeysPos,
         boolean dmlInsideTxAllowed)
@@ -103,15 +106,60 @@ public final class UpdatePlanBuilder {
 
         GridSqlStatement stmt = parser.parse(prepared);
 
-        boolean mvccEnabled = false;
+
+        List<GridH2Table> tbls = extractTablesParticipateAtQuery(parser);
 
         GridCacheContext prevCctx = null;
+        boolean mvccEnabled = false;
 
-        for (Object o : parser.objectsMap().values()) {
-            if (o instanceof GridSqlInsert)
-                o = ((GridSqlInsert)o).into();
-            else if (o instanceof GridSqlMerge)
+        for (GridH2Table h2tbl : tbls) {
+            H2Utils.checkAndStartNotStartedCache(h2tbl);
+
+            if (prevCctx == null) {
+                prevCctx = h2tbl.cacheContext();
+
+                assert prevCctx != null : h2tbl.cacheName() + " is not 
initted";
+
+                mvccEnabled = prevCctx.mvccEnabled();
+
+                if (!mvccEnabled && !dmlInsideTxAllowed && 
prevCctx.cache().context().tm().inUserTx()) {
+                    throw new IgniteSQLException("DML statements are not 
allowed inside a transaction over " +
+                        "cache(s) with TRANSACTIONAL atomicity mode (change 
atomicity mode to " +
+                        "TRANSACTIONAL_SNAPSHOT or disable this error message 
with system property " +
+                        "\"IGNITE_ALLOW_DML_INSIDE_TRANSACTION\" [cacheName=" 
+ prevCctx.name() + ']');
+                }
+            }
+            else if (h2tbl.cacheContext().mvccEnabled() != mvccEnabled)
+                MvccUtils.throwAtomicityModesMismatchException(prevCctx, 
h2tbl.cacheContext());
+        }
+
+        if (stmt instanceof GridSqlMerge || stmt instanceof GridSqlInsert)
+            return planForInsert(stmt, loc, idx, mvccEnabled, conn, fieldsQry);
+        else if (stmt instanceof GridSqlUpdate || stmt instanceof 
GridSqlDelete)
+            return planForUpdate(stmt, loc, idx, mvccEnabled, conn, fieldsQry, 
errKeysPos);
+        else
+            throw new IgniteSQLException("Unsupported operation: " + 
prepared.getSQL(),
+                IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
+    }
+
+    /**
+     * Extract all tables participate at query
+     *
+     * @param parser Parser related to the query.
+     * @return List of tables participate at query.
+     * @throws IgniteSQLException in case query contains virtual tables.
+     */
+    private static List<GridH2Table> 
extractTablesParticipateAtQuery(GridSqlQueryParser parser) throws 
IgniteSQLException {
+        Collection<?> parserObjects = parser.objectsMap().values();
+
+        List<GridH2Table> tbls = new ArrayList<>(parserObjects.size());
+
+        // check all involved caches
+        for (Object o : parserObjects) {
+            if (o instanceof GridSqlMerge)
                 o = ((GridSqlMerge)o).into();
+            else if (o instanceof GridSqlInsert)
+                o = ((GridSqlInsert)o).into();
             else if (o instanceof GridSqlUpdate)
                 o = ((GridSqlUpdate)o).target();
             else if (o instanceof GridSqlDelete)
@@ -121,39 +169,18 @@ public final class UpdatePlanBuilder {
                 o = GridSqlAlias.unwrap((GridSqlAst)o);
 
             if (o instanceof GridSqlTable) {
-                if (((GridSqlTable)o).dataTable() == null) { // Check for 
virtual tables.
+                GridH2Table h2tbl = ((GridSqlTable)o).dataTable();
+
+                if (h2tbl == null) { // Check for virtual tables.
                     throw new IgniteSQLException("Operation not supported for 
table '" +
                         ((GridSqlTable)o).tableName() + "'", 
IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
                 }
 
-                if (prevCctx == null) {
-                    prevCctx = (((GridSqlTable)o).dataTable()).cache();
-
-                    mvccEnabled = prevCctx.mvccEnabled();
-
-                    if (!mvccEnabled && !dmlInsideTxAllowed && 
prevCctx.cache().context().tm().inUserTx()) {
-                        throw new IgniteSQLException("DML statements are not 
allowed inside a transaction over " +
-                            "cache(s) with TRANSACTIONAL atomicity mode 
(change atomicity mode to " +
-                            "TRANSACTIONAL_SNAPSHOT or disable this error 
message with system property " +
-                            "\"IGNITE_ALLOW_DML_INSIDE_TRANSACTION\" 
[cacheName=" + prevCctx.name() + ']');
-                    }
-                }
-                else {
-                    GridCacheContext cctx = 
((GridSqlTable)o).dataTable().cache();
-
-                    if (cctx.mvccEnabled() != mvccEnabled)
-                        
MvccUtils.throwAtomicityModesMismatchException(prevCctx, cctx);
-                }
+                tbls.add(h2tbl);
             }
         }
 
-        if (stmt instanceof GridSqlMerge || stmt instanceof GridSqlInsert)
-            return planForInsert(stmt, loc, idx, mvccEnabled, conn, fieldsQry);
-        else if (stmt instanceof GridSqlUpdate || stmt instanceof 
GridSqlDelete)
-            return planForUpdate(stmt, loc, idx, mvccEnabled, conn, fieldsQry, 
errKeysPos);
-        else
-            throw new IgniteSQLException("Unsupported operation: " + 
prepared.getSQL(),
-                    IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
+        return tbls;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
index 9c4941d..ddfc437 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
@@ -29,6 +29,7 @@ import java.util.UUID;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.query.GridQueryProperty;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
@@ -57,6 +58,7 @@ import org.h2.value.ValueString;
 import org.h2.value.ValueTime;
 import org.h2.value.ValueTimestamp;
 import org.h2.value.ValueUuid;
+import org.jetbrains.annotations.Nullable;
 
 import static 
org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap.DEFAULT_COLUMNS_COUNT;
 import static 
org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap.KEY_COL;
@@ -171,12 +173,22 @@ public class GridH2RowDescriptor {
         return type;
     }
 
+
+    /**
+     * Gets cache context info for this row descriptor.
+     *
+     * @return Cache context info.
+     */
+    public GridCacheContextInfo<?, ?> cacheInfo() {
+        return tbl.cacheInfo();
+    }
+
     /**
      * Gets cache context for this row descriptor.
      *
      * @return Cache context.
      */
-    public GridCacheContext<?, ?> context() {
+    @Nullable public GridCacheContext<?, ?> context() {
         return tbl.cache();
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SystemIndexFactory.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SystemIndexFactory.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SystemIndexFactory.java
index f150b6a..fa1e5cb 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SystemIndexFactory.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SystemIndexFactory.java
@@ -17,19 +17,17 @@
 
 package org.apache.ignite.internal.processors.query.h2.opt;
 
-import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
-import org.h2.index.Index;
-
 import java.util.ArrayList;
+import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndexBase;
+import org.h2.index.Index;
 
 /**
  * Factory for system table indexes.
  */
 public interface GridH2SystemIndexFactory {
     /**
-     * Create list of indexes. First must be primary key, after that all 
unique indexes and
-     * only then non-unique indexes.
-     * All indexes must be subtypes of {@link H2TreeIndex}.
+     * Create list of indexes. First must be primary key, after that all 
unique indexes and only then non-unique
+     * indexes. All indexes must be subtypes of {@link H2TreeIndexBase}.
      *
      * @param tbl Table to create indexes for.
      * @return List of indexes.

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
index b2da670..ef31f20 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
@@ -31,12 +31,13 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteInterruptedException;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.cache.query.QueryTable;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.QueryField;
 import org.apache.ignite.internal.processors.query.h2.database.H2RowFactory;
-import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
+import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndexBase;
 import 
org.apache.ignite.internal.processors.query.h2.twostep.GridMapQueryExecutor;
 import org.apache.ignite.internal.util.typedef.F;
 import org.h2.command.ddl.CreateTableData;
@@ -69,8 +70,8 @@ public class GridH2Table extends TableBase {
     /** Insert hack flag. */
     private static final ThreadLocal<Boolean> INSERT_HACK = new 
ThreadLocal<>();
 
-    /** Cache context. */
-    private final GridCacheContext cctx;
+    /** Cache context info. */
+    private final GridCacheContextInfo cacheInfo;
 
     /** */
     private final GridH2RowDescriptor desc;
@@ -124,16 +125,16 @@ public class GridH2Table extends TableBase {
      * @param desc Row descriptor.
      * @param rowFactory Row factory.
      * @param idxsFactory Indexes factory.
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      */
     public GridH2Table(CreateTableData createTblData, GridH2RowDescriptor 
desc, H2RowFactory rowFactory,
-        GridH2SystemIndexFactory idxsFactory, GridCacheContext cctx) {
+        GridH2SystemIndexFactory idxsFactory, GridCacheContextInfo cacheInfo) {
         super(createTblData);
 
         assert idxsFactory != null;
 
         this.desc = desc;
-        this.cctx = cctx;
+        this.cacheInfo = cacheInfo;
 
         if (desc.context() != null && !desc.context().customAffinityMapper()) {
             boolean affinityColExists = true;
@@ -200,7 +201,7 @@ public class GridH2Table extends TableBase {
      * @return {@code true} If this is a partitioned table.
      */
     public boolean isPartitioned() {
-        return desc != null && desc.context().config().getCacheMode() == 
PARTITIONED;
+        return desc != null && desc.cacheInfo().config().getCacheMode() == 
PARTITIONED;
     }
 
     /**
@@ -226,21 +227,35 @@ public class GridH2Table extends TableBase {
      * @return Cache name.
      */
     public String cacheName() {
-        return cctx.name();
+        return cacheInfo.name();
     }
 
     /**
      * @return Cache ID.
      */
     public int cacheId() {
-        return cctx.cacheId();
+        return cacheInfo.cacheId();
+    }
+
+    /**
+     * @return Cache context info.
+     */
+    public GridCacheContextInfo cacheInfo() {
+        return cacheInfo;
+    }
+
+    /**
+     * @return {@code true} If Cache is lazy (not full inited).
+     */
+    public boolean isCacheLazy() {
+        return cacheInfo.gridCacheContext() == null;
     }
 
     /**
      * @return Cache context.
      */
-    public GridCacheContext cache() {
-        return cctx;
+    @Nullable public GridCacheContext cacheContext() {
+        return cacheInfo.gridCacheContext();
     }
 
     /** {@inheritDoc} */
@@ -854,7 +869,7 @@ public class GridH2Table extends TableBase {
      * @return Proxy index.
      */
     private Index createDuplicateIndexIfNeeded(Index target) {
-        if (!(target instanceof H2TreeIndex) && !(target instanceof 
SpatialIndex))
+        if (!(target instanceof H2TreeIndexBase) && !(target instanceof 
SpatialIndex))
             return null;
 
         IndexColumn[] cols = target.getIndexColumns();
@@ -1064,4 +1079,4 @@ public class GridH2Table extends TableBase {
 
         return true;
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
index 122a9f7..34e223c 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
@@ -1728,7 +1728,11 @@ public class GridSqlQueryParser {
                 GridH2Table tbl = ((GridSqlTable)o).dataTable();
 
                 if (tbl != null) {
-                    GridCacheContext cctx = tbl.cache();
+                    //It's not affinity cache. Can't be local.
+                    if (tbl.cacheContext() == null)
+                        return false;
+
+                    GridCacheContext cctx = tbl.cacheContext();
 
                     if (cctx.mvccEnabled())
                         return false;
@@ -1759,8 +1763,8 @@ public class GridSqlQueryParser {
             if (o instanceof GridSqlTable) {
                 GridH2Table tbl = ((GridSqlTable)o).dataTable();
 
-                if (tbl != null && tbl.cache().isPartitioned())
-                    return tbl.cache();
+                if (tbl != null && tbl.cacheContext().isPartitioned())
+                    return tbl.cacheContext();
             }
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java
index b6909e3..6e27ca2 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java
@@ -61,7 +61,7 @@ import 
org.apache.ignite.internal.processors.query.GridQueryProcessor;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.QueryTypeDescriptorImpl;
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
-import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
+import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndexBase;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
@@ -229,7 +229,7 @@ public class ValidateIndexesClosure implements 
IgniteCallable<VisorValidateIndex
                         ArrayList<Index> indexes = gridH2Tbl.getIndexes();
 
                         for (Index idx : indexes)
-                            if (idx instanceof H2TreeIndex)
+                            if (idx instanceof H2TreeIndexBase)
                                 idxArgs.add(new T2<>(ctx, idx));
                     }
                 }
@@ -517,7 +517,7 @@ public class ValidateIndexesClosure implements 
IgniteCallable<VisorValidateIndex
                     ArrayList<Index> indexes = gridH2Tbl.getIndexes();
 
                     for (Index idx : indexes) {
-                        if (!(idx instanceof H2TreeIndex))
+                        if (!(idx instanceof H2TreeIndexBase))
                             continue;
 
                         try {

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientPersistentTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientPersistentTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientPersistentTest.java
new file mode 100644
index 0000000..ab93a4c
--- /dev/null
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientPersistentTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.WALMode;
+
+/**
+ * Test lazy cache start on client nodes with persistence cache.
+ */
+public class GridCacheDynamicLoadOnClientPersistentTest extends 
GridCacheDynamicLoadOnClientTest {
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String 
igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        DataStorageConfiguration dsCfg = new DataStorageConfiguration()
+            .setDefaultDataRegionConfiguration(
+                new DataRegionConfiguration().setMaxSize(200 * 1024 * 
1024).setPersistenceEnabled(true))
+            .setWalMode(WALMode.LOG_ONLY);
+
+        cfg.setDataStorageConfiguration(dsCfg);
+
+        return cfg;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientTest.java
new file mode 100644
index 0000000..5cc559e
--- /dev/null
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientTest.java
@@ -0,0 +1,304 @@
+/*
+ * 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;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Collection;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.cache.query.SqlQuery;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.odbc.ClientListenerProcessor;
+import org.apache.ignite.internal.processors.port.GridPortRecord;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Assert;
+
+/**
+ * Test lazy cache start on client nodes with inmemory cache.
+ */
+public class GridCacheDynamicLoadOnClientTest extends GridCommonAbstractTest {
+    /** Cache name. */
+    private static final String PERSON_CACHE = "Person";
+
+    /** SQL schema name. */
+    private static final String PERSON_SCHEMA = "test";
+
+    /** Number of element to add into cache. */
+    private static final int CACHE_ELEMENT_COUNT = 10;
+
+    /** Full table name. */
+    private static final String FULL_TABLE_NAME = PERSON_SCHEMA + "." + 
PERSON_CACHE;
+
+    /** Number of nodes. */
+    private static final int NODES = 2;
+
+    /** Client or server mode for configuration. */
+    protected boolean client;
+
+    /** Instance of client node. */
+    private static IgniteEx clientNode;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String 
igniteInstanceName) throws Exception {
+        return 
super.getConfiguration(igniteInstanceName).setClientMode(client);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        client = false;
+
+        startGridsMultiThreaded(NODES - 1);
+
+        client = true;
+
+        clientNode = startGrid(NODES - 1);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        clientNode.destroyCache(PERSON_CACHE);
+
+        createAndFillServerCache();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        super.afterTestsStopped();
+
+        stopAllGrids();
+    }
+
+    /**
+     * Test from client node batch merge through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testBatchMerge() throws Exception {
+        final int BATCH_SIZE = 7;
+
+        try (Connection con = connect(clientNode);
+             Statement stmt = con.createStatement()) {
+            for (int idx = 0, i = 0; i < BATCH_SIZE; ++i, idx += i) {
+                stmt.addBatch("merge into " + FULL_TABLE_NAME + " (_key, name, 
orgId) values (" +
+                    (100 + idx) + "," +
+                    "'" + "batch-" + idx + "'" + "," +
+                    idx +
+                    ")");
+            }
+
+            int[] updCnts = stmt.executeBatch();
+
+            assertEquals("Invalid update counts size", BATCH_SIZE, 
updCnts.length);
+        }
+    }
+
+    /**
+     * Test from client node to delete cache elements through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testClientJdbcDelete() throws Exception {
+        try (Connection con = connect(clientNode);
+             Statement stmt = con.createStatement()) {
+            int cnt = stmt.executeUpdate(("DELETE " + FULL_TABLE_NAME + " 
WHERE _key=1"));
+
+            Assert.assertEquals(1, cnt);
+        }
+
+        SqlFieldsQuery qry = new SqlFieldsQuery("SELECT * FROM " + 
FULL_TABLE_NAME);
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT - 1, 
clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Test from client node to insert into cache through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testClientJdbcInsert() throws Exception {
+        try (Connection con = connect(clientNode);
+             Statement stmt = con.createStatement()) {
+            int cnt = stmt.executeUpdate(
+                "INSERT INTO " + FULL_TABLE_NAME + "(_key, name, orgId) 
VALUES(1000,'new_name', 10000)");
+
+            Assert.assertEquals(1, cnt);
+        }
+
+        SqlFieldsQuery qry = new SqlFieldsQuery("SELECT * FROM " + 
FULL_TABLE_NAME);
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT + 1, 
clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Test from client node to update cache elements through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testClientJdbcUpdate() throws Exception {
+        try (Connection con = connect(clientNode);
+             Statement stmt = con.createStatement()) {
+            int cnt = stmt.executeUpdate(("UPDATE " + FULL_TABLE_NAME + " SET 
name = 'new_name'"));
+
+            Assert.assertEquals(CACHE_ELEMENT_COUNT, cnt);
+        }
+
+        SqlFieldsQuery qry = new SqlFieldsQuery("SELECT * FROM " + 
FULL_TABLE_NAME + " WHERE name = 'new_name'");
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT, 
clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Test from client node to get cache elements through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testClientJdbc() throws Exception {
+        try (Connection con = connect(clientNode);
+             Statement st = con.createStatement()) {
+            ResultSet rs = st.executeQuery("SELECT count(*) FROM " + 
FULL_TABLE_NAME);
+
+            rs.next();
+
+            Assert.assertEquals(CACHE_ELEMENT_COUNT, rs.getInt(1));
+        }
+    }
+
+    /**
+     * Test from client node to put cache elements through cache API.
+     */
+    public void testClientPut() {
+        clientNode.cache(PERSON_CACHE).put(-100, new Person(-100, "name-"));
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT + 1, 
clientNode.cache(PERSON_CACHE).size());
+    }
+
+    /**
+     * Test from client node to get cache elements through cache API.
+     */
+    public void testClientSqlFieldsQuery() {
+        SqlFieldsQuery qry = new SqlFieldsQuery("SELECT * FROM " + 
FULL_TABLE_NAME);
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT, 
clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Test from client node to get cache elements through cache API.
+     */
+    public void testClientSqlQuery() {
+        SqlQuery<Integer, Person> qry = new SqlQuery<>(PERSON_CACHE, "FROM " + 
PERSON_CACHE);
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT,
+            clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Create cache at server node and put some values into the cache.
+     */
+    private void createAndFillServerCache() {
+        IgniteEx srvNode = grid(0);
+
+        srvNode.createCache(cacheConfiguration());
+
+        for (int i = 0; i < CACHE_ELEMENT_COUNT; i++)
+            srvNode.cache(PERSON_CACHE).put(i, new Person(i, "name-" + i));
+    }
+
+    /**
+     * @return Cache configuration.
+     */
+    private CacheConfiguration<?, ?> cacheConfiguration() {
+        CacheConfiguration ccfg = new CacheConfiguration(PERSON_CACHE);
+
+        ccfg.setSqlSchema(PERSON_SCHEMA);
+        ccfg.setCacheMode(CacheMode.PARTITIONED);
+
+        QueryEntity person = new QueryEntity();
+        person.setKeyType(Integer.class.getName());
+        person.setValueType(Person.class.getName());
+        person.addQueryField("orgId", Integer.class.getName(), null);
+        person.addQueryField("id", Integer.class.getName(), null);
+        person.addQueryField("name", String.class.getName(), null);
+        person.setIndexes(F.asList(new QueryIndex("orgId"), new 
QueryIndex("id"), new QueryIndex("name")));
+
+        ccfg.setQueryEntities(F.asList(person));
+
+        return ccfg;
+    }
+
+    /**
+     * Create SQL connection to node specified as argument
+     *
+     * @param node Node to connect.
+     * @return Connection.
+     * @throws SQLException In case of failure.
+     */
+    private static Connection connect(IgniteEx node) throws SQLException {
+        Collection<GridPortRecord> recs = node.context().ports().records();
+
+        GridPortRecord cliLsnrRec = null;
+
+        for (GridPortRecord rec : recs) {
+            if (rec.clazz() == ClientListenerProcessor.class) {
+                cliLsnrRec = rec;
+
+                break;
+            }
+        }
+
+        String connStr = "jdbc:ignite:thin://127.0.0.1:" + cliLsnrRec.port();
+
+        return DriverManager.getConnection(connStr);
+    }
+
+    /**
+     * Test object to keep in cache.
+     */
+    private static class Person implements Serializable {
+        /** */
+        @QuerySqlField
+        int orgId;
+
+        /** */
+        @QuerySqlField
+        String name;
+
+        /**
+         * @param orgId Organization ID.
+         * @param name Name.
+         */
+        public Person(int orgId, String name) {
+            this.orgId = orgId;
+            this.name = name;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
index 07c0ede..5634748 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
@@ -725,6 +725,28 @@ public class H2DynamicTableSelfTest extends 
AbstractSchemaSelfTest {
     }
 
     /**
+     * Test that {@code DROP TABLE} executed at client node actually removes 
specified cache and type descriptor on all nodes.
+     * @throws Exception if failed.
+     */
+    public void testDropTableFromClient() throws Exception {
+        execute(grid(0),"CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, 
\"city\" varchar," +
+            " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY 
(\"id\", \"city\")) WITH " +
+            "\"template=cache\"");
+
+        execute(client(), "DROP TABLE \"Person\"");
+
+        for (int i = 0; i < 4; i++) {
+            IgniteEx node = grid(i);
+
+            assertNull(node.cache("Person"));
+
+            QueryTypeDescriptorImpl desc = type(node, "Person", "Person");
+
+            assertNull(desc);
+        }
+    }
+
+    /**
      * Test that {@code DROP TABLE} actually removes specified cache and type 
descriptor on all nodes.
      * @throws Exception if failed.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SchemaExchangeSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SchemaExchangeSelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SchemaExchangeSelfTest.java
index c7709f2..bd2b578 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SchemaExchangeSelfTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SchemaExchangeSelfTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.ignite.internal.processors.cache.index;
 
+import java.util.Collections;
+import java.util.Map;
+import junit.framework.AssertionFailedError;
 import org.apache.ignite.IgniteClientDisconnectedException;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.Ignition;
@@ -26,18 +29,18 @@ import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.query.QueryTypeDescriptorImpl;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.lang.IgniteFuture;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.GridTestUtils;
 
-import java.util.Collections;
-import java.util.Map;
-
 import static 
org.apache.ignite.internal.IgniteClientReconnectAbstractTest.TestTcpDiscoverySpi;
 import static 
org.apache.ignite.internal.IgniteClientReconnectAbstractTest.reconnectClientNode;
 
@@ -171,11 +174,13 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
 
         assertTypes(node1, ValueClass.class);
         assertTypes(node2, ValueClass.class);
+        assertCacheStarted(CACHE_NAME, node1, node2);
 
-        assertTypes(node3);
+        assertTypes(node3, ValueClass.class);
+        assertCacheNotStarted(CACHE_NAME, node3);
 
         node3.cache(CACHE_NAME);
-        assertTypes(node3, ValueClass.class);
+        assertCacheStarted(CACHE_NAME, node3);
 
         // Check restarts from the first node.
         destroySqlCache(node1);
@@ -193,11 +198,14 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
 
         assertTypes(node1, ValueClass.class, ValueClass2.class);
         assertTypes(node2, ValueClass.class, ValueClass2.class);
+        assertTypes(node3, ValueClass.class, ValueClass2.class);
 
-        assertTypes(node3);
+        assertCacheStarted(CACHE_NAME, node1, node2);
+
+        assertCacheNotStarted(CACHE_NAME, node3);
 
         node3.cache(CACHE_NAME);
-        assertTypes(node3, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node3);
 
         // Check restarts from the second node.
         node2.destroyCache(CACHE_NAME);
@@ -215,16 +223,20 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
 
         assertTypes(node1, ValueClass.class, ValueClass2.class);
         assertTypes(node2, ValueClass.class, ValueClass2.class);
+        assertTypes(node3, ValueClass.class, ValueClass2.class);
+        assertTypes(node4, ValueClass.class, ValueClass2.class);
 
-        assertTypes(node3);
+        assertCacheStarted(CACHE_NAME, node1, node2);
+
+        assertCacheNotStarted(CACHE_NAME, node3);
 
         node3.cache(CACHE_NAME);
-        assertTypes(node3, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node3);
 
-        assertTypes(node4);
+        assertCacheNotStarted(CACHE_NAME, node4);
 
         node4.cache(CACHE_NAME);
-        assertTypes(node4, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node4);
 
         // Make sure that joining node observes correct state.
         assertTypes(start(5), ValueClass.class, ValueClass2.class);
@@ -234,10 +246,13 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
 
         IgniteEx node8 = startClientNoCache(8);
 
-        assertTypes(node8);
+        assertTypes(node8, ValueClass.class, ValueClass2.class);
+
+        assertCacheNotStarted(CACHE_NAME, node8);
 
         node8.cache(CACHE_NAME);
-        assertTypes(node8, ValueClass.class, ValueClass2.class);
+
+        assertCacheStarted(CACHE_NAME, node8);
     }
 
     /**
@@ -292,10 +307,15 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
         assertTypes(node2, ValueClass.class);
         assertTypes(node3, ValueClass.class);
 
-        assertTypes(node4);
+        assertTypes(node4, ValueClass.class);
+
+        assertCacheStarted(CACHE_NAME, node1, node2, node3);
+
+        assertCacheNotStarted(CACHE_NAME, node4);
 
         node4.cache(CACHE_NAME);
-        assertTypes(node4, ValueClass.class);
+
+        assertCacheStarted(CACHE_NAME, node4);
     }
 
     /**
@@ -345,40 +365,31 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
         IgniteEx node7 = startClient(7,  KeyClass.class, ValueClass.class, 
KeyClass2.class, ValueClass2.class);
         IgniteEx node8 = startClientNoCache(8);
 
-        assertTypes(node1, ValueClass.class);
-        assertTypes(node2, ValueClass.class);
-        assertTypes(node3, ValueClass.class);
-        assertTypes(node4, ValueClass.class);
-        assertTypes(node5, ValueClass.class);
-        assertTypes(node6, ValueClass.class);
-        assertTypes(node7, ValueClass.class);
+        assertCacheStarted(CACHE_NAME, node1, node2, node3, node4, node5, 
node6, node7);
+        assertCacheNotStarted(CACHE_NAME, node8);
+        assertTypes(node8, ValueClass.class);
 
-        assertTypes(node8);
         node8.cache(CACHE_NAME);
-        assertTypes(node8, ValueClass.class);
+
+        assertCacheStarted(CACHE_NAME, node8);
 
         destroySqlCache(node2);
 
         node2.getOrCreateCache(
             cacheConfiguration(KeyClass.class, ValueClass.class, 
KeyClass2.class, ValueClass2.class));
 
-        assertTypes(node1, ValueClass.class, ValueClass2.class);
-        assertTypes(node2, ValueClass.class, ValueClass2.class);
-        assertTypes(node3, ValueClass.class, ValueClass2.class);
-        assertTypes(node4, ValueClass.class, ValueClass2.class);
-        assertTypes(node5, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node1, node2, node3, node4, node5);
+        assertCacheNotStarted(CACHE_NAME, node6, node7, node8);
 
-        assertTypes(node6);
-        assertTypes(node7);
-        assertTypes(node8);
+        assertTypes(node6, ValueClass.class, ValueClass2.class);
+        assertTypes(node7, ValueClass.class, ValueClass2.class);
+        assertTypes(node8, ValueClass.class, ValueClass2.class);
 
         node6.cache(CACHE_NAME);
         node7.cache(CACHE_NAME);
         node8.cache(CACHE_NAME);
 
-        assertTypes(node6, ValueClass.class, ValueClass2.class);
-        assertTypes(node7, ValueClass.class, ValueClass2.class);
-        assertTypes(node8, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node6, node7, node8);
     }
 
     /**
@@ -399,11 +410,14 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
         IgniteEx node3 = startNoCache(3);
         assertTypes(node1, ValueClass.class);
         assertTypes(node2, ValueClass.class);
+        assertTypes(node3, ValueClass.class);
 
-        assertTypes(node3);
+        assertCacheStarted(CACHE_NAME, node1, node2);
+
+        assertCacheNotStarted(CACHE_NAME, node3);
 
         node3.cache(CACHE_NAME);
-        assertTypes(node3, ValueClass.class);
+        assertCacheStarted(CACHE_NAME, node1, node3);
     }
 
     /**
@@ -416,7 +430,12 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
         assertTypes(node1, ValueClass.class);
 
         IgniteEx node2 = startClientNoCache(2);
-        assertTypes(node2);
+
+        GridCacheContext<Object, Object> context0 = 
node2.context().cache().context().cacheContext(CU.cacheId(CACHE_NAME));
+        node2.cache(CACHE_NAME);
+        GridCacheContext<Object, Object> context = 
node2.context().cache().context().cacheContext(CU.cacheId(CACHE_NAME));
+        GridCacheAdapter<Object, Object> entries = 
node2.context().cache().internalCache(CACHE_NAME);
+        assertTrue(entries.active());
 
         node2.cache(CACHE_NAME);
         assertTypes(node2, ValueClass.class);
@@ -431,7 +450,7 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
 
         IgniteFuture reconnFut = null;
 
-        try {   
+        try {
             node2.cache(CACHE_NAME);
 
             fail();
@@ -442,13 +461,17 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
 
         node1 = start(1, KeyClass.class, ValueClass.class, KeyClass2.class, 
ValueClass2.class);
         assertTypes(node1, ValueClass.class, ValueClass2.class);
+        assertTypes(node2, ValueClass.class);
+
+        assertCacheStarted(CACHE_NAME, node1);
 
         reconnFut.get();
 
-        assertTypes(node2);
+        assertTypes(node2, ValueClass.class, ValueClass2.class);
+        assertCacheNotStarted(CACHE_NAME, node2);
 
         node2.cache(CACHE_NAME);
-        assertTypes(node2, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node2);
     }
 
     /**
@@ -462,10 +485,11 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
         assertTypes(node1, ValueClass.class);
 
         final IgniteEx node2 = startClientNoCache(2);
-        assertTypes(node2);
+        assertTypes(node2, ValueClass.class);
+        assertCacheNotStarted(CACHE_NAME, node2);
 
         node2.cache(CACHE_NAME);
-        assertTypes(node2, ValueClass.class);
+        assertCacheStarted(CACHE_NAME, node2);
 
         reconnectClientNode(log, node2, node1, new Runnable() {
             @Override public void run() {
@@ -489,6 +513,45 @@ public class SchemaExchangeSelfTest extends 
AbstractSchemaSelfTest {
     }
 
     /**
+     * Check is cache started on the given node or not.
+     *
+     * @param cacheName Cache name.
+     * @param node Node to check cache.
+     * @return {@code true} in case cache is started.
+     */
+    private boolean isCacheStarted(String cacheName, IgniteEx node) {
+        GridCacheContext cacheCtx = 
node.context().cache().context().cacheContext(CU.cacheId(cacheName));
+
+        return cacheCtx != null;
+    }
+
+    /**
+     * Check is cache started on the given nodes.
+     *
+     * @param nodes Node to check cache.
+     * @param cacheName Cache name.
+     * @throws AssertionFailedError If failed.
+     */
+    private void assertCacheStarted(String cacheName, IgniteEx... nodes) 
throws AssertionFailedError {
+        for (IgniteEx node : nodes) {
+            assertTrue(isCacheStarted(cacheName, node));
+        }
+    }
+
+    /**
+     * Check is cache not started on the given nodes.
+     *
+     * @param nodes Node to check cache.
+     * @param cacheName Cache name.
+     * @throws AssertionFailedError If failed.
+     */
+    private void assertCacheNotStarted(String cacheName, IgniteEx... nodes) 
throws AssertionFailedError {
+        for (IgniteEx node : nodes) {
+            assertFalse(isCacheStarted(cacheName, node));
+        }
+    }
+
+    /**
      * Ensure that only provided types exists for the given cache.
      *
      * @param node Node.

http://git-wip-us.apache.org/repos/asf/ignite/blob/d19123d4/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite.java
----------------------------------------------------------------------
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 25cb473..d96b445 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
@@ -43,6 +43,8 @@ import 
org.apache.ignite.internal.processors.cache.CacheReplicatedQueryMetricsLo
 import 
org.apache.ignite.internal.processors.cache.CacheSqlQueryValueCopySelfTest;
 import org.apache.ignite.internal.processors.cache.DdlTransactionSelfTest;
 import 
org.apache.ignite.internal.processors.cache.GridCacheCrossCacheQuerySelfTest;
+import 
org.apache.ignite.internal.processors.cache.GridCacheDynamicLoadOnClientPersistentTest;
+import 
org.apache.ignite.internal.processors.cache.GridCacheDynamicLoadOnClientTest;
 import 
org.apache.ignite.internal.processors.cache.GridCacheFullTextQuerySelfTest;
 import 
org.apache.ignite.internal.processors.cache.GridCacheLazyQueryPartitionsReleaseTest;
 import 
org.apache.ignite.internal.processors.cache.GridCacheQueryIndexDisabledSelfTest;
@@ -533,6 +535,9 @@ public class IgniteBinaryCacheQueryTestSuite extends 
TestSuite {
         // Partition pruning.
         suite.addTestSuite(InOperationExtractPartitionSelfTest.class);
 
+        suite.addTestSuite(GridCacheDynamicLoadOnClientTest.class);
+        suite.addTestSuite(GridCacheDynamicLoadOnClientPersistentTest.class);
+
         return suite;
     }
 }

Reply via email to