You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2018/11/13 12:10:39 UTC
ignite git commit: IGNITE-8386: SQL: unwrapped key fields for PK
index. Previously we built PK index over the whole "_KEY". This worked fine
for primitive keys,
but led to unusable PK index in case of composite key (what affected affinity
co-location cas
Repository: ignite
Updated Branches:
refs/heads/master 0f387681b -> c3462ffff
IGNITE-8386: SQL: unwrapped key fields for PK index. Previously we built PK index over the whole "_KEY". This worked fine for primitive keys, but led to unusable PK index in case of composite key (what affected affinity co-location cases as well because in this case key is complex by default). Now we build index of _KEY fields rather than _KEY itself. This is only possible for caches created with "CREATE TABLE", because in this case generated keys do not contain any hidden non-indexed fields, which might broke PK uniqueness property otherwise. In future we will unwrap PKs embedded to secondary indexes as well (see IGNITE-10217). This closes #4184.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/c3462fff
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/c3462fff
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/c3462fff
Branch: refs/heads/master
Commit: c3462fffff3b09c52c4c0bcb55867015449a2fb6
Parents: 0f38768
Author: Yuriy Gerzhedovich <yg...@gridgain.com>
Authored: Tue Nov 13 15:10:31 2018 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Tue Nov 13 15:10:31 2018 +0300
----------------------------------------------------------------------
modules/compatibility/pom.xml | 7 +
.../IgnitePKIndexesMigrationToUnwrapPkTest.java | 247 ++++++++++++++
.../testframework/junits/Dependency.java | 28 +-
.../junits/IgniteCompatibilityAbstractTest.java | 10 +-
.../processors/cache/GridCacheProcessor.java | 9 +-
.../cache/persistence/tree/io/BPlusMetaIO.java | 20 +-
.../processors/query/GridQueryIndexing.java | 2 +-
.../processors/query/GridQueryProcessor.java | 16 +-
...IgniteClientCacheInitializationFailTest.java | 2 +-
.../processors/query/h2/H2TableDescriptor.java | 123 ++++++-
.../processors/query/h2/IgniteH2Indexing.java | 13 +-
.../processors/query/h2/database/H2Tree.java | 69 +++-
.../query/h2/database/H2TreeIndex.java | 87 ++++-
.../index/ComplexPrimaryKeyUnwrapSelfTest.java | 337 +++++++++++++++++++
.../IgniteBinaryCacheQueryTestSuite.java | 10 +-
15 files changed, 914 insertions(+), 66 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/compatibility/pom.xml
----------------------------------------------------------------------
diff --git a/modules/compatibility/pom.xml b/modules/compatibility/pom.xml
index 7f24efe..68948e0 100644
--- a/modules/compatibility/pom.xml
+++ b/modules/compatibility/pom.xml
@@ -48,6 +48,13 @@
</dependency>
<dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-indexing</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/IgnitePKIndexesMigrationToUnwrapPkTest.java
----------------------------------------------------------------------
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/IgnitePKIndexesMigrationToUnwrapPkTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/IgnitePKIndexesMigrationToUnwrapPkTest.java
new file mode 100644
index 0000000..22ccae0
--- /dev/null
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/IgnitePKIndexesMigrationToUnwrapPkTest.java
@@ -0,0 +1,247 @@
+
+/*
+ * 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.compatibility.persistence;
+
+import java.util.Collection;
+import java.util.List;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.compatibility.testframework.junits.Dependency;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.cache.GridCacheAbstractFullApiSelfTest;
+import org.apache.ignite.lang.IgniteInClosure;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Test to check that starting node with PK index of the old format present doesn't break anything.
+ */
+public class IgnitePKIndexesMigrationToUnwrapPkTest extends IgnitePersistenceCompatibilityAbstractTest {
+ /** */
+ private static String TABLE_NAME = "TEST_IDX_TABLE";
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ new ConfigurationClosure().apply(cfg);
+
+ return cfg;
+ }
+
+ /** {@inheritDoc} */
+ @NotNull @Override protected Collection<Dependency> getDependencies(String igniteVer) {
+ Collection<Dependency> dependencies = super.getDependencies(igniteVer);
+
+ dependencies.add(new Dependency("indexing", null, "ignite-indexing", igniteVer));
+ dependencies.add(new Dependency("h2", "com.h2database", "h2", "1.4.195", true));
+
+ return dependencies;
+ }
+
+ /**
+ * Tests opportunity to read data from previous Ignite DB version.
+ *
+ * @throws Exception If failed.
+ */
+ public void testSecondaryIndexesMigration_2_5() throws Exception {
+ doTestStartupWithOldVersion("2.5.0");
+ }
+
+ /**
+ * Tests opportunity to read data from previous Ignite DB version.
+ *
+ * @throws Exception If failed.
+ */
+ public void testSecondaryIndexesMigration_2_4() throws Exception {
+ doTestStartupWithOldVersion("2.4.0");
+ }
+
+ /**
+ * Tests opportunity to read data from previous Ignite DB version.
+ *
+ * @param ver 3-digits version of ignite
+ * @throws Exception If failed.
+ */
+ @SuppressWarnings("unchecked")
+ private void doTestStartupWithOldVersion(String ver) throws Exception {
+ try {
+ startGrid(1, ver, new ConfigurationClosure(), new PostStartupClosure(true));
+
+ stopAllGrids();
+
+ IgniteEx igniteEx = startGrid(0);
+
+ new PostStartupClosure(false).apply(igniteEx);
+
+ igniteEx.active(true);
+
+ assertDontUsingPkIndex(igniteEx, TABLE_NAME);
+
+ String newTblName = TABLE_NAME + "_NEW";
+
+ initializeTable(igniteEx, newTblName);
+
+ checkUsingIndexes(igniteEx, newTblName);
+
+ igniteEx.active(false);
+ }
+ finally {
+ stopAllGrids();
+ }
+ }
+
+ /** */
+ private static class PostStartupClosure implements IgniteInClosure<Ignite> {
+
+ /** */
+ boolean createTable;
+
+ /**
+ * @param createTable {@code true} In case table should be created
+ */
+ public PostStartupClosure(boolean createTable) {
+ this.createTable = createTable;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void apply(Ignite ignite) {
+ ignite.active(true);
+
+ IgniteEx igniteEx = (IgniteEx)ignite;
+
+ if (createTable)
+ initializeTable(igniteEx, TABLE_NAME);
+
+ assertDontUsingPkIndex(igniteEx, TABLE_NAME);
+
+ ignite.active(false);
+ }
+ }
+
+ /**
+ * @param igniteEx Ignite instance.
+ * @param tblName Table name.
+ */
+ @NotNull private static void initializeTable(IgniteEx igniteEx, String tblName) {
+ executeSql(igniteEx, "CREATE TABLE " + tblName + " (id int, name varchar, age int, company varchar, city varchar, " +
+ "primary key (id, name, city))");
+
+ executeSql(igniteEx, "INSERT INTO " + tblName + " (id, name, age, company, city) VALUES(1,'name',2,'company', 'city')");
+
+ }
+
+ /**
+ * Run SQL statement on specified node.
+ *
+ * @param node node to execute query.
+ * @param stmt Statement to run.
+ * @param args arguments of statements
+ * @return Run result.
+ */
+ private static List<List<?>> executeSql(IgniteEx node, String stmt, Object... args) {
+ return node.context().query().querySqlFields(new SqlFieldsQuery(stmt).setArgs(args), true).getAll();
+ }
+
+ /**
+ * Check using PK indexes for few cases.
+ *
+ * @param ignite Ignite instance.
+ * @param tblName name of table which should be checked to using PK indexes.
+ */
+ private static void checkUsingIndexes(IgniteEx ignite, String tblName) {
+ String explainSQL = "explain SELECT * FROM " + tblName + " WHERE ";
+
+ List<List<?>> results = executeSql(ignite, explainSQL + "id=1");
+
+ assertUsingPkIndex(results);
+
+ results = executeSql(ignite, explainSQL + "id=1 and name='name'");
+
+ assertUsingPkIndex(results);
+
+ results = executeSql(ignite, explainSQL + "id=1 and name='name' and city='city' and age=2");
+
+ assertUsingPkIndex(results);
+ }
+
+ /**
+ * Check that explain plan result shown using PK index and don't use scan.
+ *
+ * @param results Result list of explain of query.
+ */
+ private static void assertUsingPkIndex(List<List<?>> results) {
+ assertEquals(2, results.size());
+
+ String explainPlan = (String)results.get(0).get(0);
+
+ assertTrue(explainPlan.contains("\"_key_PK"));
+
+ assertFalse(explainPlan.contains("_SCAN_"));
+ }
+
+ /**
+ * Check that explain plan result shown don't use PK index and use scan.
+ *
+ * @param igniteEx Ignite instance.
+ * @param tblName Name of table.
+ */
+ private static void assertDontUsingPkIndex(IgniteEx igniteEx, String tblName) {
+ List<List<?>> results = executeSql(igniteEx, "explain SELECT * FROM " + tblName + " WHERE id=1");
+
+ assertEquals(2, results.size());
+
+ String explainPlan = (String)results.get(0).get(0);
+
+ System.out.println(explainPlan);
+
+ assertFalse(explainPlan, explainPlan.contains("\"_key_PK\""));
+
+ assertTrue(explainPlan, explainPlan.contains("_SCAN_"));
+ }
+
+ /** */
+ private static class ConfigurationClosure implements IgniteInClosure<IgniteConfiguration> {
+ /** {@inheritDoc} */
+ @Override public void apply(IgniteConfiguration cfg) {
+ cfg.setLocalHost("127.0.0.1");
+
+ TcpDiscoverySpi disco = new TcpDiscoverySpi();
+ disco.setIpFinder(GridCacheAbstractFullApiSelfTest.LOCAL_IP_FINDER);
+
+ cfg.setDiscoverySpi(disco);
+
+ cfg.setPeerClassLoadingEnabled(false);
+
+ DataStorageConfiguration memCfg = new DataStorageConfiguration()
+ .setDefaultDataRegionConfiguration(
+ new DataRegionConfiguration().setPersistenceEnabled(true)
+ .setInitialSize(1024 * 1024 * 10).setMaxSize(1024 * 1024 * 15))
+ .setSystemRegionInitialSize(1024 * 1024 * 10)
+ .setSystemRegionMaxSize(1024 * 1024 * 15);
+
+ cfg.setDataStorageConfiguration(memCfg);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/Dependency.java
----------------------------------------------------------------------
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/Dependency.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/Dependency.java
index 56da0e9..a30fb1e 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/Dependency.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/Dependency.java
@@ -40,6 +40,9 @@ public class Dependency {
/** Test flag. Test jar should have {@code true} value. Default is {@code false}. */
private boolean test;
+ /** */
+ private String exludePathFromClassPath;
+
/**
* Creates dependency.
*
@@ -71,13 +74,36 @@ public class Dependency {
* @param version Version. Null means default Ignite version is to be used. M
*/
public Dependency(String locModuleName, @Nullable String grpName, String artifactName, @Nullable String version) {
- this.locModuleName = locModuleName;
+ this(locModuleName, grpName, artifactName, version, false);
+ }
+
+ /**
+ * @param excludeName Local module name or part of exclude path.
+ * @param grpName Group name. Null means ignite default group name.
+ * @param artifactName Artifact name (artifact ID) without group na
+ * @param version Version. Null means default Ignite version is to be used. M
+ * @param exludeNotLocModule {@code true} In case param @excludeName should exclude path instead of local module.
+ */
+ public Dependency(String excludeName, @Nullable String grpName, String artifactName, @Nullable String version,
+ boolean exludeNotLocModule) {
+ if (exludeNotLocModule)
+ this.exludePathFromClassPath = excludeName;
+ else
+ this.locModuleName = excludeName;
+
this.groupName = grpName;
this.artifactName = artifactName;
this.version = version;
}
/**
+ * @return Path to exclude form classpath.
+ */
+ public String excludePathFromClassPath() {
+ return exludePathFromClassPath;
+ }
+
+ /**
* @return path based on local module name to exclude from classpath
*/
public String localPathTemplate() {
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
----------------------------------------------------------------------
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
index 2301717..71ff9ff 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
@@ -21,6 +21,7 @@ import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
@@ -168,14 +169,16 @@ public abstract class IgniteCompatibilityAbstractTest extends GridCommonAbstract
final Collection<Dependency> dependencies = getDependencies(ver);
- Set<String> excluded = dependencies.stream().map(Dependency::localPathTemplate).collect(Collectors.toSet());
+ Set<String> excludedModules = dependencies.stream().map(Dependency::localPathTemplate).collect(Collectors.toSet());
+
+ Set<String> excludedPaths = dependencies.stream().map(Dependency::excludePathFromClassPath).filter(Objects::nonNull).collect(Collectors.toSet());
StringBuilder pathBuilder = new StringBuilder();
for (URL url : CompatibilityTestsUtils.classLoaderUrls(CLASS_LOADER)) {
String path = url.getPath();
- if (excluded.stream().noneMatch(path::contains))
+ if (excludedModules.stream().noneMatch(path::contains) && excludedPaths.stream().noneMatch(path::contains))
pathBuilder.append(path).append(File.pathSeparator);
}
@@ -243,6 +246,9 @@ public abstract class IgniteCompatibilityAbstractTest extends GridCommonAbstract
dependencies.add(new Dependency("core", "ignite-core"));
dependencies.add(new Dependency("core", "ignite-core", true));
+ //Just to exclude indexing module
+ dependencies.add(new Dependency("indexing", "ignite-core"));
+
return dependencies;
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
index 2e2fa47..7ba4ff9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
@@ -1257,7 +1257,7 @@ public class GridCacheProcessor extends GridProcessorAdapter {
boolean rmvIdx = !cache.context().group().persistenceEnabled();
ctx.query().onCacheStop0(cctx, rmvIdx);
- ctx.query().onCacheStart0(cctx, desc.schema());
+ ctx.query().onCacheStart0(cctx, desc.schema(), desc.sql());
}
}
}
@@ -2138,7 +2138,8 @@ public class GridCacheProcessor extends GridProcessorAdapter {
cctx,
cacheInfo.getCacheDescriptor().schema() != null
? cacheInfo.getCacheDescriptor().schema()
- : new QuerySchema()
+ : new QuerySchema(),
+ cacheInfo.getCacheDescriptor().sql()
);
}
@@ -2194,7 +2195,7 @@ public class GridCacheProcessor extends GridProcessorAdapter {
) throws IgniteCheckedException {
GridCacheContext cacheCtx = prepareCacheContext(startCfg, desc, reqNearCfg, exchTopVer, disabledAfterStart);
- ctx.query().onCacheStart(cacheCtx, desc.schema() != null ? desc.schema() : new QuerySchema());
+ ctx.query().onCacheStart(cacheCtx, desc.schema() != null ? desc.schema() : new QuerySchema(), desc.sql());
if (cacheCtx.isRecoveryMode())
finishRecovery(exchTopVer, cacheCtx);
@@ -2555,7 +2556,7 @@ public class GridCacheProcessor extends GridProcessorAdapter {
grp.onCacheStarted(cacheCtx);
- ctx.query().onCacheStart(cacheCtx, desc.schema() != null ? desc.schema() : new QuerySchema());
+ ctx.query().onCacheStart(cacheCtx, desc.schema() != null ? desc.schema() : new QuerySchema(), desc.sql());
if (log.isInfoEnabled()) {
log.info("Started cache in recovery mode [name=" + cfg.getName() +
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusMetaIO.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusMetaIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusMetaIO.java
index 623951b..fef58fd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusMetaIO.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusMetaIO.java
@@ -28,7 +28,7 @@ import org.apache.ignite.internal.util.GridStringBuilder;
public class BPlusMetaIO extends PageIO {
/** */
public static final IOVersions<BPlusMetaIO> VERSIONS = new IOVersions<>(
- new BPlusMetaIO(1), new BPlusMetaIO(2)
+ new BPlusMetaIO(1), new BPlusMetaIO(2), new BPlusMetaIO(3)
);
/** */
@@ -40,6 +40,9 @@ public class BPlusMetaIO extends PageIO {
/** */
private final int inlineSizeOff;
+ /** */
+ private boolean unwrappedPk;
+
/**
* @param ver Page format version.
*/
@@ -50,11 +53,19 @@ public class BPlusMetaIO extends PageIO {
case 1:
inlineSizeOff = -1;
refsOff = LVLS_OFF + 1;
+ unwrappedPk = false;
break;
case 2:
inlineSizeOff = LVLS_OFF + 1;
refsOff = inlineSizeOff + 2;
+ unwrappedPk = false;
+ break;
+
+ case 3:
+ inlineSizeOff = LVLS_OFF + 1;
+ refsOff = inlineSizeOff + 2;
+ unwrappedPk = true;
break;
default:
@@ -182,6 +193,13 @@ public class BPlusMetaIO extends PageIO {
return getVersion() > 1 ? PageUtils.getShort(pageAddr, inlineSizeOff) : 0;
}
+ /**
+ * @return {@code true} In case use unwrapped PK.
+ */
+ public boolean unwrappedPk() {
+ return unwrappedPk;
+ }
+
/** {@inheritDoc} */
@Override protected void printPage(long addr, int pageSize, GridStringBuilder sb) throws IgniteCheckedException {
sb.a("BPlusMeta [\n\tlevelsCnt=").a(getLevelsCount(addr))
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java
index a8ccc7e..60b0221 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java
@@ -259,7 +259,7 @@ public interface GridQueryIndexing {
* @throws IgniteCheckedException If failed.
* @return {@code True} if type was registered, {@code false} if for some reason it was rejected.
*/
- public boolean registerType(GridCacheContext cctx, GridQueryTypeDescriptor desc) throws IgniteCheckedException;
+ public boolean registerType(GridCacheContext cctx, GridQueryTypeDescriptor desc, boolean isSql) throws IgniteCheckedException;
/**
* Updates index. Note that key is unique for cache, so if cache contains multiple indexes
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
index 7650fce..24f79fc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
@@ -675,9 +675,10 @@ public class GridQueryProcessor extends GridProcessorAdapter {
* Use with {@link #busyLock} where appropriate.
* @param cctx Cache context.
* @param schema Initial schema.
+ * @param isSql {@code true} in case create cache initialized from SQL.
* @throws IgniteCheckedException If failed.
*/
- public void onCacheStart0(GridCacheContext<?, ?> cctx, QuerySchema schema)
+ public void onCacheStart0(GridCacheContext<?, ?> cctx, QuerySchema schema, boolean isSql)
throws IgniteCheckedException {
cctx.shared().database().checkpointReadLock();
@@ -798,7 +799,7 @@ public class GridQueryProcessor extends GridProcessorAdapter {
}
// Ready to register at this point.
- registerCache0(cacheName, schemaName, cctx, cands);
+ registerCache0(cacheName, schemaName, cctx, cands, isSql);
// Warn about possible implicit deserialization.
if (!mustDeserializeClss.isEmpty()) {
@@ -849,9 +850,10 @@ public class GridQueryProcessor extends GridProcessorAdapter {
*
* @param cctx Cache context.
* @param schema Index states.
+ * @param isSql {@code true} in case create cache initialized from SQL.
* @throws IgniteCheckedException If failed.
*/
- public void onCacheStart(GridCacheContext cctx, QuerySchema schema) throws IgniteCheckedException {
+ public void onCacheStart(GridCacheContext cctx, QuerySchema schema, boolean isSql) throws IgniteCheckedException {
if (idx == null)
return;
@@ -859,7 +861,7 @@ public class GridQueryProcessor extends GridProcessorAdapter {
return;
try {
- onCacheStart0(cctx, schema);
+ onCacheStart0(cctx, schema, isSql);
}
finally {
busyLock.leaveBusy();
@@ -1582,13 +1584,15 @@ public class GridQueryProcessor extends GridProcessorAdapter {
* @param schemaName Schema name.
* @param cctx Cache context.
* @param cands Candidates.
+ * @param isSql {@code true} in case create cache initialized from SQL.
* @throws IgniteCheckedException If failed.
*/
private void registerCache0(
String cacheName,
String schemaName,
GridCacheContext<?, ?> cctx,
- Collection<QueryTypeCandidate> cands
+ Collection<QueryTypeCandidate> cands,
+ boolean isSql
) throws IgniteCheckedException {
synchronized (stateMux) {
if (idx != null)
@@ -1623,7 +1627,7 @@ public class GridQueryProcessor extends GridProcessorAdapter {
}
if (idx != null)
- idx.registerType(cctx, desc);
+ idx.registerType(cctx, desc, isSql);
}
cacheNames.add(CU.mask(cacheName));
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java
index 4336a25..69b1655 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java
@@ -329,7 +329,7 @@ public class IgniteClientCacheInitializationFailTest extends GridCommonAbstractT
/** {@inheritDoc} */
@Override public boolean registerType(GridCacheContext cctx,
- GridQueryTypeDescriptor desc) throws IgniteCheckedException {
+ GridQueryTypeDescriptor desc, boolean isSql) throws IgniteCheckedException {
return false;
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
index 988ec2f..aa66939 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
@@ -17,12 +17,18 @@
package org.apache.ignite.internal.processors.query.h2;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.cache.QueryIndexType;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
+import org.apache.ignite.internal.processors.query.GridQueryProperty;
import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
+import org.apache.ignite.internal.processors.query.QueryUtils;
import org.apache.ignite.internal.processors.query.h2.database.H2PkHashIndex;
import org.apache.ignite.internal.processors.query.h2.database.H2RowFactory;
import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
@@ -36,10 +42,7 @@ import org.h2.index.Index;
import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
+import org.jetbrains.annotations.NotNull;
import static org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap.KEY_COL;
@@ -47,6 +50,15 @@ import static org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueR
* Information about table in database.
*/
public class H2TableDescriptor implements GridH2SystemIndexFactory {
+ /** PK index name. */
+ public static final String PK_IDX_NAME = "_key_PK";
+
+ /** PK hashindex name */
+ public static final String PK_HASH_IDX_NAME = "_key_PK_hash";
+
+ /** Affinity key index name */
+ public static final String AFFINITY_KEY_IDX_NAME = "AFFINITY_KEY";
+
/** Indexing. */
private final IgniteH2Indexing idx;
@@ -71,6 +83,9 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
/** */
private H2PkHashIndex pkHashIdx;
+ /** Flag of table has been created from SQL*/
+ private boolean isSql;
+
/**
* Constructor.
*
@@ -78,13 +93,15 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
* @param schema Schema.
* @param type Type descriptor.
* @param cctx Cache context.
+ * @param isSql {@code true} in case table has been created from SQL.
*/
public H2TableDescriptor(IgniteH2Indexing idx, H2Schema schema, GridQueryTypeDescriptor type,
- GridCacheContext cctx) {
+ GridCacheContext cctx, boolean isSql) {
this.idx = idx;
this.type = type;
this.schema = schema;
this.cctx = cctx;
+ this.isSql = isSql;
fullTblName = H2Utils.withQuotes(schema.schemaName()) + "." + H2Utils.withQuotes(type.tableName());
}
@@ -187,12 +204,15 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
if (affCol != null && H2Utils.equals(affCol, keyCol))
affCol = null;
- GridH2RowDescriptor desc = tbl.rowDescriptor();
+ List<IndexColumn> unwrappedKeyCols = extractKeyColumns(tbl, keyCol, affCol);
+
+ List<IndexColumn> wrappedKeyCols = H2Utils.treeIndexColumns(tbl.rowDescriptor(),
+ new ArrayList<>(2), keyCol, affCol);
Index hashIdx = createHashIndex(
tbl,
- "_key_PK_hash",
- H2Utils.treeIndexColumns(desc, new ArrayList<IndexColumn>(2), keyCol, affCol)
+ PK_HASH_IDX_NAME,
+ wrappedKeyCols
);
if (hashIdx != null)
@@ -200,11 +220,12 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
// Add primary key index.
Index pkIdx = idx.createSortedIndex(
- "_key_PK",
+ PK_IDX_NAME,
tbl,
true,
false,
- H2Utils.treeIndexColumns(desc, new ArrayList<IndexColumn>(2), keyCol, affCol),
+ unwrappedKeyCols,
+ wrappedKeyCols,
-1
);
@@ -219,8 +240,6 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
}
}
- boolean affIdxFound = false;
-
GridQueryIndexDescriptor textIdx = type.textIndex();
if (textIdx != null) {
@@ -234,6 +253,8 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
// Locate index where affinity column is first (if any).
if (affCol != null) {
+ boolean affIdxFound = false;
+
for (GridQueryIndexDescriptor idxDesc : type.indexes().values()) {
if (idxDesc.type() != QueryIndexType.SORTED)
continue;
@@ -247,18 +268,76 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
affIdxFound |= H2Utils.equals(idxCol, affCol);
}
- }
- // Add explicit affinity key index if nothing alike was found.
- if (affCol != null && !affIdxFound) {
- idxs.add(idx.createSortedIndex("AFFINITY_KEY", tbl, false, true,
- H2Utils.treeIndexColumns(desc, new ArrayList<IndexColumn>(2), affCol, keyCol), -1));
+ // Add explicit affinity key index if nothing alike was found.
+ if (!affIdxFound) {
+ List<IndexColumn> columns = H2Utils.treeIndexColumns(tbl.rowDescriptor(), new ArrayList<>(2), affCol, keyCol);
+ idxs.add(idx.createSortedIndex(
+ AFFINITY_KEY_IDX_NAME,
+ tbl,
+ false,
+ true,
+ columns,
+ columns,
+ -1)
+ );
+ }
}
return idxs;
}
/**
+ * Create list of affinity and key index columns. Key, if it possible, partitions into simple components.
+ *
+ * @param tbl GridH2Table instance
+ * @param keyCol Key index column.
+ * @param affCol Affinity index column.
+ *
+ * @return List of key and affinity columns. Key's, if it possible, splitted into simple components.
+ */
+ @NotNull private List<IndexColumn> extractKeyColumns(GridH2Table tbl, IndexColumn keyCol, IndexColumn affCol) {
+ ArrayList<IndexColumn> keyCols;
+
+ if (isSql) {
+ keyCols = new ArrayList<>(type.fields().size() + 1);
+
+ // Check if key is simple type.
+ if(QueryUtils.isSqlType(type.keyClass()))
+ keyCols.add(keyCol);
+ else {
+ for (String propName : type.fields().keySet()) {
+ GridQueryProperty prop = type.property(propName);
+
+ if (prop.key()) {
+ Column col = tbl.getColumn(propName);
+
+ keyCols.add(tbl.indexColumn(col.getColumnId(), SortOrder.ASCENDING));
+ }
+ }
+
+ // If key is object but the user has not specified any particular columns,
+ // we have to fall back to whole-key index.
+ if (keyCols.isEmpty())
+ keyCols.add(keyCol);
+ }
+
+ }
+ else {
+ keyCols = new ArrayList<>(2);
+
+ keyCols.add(keyCol);
+ }
+
+ if (affCol != null && !H2Utils.containsColumn(keyCols, affCol))
+ keyCols.add(affCol);
+ else
+ keyCols.trimToSize();
+
+ return Collections.unmodifiableList(keyCols);
+ }
+
+ /**
* Get collection of user indexes.
*
* @return User indexes.
@@ -301,7 +380,15 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
if (idxDesc.type() == QueryIndexType.SORTED) {
cols = H2Utils.treeIndexColumns(desc, cols, keyCol, affCol);
- return idx.createSortedIndex(idxDesc.name(), tbl, false, false, cols, idxDesc.inlineSize());
+ return idx.createSortedIndex(
+ idxDesc.name(),
+ tbl,
+ false,
+ false,
+ cols,
+ cols,
+ idxDesc.inlineSize()
+ );
}
else if (idxDesc.type() == QueryIndexType.GEOSPATIAL)
return H2Utils.createSpatialIndex(tbl, idxDesc.name(), cols.toArray(new IndexColumn[cols.size()]));
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/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 7d93ecf..283e503 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
@@ -993,13 +993,13 @@ public class IgniteH2Indexing implements GridQueryIndexing {
* @param tbl Table.
* @param pk Primary key flag.
* @param affinityKey Affinity key flag.
- * @param cols Columns.
+ * @param unwrappedCols Unwrapped index columns for complex types.
+ * @param wrappedCols Index columns as is complex types.
* @param inlineSize Index inline size.
* @return Index.
*/
GridH2IndexBase createSortedIndex(String name, GridH2Table tbl, boolean pk, boolean affinityKey,
- List<IndexColumn> cols,
- int inlineSize) {
+ List<IndexColumn> unwrappedCols, List<IndexColumn> wrappedCols, int inlineSize) {
try {
GridCacheContext cctx = tbl.cache();
@@ -1010,7 +1010,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
H2RowCache cache = rowCache.forGroup(cctx.groupId());
- return new H2TreeIndex(cctx, cache, tbl, name, pk, affinityKey, cols, inlineSize, segments);
+ return new H2TreeIndex(cctx, cache, tbl, name, pk, affinityKey, unwrappedCols, wrappedCols, inlineSize, segments);
}
catch (IgniteCheckedException e) {
throw new IgniteException(e);
@@ -2828,9 +2828,10 @@ public class IgniteH2Indexing implements GridQueryIndexing {
* This implementation doesn't support type reregistration.
*
* @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)
+ @Override public boolean registerType(GridCacheContext cctx, GridQueryTypeDescriptor type, boolean isSql)
throws IgniteCheckedException {
validateTypeDescriptor(type);
@@ -2838,7 +2839,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
H2Schema schema = schemas.get(schemaName);
- H2TableDescriptor tbl = new H2TableDescriptor(this, schema, type, cctx);
+ H2TableDescriptor tbl = new H2TableDescriptor(this, schema, type, cctx, isSql);
try {
Connection conn = connectionForThread(schemaName);
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
index 4c6c0c0..71cea7e 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
@@ -108,6 +108,8 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
/** */
private final IgniteLogger log;
+ private boolean unwrappedPk;
+
/**
* Constructor.
*
@@ -143,9 +145,8 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
H2RowFactory rowStore,
long metaPageId,
boolean initNew,
- IndexColumn[] cols,
- List<InlineIndexHelper> inlineIdxs,
- int inlineSize,
+ H2TreeIndex.IndexColumnsInfo unwrappedColsInfo,
+ H2TreeIndex.IndexColumnsInfo wrappedColsInfo,
AtomicInteger maxCalculatedInlineSize,
boolean pk,
boolean affinityKey,
@@ -157,15 +158,23 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
super(name, grpId, pageMem, wal, globalRmvId, metaPageId, reuseList, failureProcessor);
if (!initNew) {
- // Page is ready - read inline size from it.
- inlineSize = getMetaInlineSize();
+ // Page is ready - read meta information.
+ MetaPageInfo metaInfo = getMetaInfo();
+
+ inlineSize = metaInfo.inlineSize();
+
+ unwrappedPk = metaInfo.useUnwrappedPk();
+ }
+ else {
+ unwrappedPk = true;
+
+ inlineSize = unwrappedColsInfo.inlineSize();
}
this.idxName = idxName;
this.cacheName = cacheName;
this.tblName = tblName;
- this.inlineSize = inlineSize;
this.maxCalculatedInlineSize = maxCalculatedInlineSize;
this.pk = pk;
@@ -176,8 +185,8 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
assert rowStore != null;
this.rowStore = rowStore;
- this.inlineIdxs = inlineIdxs;
- this.cols = cols;
+ this.inlineIdxs = unwrappedPk ? unwrappedColsInfo.inlineIdx() : wrappedColsInfo.inlineIdx();
+ this.cols = unwrappedPk ? unwrappedColsInfo.cols() : wrappedColsInfo.cols();
this.columnIds = new int[cols.length];
@@ -259,7 +268,7 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
* @return Inline size.
* @throws IgniteCheckedException If failed.
*/
- private int getMetaInlineSize() throws IgniteCheckedException {
+ private MetaPageInfo getMetaInfo() throws IgniteCheckedException {
final long metaPage = acquirePage(metaPageId);
try {
@@ -271,7 +280,7 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
try {
BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr);
- return io.getInlineSize(pageAddr);
+ return new MetaPageInfo(io.getInlineSize(pageAddr), io.unwrappedPk());
}
finally {
readUnlock(metaPageId, metaPage, pageAddr);
@@ -501,6 +510,46 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
}
/**
+ * @return {@code true} In case use unwrapped columns for PK
+ */
+ public boolean unwrappedPk() {
+ return unwrappedPk;
+ }
+
+ /**
+ *
+ */
+ private class MetaPageInfo {
+ /** */
+ int inlineSize;
+ /** */
+ boolean useUnwrappedPk;
+
+ /**
+ * @param inlineSize Inline size.
+ * @param useUnwrappedPk {@code true} In case use unwrapped PK for indexes.
+ */
+ public MetaPageInfo(int inlineSize, boolean useUnwrappedPk) {
+ this.inlineSize = inlineSize;
+ this.useUnwrappedPk = useUnwrappedPk;
+ }
+
+ /**
+ * @return Inline size.
+ */
+ public int inlineSize() {
+ return inlineSize;
+ }
+
+ /**
+ * @return {@code true} In case use unwrapped PK for indexes.
+ */
+ public boolean useUnwrappedPk() {
+ return useUnwrappedPk;
+ }
+ }
+
+ /**
* @param v1 First value.
* @param v2 Second value.
* @return Comparison result.
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/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 e9cca9e..b7179b7 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
@@ -93,12 +93,15 @@ public class H2TreeIndex extends GridH2IndexBase {
/**
* @param cctx Cache context.
+ * @param rowCache Row cache.
* @param tbl Table.
* @param idxName Index name.
* @param pk Primary key.
* @param affinityKey {@code true} for affinity key.
- * @param colsList Index columns.
+ * @param unwrappedColsList Unwrapped index columns for complex types.
+ * @param wrappedColsList Index columns as is.
* @param inlineSize Inline size.
+ * @param segmentsCnt Count of tree segments.
* @throws IgniteCheckedException If failed.
*/
public H2TreeIndex(
@@ -108,7 +111,8 @@ public class H2TreeIndex extends GridH2IndexBase {
String idxName,
boolean pk,
boolean affinityKey,
- List<IndexColumn> colsList,
+ List<IndexColumn> unwrappedColsList,
+ List<IndexColumn> wrappedColsList,
int inlineSize,
int segmentsCnt
) throws IgniteCheckedException {
@@ -124,12 +128,8 @@ public class H2TreeIndex extends GridH2IndexBase {
this.tblName = tbl.getName();
this.idxName = idxName;
- IndexColumn[] cols = colsList.toArray(new IndexColumn[colsList.size()]);
+ this.table = tbl;
- IndexColumn.mapColumns(cols, tbl);
-
- initBaseIndex(tbl, 0, idxName, cols,
- pk ? IndexType.createPrimaryKey(false, false) : IndexType.createNonUnique(false, false, false));
GridQueryTypeDescriptor typeDesc = tbl.rowDescriptor().type();
@@ -139,9 +139,13 @@ public class H2TreeIndex extends GridH2IndexBase {
treeName = BPlusTree.treeName(treeName, "H2Tree");
- if (cctx.affinityNode()) {
- inlineIdxs = getAvailableInlineColumns(cols);
+ IndexColumnsInfo unwrappedColsInfo = new IndexColumnsInfo(unwrappedColsList, inlineSize);
+
+ IndexColumnsInfo wrappedColsInfo = new IndexColumnsInfo(wrappedColsList, inlineSize);
+ IndexColumn[] cols;
+
+ if (cctx.affinityNode()) {
segments = new H2Tree[segmentsCnt];
IgniteCacheDatabaseSharedManager db = cctx.shared().database();
@@ -167,9 +171,8 @@ public class H2TreeIndex extends GridH2IndexBase {
tbl.rowFactory(),
page.pageId().pageId(),
page.isAllocated(),
- cols,
- inlineIdxs,
- computeInlineSize(inlineIdxs, inlineSize),
+ unwrappedColsInfo,
+ wrappedColsInfo,
maxCalculatedInlineSize,
pk,
affinityKey,
@@ -186,13 +189,28 @@ public class H2TreeIndex extends GridH2IndexBase {
db.checkpointReadUnlock();
}
}
+
+ boolean useUnwrappedCols = segments[0].unwrappedPk();
+
+ IndexColumnsInfo colsInfo = useUnwrappedCols ? unwrappedColsInfo : wrappedColsInfo;
+
+ cols = colsInfo.cols();
+
+ inlineIdxs = colsInfo.inlineIdx();
}
else {
// We need indexes on the client node, but index will not contain any data.
segments = null;
inlineIdxs = null;
+
+ cols = unwrappedColsInfo.cols();
}
+ IndexColumn.mapColumns(cols, tbl);
+
+ initBaseIndex(tbl, 0, idxName, cols,
+ pk ? IndexType.createPrimaryKey(false, false) : IndexType.createNonUnique(false, false, false));
+
initDistributedJoinMessaging(tbl);
}
@@ -540,4 +558,49 @@ public class H2TreeIndex extends GridH2IndexBase {
for (int pos = 0; pos < inlineHelpers.size(); ++pos)
inlineIdxs.set(pos, inlineHelpers.get(pos));
}
+
+ /**
+ *
+ */
+ public class IndexColumnsInfo {
+ /** */
+ private final int inlineSize;
+ /** */
+ private final IndexColumn[] cols;
+ /** */
+ private final List<InlineIndexHelper> inlineIdx;
+
+ /**
+ * @param colsList Index columns list
+ * @param cfgInlineSize Inline size from cache config.
+ */
+ public IndexColumnsInfo(List<IndexColumn> colsList, int cfgInlineSize) {
+ this.cols = colsList.toArray(new IndexColumn[colsList.size()]);
+
+ this.inlineIdx = getAvailableInlineColumns(cols);
+
+ this.inlineSize = computeInlineSize(inlineIdx, cfgInlineSize);
+ }
+
+ /**
+ * @return Inline size.
+ */
+ public int inlineSize() {
+ return inlineSize;
+ }
+
+ /**
+ * @return Index columns.
+ */
+ public IndexColumn[] cols() {
+ return cols;
+ }
+
+ /**
+ * @return Inline indexes.
+ */
+ public List<InlineIndexHelper> inlineIdx() {
+ return inlineIdx;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/ComplexPrimaryKeyUnwrapSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/ComplexPrimaryKeyUnwrapSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/ComplexPrimaryKeyUnwrapSelfTest.java
new file mode 100644
index 0000000..8f4eaf0
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/ComplexPrimaryKeyUnwrapSelfTest.java
@@ -0,0 +1,337 @@
+/*
+ * 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.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ * Test of creating and using PK indexes for tables created through SQL.
+ */
+@SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+public class ComplexPrimaryKeyUnwrapSelfTest extends GridCommonAbstractTest {
+
+ /** Counter to generate unique table names. */
+ private static int tblCnt = 0;
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ startGrid(0);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTestsStopped() throws Exception {
+ super.afterTestsStopped();
+
+ stopAllGrids();
+ }
+
+ /**
+ * Test using PK indexes for complex primary key.
+ */
+ public void testComplexPk() {
+ String tblName = createTableName();
+
+ executeSql("CREATE TABLE " + tblName + " (id int, name varchar, age int, company varchar, city varchar, " +
+ "primary key (id, name, city))");
+
+ checkUsingIndexes(tblName, "1");
+ }
+
+ /**
+ * Test using PK indexes for simple primary key.
+ */
+ public void testSimplePk() {
+ //ToDo: IGNITE-8386: need to add DATE type into the test.
+ HashMap<String, String> types = new HashMap() {
+ {
+ put("boolean", "1");
+ put("char", "'1'");
+ put("varchar", "'1'");
+ put("real", "1");
+ put("number", "1");
+ put("int", "1");
+ put("long", "1");
+ put("float", "1");
+ put("double", "1");
+ put("tinyint", "1");
+ put("smallint", "1");
+ put("bigint", "1");
+ put("varchar_ignorecase", "'1'");
+ put("time", "'11:11:11'");
+ put("timestamp", "'20018-11-02 11:11:11'");
+ put("uuid", "'1'");
+ }
+ };
+ for (Map.Entry<String, String> entry : types.entrySet()) {
+
+ String tblName = createTableName();
+
+ String type = entry.getKey();
+ String value = entry.getValue();
+
+ executeSql("CREATE TABLE " + tblName +
+ " (id " + type + " , name varchar, age int, company varchar, city varchar," +
+ " primary key (id))");
+
+ checkUsingIndexes(tblName, value);
+ }
+ }
+
+ /**
+ * Test using PK indexes for simple primary key and affinity key.
+ */
+ public void testSimplePkWithAffinityKey() {
+ //ToDo: IGNITE-8386: need to add DATE type into the test.
+ HashMap<String, String> types = new HashMap() {
+ {
+ put("boolean", "1");
+ put("char", "'1'");
+ put("varchar", "'1'");
+ put("real", "1");
+ put("number", "1");
+ put("int", "1");
+ put("long", "1");
+ put("float", "1");
+ put("double", "1");
+ put("tinyint", "1");
+ put("smallint", "1");
+ put("bigint", "1");
+ put("varchar_ignorecase", "'1'");
+ put("time", "'11:11:11'");
+ put("timestamp", "'20018-11-02 11:11:11'");
+ put("uuid", "'1'");
+ }
+ };
+ for (Map.Entry<String, String> entry : types.entrySet()) {
+
+ String tblName = createTableName();
+
+ String type = entry.getKey();
+ String value = entry.getValue();
+
+ executeSql("CREATE TABLE " + tblName +
+ " (id " + type + " , name varchar, age int, company varchar, city varchar," +
+ " primary key (id)) WITH \"affinity_key=id\"");
+
+ checkUsingIndexes(tblName, value);
+ }
+ }
+
+ /**
+ * Test using PK indexes for wrapped primary key.
+ */
+ public void testWrappedPk() {
+ String tblName = createTableName();
+
+ executeSql("CREATE TABLE " + tblName + " (id int, name varchar, age int, company varchar, city varchar, " +
+ "primary key (id)) WITH \"wrap_key=true\"");
+
+ checkUsingIndexes(tblName, "1");
+ }
+
+ /**
+ * Check using PK indexes for few cases.
+ *
+ * @param tblName name of table which should be checked to using PK indexes.
+ */
+ private void checkUsingIndexes(String tblName, String idValue) {
+ String explainSQL = "explain SELECT * FROM " + tblName + " WHERE ";
+
+ List<List<?>> results = executeSql(explainSQL + "id=" + idValue);
+
+ assertUsingPkIndex(results);
+
+ results = executeSql(explainSQL + "id=" + idValue + " and name=''");
+
+ assertUsingPkIndex(results);
+
+ results = executeSql(explainSQL + "id=" + idValue + " and name='' and city='' and age=0");
+
+ assertUsingPkIndex(results);
+ }
+
+ /**
+ * Test don't using PK indexes for table created through cache API.
+ */
+ public void testIndexesForCachesCreatedThroughCashApi() {
+ String tblName = TestValue.class.getSimpleName();
+
+ CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+ ccfg.setSqlSchema("PUBLIC");
+ ccfg.setName(tblName);
+
+ QueryEntity qryEntity = new QueryEntity(TestKey.class, TestValue.class);
+
+ ccfg.setQueryEntities(F.asList(qryEntity));
+
+ node().createCache(ccfg);
+
+ List<List<?>> results = executeSql("explain SELECT * FROM " + tblName + " WHERE id=1");
+
+ assertDontUsingPkIndex(results);
+ }
+
+ /**
+ * Check that explain plan result shown using PK index and don't use scan.
+ *
+ * @param results result of execut explain plan query.
+ */
+ private void assertUsingPkIndex(List<List<?>> results) {
+ assertEquals(2, results.size());
+
+ String explainPlan = (String)results.get(0).get(0);
+
+ assertTrue(explainPlan.contains("\"_key_PK"));
+
+ assertFalse(explainPlan.contains("_SCAN_"));
+ }
+
+ /**
+ * Check that explain plan result shown don't use PK index and use scan.
+ *
+ * @param results result of execut explain plan query.
+ */
+ private void assertDontUsingPkIndex(List<List<?>> results) {
+ assertEquals(2, results.size());
+
+ String explainPlan = (String)results.get(0).get(0);
+
+ System.out.println(explainPlan);
+
+ assertFalse(explainPlan.contains("\"_key_PK\""));
+
+ assertTrue(explainPlan.contains("_SCAN_"));
+ }
+
+ /**
+ * Create unique table name.
+ *
+ * @return unique name of table.
+ */
+ private String createTableName() {
+ return "TST_TABLE_" + tblCnt++;
+ }
+
+ /**
+ * Run SQL statement on default node.
+ *
+ * @param stmt Statement to run.
+ * @param args arguments of statements
+ * @return Run result.
+ */
+ private List<List<?>> executeSql(String stmt, Object... args) {
+ return executeSql(node(), stmt, args);
+ }
+
+ /**
+ * Run SQL statement on specified node.
+ *
+ * @param node node to execute query.
+ * @param stmt Statement to run.
+ * @param args arguments of statements
+ * @return Run result.
+ */
+ private List<List<?>> executeSql(IgniteEx node, String stmt, Object... args) {
+ return node.context().query().querySqlFields(new SqlFieldsQuery(stmt).setArgs(args), true).getAll();
+ }
+
+ /**
+ * @return Node to initiate operations from.
+ */
+ private IgniteEx node() {
+ return grid(0);
+ }
+
+ /**
+ *
+ */
+ static class TestKey {
+ /** */
+ @QuerySqlField
+ private int id;
+
+ /**
+ * @param id ID.
+ */
+ public TestKey(int id) {
+ this.id = id;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ TestKey testKey = (TestKey)o;
+
+ return id == testKey.id;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return id;
+ }
+ }
+
+ /**
+ *
+ */
+ static class TestValue {
+ /** */
+ @QuerySqlField()
+ private String name;
+ /** */
+ @QuerySqlField()
+ private String company;
+ /** */
+ @QuerySqlField()
+ private String city;
+ /** */
+ @QuerySqlField()
+ private int age;
+
+ /**
+ * @param age Age.
+ * @param name Name.
+ * @param company Company.
+ * @param city City.
+ */
+ public TestValue(int age, String name, String company, String city) {
+ this.age = age;
+ this.name = name;
+ this.company = company;
+ this.city = city;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/c3462fff/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 8213380..aeb49e1 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
@@ -120,6 +120,7 @@ import org.apache.ignite.internal.processors.cache.distributed.replicated.Ignite
import org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheReplicatedQuerySelfTest;
import org.apache.ignite.internal.processors.cache.encryption.EncryptedSqlTableTest;
import org.apache.ignite.internal.processors.cache.index.BasicIndexTest;
+import org.apache.ignite.internal.processors.cache.index.ComplexPrimaryKeyUnwrapSelfTest;
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;
@@ -127,10 +128,6 @@ import org.apache.ignite.internal.processors.cache.index.DynamicIndexServerCoord
import org.apache.ignite.internal.processors.cache.index.DynamicIndexServerNodeFIlterBasicSelfTest;
import org.apache.ignite.internal.processors.cache.index.DynamicIndexServerNodeFilterCoordinatorBasicSelfTest;
import org.apache.ignite.internal.processors.cache.index.H2ConnectionLeaksSelfTest;
-import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexClientAtomicPartitionedNoBackupsTest;
-import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexClientTransactionalPartitionedNoBackupsTest;
-import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerAtomicPartitionedNoBackupsTest;
-import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerTransactionalPartitionedNoBackupsTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicColumnsClientBasicSelfTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicColumnsServerBasicSelfTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicColumnsServerCoordinatorBasicSelfTest;
@@ -140,12 +137,16 @@ import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexAtomicRep
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexTransactionalPartitionedNearSelfTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexTransactionalPartitionedSelfTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexTransactionalReplicatedSelfTest;
+import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexClientAtomicPartitionedNoBackupsTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexClientAtomicPartitionedTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexClientAtomicReplicatedTest;
+import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexClientTransactionalPartitionedNoBackupsTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexClientTransactionalPartitionedTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexClientTransactionalReplicatedTest;
+import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerAtomicPartitionedNoBackupsTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerAtomicPartitionedTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerAtomicReplicatedTest;
+import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerTransactionalPartitionedNoBackupsTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerTransactionalPartitionedTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerTransactionalReplicatedTest;
import org.apache.ignite.internal.processors.cache.index.H2DynamicTableSelfTest;
@@ -242,6 +243,7 @@ public class IgniteBinaryCacheQueryTestSuite extends TestSuite {
suite.addTestSuite(AffinityKeyNameAndValueFieldNameConflictTest.class);
suite.addTestSuite(DmlInsideTransactionTest.class);
+ suite.addTestSuite(ComplexPrimaryKeyUnwrapSelfTest.class);
suite.addTestSuite(PartitionedSqlTest.class);
suite.addTestSuite(ReplicatedSqlTest.class);