You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2017/04/27 07:17:05 UTC
[03/37] ignite git commit: IGNITE-3487: hidden _key and _val columns
- Fixes #1865.
IGNITE-3487: hidden _key and _val columns - Fixes #1865.
Signed-off-by: Sergi Vladykin <se...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/efb7abce
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/efb7abce
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/efb7abce
Branch: refs/heads/ignite-5090
Commit: efb7abce8323e0dc3449d7ce1bcd1d9558e6f2bc
Parents: 760cf95
Author: devozerov <vo...@gridgain.com>
Authored: Wed Apr 26 17:17:12 2017 +0300
Committer: Sergi Vladykin <se...@gmail.com>
Committed: Wed Apr 26 17:17:12 2017 +0300
----------------------------------------------------------------------
.../jdbc2/JdbcAbstractDmlStatementSelfTest.java | 6 +
.../internal/jdbc2/JdbcMetadataSelfTest.java | 28 +-
.../ignite/jdbc/JdbcMetadataSelfTest.java | 8 +-
.../org/apache/ignite/cache/QueryEntity.java | 81 ++++
.../configuration/CacheConfiguration.java | 12 +-
.../cache/query/GridCacheQueryManager.java | 14 +-
.../utils/PlatformConfigurationUtils.java | 6 +
.../query/GridQueryTypeDescriptor.java | 12 +
.../query/QueryTypeDescriptorImpl.java | 34 +-
.../internal/processors/query/QueryUtils.java | 134 +++++--
.../query/h2/DmlStatementsProcessor.java | 17 +-
.../processors/query/h2/IgniteH2Indexing.java | 191 ++++++++-
.../query/h2/dml/UpdatePlanBuilder.java | 32 +-
.../query/h2/opt/GridH2AbstractKeyValueRow.java | 78 ++--
.../query/h2/opt/GridH2CollocationModel.java | 4 +-
.../query/h2/opt/GridH2IndexBase.java | 15 +-
.../query/h2/opt/GridH2KeyValueRowOffheap.java | 6 +-
.../query/h2/opt/GridH2KeyValueRowOnheap.java | 6 +-
.../query/h2/opt/GridH2ProxyIndex.java | 204 ++++++++++
.../query/h2/opt/GridH2ProxySpatialIndex.java | 70 ++++
.../query/h2/opt/GridH2RowDescriptor.java | 67 ++++
.../processors/query/h2/opt/GridH2Table.java | 114 +++++-
.../query/h2/opt/GridLuceneIndex.java | 4 +-
.../processors/query/h2/sql/DmlAstUtils.java | 36 +-
.../IgniteBinaryObjectQueryArgumentsTest.java | 4 +-
.../IgniteCacheAbstractFieldsQuerySelfTest.java | 15 +-
.../IgniteCacheDeleteSqlQuerySelfTest.java | 6 +-
.../IgniteCacheUpdateSqlQuerySelfTest.java | 8 +-
.../cache/index/AbstractSchemaSelfTest.java | 3 +
.../index/DynamicIndexAbstractSelfTest.java | 3 +
.../query/IgniteSqlKeyValueFieldsTest.java | 392 +++++++++++++++++++
.../query/IgniteSqlSplitterSelfTest.java | 8 +-
.../h2/GridIndexingSpiAbstractSelfTest.java | 10 +
.../query/h2/sql/GridQueryParsingTest.java | 2 +-
.../IgniteCacheQuerySelfTestSuite.java | 2 +
.../core-test/config/cache-query-default.xml | 6 +
.../cpp/core-test/src/cache_query_test.cpp | 82 ++++
.../cpp/odbc-test/config/queries-default.xml | 5 +
.../cpp/odbc-test/include/complex_type.h | 25 ++
.../cpp/odbc-test/src/queries_test.cpp | 148 +++++++
.../Cache/Query/CacheLinqTest.cs | 7 +
.../Cache/Query/CacheQueriesTest.cs | 52 +++
.../IgniteConfigurationSerializerTest.cs | 4 +-
.../Cache/Configuration/QueryEntity.cs | 20 +
.../IgniteConfigurationSection.xsd | 14 +
.../Impl/CacheQueryExpressionVisitor.cs | 14 +-
.../Impl/CacheQueryModelVisitor.cs | 12 +-
47 files changed, 1822 insertions(+), 199 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcAbstractDmlStatementSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcAbstractDmlStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcAbstractDmlStatementSelfTest.java
index f23dde7..90f52bd 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcAbstractDmlStatementSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcAbstractDmlStatementSelfTest.java
@@ -44,6 +44,9 @@ public abstract class JdbcAbstractDmlStatementSelfTest extends GridCommonAbstrac
/** SQL SELECT query for verification. */
static final String SQL_SELECT = "select _key, id, firstName, lastName, age from Person";
+ /** Alias for _key */
+ private static final String KEY_ALIAS = "key";
+
/** Connection. */
protected Connection conn;
@@ -97,6 +100,9 @@ public abstract class JdbcAbstractDmlStatementSelfTest extends GridCommonAbstrac
e.setKeyType(String.class.getName());
e.setValueType("Person");
+ e.setKeyFieldName(KEY_ALIAS);
+
+ e.addQueryField(KEY_ALIAS, e.getKeyType(), null);
e.addQueryField("id", Integer.class.getName(), null);
e.addQueryField("age", Integer.class.getName(), null);
e.addQueryField("firstName", String.class.getName(), null);
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
index 750af74..ebf8874 100755
--- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
@@ -203,8 +203,6 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
names.add("NAME");
names.add("AGE");
names.add("ORGID");
- names.add("_KEY");
- names.add("_VAL");
int cnt = 0;
@@ -222,22 +220,12 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
assertEquals("INTEGER", rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("NULLABLE"));
}
- if ("_KEY".equals(name)) {
- assertEquals(OTHER, rs.getInt("DATA_TYPE"));
- assertEquals("OTHER", rs.getString("TYPE_NAME"));
- assertEquals(0, rs.getInt("NULLABLE"));
- }
- if ("_VAL".equals(name)) {
- assertEquals(OTHER, rs.getInt("DATA_TYPE"));
- assertEquals("OTHER", rs.getString("TYPE_NAME"));
- assertEquals(0, rs.getInt("NULLABLE"));
- }
cnt++;
}
assertTrue(names.isEmpty());
- assertEquals(5, cnt);
+ assertEquals(3, cnt);
rs = meta.getColumns("", "org", "Organization", "%");
@@ -245,8 +233,6 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
names.add("ID");
names.add("NAME");
- names.add("_KEY");
- names.add("_VAL");
cnt = 0;
@@ -264,22 +250,12 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
assertEquals("VARCHAR", rs.getString("TYPE_NAME"));
assertEquals(1, rs.getInt("NULLABLE"));
}
- if ("_KEY".equals(name)) {
- assertEquals(VARCHAR, rs.getInt("DATA_TYPE"));
- assertEquals("VARCHAR", rs.getString("TYPE_NAME"));
- assertEquals(0, rs.getInt("NULLABLE"));
- }
- if ("_VAL".equals(name)) {
- assertEquals(OTHER, rs.getInt("DATA_TYPE"));
- assertEquals("OTHER", rs.getString("TYPE_NAME"));
- assertEquals(0, rs.getInt("NULLABLE"));
- }
cnt++;
}
assertTrue(names.isEmpty());
- assertEquals(4, cnt);
+ assertEquals(2, cnt);
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java
index 3ba5ed2..a02f489 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java
@@ -195,8 +195,6 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
names.add("NAME");
names.add("AGE");
names.add("ORGID");
- names.add("_KEY");
- names.add("_VAL");
int cnt = 0;
@@ -229,7 +227,7 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
}
assert names.isEmpty();
- assert cnt == 5;
+ assert cnt == 3;
rs = meta.getColumns("", "org", "Organization", "%");
@@ -237,8 +235,6 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
names.add("ID");
names.add("NAME");
- names.add("_KEY");
- names.add("_VAL");
cnt = 0;
@@ -271,7 +267,7 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
}
assert names.isEmpty();
- assert cnt == 4;
+ assert cnt == 2;
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
index 806cd7d..31d89a3 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
@@ -45,6 +45,12 @@ public class QueryEntity implements Serializable {
/** Value type. */
private String valType;
+ /** Key name. Can be used in field list to denote the key as a whole. */
+ private String keyFieldName;
+
+ /** Value name. Can be used in field list to denote the entire value. */
+ private String valueFieldName;
+
/** Fields available for query. A map from field name to type name. */
@GridToStringInclude
private LinkedHashMap<String, String> fields = new LinkedHashMap<>();
@@ -80,6 +86,9 @@ public class QueryEntity implements Serializable {
keyType = other.keyType;
valType = other.valType;
+ keyFieldName = other.keyFieldName;
+ valueFieldName = other.valueFieldName;
+
fields = new LinkedHashMap<>(other.fields);
keyFields = other.keyFields != null ? new HashSet<>(other.keyFields) : null;
@@ -110,6 +119,21 @@ public class QueryEntity implements Serializable {
}
/**
+ * Attempts to get key type from fields in case it was not set directly.
+ *
+ * @return Key type.
+ */
+ public String findKeyType() {
+ if (keyType != null)
+ return keyType;
+
+ if (fields != null && keyFieldName != null)
+ return fields.get(keyFieldName);
+
+ return null;
+ }
+
+ /**
* Sets key type for this query pair.
*
* @param keyType Key type.
@@ -131,6 +155,21 @@ public class QueryEntity implements Serializable {
}
/**
+ * Attempts to get value type from fields in case it was not set directly.
+ *
+ * @return Value type.
+ */
+ public String findValueType() {
+ if (valType != null)
+ return valType;
+
+ if (fields != null && valueFieldName != null)
+ return fields.get(valueFieldName);
+
+ return null;
+ }
+
+ /**
* Sets value type for this query pair.
*
* @param valType Value type.
@@ -191,6 +230,48 @@ public class QueryEntity implements Serializable {
}
/**
+ * Gets key field name.
+ *
+ * @return Key name.
+ */
+ public String getKeyFieldName() {
+ return keyFieldName;
+ }
+
+ /**
+ * Sets key field name.
+ *
+ * @param keyFieldName Key name.
+ * @return {@code this} for chaining.
+ */
+ public QueryEntity setKeyFieldName(String keyFieldName) {
+ this.keyFieldName = keyFieldName;
+
+ return this;
+ }
+
+ /**
+ * Get value field name.
+ *
+ * @return Value name.
+ */
+ public String getValueFieldName() {
+ return valueFieldName;
+ }
+
+ /**
+ * Sets value field name.
+ *
+ * @param valueFieldName value name.
+ * @return {@code this} for chaining.
+ */
+ public QueryEntity setValueFieldName(String valueFieldName) {
+ this.valueFieldName = valueFieldName;
+
+ return this;
+ }
+
+ /**
* Gets a collection of index entities.
*
* @return Collection of index entities.
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
index 8a3874f..275a21e 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
@@ -1749,7 +1749,7 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
boolean dup = false;
for (QueryEntity entity : qryEntities) {
- if (F.eq(entity.getValueType(), converted.getValueType())) {
+ if (F.eq(entity.findValueType(), converted.findValueType())) {
dup = true;
break;
@@ -1832,7 +1832,7 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
boolean found = false;
for (QueryEntity existing : this.qryEntities) {
- if (F.eq(entity.getValueType(), existing.getValueType())) {
+ if (F.eq(entity.findValueType(), existing.findValueType())) {
found = true;
break;
@@ -2032,10 +2032,10 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
txtIdx.setIndexType(QueryIndexType.FULLTEXT);
- txtIdx.setFieldNames(Arrays.asList(QueryUtils._VAL), true);
+ txtIdx.setFieldNames(Arrays.asList(QueryUtils.VAL_FIELD_NAME), true);
}
else
- txtIdx.getFields().put(QueryUtils._VAL, true);
+ txtIdx.getFields().put(QueryUtils.VAL_FIELD_NAME, true);
}
if (txtIdx != null)
@@ -2089,12 +2089,12 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
@Nullable ClassProperty parent) {
if (U.isJdk(cls) || QueryUtils.isGeometryClass(cls)) {
if (parent == null && !key && QueryUtils.isSqlType(cls)) { // We have to index primitive _val.
- String idxName = cls.getSimpleName() + "_" + QueryUtils._VAL + "_idx";
+ String idxName = cls.getSimpleName() + "_" + QueryUtils.VAL_FIELD_NAME + "_idx";
type.addIndex(idxName, QueryUtils.isGeometryClass(cls) ?
QueryIndexType.GEOSPATIAL : QueryIndexType.SORTED);
- type.addFieldToIndex(idxName, QueryUtils._VAL, 0, false);
+ type.addFieldToIndex(idxName, QueryUtils.VAL_FIELD_NAME, 0, false);
}
return;
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
index 900e96f..0f7b0df 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
@@ -2031,6 +2031,12 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte
/** */
private static final long serialVersionUID = 0L;
+ /**
+ * Number of fields to report when no fields defined.
+ * Includes _key and _val columns.
+ */
+ private static final int NO_FIELDS_COLUMNS_COUNT = 2;
+
/** Grid */
@IgniteInstanceResource
private Ignite ignite;
@@ -2073,13 +2079,15 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte
keyClasses.put(type.name(), type.keyClass().getName());
valClasses.put(type.name(), type.valueClass().getName());
- int size = 2 + type.fields().size();
+ int size = type.fields().isEmpty() ? NO_FIELDS_COLUMNS_COUNT : type.fields().size();
Map<String, String> fieldsMap = U.newLinkedHashMap(size);
// _KEY and _VAL are not included in GridIndexingTypeDescriptor.valueFields
- fieldsMap.put("_KEY", type.keyClass().getName());
- fieldsMap.put("_VAL", type.valueClass().getName());
+ if (type.fields().isEmpty()) {
+ fieldsMap.put("_KEY", type.keyClass().getName());
+ fieldsMap.put("_VAL", type.valueClass().getName());
+ }
for (Map.Entry<String, Class<?>> e : type.fields().entrySet())
fieldsMap.put(e.getKey().toUpperCase(), e.getValue().getName());
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
index eb3e716..9bbf5d6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
@@ -493,6 +493,9 @@ public class PlatformConfigurationUtils {
res.setIndexes(indexes);
}
+ res.setKeyFieldName(in.readString());
+ res.setValueFieldName(in.readString());
+
return res;
}
@@ -909,6 +912,9 @@ public class PlatformConfigurationUtils {
}
else
writer.writeInt(0);
+
+ writer.writeString(queryEntity.getKeyFieldName());
+ writer.writeString(queryEntity.getValueFieldName());
}
/**
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
index b7434d3..3c75ac4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
@@ -133,4 +133,16 @@ public interface GridQueryTypeDescriptor {
* @return BinaryObject's type ID if indexed value is BinaryObject, otherwise value class' hash code.
*/
public int typeId();
+
+ /**
+ * Gets key field name.
+ * @return Key field name.
+ */
+ public String keyFieldName();
+
+ /**
+ * Gets value field name.
+ * @return value field name.
+ */
+ public String valueFieldName();
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
index 119a389..56c6aa5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
@@ -90,6 +90,12 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor {
/** */
private String affKey;
+ /** */
+ private String keyFieldName;
+
+ /** */
+ private String valFieldName;
+
/** Obsolete. */
private volatile boolean obsolete;
@@ -265,7 +271,7 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor {
* @return {@code True} if exists.
*/
public boolean hasField(String field) {
- return props.containsKey(field) || QueryUtils._VAL.equalsIgnoreCase(field);
+ return props.containsKey(field) || QueryUtils.VAL_FIELD_NAME.equalsIgnoreCase(field);
}
/**
@@ -415,4 +421,30 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor {
@Override public String toString() {
return S.toString(QueryTypeDescriptorImpl.class, this);
}
+
+ /**
+ * Sets key field name.
+ * @param keyFieldName Key field name.
+ */
+ public void keyFieldName(String keyFieldName) {
+ this.keyFieldName = keyFieldName;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String keyFieldName() {
+ return keyFieldName;
+ }
+
+ /**
+ * Sets value field name.
+ * @param valueFieldName value field name.
+ */
+ public void valueFieldName(String valueFieldName) {
+ this.valFieldName = valueFieldName;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String valueFieldName() {
+ return valFieldName;
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
index e56f39f..1a80a37 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
@@ -45,8 +45,10 @@ import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Time;
import java.sql.Timestamp;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -60,8 +62,15 @@ import static org.apache.ignite.IgniteSystemProperties.getInteger;
* Utility methods for queries.
*/
public class QueryUtils {
- /** */
- public static final String _VAL = "_val";
+
+ /** Field name for key. */
+ public static final String KEY_FIELD_NAME = "_key";
+
+ /** Field name for value. */
+ public static final String VAL_FIELD_NAME = "_val";
+
+ /** Version field name. */
+ public static final String VER_FIELD_NAME = "_ver";
/** Discovery history size. */
private static final int DISCO_HIST_SIZE = getInteger(IGNITE_INDEXING_DISCOVERY_HISTORY_SIZE, 1000);
@@ -98,7 +107,7 @@ public class QueryUtils {
String res = entity.getTableName();
if (res == null)
- res = typeName(entity.getValueType());
+ res = typeName(entity.findValueType());
return res;
}
@@ -176,8 +185,8 @@ public class QueryUtils {
// Key and value classes still can be available if they are primitive or JDK part.
// We need that to set correct types for _key and _val columns.
- Class<?> keyCls = U.classForName(qryEntity.getKeyType(), null);
- Class<?> valCls = U.classForName(qryEntity.getValueType(), null);
+ Class<?> keyCls = U.classForName(qryEntity.findKeyType(), null);
+ Class<?> valCls = U.classForName(qryEntity.findValueType(), null);
// If local node has the classes and they are externalizable, we must use reflection properties.
boolean keyMustDeserialize = mustDeserializeBinary(ctx, keyCls);
@@ -188,7 +197,7 @@ public class QueryUtils {
if (keyCls == null)
keyCls = Object.class;
- String simpleValType = ((valCls == null) ? typeName(qryEntity.getValueType()) : typeName(valCls));
+ String simpleValType = ((valCls == null) ? typeName(qryEntity.findValueType()) : typeName(valCls));
desc.name(simpleValType);
@@ -209,14 +218,17 @@ public class QueryUtils {
else {
if (valCls == null)
throw new IgniteCheckedException("Failed to find value class in the node classpath " +
- "(use default marshaller to enable binary objects) : " + qryEntity.getValueType());
+ "(use default marshaller to enable binary objects) : " + qryEntity.findValueType());
desc.valueClass(valCls);
desc.keyClass(keyCls);
}
- desc.keyTypeName(qryEntity.getKeyType());
- desc.valueTypeName(qryEntity.getValueType());
+ desc.keyTypeName(qryEntity.findKeyType());
+ desc.valueTypeName(qryEntity.findValueType());
+
+ desc.keyFieldName(qryEntity.getKeyFieldName());
+ desc.valueFieldName(qryEntity.getValueFieldName());
if (binaryEnabled && keyOrValMustDeserialize) {
if (keyMustDeserialize)
@@ -232,14 +244,14 @@ public class QueryUtils {
if (valCls == null || (binaryEnabled && !keyOrValMustDeserialize)) {
processBinaryMeta(ctx, qryEntity, desc);
- typeId = new QueryTypeIdKey(space, ctx.cacheObjects().typeId(qryEntity.getValueType()));
+ typeId = new QueryTypeIdKey(space, ctx.cacheObjects().typeId(qryEntity.findValueType()));
if (valCls != null)
altTypeId = new QueryTypeIdKey(space, valCls);
- if (!cctx.customAffinityMapper() && qryEntity.getKeyType() != null) {
+ if (!cctx.customAffinityMapper() && qryEntity.findKeyType() != null) {
// Need to setup affinity key for distributed joins.
- String affField = ctx.cacheObjects().affinityField(qryEntity.getKeyType());
+ String affField = ctx.cacheObjects().affinityField(qryEntity.findKeyType());
if (affField != null)
desc.affinityKey(affField);
@@ -259,7 +271,7 @@ public class QueryUtils {
}
typeId = new QueryTypeIdKey(space, valCls);
- altTypeId = new QueryTypeIdKey(space, ctx.cacheObjects().typeId(qryEntity.getValueType()));
+ altTypeId = new QueryTypeIdKey(space, ctx.cacheObjects().typeId(qryEntity.findValueType()));
}
return new QueryTypeCandidate(typeId, altTypeId, desc);
@@ -310,7 +322,7 @@ public class QueryUtils {
processIndexes(qryEntity, d);
}
-
+
/**
* Processes declarative metadata for binary object.
*
@@ -321,9 +333,11 @@ public class QueryUtils {
public static void processClassMeta(QueryEntity qryEntity, QueryTypeDescriptorImpl d, CacheObjectContext coCtx)
throws IgniteCheckedException {
for (Map.Entry<String, String> entry : qryEntity.getFields().entrySet()) {
- QueryClassProperty prop = buildClassProperty(
+ GridQueryProperty prop = buildProperty(
d.keyClass(),
d.valueClass(),
+ d.keyFieldName(),
+ d.valueFieldName(),
entry.getKey(),
U.classForName(entry.getValue(), Object.class),
d.aliases(),
@@ -429,7 +443,7 @@ public class QueryUtils {
else
throw new IllegalArgumentException("Index type is not set: " + idx.getName());
}
-
+
/**
* Builds binary object property.
*
@@ -443,7 +457,7 @@ public class QueryUtils {
* @return Binary property.
*/
public static QueryBinaryProperty buildBinaryProperty(GridKernalContext ctx, String pathStr, Class<?> resType,
- Map<String, String> aliases, @Nullable Boolean isKeyField) throws IgniteCheckedException {
+ Map<String, String> aliases, @Nullable Boolean isKeyField) throws IgniteCheckedException {
String[] path = pathStr.split("\\.");
QueryBinaryProperty res = null;
@@ -464,7 +478,7 @@ public class QueryUtils {
return res;
}
-
+
/**
* @param keyCls Key class.
* @param valCls Value class.
@@ -494,6 +508,33 @@ public class QueryUtils {
}
/**
+ * @param keyCls Key class.
+ * @param valCls Value class.
+ * @param keyFieldName Key Field.
+ * @param valueFieldName Value Field.
+ * @param pathStr Path string.
+ * @param resType Result type.
+ * @param aliases Aliases.
+ * @return Class property.
+ * @throws IgniteCheckedException If failed.
+ */
+ public static GridQueryProperty buildProperty(Class<?> keyCls, Class<?> valCls, String keyFieldName, String valueFieldName, String pathStr,
+ Class<?> resType, Map<String,String> aliases, CacheObjectContext coCtx) throws IgniteCheckedException {
+ if (pathStr.equals(keyFieldName))
+ return new KeyOrValProperty(true, pathStr, keyCls);
+
+ if (pathStr.equals(valueFieldName))
+ return new KeyOrValProperty(false, pathStr, valCls);
+
+ return buildClassProperty(keyCls,
+ valCls,
+ pathStr,
+ resType,
+ aliases,
+ coCtx);
+ }
+
+ /**
* Exception message to compare in tests.
*
* @param keyCls key class
@@ -508,7 +549,7 @@ public class QueryUtils {
resType.getName() + "' for key class '" + keyCls + "' and value class '" + valCls + "'. " +
"Make sure that one of these classes contains respective getter method or field.";
}
-
+
/**
* @param key If this is a key property.
* @param cls Source type class.
@@ -553,7 +594,7 @@ public class QueryUtils {
return res;
}
-
+
/**
* Find a member (either a getter method or a field) with given name of given class.
* @param prop Property name.
@@ -807,7 +848,7 @@ public class QueryUtils {
if (!F.isEmpty(entities)) {
for (QueryEntity entity : entities) {
- if (F.isEmpty(entity.getValueType()))
+ if (F.isEmpty(entity.findValueType()))
continue;
Collection<QueryIndex> idxs = entity.getIndexes();
@@ -839,7 +880,7 @@ public class QueryUtils {
if (!F.isEmpty(entities)) {
for (QueryEntity entity : entities) {
- if (F.isEmpty(entity.getValueType()))
+ if (F.isEmpty(entity.findValueType()))
throw new IgniteCheckedException("Value type cannot be null or empty [cacheName=" +
ccfg.getName() + ", queryEntity=" + entity + ']');
@@ -875,4 +916,53 @@ public class QueryUtils {
private QueryUtils() {
// No-op.
}
+
+ /** Property used for keyFieldName or valueFieldName */
+ public static class KeyOrValProperty implements GridQueryProperty {
+ /** */
+ boolean isKey;
+
+ /** */
+ String name;
+
+ /** */
+ Class<?> cls;
+
+ /** */
+ public KeyOrValProperty(boolean key, String name, Class<?> cls) {
+ this.isKey = key;
+ this.name = name;
+ this.cls = cls;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object value(Object key, Object val) throws IgniteCheckedException {
+ return isKey ? key : val;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void setValue(Object key, Object val, Object propVal) throws IgniteCheckedException {
+ //No-op
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return name;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Class<?> type() {
+ return cls;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean key() {
+ return isKey;
+ }
+
+ /** {@inheritDoc} */
+ @Override public GridQueryProperty parent() {
+ return null;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
index e8dc73b..4194bc7 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
@@ -86,6 +86,7 @@ import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.createJdbcSqlException;
import static org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.UPDATE_RESULT_META;
+import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.DEFAULT_COLUMNS_COUNT;
/**
*
@@ -587,9 +588,12 @@ public class DmlStatementsProcessor {
if (newVal == null)
throw new IgniteSQLException("New value for UPDATE must not be null", IgniteQueryErrorCode.NULL_VALUE);
- // Skip key and value - that's why we start off with 2nd column
- for (int i = 0; i < plan.tbl.getColumns().length - 2; i++) {
- Column c = plan.tbl.getColumn(i + 2);
+ // Skip key and value - that's why we start off with 3rd column
+ for (int i = 0; i < plan.tbl.getColumns().length - DEFAULT_COLUMNS_COUNT; i++) {
+ Column c = plan.tbl.getColumn(i + DEFAULT_COLUMNS_COUNT);
+
+ if (desc.isKeyValueOrVersionColumn(c.getColumnId()))
+ continue;
GridQueryProperty prop = desc.type().property(c.getName());
@@ -965,8 +969,11 @@ public class DmlStatementsProcessor {
// column order preserves their precedence for correct update of nested properties.
Column[] cols = plan.tbl.getColumns();
- // First 2 columns are _key and _val, skip 'em.
- for (int i = 2; i < cols.length; i++) {
+ // First 3 columns are _key, _val and _ver. Skip 'em.
+ for (int i = DEFAULT_COLUMNS_COUNT; i < cols.length; i++) {
+ if (plan.tbl.rowDescriptor().isKeyValueOrVersionColumn(i))
+ continue;
+
String colName = cols[i].getName();
if (!newColVals.containsKey(colName))
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/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 361b55b..83fb1f2 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
@@ -115,6 +115,7 @@ import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
import org.apache.ignite.internal.processors.query.h2.opt.GridH2SystemIndexFactory;
import org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOffheap;
import org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2ProxyIndex;
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.GridH2RowDescriptor;
@@ -165,11 +166,14 @@ import org.h2.engine.Session;
import org.h2.engine.SysProperties;
import org.h2.index.Cursor;
import org.h2.index.Index;
+import org.h2.index.SpatialIndex;
import org.h2.jdbc.JdbcConnection;
import org.h2.jdbc.JdbcPreparedStatement;
import org.h2.jdbc.JdbcStatement;
import org.h2.message.DbException;
import org.h2.mvstore.cache.CacheLongKeyLIRS;
+import org.h2.result.SearchRow;
+import org.h2.result.SimpleRow;
import org.h2.result.SortOrder;
import org.h2.server.web.WebServer;
import org.h2.table.Column;
@@ -209,9 +213,15 @@ import static org.apache.ignite.IgniteSystemProperties.getString;
import static org.apache.ignite.internal.processors.cache.query.GridCacheQueryType.SQL;
import static org.apache.ignite.internal.processors.cache.query.GridCacheQueryType.SQL_FIELDS;
import static org.apache.ignite.internal.processors.cache.query.GridCacheQueryType.TEXT;
+import static org.apache.ignite.internal.processors.query.QueryUtils.KEY_FIELD_NAME;
+import static org.apache.ignite.internal.processors.query.QueryUtils.VAL_FIELD_NAME;
+import static org.apache.ignite.internal.processors.query.QueryUtils.VER_FIELD_NAME;
import static org.apache.ignite.internal.processors.query.h2.opt.DistributedJoinMode.OFF;
import static org.apache.ignite.internal.processors.query.h2.opt.DistributedJoinMode.distributedJoinMode;
+import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.DEFAULT_COLUMNS_COUNT;
import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.KEY_COL;
+import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.VAL_COL;
+import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.VER_COL;
import static org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryType.LOCAL;
import static org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryType.PREPARE;
@@ -262,12 +272,6 @@ public class IgniteH2Indexing implements GridQueryIndexing {
/** */
private static final int TWO_STEP_QRY_CACHE_SIZE = 1024;
- /** Field name for key. */
- public static final String KEY_FIELD_NAME = "_KEY";
-
- /** Field name for value. */
- public static final String VAL_FIELD_NAME = "_VAL";
-
/** */
private static final Field COMMAND_FIELD;
@@ -1886,9 +1890,23 @@ public class IgniteH2Indexing implements GridQueryIndexing {
String ptrn = "Name ''{0}'' is reserved and cannot be used as a field name [type=" + type.name() + "]";
for (String name : names) {
- if (name.equalsIgnoreCase(KEY_FIELD_NAME) || name.equalsIgnoreCase(VAL_FIELD_NAME))
+ if (name.equalsIgnoreCase(KEY_FIELD_NAME) ||
+ name.equalsIgnoreCase(VAL_FIELD_NAME) ||
+ name.equalsIgnoreCase(VER_FIELD_NAME))
throw new IgniteCheckedException(MessageFormat.format(ptrn, name));
}
+
+ if (type.keyFieldName() != null && !type.fields().containsKey(type.keyFieldName())) {
+ throw new IgniteCheckedException(
+ MessageFormat.format("Name ''{0}'' must be amongst fields since it is configured as ''keyFieldName'' [type=" +
+ type.name() + "]", type.keyFieldName()));
+ }
+
+ if (type.valueFieldName() != null && !type.fields().containsKey(type.valueFieldName())) {
+ throw new IgniteCheckedException(
+ MessageFormat.format("Name ''{0}'' must be amongst fields since it is configured as ''valueFieldName'' [type=" +
+ type.name() + "]", type.valueFieldName()));
+ }
}
/**
@@ -1965,10 +1983,13 @@ public class IgniteH2Indexing implements GridQueryIndexing {
SB sql = new SB();
+ String keyValVisibility = tbl.type().fields().isEmpty() ? " VISIBLE" : " INVISIBLE";
+
sql.a("CREATE TABLE ").a(tbl.fullTableName()).a(" (")
- .a(KEY_FIELD_NAME).a(' ').a(keyType).a(" NOT NULL");
+ .a(KEY_FIELD_NAME).a(' ').a(keyType).a(keyValVisibility).a(" NOT NULL");
- sql.a(',').a(VAL_FIELD_NAME).a(' ').a(valTypeStr);
+ sql.a(',').a(VAL_FIELD_NAME).a(' ').a(valTypeStr).a(keyValVisibility);
+ sql.a(',').a(VER_FIELD_NAME).a(" OTHER INVISIBLE");
for (Map.Entry<String, Class<?>> e : tbl.type().fields().entrySet())
sql.a(',').a(escapeName(e.getKey(), escapeAll)).a(' ').a(dbTypeFromClass(e.getValue()));
@@ -2758,15 +2779,32 @@ public class IgniteH2Indexing implements GridQueryIndexing {
}
/**
+ * Check whether columns list contains key or key alias column.
+ *
+ * @param desc Row descriptor.
+ * @param cols Columns list.
+ * @return Result.
+ */
+ private static boolean containsKeyColumn(GridH2RowDescriptor desc, List<IndexColumn> cols) {
+ for (int i = cols.size() - 1; i >= 0; i--) {
+ if (desc.isKeyColumn(cols.get(i).column.getColumnId()))
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param desc Row descriptor.
* @param cols Columns list.
* @param keyCol Primary key column.
* @param affCol Affinity key column.
* @return The same list back.
*/
- private static List<IndexColumn> treeIndexColumns(List<IndexColumn> cols, IndexColumn keyCol, IndexColumn affCol) {
+ private static List<IndexColumn> treeIndexColumns(GridH2RowDescriptor desc, List<IndexColumn> cols, IndexColumn keyCol, IndexColumn affCol) {
assert keyCol != null;
- if (!containsColumn(cols, keyCol))
+ if (!containsKeyColumn(desc, cols))
cols.add(keyCol);
if (affCol != null && !containsColumn(cols, affCol))
@@ -3077,11 +3115,13 @@ public class IgniteH2Indexing implements GridQueryIndexing {
if (affCol != null && equal(affCol, keyCol))
affCol = null;
+ GridH2RowDescriptor desc = tbl.rowDescriptor();
+
Index hashIdx = createHashIndex(
schema,
tbl,
"_key_PK_hash",
- treeIndexColumns(new ArrayList<IndexColumn>(2), keyCol, affCol)
+ treeIndexColumns(desc, new ArrayList<IndexColumn>(2), keyCol, affCol)
);
if (hashIdx != null)
@@ -3093,7 +3133,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
"_key_PK",
tbl,
true,
- treeIndexColumns(new ArrayList<IndexColumn>(2), keyCol, affCol),
+ treeIndexColumns(desc, new ArrayList<IndexColumn>(2), keyCol, affCol),
-1
);
@@ -3144,7 +3184,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
// Add explicit affinity key index if nothing alike was found.
if (affCol != null && !affIdxFound) {
idxs.add(createSortedIndex(schema, "AFFINITY_KEY", tbl, false,
- treeIndexColumns(new ArrayList<IndexColumn>(2), affCol, keyCol), -1));
+ treeIndexColumns(desc, new ArrayList<IndexColumn>(2), affCol, keyCol), -1));
}
return idxs;
@@ -3194,13 +3234,14 @@ public class IgniteH2Indexing implements GridQueryIndexing {
idxDesc.descending(field) ? SortOrder.DESCENDING : SortOrder.ASCENDING));
}
+ GridH2RowDescriptor desc = tbl.rowDescriptor();
if (idxDesc.type() == QueryIndexType.SORTED) {
- cols = treeIndexColumns(cols, keyCol, affCol);
-
+ cols = treeIndexColumns(desc, cols, keyCol, affCol);
return createSortedIndex(schema, name, tbl, false, cols, idxDesc.inlineSize());
}
- else if (idxDesc.type() == QueryIndexType.GEOSPATIAL)
+ else if (idxDesc.type() == QueryIndexType.GEOSPATIAL) {
return createSpatialIndex(tbl, name, cols.toArray(new IndexColumn[cols.size()]));
+ }
throw new IllegalStateException("Index type: " + idxDesc.type());
}
@@ -3483,6 +3524,12 @@ public class IgniteH2Indexing implements GridQueryIndexing {
/** */
private final GridQueryProperty[] props;
+ /** Id of user-defined key column */
+ private final int keyAliasColumnId;
+
+ /** Id of user-defined value column */
+ private final int valueAliasColumnId;
+
/**
* @param type Type descriptor.
* @param schema Schema.
@@ -3522,6 +3569,10 @@ public class IgniteH2Indexing implements GridQueryIndexing {
props[i] = p;
}
+ final List<String> fieldsList = Arrays.asList(fields);
+ keyAliasColumnId = (type.keyFieldName() != null) ? DEFAULT_COLUMNS_COUNT + fieldsList.indexOf(type.keyFieldName()) : -1;
+ valueAliasColumnId = (type.valueFieldName() != null) ? DEFAULT_COLUMNS_COUNT + fieldsList.indexOf(type.valueFieldName()) : -1;
+
// Index is not snapshotable in db-x.
snapshotableIdx = false;
}
@@ -3649,8 +3700,8 @@ public class IgniteH2Indexing implements GridQueryIndexing {
row = GridH2RowFactory.create(wrap(key, keyType));
else
row = schema.offheap == null ?
- new GridH2KeyValueRowOnheap(this, key, keyType, val, valType, expirationTime) :
- new GridH2KeyValueRowOffheap(this, key, keyType, val, valType, expirationTime);
+ new GridH2KeyValueRowOnheap(this, key, keyType, val, valType, ver, expirationTime) :
+ new GridH2KeyValueRowOffheap(this, key, keyType, val, valType, ver, expirationTime);
}
catch (ClassCastException e) {
throw new IgniteCheckedException("Failed to convert key to SQL type. " +
@@ -3733,6 +3784,108 @@ public class IgniteH2Indexing implements GridQueryIndexing {
@Override public boolean snapshotableIndex() {
return snapshotableIdx;
}
+
+ /** {@inheritDoc} */
+ @Override public boolean isKeyColumn(int columnId) {
+ assert columnId >= 0;
+ return columnId == KEY_COL || columnId == keyAliasColumnId;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean isValueColumn(int columnId) {
+ assert columnId >= 0;
+ return columnId == VAL_COL || columnId == valueAliasColumnId;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean isKeyValueOrVersionColumn(int columnId) {
+ assert columnId >= 0;
+ if (columnId < DEFAULT_COLUMNS_COUNT)
+ return true;
+ if (columnId == keyAliasColumnId)
+ return true;
+ if (columnId == valueAliasColumnId)
+ return true;
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean checkKeyIndexCondition(int masks[], int mask) {
+ assert masks != null;
+ assert masks.length > 0;
+
+ if (keyAliasColumnId < 0)
+ return (masks[KEY_COL] & mask) != 0;
+ else
+ return (masks[KEY_COL] & mask) != 0 || (masks[keyAliasColumnId] & mask) != 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void initValueCache(Value valCache[], Value key, Value value, Value version) {
+ assert valCache != null;
+ assert valCache.length > 0;
+
+ valCache[KEY_COL] = key;
+ valCache[VAL_COL] = value;
+ valCache[VER_COL] = version;
+
+ if (keyAliasColumnId > 0)
+ valCache[keyAliasColumnId] = key;
+
+ if (valueAliasColumnId > 0)
+ valCache[valueAliasColumnId] = value;
+ }
+
+ /** {@inheritDoc} */
+ @Override public SearchRow prepareProxyIndexRow(SearchRow row) {
+ if (row == null)
+ return null;
+
+ Value[] data = new Value[row.getColumnCount()];
+ for (int idx = 0; idx < data.length; idx++)
+ data[idx] = row.getValue(idx);
+
+ copyAliasColumnData(data, KEY_COL, keyAliasColumnId);
+ copyAliasColumnData(data, VAL_COL, valueAliasColumnId);
+
+ return new SimpleRow(data);
+ }
+
+ /**
+ * Copies data between original and alias columns
+ *
+ * @param data Array of values.
+ * @param colId Original column id.
+ * @param aliasColId Alias column id.
+ */
+ private void copyAliasColumnData(Value[] data, int colId, int aliasColId) {
+ if (aliasColId <= 0)
+ return;
+
+ if (data[aliasColId] == null && data[colId] != null)
+ data[aliasColId] = data[colId];
+
+ if (data[colId] == null && data[aliasColId] != null)
+ data[colId] = data[aliasColId];
+ }
+
+ /** {@inheritDoc} */
+ @Override public int getAlternativeColumnId(int colId) {
+ if (keyAliasColumnId > 0) {
+ if (colId == KEY_COL)
+ return keyAliasColumnId;
+ else if (colId == keyAliasColumnId)
+ return KEY_COL;
+ }
+ if (valueAliasColumnId > 0) {
+ if (colId == VAL_COL)
+ return valueAliasColumnId;
+ else if (colId == valueAliasColumnId)
+ return VAL_COL;
+ }
+
+ return colId;
+ }
}
/**
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/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 77946dd..22c3e33 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
@@ -31,7 +31,6 @@ 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.IgniteH2Indexing;
import org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor;
import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
import org.apache.ignite.internal.processors.query.h2.sql.DmlAstUtils;
@@ -54,8 +53,7 @@ import org.h2.command.Prepared;
import org.h2.table.Column;
import org.jetbrains.annotations.Nullable;
-import static org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.KEY_FIELD_NAME;
-import static org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.VAL_FIELD_NAME;
+import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.DEFAULT_COLUMNS_COUNT;
/**
* Logic for building update plans performed by {@link DmlStatementsProcessor}.
@@ -133,7 +131,7 @@ public final class UpdatePlanBuilder {
// not for updates, and hence will allow putting new pairs only.
// We don't quote _key and _val column names on CREATE TABLE, so they are always uppercase here.
GridSqlColumn[] keys = merge.keys();
- if (keys.length != 1 || !IgniteH2Indexing.KEY_FIELD_NAME.equals(keys[0].columnName()))
+ if (keys.length != 1 || !desc.isKeyColumn(tbl.dataTable().getColumn(keys[0].columnName()).getColumnId()))
throw new CacheException("SQL MERGE does not support arbitrary keys");
cols = merge.columns();
@@ -173,12 +171,13 @@ public final class UpdatePlanBuilder {
colTypes[i] = col.resultType().type();
- if (KEY_FIELD_NAME.equals(colName)) {
+ int colId = col.column().getColumnId();
+ if (desc.isKeyColumn(colId)) {
keyColIdx = i;
continue;
}
- if (VAL_FIELD_NAME.equals(colName)) {
+ if (desc.isValueColumn(colId)) {
valColIdx = i;
continue;
}
@@ -267,7 +266,8 @@ public final class UpdatePlanBuilder {
colTypes[i] = updatedCols.get(i).resultType().type();
- if (VAL_FIELD_NAME.equals(colNames[i]))
+ Column column = updatedCols.get(i).column();
+ if (desc.isValueColumn(column.getColumnId()))
valColIdx = i;
}
@@ -485,17 +485,19 @@ public final class UpdatePlanBuilder {
private static boolean updateAffectsKeyColumns(GridH2Table gridTbl, Set<String> affectedColNames) {
GridH2RowDescriptor desc = gridTbl.rowDescriptor();
- Column[] cols = gridTbl.getColumns();
+ for (String colName : affectedColNames) {
+ int colId = gridTbl.getColumn(colName).getColumnId();
- // Check "_key" column itself - always has index of 0.
- if (affectedColNames.contains(cols[0].getName()))
- return true;
-
- // Start off from i = 2 to skip indices of 0 an 1 corresponding to key and value respectively.
- for (int i = 2; i < cols.length; i++)
- if (affectedColNames.contains(cols[i].getName()) && desc.isColumnKeyProperty(i - 2))
+ // Check "_key" column and alias key column
+ if (desc.isKeyColumn(colId))
return true;
+ // column ids 0..2 are _key, _val, _ver
+ if (colId >= DEFAULT_COLUMNS_COUNT) {
+ if (desc.isColumnKeyProperty(colId - DEFAULT_COLUMNS_COUNT))
+ return true;
+ }
+ }
return false;
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2AbstractKeyValueRow.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2AbstractKeyValueRow.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2AbstractKeyValueRow.java
index 28dd891..499d258 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2AbstractKeyValueRow.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2AbstractKeyValueRow.java
@@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.IgniteInterruptedException;
+import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
import org.apache.ignite.internal.util.typedef.internal.SB;
import org.apache.ignite.internal.util.typedef.internal.U;
@@ -40,7 +41,7 @@ import org.jetbrains.annotations.Nullable;
*/
public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
/** */
- public static final int DEFAULT_COLUMNS_COUNT = 2;
+ public static final int DEFAULT_COLUMNS_COUNT = 3;
/** Key column. */
public static final int KEY_COL = 0;
@@ -48,6 +49,9 @@ public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
/** Value column. */
public static final int VAL_COL = 1;
+ /** Version column. */
+ public static final int VER_COL = 2;
+
/** */
protected final GridH2RowDescriptor desc;
@@ -64,6 +68,9 @@ public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
/** */
private Value[] valCache;
+ /** */
+ private Value version;
+
/**
* Constructor.
*
@@ -76,14 +83,17 @@ public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
* @throws IgniteCheckedException If failed.
*/
protected GridH2AbstractKeyValueRow(GridH2RowDescriptor desc, Object key, int keyType, @Nullable Object val,
- int valType, long expirationTime) throws IgniteCheckedException {
+ int valType, GridCacheVersion ver, long expirationTime) throws IgniteCheckedException {
+ this.desc = desc;
+ this.expirationTime = expirationTime;
+
setValue(KEY_COL, desc.wrap(key, keyType));
if (val != null) // We remove by key only, so value can be null here.
setValue(VAL_COL, desc.wrap(val, valType));
- this.desc = desc;
- this.expirationTime = expirationTime;
+ if (ver != null)
+ setValue(VER_COL, desc.wrap(ver, Value.JAVA_OBJECT));
}
/** {@inheritDoc} */
@@ -165,7 +175,13 @@ public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
* @return Value if exists.
*/
protected final Value peekValue(int col) {
- return col == KEY_COL ? key : val;
+ if (col == KEY_COL)
+ return key;
+ if (col == VAL_COL)
+ return val;
+
+ assert col == VER_COL;
+ return version;
}
/** {@inheritDoc} */
@@ -179,32 +195,33 @@ public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
return v;
}
- if (col < DEFAULT_COLUMNS_COUNT) {
- Value v;
+ Value v;
- if (col == VAL_COL)
- v = peekValue(VAL_COL);
- else {
- assert col == KEY_COL : col;
+ if (desc.isValueColumn(col)) {
+ v = peekValue(VAL_COL);
- v = peekValue(KEY_COL);
+ assert !(v instanceof WeakValue) : v;
+ return v;
+ }
+ else if (desc.isKeyColumn(col)) {
+ v = peekValue(KEY_COL);
- if (v == null) {
- v = getOffheapValue(KEY_COL);
+ if (v == null) {
+ v = getOffheapValue(KEY_COL);
- assert v != null;
+ assert v != null;
- setValue(KEY_COL, v);
+ setValue(KEY_COL, v);
- if (peekValue(VAL_COL) == null)
- cache();
- }
+ if (peekValue(VAL_COL) == null)
+ cache();
}
assert !(v instanceof WeakValue) : v;
-
return v;
}
+ else if (col == VER_COL)
+ return version;
col -= DEFAULT_COLUMNS_COUNT;
@@ -218,8 +235,6 @@ public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
Object res = desc.columnValue(key.getObject(), val.getObject(), col);
- Value v;
-
if (res == null)
v = ValueNull.INSTANCE;
else {
@@ -242,8 +257,7 @@ public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
*/
public void valuesCache(Value[] valCache) {
if (valCache != null) {
- valCache[KEY_COL] = key;
- valCache[VAL_COL] = val;
+ desc.initValueCache(valCache, key, val, version);
}
this.valCache = valCache;
@@ -281,16 +295,20 @@ public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
v = WeakValue.unwrap(peekValue(VAL_COL));
sb.a(", val: ").a(v == null ? "nil" : v.getString());
+ v = peekValue(VER_COL);
+ sb.a(", ver: ").a(v == null ? "nil" : v.getString());
+
sb.a(" ][ ");
if (v != null) {
- for (int i = 2, cnt = getColumnCount(); i < cnt; i++) {
+ for (int i = DEFAULT_COLUMNS_COUNT, cnt = getColumnCount(); i < cnt; i++) {
v = getValue(i);
- if (i != 2)
+ if (i != DEFAULT_COLUMNS_COUNT)
sb.a(", ");
- sb.a(v == null ? "nil" : v.getString());
+ if (!desc.isKeyValueOrVersionColumn(i))
+ sb.a(v == null ? "nil" : v.getString());
}
}
@@ -418,10 +436,12 @@ public abstract class GridH2AbstractKeyValueRow extends GridH2Row {
/** {@inheritDoc} */
@Override public void setValue(int idx, Value v) {
- if (idx == VAL_COL)
+ if (desc.isValueColumn(idx))
val = v;
+ else if (idx == VER_COL)
+ version = v;
else {
- assert idx == KEY_COL : idx + " " + v;
+ assert desc.isKeyColumn(idx) : idx + " " + v;
key = v;
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2CollocationModel.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2CollocationModel.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2CollocationModel.java
index 4df355e..037607b 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2CollocationModel.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2CollocationModel.java
@@ -39,8 +39,6 @@ import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.table.TableView;
-import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.KEY_COL;
-
/**
* Collocation model for a query.
*/
@@ -413,7 +411,7 @@ public final class GridH2CollocationModel {
int cmpType = c.getCompareType();
if ((cmpType == Comparison.EQUAL || cmpType == Comparison.EQUAL_NULL_SAFE) &&
- (colId == affColId || colId == KEY_COL) && c.isEvaluatable()) {
+ (colId == affColId || tbl.rowDescriptor().isKeyColumn(colId)) && c.isEvaluatable()) {
affKeyCondFound = true;
Expression exp = c.getExpression();
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java
index 81a9620..623da09 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java
@@ -397,6 +397,7 @@ public abstract class GridH2IndexBase extends BaseIndex {
return null;
IndexColumn affCol = getTable().getAffinityKeyColumn();
+ GridH2RowDescriptor desc = getTable().rowDescriptor();
int affColId = -1;
boolean ucast = false;
@@ -407,7 +408,7 @@ public abstract class GridH2IndexBase extends BaseIndex {
if (masks != null) {
ucast = (masks[affColId] & IndexCondition.EQUALITY) != 0 ||
- (masks[KEY_COL] & IndexCondition.EQUALITY) != 0;
+ desc.checkKeyIndexCondition(masks, IndexCondition.EQUALITY);
}
}
@@ -416,6 +417,16 @@ public abstract class GridH2IndexBase extends BaseIndex {
return new DistributedLookupBatch(cctx, ucast, affColId);
}
+ /** {@inheritDoc} */
+ @Override public void removeChildrenAndResources(Session session) {
+ // The sole purpose of this override is to pass session to table.removeIndex
+ assert table instanceof GridH2Table;
+
+ ((GridH2Table)table).removeIndex(session, this);
+ remove(session);
+ database.removeMeta(session, getId());
+ }
+
/**
* @param nodes Nodes.
* @param msg Message.
@@ -1130,7 +1141,7 @@ public abstract class GridH2IndexBase extends BaseIndex {
if (affKeyFirst != null && equal(affKeyFirst, affKeyLast))
return affKeyFirst == ValueNull.INSTANCE ? EXPLICIT_NULL : affKeyFirst.getObject();
- if (affColId == KEY_COL)
+ if (getTable().rowDescriptor().isKeyColumn(affColId))
return null;
// Try to extract affinity key from primary key.
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOffheap.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOffheap.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOffheap.java
index fd310ce..3d92777 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOffheap.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOffheap.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.processors.query.h2.opt;
import java.util.concurrent.locks.Lock;
import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.util.GridStripedLock;
import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory;
import org.apache.ignite.internal.util.typedef.internal.SB;
@@ -84,12 +85,13 @@ public class GridH2KeyValueRowOffheap extends GridH2AbstractKeyValueRow {
* @param keyType Key type.
* @param val Value.
* @param valType Value type.
+ * @param ver Version.
* @param expirationTime Expiration time.
* @throws IgniteCheckedException If failed.
*/
public GridH2KeyValueRowOffheap(GridH2RowDescriptor desc, Object key, int keyType, @Nullable Object val, int valType,
- long expirationTime) throws IgniteCheckedException {
- super(desc, key, keyType, val, valType, expirationTime);
+ GridCacheVersion ver, long expirationTime) throws IgniteCheckedException {
+ super(desc, key, keyType, val, valType, ver, expirationTime);
}
/** {@inheritDoc} */
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOnheap.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOnheap.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOnheap.java
index 772302f..4975092 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOnheap.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2KeyValueRowOnheap.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.processors.query.h2.opt;
import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.h2.value.Value;
import org.jetbrains.annotations.Nullable;
@@ -34,12 +35,13 @@ public class GridH2KeyValueRowOnheap extends GridH2AbstractKeyValueRow {
* @param keyType Key type.
* @param val Value.
* @param valType Value type.
+ * @param ver Version.
* @param expirationTime Expiration time.
* @throws IgniteCheckedException If failed.
*/
public GridH2KeyValueRowOnheap(GridH2RowDescriptor desc, Object key, int keyType, @Nullable Object val, int valType,
- long expirationTime) throws IgniteCheckedException {
- super(desc, key, keyType, val, valType, expirationTime);
+ GridCacheVersion ver, long expirationTime) throws IgniteCheckedException {
+ super(desc, key, keyType, val, valType, ver, expirationTime);
}
/** {@inheritDoc} */
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ProxyIndex.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ProxyIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ProxyIndex.java
new file mode 100644
index 0000000..7c70ded
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ProxyIndex.java
@@ -0,0 +1,204 @@
+/*
+ * 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.opt;
+
+import org.h2.engine.Session;
+import org.h2.index.BaseIndex;
+import org.h2.index.Cursor;
+import org.h2.index.Index;
+import org.h2.index.IndexLookupBatch;
+import org.h2.index.IndexType;
+import org.h2.index.SpatialIndex;
+import org.h2.message.DbException;
+import org.h2.result.Row;
+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 java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.Future;
+
+/**
+ * Allows to have 'free' index for alias columns
+ * Delegates the calls to underlying normal index
+ */
+public class GridH2ProxyIndex extends BaseIndex {
+
+ /** Underlying normal index */
+ protected Index idx;
+
+ /**
+ *
+ * @param tbl Table.
+ * @param name Name of the proxy index.
+ * @param colsList Column list for the proxy index.
+ * @param idx Target index.
+ */
+ public GridH2ProxyIndex(GridH2Table tbl,
+ String name,
+ List<IndexColumn> colsList,
+ Index idx) {
+
+ IndexColumn[] cols = colsList.toArray(new IndexColumn[colsList.size()]);
+
+ IndexColumn.mapColumns(cols, tbl);
+
+ initBaseIndex(tbl, 0, name, cols, IndexType.createNonUnique(false, false, idx instanceof SpatialIndex));
+
+ this.idx = idx;
+ }
+
+ /**
+ * @return Underlying index.
+ */
+ public Index underlyingIndex() {
+ return idx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void checkRename() {
+ throw DbException.getUnsupportedException("rename");
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close(Session session) {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void add(Session session, Row row) {
+ throw DbException.getUnsupportedException("add");
+ }
+
+ /** {@inheritDoc} */
+ @Override public void remove(Session session, Row row) {
+ throw DbException.getUnsupportedException("remove row");
+ }
+
+ /** {@inheritDoc} */
+ @Override public Cursor find(Session session, SearchRow first, SearchRow last) {
+ GridH2RowDescriptor desc = ((GridH2Table)idx.getTable()).rowDescriptor();
+ return idx.find(session, desc.prepareProxyIndexRow(first), desc.prepareProxyIndexRow(last));
+ }
+
+ /** {@inheritDoc} */
+ @Override public double getCost(Session session, 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 = ((GridH2IndexBase)idx).getDistributedMultiplier(session, filters, filter);
+
+ return mul * baseCost;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void remove(Session session) {
+ throw DbException.getUnsupportedException("remove index");
+ }
+
+ /** {@inheritDoc} */
+ @Override public void truncate(Session session) {
+ throw DbException.getUnsupportedException("truncate");
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean canGetFirstOrLast() {
+ return idx.canGetFirstOrLast();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Cursor findFirstOrLast(Session session, boolean first) {
+ return idx.findFirstOrLast(session, first);
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean needRebuild() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public long getRowCount(Session session) {
+ return idx.getRowCount(session);
+ }
+
+ /** {@inheritDoc} */
+ @Override public long getRowCountApproximation() {
+ return idx.getRowCountApproximation();
+ }
+
+ /** {@inheritDoc} */
+ @Override public long getDiskSpaceUsed() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override public IndexLookupBatch createLookupBatch(TableFilter[] filters, int filter) {
+ return new ProxyIndexLookupBatch(idx.createLookupBatch(filters, filter));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void removeChildrenAndResources(Session session) {
+ // No-op. Will be removed when underlying index is removed
+ }
+
+ /** Proxy lookup batch */
+ private class ProxyIndexLookupBatch implements IndexLookupBatch {
+
+ /** Underlying normal lookup batch */
+ private final IndexLookupBatch target;
+
+ /**
+ * Creates proxy lookup batch.
+ *
+ * @param target Underlying index lookup batch.
+ */
+ private ProxyIndexLookupBatch(IndexLookupBatch target) {
+ this.target = target;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean addSearchRows(SearchRow first, SearchRow last) {
+ GridH2RowDescriptor desc = ((GridH2Table)idx.getTable()).rowDescriptor();
+ return target.addSearchRows(desc.prepareProxyIndexRow(first), desc.prepareProxyIndexRow(last));
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean isBatchFull() {
+ return target.isBatchFull();
+ }
+
+ /** {@inheritDoc} */
+ @Override public List<Future<Cursor>> find() {
+ return target.find();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String getPlanSQL() {
+ return target.getPlanSQL();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void reset(boolean beforeQuery) {
+ target.reset(beforeQuery);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ProxySpatialIndex.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ProxySpatialIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ProxySpatialIndex.java
new file mode 100644
index 0000000..8af5099
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2ProxySpatialIndex.java
@@ -0,0 +1,70 @@
+/*
+ * 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.opt;
+
+
+import org.h2.engine.Session;
+import org.h2.index.Cursor;
+import org.h2.index.Index;
+import org.h2.index.SpatialIndex;
+import org.h2.index.SpatialTreeIndex;
+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 java.util.HashSet;
+import java.util.List;
+
+/**
+ * Allows to have 'free' spatial index for alias columns
+ * Delegates the calls to underlying normal index
+ */
+public class GridH2ProxySpatialIndex extends GridH2ProxyIndex implements SpatialIndex {
+ /**
+ *
+ * @param tbl Table.
+ * @param name Name of the proxy index.
+ * @param colsList Column list for the proxy index.
+ * @param idx Target index.
+ */
+ public GridH2ProxySpatialIndex(GridH2Table tbl,
+ String name,
+ List<IndexColumn> colsList,
+ Index idx) {
+ super(tbl, name, colsList, idx);
+ }
+
+ /** {@inheritDoc} */
+ @Override public double getCost(Session ses, int[] masks, TableFilter[] filters, int filter,
+ SortOrder sortOrder, HashSet<Column> cols) {
+ return SpatialTreeIndex.getCostRangeIndex(masks,
+ table.getRowCountApproximation(), columns) / 10;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Cursor findByGeometry(TableFilter filter, SearchRow first, SearchRow last, SearchRow intersection) {
+ GridH2RowDescriptor desc = ((GridH2Table)idx.getTable()).rowDescriptor();
+
+ return ((SpatialIndex)idx).findByGeometry(filter,
+ desc.prepareProxyIndexRow(first),
+ desc.prepareProxyIndexRow(last),
+ desc.prepareProxyIndexRow(intersection));
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/efb7abce/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 61de362..778ebfb 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
@@ -28,6 +28,7 @@ import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
import org.apache.ignite.internal.util.offheap.unsafe.GridOffHeapSmartPointerFactory;
import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeGuard;
import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory;
+import org.h2.result.SearchRow;
import org.h2.value.Value;
import org.jetbrains.annotations.Nullable;
@@ -161,4 +162,70 @@ public interface GridH2RowDescriptor extends GridOffHeapSmartPointerFactory<Grid
* @return {@code True} if index should support snapshots.
*/
public boolean snapshotableIndex();
+
+ /**
+ * Checks if provided column id matches key column or key alias.
+ *
+ * @param colId Column id.
+ * @return Result.
+ */
+ public boolean isKeyColumn(int colId);
+
+ /**
+ * Checks if provided column id matches value column or alias.
+ *
+ * @param colId Column id.
+ * @return Result.
+ */
+ public boolean isValueColumn(int colId);
+
+ /**
+ * Checks if provided column id matches key, key alias,
+ * value, value alias or version column.
+ *
+ * @param colId Column id.
+ * @return Result.
+ */
+ public boolean isKeyValueOrVersionColumn(int colId);
+
+ /**
+ * Checks if provided index condition is allowed for key column or key alias column.
+ *
+ * @param masks Array containing Index Condition masks for each column.
+ * @param mask Index Condition to check.
+ * @return Result.
+ */
+ public boolean checkKeyIndexCondition(int masks[], int mask);
+
+ /**
+ * Initializes value cache with key, val and version.
+ *
+ * @param valCache Value cache.
+ * @param key Key.
+ * @param value Value.
+ * @param version Version.
+ */
+ public void initValueCache(Value valCache[], Value key, Value value, Value version);
+
+ /**
+ * Clones provided row and copies values of alias key and val columns
+ * into respective key and val positions.
+ *
+ * @param row Source row.
+ * @return Result.
+ */
+ public SearchRow prepareProxyIndexRow(SearchRow row);
+
+ /**
+ * Gets alternative column id that may substitute the given column id.
+ *
+ * For alias column returns original one.
+ * For original column returns its alias.
+ *
+ * Otherwise, returns the given column id.
+ *
+ * @param colId Column id.
+ * @return Result.
+ */
+ public int getAlternativeColumnId(int colId);
}
\ No newline at end of file