You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2015/01/19 03:25:15 UTC
[3/3] incubator-ignite git commit: # IGNITE-32 WIP: Reworked store
after review.
# IGNITE-32 WIP: Reworked store after review.
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/79f3a5f7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/79f3a5f7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/79f3a5f7
Branch: refs/heads/ignite-32
Commit: 79f3a5f793bb7d50369c6713fd9fca4063e2edf1
Parents: d5fd7c2
Author: AKuznetsov <ak...@gridgain.com>
Authored: Mon Jan 19 09:25:33 2015 +0700
Committer: AKuznetsov <ak...@gridgain.com>
Committed: Mon Jan 19 09:25:33 2015 +0700
----------------------------------------------------------------------
.../grid/cache/store/auto/AutoCacheStore.java | 491 +++++++++++--------
.../grid/cache/store/auto/H2PojoCacheStore.java | 30 --
.../grid/cache/store/auto/JdbcMapper.java | 40 --
.../grid/cache/store/auto/PojoCacheStore.java | 169 ++++++-
.../grid/cache/store/auto/PojoJdbcMapper.java | 160 ------
.../cache/store/auto/dialect/H2Dialect.java | 31 ++
.../cache/store/auto/dialect/JdbcDialect.java | 244 +++++++++
.../store/auto/AutoCacheStoreSelfTest.java | 7 +-
8 files changed, 728 insertions(+), 444 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/79f3a5f7/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/AutoCacheStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/AutoCacheStore.java b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/AutoCacheStore.java
index ee56152..6e5af2b 100644
--- a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/AutoCacheStore.java
+++ b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/AutoCacheStore.java
@@ -1,10 +1,18 @@
-/* @java.file.header */
-
-/* _________ _____ __________________ _____
- * __ ____/___________(_)______ /__ ____/______ ____(_)_______
- * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \
- * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / /
- * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/
+/*
+ * 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.gridgain.grid.cache.store.auto;
@@ -15,6 +23,7 @@ import org.apache.ignite.resources.*;
import org.apache.ignite.transactions.*;
import org.gridgain.grid.cache.query.*;
import org.gridgain.grid.cache.store.*;
+import org.gridgain.grid.cache.store.auto.dialect.*;
import org.gridgain.grid.kernal.processors.spring.*;
import org.gridgain.grid.util.tostring.*;
import org.gridgain.grid.util.typedef.*;
@@ -36,9 +45,12 @@ import static org.gridgain.grid.kernal.GridComponentType.*;
*/
public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
/**
- * Type mapping cache.
+ * Query cache by type.
*/
- protected class TypeCache {
+ protected static class QueryCache {
+ /** Database dialect. */
+ protected final JdbcDialect dialect;
+
/** Select all items query. */
protected final String loadCacheQry;
@@ -48,8 +60,14 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
/** Select items query. */
private final String loadQry;
- /** Put item(s) query. */
- protected final String putQry;
+ /** Merge item(s) query. */
+ protected final String mergeQry;
+
+ /** Update item query. */
+ protected final String insQry;
+
+ /** Update item query. */
+ protected final String updQry;
/** Remove item(s) query. */
protected final String remQry;
@@ -57,63 +75,71 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
/** Max key count for load query per statement. */
protected final int maxKeysPerStmt;
- /** Database table name. */
- private final String tblName;
-
- /** Database key columns. */
+ /** Database key columns. */
private final Collection<String> keyCols;
- /** Database value columns. */
+ /** Database value columns. */
private final Collection<String> valCols;
- /** Database unique columns. */
- private final Set<String> uniqCols;
+ /** Database unique value columns. */
+ private final Collection<String> uniqValCols;
- /** Mapper for key. */
- protected final JdbcMapper<K> keyMapper;
+ /** Type metadata. */
+ private final GridCacheQueryTypeMetadata typeMetadata;
- /** Mapper for value. */
- protected final JdbcMapper<V> valMapper;
+ private final Collection<GridCacheQueryTypeDescriptor> uniqValFields;
/**
- *
- * @param m Type metadata.
- * @param keyMapper Mapper for key.
- * @param valMapper Mapper for value.
+ * @param typeMetadata Type metadata.
*/
- protected TypeCache(GridCacheQueryTypeMetadata m, JdbcMapper<K> keyMapper, JdbcMapper<V> valMapper) {
- keyCols = databaseColumns(m.getKeyDescriptors());
+ protected QueryCache(JdbcDialect dialect, GridCacheQueryTypeMetadata typeMetadata) {
+ this.dialect = dialect;
+
+ this.typeMetadata = typeMetadata;
+
+ final Collection<GridCacheQueryTypeDescriptor> keyFields = typeMetadata.getKeyDescriptors();
+
+ Collection<GridCacheQueryTypeDescriptor> valFields = typeMetadata.getValueDescriptors();
+
+ uniqValFields = F.view(typeMetadata.getValueDescriptors(),
+ new IgnitePredicate<GridCacheQueryTypeDescriptor>() {
+ @Override public boolean apply(GridCacheQueryTypeDescriptor desc) {
+ return !keyFields.contains(desc);
+ }
+ });
- valCols = databaseColumns(m.getValueDescriptors());
+ String schema = typeMetadata.getSchema();
- uniqCols = U.newLinkedHashSet(keyCols.size() + valCols.size());
- uniqCols.addAll(keyCols);
- uniqCols.addAll(valCols);
+ String tblName = typeMetadata.getTableName();
- tblName = String.format("%s.%s", m.getSchema(), m.getTableName());
+ keyCols = databaseColumns(keyFields);
- loadCacheQry = loadCacheQuery(tblName, uniqCols);
+ valCols = databaseColumns(valFields);
- loadQrySingle = loadQuery(tblName, keyCols, valCols, 1);
+ uniqValCols = databaseColumns(uniqValFields);
- maxKeysPerStmt = maxParamsCnt / keyCols.size();
+ loadCacheQry = dialect.loadCacheQuery(schema, tblName, F.concat(false, keyCols, uniqValCols));
- loadQry = loadQuery(tblName, keyCols, uniqCols, maxKeysPerStmt);
+ loadQrySingle = dialect.loadQuery(schema, tblName, keyCols, valCols, 1);
- putQry = putQuery(tblName, keyCols, uniqCols);
+ maxKeysPerStmt = dialect.getMaxParamsCnt() / keyCols.size();
- remQry = removeQuery(tblName, keyCols);
+ loadQry = dialect.loadQuery(schema, tblName, keyCols, uniqValCols, maxKeysPerStmt);
- this.keyMapper = keyMapper;
+ insQry = dialect.insertQuery(schema, tblName, keyCols, uniqValCols);
- this.valMapper = valMapper;
+ updQry = dialect.updateQuery(schema, tblName, keyCols, uniqValCols);
+
+ mergeQry = dialect.mergeQuery(schema, tblName, keyCols, uniqValCols);
+
+ remQry = dialect.removeQuery(schema, tblName, keyCols);
}
/**
* Construct query for select values with key count less or equal {@code maxKeysPerStmt}
* @param keyCnt Key count.
*/
- protected String loadQueryLast(int keyCnt) {
+ protected String loadQuery(int keyCnt) {
assert keyCnt >= maxKeysPerStmt;
if (keyCnt == maxKeysPerStmt)
@@ -122,12 +148,37 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
if (keyCnt == 1)
return loadQrySingle;
- return loadQuery(tblName, keyCols, uniqCols, keyCnt);
+ return dialect.loadQuery(typeMetadata.getSchema(), typeMetadata.getSchema(), keyCols, uniqValCols, keyCnt);
+ }
+
+ /** Key type. */
+ protected String keyType() {
+ return typeMetadata.getKeyType();
}
- }
- /** Default max query parameters count. */
- protected static final int DFLT_MAX_PARAMS_CNT = 2000;
+ /** Value type. */
+ protected String valueType() {
+ return typeMetadata.getType();
+ }
+
+ /**
+ * Gets key fields type descriptors.
+ *
+ * @return Key fields type descriptors.
+ */
+ protected Collection<GridCacheQueryTypeDescriptor> keyDescriptors() {
+ return typeMetadata.getKeyDescriptors();
+ }
+
+ /**
+ * Gets value fields type descriptors.
+ *
+ * @return Key value type descriptors.
+ */
+ protected Collection<GridCacheQueryTypeDescriptor> valueDescriptors() {
+ return typeMetadata.getValueDescriptors();
+ }
+ }
/** Default batch size for put and remove operations. */
protected static final int DFLT_BATCH_SIZE = 512;
@@ -176,15 +227,15 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
/** Type mapping description. */
protected Collection<GridCacheQueryTypeMetadata> typeMetadata;
- /** Type cache. */
- protected Map<Object, TypeCache> typesCache;
+ /** Cache with query by type. */
+ protected Map<Object, QueryCache> entryQtyCache;
+
+ /** Database dialect. */
+ protected JdbcDialect dialect = new JdbcDialect();
/** Max workers thread count. These threads are responsible for execute query. */
protected int maxPoolSz = Runtime.getRuntime().availableProcessors();
- /** Max query parameters count. */
- protected int maxParamsCnt = DFLT_MAX_PARAMS_CNT;
-
/** Maximum batch size for put and remove operations. */
protected int batchSz = DFLT_BATCH_SIZE;
@@ -340,6 +391,28 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
}
/**
+ * Get field value from object.
+ *
+ * @param typeName Type name.
+ * @param fieldName Field name.
+ * @param obj Cache object.
+ * @return Field value from object.
+ */
+ @Nullable protected abstract Object extractField(String typeName, String fieldName, Object obj) throws IgniteCheckedException;
+
+ /**
+ * Construct object from query result.
+ *
+ * @param <R> Type of result object.
+ * @param typeName Type name.
+ * @param fields Fields descriptors.
+ * @param rs ResultSet.
+ * @return Constructed object.
+ */
+ protected abstract <R> R buildObject(String typeName, Collection<GridCacheQueryTypeDescriptor> fields, ResultSet rs)
+ throws IgniteCheckedException;
+
+ /**
* Concatenates elements using provided separator.
*
* @param elems Concatenated elements.
@@ -436,81 +509,6 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
}
/**
- * Construct load cache query.
- *
- * @param tblName Database table name.
- * @param uniqCols Database unique columns.
- * @return Load cache query.
- */
- protected String loadCacheQuery(String tblName, Iterable<String> uniqCols) {
- return String.format("SELECT %s FROM %s", mkString(uniqCols, ","), tblName);
- }
-
- /**
- * Construct load query.
- *
- * @param tblName Database table name.
- * @param keyCols Database key columns.
- * @param valCols Database value columns.
- * @param keyCnt Key count.
- * @return Load query.
- */
- protected String loadQuery(String tblName, Collection<String> keyCols, Iterable<String> valCols, int keyCnt) {
- assert !keyCols.isEmpty();
-
- assert keyCols.size() * keyCnt <= maxParamsCnt;
-
- SB sb = new SB(String.format("SELECT %s FROM %s WHERE ", mkString(valCols, ","), tblName));
-
- if (keyCols.size() == 1) {
- String keyCol = keyCols.iterator().next();
-
- if (keyCnt == 1)
- sb.a(keyCol+ "=?");
- else
- sb.a(repeat("?", keyCnt, keyCol + " IN (", ",", ")"));
- }
- else {
- String keyParams = mkString(keyCols, new C1<String, String>() {
- @Override public String apply(String s) {
- return s + "=?";
- }
- }, "(", " AND ", ")");
-
- sb.a(repeat(keyParams, keyCnt, "", " OR ", ""));
- }
-
- return sb.toString();
- }
-
- /**
- * Construct put query.
- *
- * @param tblName Database table name.
- * @param keyCols Database key columns.
- * @param uniqCols Database unique columns.
- * @return Put query.
- */
- protected abstract String putQuery(String tblName, Collection<String> keyCols, Collection<String> uniqCols);
-
- /**
- * Construct remove query.
- *
- * @param tblName Database table name.
- * @param keyCols Database key columns.
- * @return Remove query.
- */
- protected String removeQuery(String tblName, Iterable<String> keyCols) {
- String whereParams = mkString(keyCols, new C1<String, String>() {
- @Override public String apply(String s) {
- return s + "=?";
- }
- }, "", " AND ", "");
-
- return String.format("DELETE FROM %s WHERE %s", tblName, whereParams);
- }
-
- /**
* Extract type key from object.
*
* @param key Key object.
@@ -525,7 +523,6 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
*/
protected abstract void buildTypeCache() throws IgniteCheckedException;
-
/** {@inheritDoc} */
@Override public void loadCache(final IgniteBiInClosure<K, V> clo, @Nullable Object... args)
throws IgniteCheckedException {
@@ -536,7 +533,7 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
Collection<Future<?>> futs = new ArrayList<>();
- for (final TypeCache type : typesCache.values())
+ for (final QueryCache type : entryQtyCache.values())
futs.add(exec.submit(new Callable<Void>() {
@Override public Void call() throws Exception {
Connection conn = null;
@@ -552,8 +549,8 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
- K key = type.keyMapper.readObject(ignite, rs);
- V val = type.valMapper.readObject(ignite, rs);
+ K key = buildObject(type.keyType(), type.keyDescriptors(), rs);
+ V val = buildObject(type.valueType(), type.valueDescriptors(), rs);
clo.apply(key, val);
}
@@ -577,11 +574,72 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
U.get(fut);
}
+ /**
+ * @param stmt Prepare statement.
+ * @param i Start index for parameters.
+ * @param type Type description.
+ * @param key Key object.
+ * @return Next index for parameters.
+ */
+ protected int fillKeyParameters(PreparedStatement stmt, int i, QueryCache type, K key) throws IgniteCheckedException {
+ for (GridCacheQueryTypeDescriptor field : type.keyDescriptors()) {
+ Object fieldVal = extractField(type.keyType(), field.getJavaName(), key);
+
+ try {
+ if (fieldVal != null)
+ stmt.setObject(i++, fieldVal);
+ else
+ stmt.setNull(i++, field.getDbType());
+ }
+ catch (SQLException e) {
+ throw new IgniteCheckedException("Failed to set statement parameter name: " + field.getDbName(), e);
+ }
+ }
+
+ return i;
+ }
+
+ /**
+ * @param stmt Prepare statement.
+ * @param type Type description.
+ * @param key Key object.
+ * @return Next index for parameters.
+ */
+ protected int fillKeyParameters(PreparedStatement stmt, QueryCache type, K key) throws IgniteCheckedException {
+ return fillKeyParameters(stmt, 1, type, key);
+ }
+
+ /**
+ * @param stmt Prepare statement.
+ * @param i Start index for parameters.
+ * @param type Type description.
+ * @param val Value object.
+ * @return Next index for parameters.
+ */
+ protected int fillValueParameters(PreparedStatement stmt, int i, QueryCache type, V val)
+ throws IgniteCheckedException {
+ for (GridCacheQueryTypeDescriptor field : type.uniqValFields) {
+ Object fieldVal = extractField(type.valueType(), field.getJavaName(), val);
+
+ try {
+ if (fieldVal != null)
+ stmt.setObject(i++, fieldVal);
+ else
+ stmt.setNull(i++, field.getDbType());
+ }
+ catch (SQLException e) {
+ throw new IgniteCheckedException("Failed to set statement parameter name: " + field.getDbName(), e);
+ }
+ }
+
+ return i;
+ }
+
/** {@inheritDoc} */
@Nullable @Override public V load(@Nullable IgniteTx tx, K key) throws IgniteCheckedException {
init();
- TypeCache type = typesCache.get(key.getClass());
+ QueryCache type = entryQtyCache.get(key.getClass());
if (type == null)
throw new IgniteCheckedException("Failed to find mapping description for type: " + key.getClass());
@@ -598,12 +656,12 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
stmt = conn.prepareStatement(type.loadQrySingle);
- type.keyMapper.setParameters(stmt, 1, key);
+ fillKeyParameters(stmt, type, key);
ResultSet rs = stmt.executeQuery();
if (rs.next())
- return type.valMapper.readObject(ignite, rs);
+ return buildObject(type.valueType(), type.valueDescriptors(), rs);
}
catch (SQLException e) {
throw new IgniteCheckedException("Failed to load object by key: " + key, e);
@@ -628,7 +686,7 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
IgniteBiInClosure<K, V> c) throws IgniteCheckedException {
init();
- TypeCache type = typesCache.get(typeKey);
+ QueryCache type = entryQtyCache.get(typeKey);
if (type == null)
throw new IgniteCheckedException("Failed to find metadata for type: " + typeKey);
@@ -640,26 +698,32 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
try {
conn = connection(tx);
- stmt = conn.prepareStatement(type.loadQueryLast(keys.size()));
+ stmt = conn.prepareStatement(type.loadQuery(keys.size()));
- int startIdx = 1;
+ int i = 1;
- for (K key : keys)
- startIdx = type.keyMapper.setParameters(stmt, startIdx, key);
+ for (K key : keys) {
+ for (GridCacheQueryTypeDescriptor field : type.keyDescriptors()) {
+ Object fieldVal = extractField(type.keyType(), field.getJavaName(), key);
- stmt.executeQuery();
+ if (fieldVal != null)
+ stmt.setObject(i++, fieldVal);
+ else
+ stmt.setNull(i++, field.getDbType());
+ }
+ }
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
- K key = type.keyMapper.readObject(ignite, rs);
- V val = type.valMapper.readObject(ignite, rs);
+ K key = buildObject(type.keyType(), type.keyDescriptors(), rs);
+ V val = buildObject(type.valueType(), type.valueDescriptors(), rs);
c.apply(key, val);
}
}
catch (SQLException e) {
- throw new IgniteCheckedException("Failed to put objects", e);
+ throw new IgniteCheckedException("Failed to load objects", e);
}
finally {
end(tx, conn, stmt);
@@ -668,9 +732,10 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
/** {@inheritDoc} */
@Override public void loadAll(@Nullable final IgniteTx tx, Collection<? extends K> keys,
- final IgniteBiInClosure<K, V> c)
- throws IgniteCheckedException {
- Map<Object, Collection<K>> splittedKeys = U.newHashMap(typesCache.size());
+ final IgniteBiInClosure<K, V> c) throws IgniteCheckedException {
+ assert keys != null;
+
+ Map<Object, Collection<K>> splittedKeys = U.newHashMap(entryQtyCache.size());
final Collection<Future<?>> futs = new ArrayList<>();
@@ -684,7 +749,7 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
batch.add(key);
- if (batch.size() == typesCache.get(typeKey).maxKeysPerStmt) {
+ if (batch.size() == entryQtyCache.get(typeKey).maxKeysPerStmt) {
final Collection<K> p = splittedKeys.remove(typeKey);
futs.add(exec.submit(new Callable<Void>() {
@@ -714,7 +779,7 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
@Override public void put(@Nullable IgniteTx tx, K key, V val) throws IgniteCheckedException {
init();
- TypeCache type = typesCache.get(key.getClass());
+ QueryCache type = entryQtyCache.get(key.getClass());
if (type == null)
throw new IgniteCheckedException("Failed to find metadata for type: " + key.getClass());
@@ -729,12 +794,34 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
try {
conn = connection(tx);
- stmt = conn.prepareStatement(type.putQry);
+ if (dialect.hasMerge()) {
+ stmt = conn.prepareStatement(type.mergeQry);
- int idx = type.keyMapper.setParameters(stmt, 1, key);
- type.valMapper.setParameters(stmt, idx, val);
+ int i = fillKeyParameters(stmt, type, key);
- stmt.executeUpdate();
+ fillValueParameters(stmt, i, type, val);
+
+ stmt.executeUpdate();
+ }
+ else {
+ stmt = conn.prepareStatement(type.updQry);
+
+ int i = fillValueParameters(stmt, 1, type, val);
+
+ fillKeyParameters(stmt, i, type, key);
+
+ if (stmt.executeUpdate() == 0) {
+ stmt.close();
+
+ stmt = conn.prepareStatement(type.insQry);
+
+ i = fillKeyParameters(stmt, type, key);
+
+ fillValueParameters(stmt, i, type, val);
+
+ stmt.executeUpdate();
+ }
+ }
}
catch (SQLException e) {
throw new IgniteCheckedException("Failed to load object by key: " + key, e);
@@ -759,7 +846,7 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
init();
- TypeCache type = typesCache.get(typeKey);
+ QueryCache type = entryQtyCache.get(typeKey);
if (type == null)
throw new IgniteCheckedException("Failed to find metadata for type: " + typeKey);
@@ -771,14 +858,14 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
try {
conn = connection(tx);
- stmt = conn.prepareStatement(type.putQry);
+ stmt = conn.prepareStatement(type.mergeQry);
int cnt = 0;
for (Map.Entry<? extends K, ? extends V> entry : map) {
- int startIdx = type.keyMapper.setParameters(stmt, 1, entry.getKey());
+ int i = fillKeyParameters(stmt, type, entry.getKey());
- type.valMapper.setParameters(stmt, startIdx, entry.getValue());
+ fillValueParameters(stmt, i, type, entry.getValue());
stmt.addBatch();
@@ -800,39 +887,46 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
/** {@inheritDoc} */
@Override public void putAll(@Nullable final IgniteTx tx, Map<? extends K, ? extends V> map)
throws IgniteCheckedException {
- Map<Object, Collection<Map.Entry<? extends K, ? extends V>>> keyByType = U.newHashMap(typesCache.size());
+ assert map != null;
- for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
- Object typeKey = typeKey(entry.getKey());
+ Map<Object, Collection<Map.Entry<? extends K, ? extends V>>> keyByType = U.newHashMap(entryQtyCache.size());
- Collection<Map.Entry<? extends K, ? extends V>> batch = keyByType.get(typeKey);
+ if (dialect.hasMerge()) {
+ for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ Object typeKey = typeKey(entry.getKey());
- if (batch == null)
- keyByType.put(typeKey, batch = new ArrayList<>());
+ Collection<Map.Entry<? extends K, ? extends V>> batch = keyByType.get(typeKey);
- batch.add(entry);
- }
+ if (batch == null)
+ keyByType.put(typeKey, batch = new ArrayList<>());
- final Collection<Future<?>> futs = new ArrayList<>();
+ batch.add(entry);
+ }
- for (final Map.Entry<Object, Collection<Map.Entry<? extends K, ? extends V>>> entry : keyByType.entrySet())
- futs.add(exec.submit(new Callable<Void>() {
- @Override public Void call() throws Exception {
- putAll(tx, entry.getKey(), entry.getValue());
+ final Collection<Future<?>> futs = new ArrayList<>();
- return null;
- }
- }));
+ for (final Map.Entry<Object, Collection<Map.Entry<? extends K, ? extends V>>> entry : keyByType.entrySet())
+ futs.add(exec.submit(new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ putAll(tx, entry.getKey(), entry.getValue());
- for (Future<?> fut : futs)
- U.get(fut);
+ return null;
+ }
+ }));
+
+ for (Future<?> fut : futs)
+ U.get(fut);
+ }
+ else
+ for (Map.Entry<? extends K, ? extends V> e : map.entrySet())
+ put(tx, e.getKey(), e.getValue());
}
/** {@inheritDoc} */
@Override public void remove(@Nullable IgniteTx tx, K key) throws IgniteCheckedException {
init();
- TypeCache type = typesCache.get(key.getClass());
+ QueryCache type = entryQtyCache.get(key.getClass());
if (type == null)
throw new IgniteCheckedException("Failed to find metadata for type: " + key.getClass());
@@ -849,7 +943,7 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
stmt = conn.prepareStatement(type.remQry);
- type.keyMapper.setParameters(stmt, 1, key);
+ fillKeyParameters(stmt, type, key);
stmt.executeUpdate();
}
@@ -869,13 +963,14 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
* @param keys Collection of keys to remove.
* @throws IgniteCheckedException If remove failed.
*/
- protected void removeAll(@Nullable IgniteTx tx, Object typeKey, Collection<? extends K> keys) throws IgniteCheckedException {
+ protected void removeAll(@Nullable IgniteTx tx, Object typeKey, Collection<? extends K> keys)
+ throws IgniteCheckedException {
assert keys != null;
assert keys.size() > 1;
init();
- TypeCache type = typesCache.get(typeKey);
+ QueryCache type = entryQtyCache.get(typeKey);
if (type == null)
throw new IgniteCheckedException("Failed to find metadata for type: " + typeKey);
@@ -895,7 +990,7 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
int cnt = 0;
for (K key : keys) {
- type.keyMapper.setParameters(stmt, 1, key);
+ fillKeyParameters(stmt, type, key);
stmt.addBatch();
@@ -915,9 +1010,10 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
}
/** {@inheritDoc} */
- @Override public void removeAll(@Nullable IgniteTx tx, Collection<? extends K> keys)
- throws IgniteCheckedException {
- Map<Object, Collection<K>> keyByType = U.newHashMap(typesCache.size());
+ @Override public void removeAll(@Nullable IgniteTx tx, Collection<? extends K> keys) throws IgniteCheckedException {
+ assert keys != null;
+
+ Map<Object, Collection<K>> keyByType = U.newHashMap(entryQtyCache.size());
for (K key : keys) {
Object typeKey = typeKey(key);
@@ -1016,39 +1112,40 @@ public abstract class AutoCacheStore<K, V> implements GridCacheStore<K, V> {
}
/**
- * Get Max workers thread count. These threads are responsible for execute query.
+ * Get database dialect.
*
- * @return Max workers thread count.
+ * @return Database dialect.
*/
- public int getMaxPoolSize() {
- return maxPoolSz;
+ public JdbcDialect getDialect() {
+ return dialect;
}
+
/**
- * Set Max workers thread count. These threads are responsible for execute query.
+ * Set database dialect.
*
- * @param maxPoolSz Max workers thread count.
+ * @param dialect Database dialect.
*/
- public void setMaxPoolSize(int maxPoolSz) {
- this.maxPoolSz = maxPoolSz;
+ public void setDialect(JdbcDialect dialect) {
+ this.dialect = dialect;
}
/**
- * Get max query parameters count.
+ * Get Max workers thread count. These threads are responsible for execute query.
*
- * @return Max query parameters count.
+ * @return Max workers thread count.
*/
- public int getMaxParamsCnt() {
- return maxParamsCnt;
+ public int getMaxPoolSize() {
+ return maxPoolSz;
}
/**
- * Set max query parameters count.
+ * Set Max workers thread count. These threads are responsible for execute query.
*
- * @param maxParamsCnt Max query parameters count.
+ * @param maxPoolSz Max workers thread count.
*/
- public void setMaxParamsCnt(int maxParamsCnt) {
- this.maxParamsCnt = maxParamsCnt;
+ public void setMaxPoolSize(int maxPoolSz) {
+ this.maxPoolSz = maxPoolSz;
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/79f3a5f7/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/H2PojoCacheStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/H2PojoCacheStore.java b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/H2PojoCacheStore.java
deleted file mode 100644
index 7198e8a..0000000
--- a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/H2PojoCacheStore.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/* @java.file.header */
-
-/* _________ _____ __________________ _____
- * __ ____/___________(_)______ /__ ____/______ ____(_)_______
- * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \
- * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / /
- * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/
- */
-
-package org.gridgain.grid.cache.store.auto;
-
-import org.gridgain.grid.util.typedef.internal.*;
-
-import java.util.*;
-
-/**
- * Store implementation for H2 database.
- */
-public class H2PojoCacheStore extends PojoCacheStore {
- /** {@inheritDoc} */
- @Override protected String putQuery(String tblName, Collection<String> keyCols, Collection<String> uniqCols) {
- return String.format("MERGE INTO %s (%s) KEY (%s) VALUES(%s)", tblName, mkString(uniqCols, ","),
- mkString(keyCols, ","), repeat("?", uniqCols.size(), "",", ",""));
- }
-
- /** {@inheritDoc} */
- @Override public String toString() {
- return S.toString(H2PojoCacheStore.class, this, "passwd", passwd != null ? "*" : null);
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/79f3a5f7/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/JdbcMapper.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/JdbcMapper.java b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/JdbcMapper.java
deleted file mode 100644
index 2d0c98e..0000000
--- a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/JdbcMapper.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/* @java.file.header */
-
-/* _________ _____ __________________ _____
- * __ ____/___________(_)______ /__ ____/______ ____(_)_______
- * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \
- * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / /
- * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/
- */
-
-package org.gridgain.grid.cache.store.auto;
-
-import org.apache.ignite.*;
-
-import java.sql.*;
-
-/**
- * Mapper between JDBC objects and cache objects.
- */
-public interface JdbcMapper<T> {
- /**
- * Set parameters in prepare statement from cache object.
- *
- * @param stmt Prepare statement.
- * @param startIdx Start index for set parameters in prepare statement.
- * @param obj Cache object.
- * @return Last parameter index.
- * @throws IgniteCheckedException If failed.
- */
- public int setParameters(PreparedStatement stmt, int startIdx, T obj) throws IgniteCheckedException;
-
- /**
- * Read cache object from result set.
- *
- * @param ignite Grid.
- * @param rs Result set.
- * @return cache object.
- * @throws IgniteCheckedException If failed.
- */
- public T readObject(Ignite ignite, ResultSet rs) throws IgniteCheckedException;
-}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/79f3a5f7/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/PojoCacheStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/PojoCacheStore.java b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/PojoCacheStore.java
index a349cb9..d3892c3 100644
--- a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/PojoCacheStore.java
+++ b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/PojoCacheStore.java
@@ -1,10 +1,18 @@
-/* @java.file.header */
-
-/* _________ _____ __________________ _____
- * __ ____/___________(_)______ /__ ____/______ ____(_)_______
- * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \
- * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / /
- * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/
+/*
+ * 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.gridgain.grid.cache.store.auto;
@@ -13,7 +21,10 @@ import org.apache.ignite.*;
import org.gridgain.grid.cache.query.*;
import org.gridgain.grid.cache.store.*;
import org.gridgain.grid.util.typedef.internal.*;
+import org.jetbrains.annotations.*;
+import java.lang.reflect.*;
+import java.sql.*;
import java.util.*;
/**
@@ -21,22 +32,150 @@ import java.util.*;
*
* This implementation stores objects in underlying database using java beans mapping description via reflection.
*/
-public abstract class PojoCacheStore extends AutoCacheStore<Object, Object> {
+public class PojoCacheStore extends AutoCacheStore<Object, Object> {
+ /**
+ * POJO methods cache.
+ */
+ protected static class PojoMethodsCache {
+ /** POJO class. */
+ protected final Class<?> cls;
+
+ /** Constructor for POJO object. */
+ private final Constructor ctor;
+
+ /** Cached setters for POJO object. */
+ private final Map<String, Method> getters;
+
+ /** Cached getters for POJO object. */
+ private final Map<String, Method> setters;
+
+ /**
+ * POJO methods cache.
+ *
+ * @param clsName Class name.
+ * @param fields Fields.
+ */
+ public PojoMethodsCache(String clsName, Collection<GridCacheQueryTypeDescriptor> fields) throws IgniteCheckedException {
+
+ try {
+ cls = Class.forName(clsName);
+
+ ctor = cls.getDeclaredConstructor();
+
+ if (!ctor.isAccessible())
+ ctor.setAccessible(true);
+ }
+ catch (ClassNotFoundException e) {
+ throw new IgniteCheckedException("Failed to find class: " + clsName, e);
+ }
+ catch (NoSuchMethodException e) {
+ throw new IgniteCheckedException("Failed to find empty constructor for class: " + clsName, e);
+ }
+
+ setters = U.newHashMap(fields.size());
+
+ getters = U.newHashMap(fields.size());
+
+ for (GridCacheQueryTypeDescriptor field : fields) {
+ String prop = capitalFirst(field.getJavaName());
+
+ try {
+ getters.put(field.getJavaName(), cls.getMethod("get" + prop));
+ }
+ catch (NoSuchMethodException ignored) {
+ try {
+ getters.put(field.getJavaName(), cls.getMethod("is" + prop));
+ }
+ catch (NoSuchMethodException e) {
+ throw new IgniteCheckedException("Failed to find getter for property " + field.getJavaName() +
+ " of class: " + cls.getName(), e);
+ }
+ }
+
+ try {
+ setters.put(field.getJavaName(), cls.getMethod("set" + prop, field.getJavaType()));
+ }
+ catch (NoSuchMethodException e) {
+ throw new IgniteCheckedException("Failed to find setter for property " + field.getJavaName() +
+ " of class: " + clsName, e);
+ }
+ }
+ }
+
+ /**
+ * Capitalizes the first character of the given string.
+ *
+ * @param str String.
+ * @return String with capitalized first character.
+ */
+ @Nullable private String capitalFirst(@Nullable String str) {
+ return str == null ? null :
+ str.isEmpty() ? "" : Character.toUpperCase(str.charAt(0)) + str.substring(1);
+ }
+
+ /**
+ * Construct new instance of pojo object.
+ *
+ * @return pojo object.
+ * @throws IgniteCheckedException If construct new instance failed.
+ */
+ protected Object newInstance() throws IgniteCheckedException {
+ try {
+ return ctor.newInstance();
+ }
+ catch (Exception e) {
+ throw new IgniteCheckedException("Failed to create new instance for class: " + cls, e);
+ }
+ }
+ }
+
+ Map<String, PojoMethodsCache> mtdsCache;
+
/** {@inheritDoc} */
@Override protected void buildTypeCache() throws IgniteCheckedException {
- typesCache = U.newHashMap(typeMetadata.size());
+ entryQtyCache = U.newHashMap(typeMetadata.size());
+
+ mtdsCache = U.newHashMap(typeMetadata.size() * 2);
for (GridCacheQueryTypeMetadata type : typeMetadata) {
- Collection<String> excludeValCols = new LinkedHashSet<>(databaseColumns(type.getValueDescriptors()));
+ PojoMethodsCache keyCache = new PojoMethodsCache(type.getKeyType(), type.getKeyDescriptors());
+
+ mtdsCache.put(type.getKeyType(), keyCache);
+
+ entryQtyCache.put(keyCache.cls, new QueryCache(dialect, type));
+
+ mtdsCache.put(type.getType(), new PojoMethodsCache(type.getType(), type.getValueDescriptors()));
+ }
+ }
- excludeValCols.retainAll(databaseColumns(type.getKeyDescriptors()));
+ /** {@inheritDoc} */
+ @Override protected <R> R buildObject(String typeName, Collection<GridCacheQueryTypeDescriptor> fields,
+ ResultSet rs) throws IgniteCheckedException {
+ PojoMethodsCache t = mtdsCache.get(typeName);
- PojoJdbcMapper keyMapper = new PojoJdbcMapper(type.getKeyType(), type.getKeyDescriptors(),
- Collections.<String>emptyList());
+ Object obj = t.newInstance();
- PojoJdbcMapper valMapper = new PojoJdbcMapper(type.getType(), type.getValueDescriptors(), excludeValCols);
+ try {
+ for (GridCacheQueryTypeDescriptor field : fields)
+ t.setters.get(field.getJavaName()).invoke(obj, rs.getObject(field.getDbName()));
- typesCache.put(keyMapper.cls, new TypeCache(type, keyMapper, valMapper));
+ return (R)obj;
+ }
+ catch (Exception e) {
+ throw new IgniteCheckedException("Failed to read object of class: " + typeName, e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Nullable @Override protected Object extractField(String typeName, String fieldName, Object obj)
+ throws IgniteCheckedException {
+ try {
+ PojoMethodsCache t = mtdsCache.get(typeName);
+
+ return t.getters.get(fieldName).invoke(obj);
+ }
+ catch (Exception e) {
+ throw new IgniteCheckedException("Failed to read object of class: " + typeName, e);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/79f3a5f7/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/PojoJdbcMapper.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/PojoJdbcMapper.java b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/PojoJdbcMapper.java
deleted file mode 100644
index f1544a9..0000000
--- a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/PojoJdbcMapper.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/* @java.file.header */
-
-/* _________ _____ __________________ _____
- * __ ____/___________(_)______ /__ ____/______ ____(_)_______
- * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \
- * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / /
- * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/
- */
-
-package org.gridgain.grid.cache.store.auto;
-
-import org.apache.ignite.*;
-import org.gridgain.grid.cache.query.*;
-import org.jetbrains.annotations.*;
-
-import java.lang.reflect.*;
-import java.sql.*;
-import java.util.*;
-
-/**
- * Mapper between JDBC objects and POJO.
- */
-public class PojoJdbcMapper implements JdbcMapper<Object> {
- /** POJO class. */
- protected final Class<?> cls;
-
- /** Constructor for POJO object. */
- private final Constructor ctor;
-
- /** Database column names. */
- private final String[] colNames;
-
- /** Cached setters for POJO object. */
- private final Method[] setters;
-
- /** Cached getters for POJO object. */
- private final Method[] getters;
-
- /**
- * @param clsName POJO class name.
- * @param descs Fields descriptors.
- * @param excludeCols Columns for exclude from set parameters.
- */
- protected PojoJdbcMapper(String clsName, Collection<GridCacheQueryTypeDescriptor> descs,
- Collection<String> excludeCols) throws IgniteCheckedException {
- assert descs != null && !descs.isEmpty();
- assert excludeCols != null;
-
- try {
- cls = Class.forName(clsName);
-
- ctor = cls.getDeclaredConstructor();
-
- if (!ctor.isAccessible())
- ctor.setAccessible(true);
- }
- catch (ClassNotFoundException e) {
- throw new IgniteCheckedException("Failed to find class: " + clsName, e);
- }
- catch (NoSuchMethodException e) {
- throw new IgniteCheckedException("Failed to find empty constructor for class: " + clsName, e);
- }
-
- colNames = new String[descs.size()];
-
- List<Method> getters = new ArrayList<>(descs.size() - excludeCols.size());
-
- setters = new Method[descs.size()];
-
- int i = 0;
-
- for (GridCacheQueryTypeDescriptor desc : descs) {
- colNames[i] = desc.getDbName();
-
- String prop = capitalFirst(desc.getJavaName());
-
- try {
- setters[i] = cls.getMethod("set" + prop, desc.getJavaType());
- }
- catch (NoSuchMethodException e) {
- throw new IgniteCheckedException("Failed to find setter for property " + desc.getJavaName() +
- " of class: " + clsName, e);
- }
-
- if (!excludeCols.contains(colNames[i])) {
- try {
- getters.add(cls.getMethod("get" + prop));
- }
- catch (NoSuchMethodException ignored) {
- try {
- getters.add(cls.getMethod("is" + prop));
- }
- catch (NoSuchMethodException e) {
- throw new IgniteCheckedException("Failed to find getter for property " + desc.getJavaName() +
- " of class: " + cls.getName(), e);
- }
- }
- }
-
- i++;
- }
-
- this.getters = getters.toArray(new Method[getters.size()]);
- }
-
- /**
- * Capitalizes the first character of the given string.
- *
- * @param str String.
- * @return String with capitalized first character.
- */
- private String capitalFirst(@Nullable String str) {
- return str == null ? null :
- str.isEmpty() ? "" : Character.toUpperCase(str.charAt(0)) + str.substring(1);
- }
-
- /**
- * Construct new instance of pojo object.
- *
- * @return pojo object.
- * @throws IgniteCheckedException If construct new instance failed.
- */
- private Object newInstance() throws IgniteCheckedException {
- try {
- return ctor.newInstance();
- }
- catch (Exception e) {
- throw new IgniteCheckedException("Failed to create new instance for class: " + cls, e);
- }
- }
-
- /** {@inheritDoc} */
- @Override public int setParameters(PreparedStatement stmt, int startIdx, Object obj)
- throws IgniteCheckedException {
- try {
- for (int i = 0; i < getters.length; i++)
- stmt.setObject(startIdx + i, getters[i].invoke(obj));
-
- return startIdx + getters.length;
- }
- catch (Exception e) {
- throw new IgniteCheckedException("Failed to set parameters for query.", e);
- }
- }
-
- /** {@inheritDoc} */
- @Override public Object readObject(Ignite ignite, ResultSet rs) throws IgniteCheckedException {
- Object obj = newInstance();
-
- try {
- for (int i = 0; i < setters.length; i++)
- setters[i].invoke(obj, rs.getObject(colNames[i]));
-
- return obj;
- }
- catch (Exception e) {
- throw new IgniteCheckedException("Failed to read object of class: " + cls, e);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/79f3a5f7/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/dialect/H2Dialect.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/dialect/H2Dialect.java b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/dialect/H2Dialect.java
new file mode 100644
index 0000000..c9c3710
--- /dev/null
+++ b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/dialect/H2Dialect.java
@@ -0,0 +1,31 @@
+/*
+ * 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.gridgain.grid.cache.store.auto.dialect;
+
+import java.util.*;
+
+/**
+ *
+ */
+public class H2Dialect extends JdbcDialect {
+ /** {@inheritDoc} */
+ @Override public String mergeQuery(String schema, String tblName, Collection<String> keyCols, Collection<String> uniqCols) {
+ return String.format("MERGE INTO %s (%s) KEY (%s) VALUES(%s)", tblName, mkString(uniqCols, ","),
+ mkString(keyCols, ","), repeat("?", uniqCols.size(), "",", ",""));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/79f3a5f7/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/dialect/JdbcDialect.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/dialect/JdbcDialect.java b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/dialect/JdbcDialect.java
new file mode 100644
index 0000000..3f65971
--- /dev/null
+++ b/modules/core/src/main/java/org/gridgain/grid/cache/store/auto/dialect/JdbcDialect.java
@@ -0,0 +1,244 @@
+/*
+ * 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.gridgain.grid.cache.store.auto.dialect;
+
+import org.gridgain.grid.util.typedef.*;
+import org.gridgain.grid.util.typedef.internal.*;
+
+import java.util.*;
+
+/**
+ *
+ */
+public class JdbcDialect {
+ /** Default max query parameters count. */
+ protected static final int DFLT_MAX_PARAMS_CNT = 2000;
+
+ /** Max query parameters count. */
+ protected int maxParamsCnt = DFLT_MAX_PARAMS_CNT;
+
+ /**
+ * Concatenates elements using provided separator.
+ *
+ * @param elems Concatenated elements.
+ * @param f closure used for transform element.
+ * @param start Start string.
+ * @param sep Separator.
+ * @param end End string.
+ * @return Concatenated string.
+ */
+ protected static <T> String mkString(Iterable<T> elems, C1<T, String> f, String start, String sep, String end) {
+ SB sb = new SB(start);
+
+ boolean first = true;
+
+ for (T elem : elems) {
+ if (!first)
+ sb.a(sep);
+
+ sb.a(f.apply(elem));
+
+ first = false;
+ }
+
+ return sb.a(end).toString();
+ }
+
+ /**
+ * Concatenates elements using provided separator.
+ *
+ * @param strs Concatenated string.
+ * @param start Start string.
+ * @param sep Delimiter.
+ * @param end End string.
+ * @return Concatenated string.
+ */
+ protected static String mkString(Iterable<String> strs, String start, String sep, String end) {
+ return mkString(strs, new C1<String, String>() {
+ @Override public String apply(String s) {
+ return s;
+ }
+ }, start, sep, end);
+ }
+
+ /**
+ * Concatenates strings using provided separator.
+ *
+ * @param strs Concatenated string.
+ * @param sep Separator.
+ * @return Concatenated string.
+ */
+ protected static String mkString(Iterable<String> strs, String sep) {
+ return mkString(strs, new C1<String, String>() {
+ @Override public String apply(String s) {
+ return s;
+ }
+ }, "", sep, "");
+ }
+
+ /**
+ * Concatenates elements using provided delimiter.
+ *
+ * @param str Repeated string.
+ * @param cnt Repeat count.
+ * @param start Start string.
+ * @param sep Separator.
+ * @param end End string.
+ */
+ protected static String repeat(String str, int cnt, String start, String sep, String end) {
+ SB sb = new SB(str.length() * cnt + sep.length() * (cnt - 1) + start.length() + end.length());
+
+ sb.a(start);
+
+ for (int i = 0; i < cnt; i++) {
+ if (i > 0)
+ sb.a(sep);
+
+ sb.a(str);
+ }
+
+ return sb.a(end).toString();
+ }
+
+ protected static String where(Collection<String> keyCols, int keyCnt) {
+ SB sb = new SB();
+
+ if (keyCols.size() == 1) {
+ String keyCol = keyCols.iterator().next();
+
+ if (keyCnt == 1)
+ sb.a(keyCol+ "=?");
+ else
+ sb.a(repeat("?", keyCnt, keyCol + " IN (", ",", ")"));
+ }
+ else {
+ String keyParams = mkString(keyCols, new C1<String, String>() {
+ @Override public String apply(String s) {
+ return s + "=?";
+ }
+ }, "(", " AND ", ")");
+
+ sb.a(repeat(keyParams, keyCnt, "", " OR ", ""));
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Construct load cache query.
+ *
+ * @param schema Database schema name.
+ * @param tblName Database table name.
+ * @param uniqCols Database unique columns.
+ * @return Load cache query.
+ */
+ public String loadCacheQuery(String schema, String tblName, Iterable<String> uniqCols) {
+ return String.format("SELECT %s FROM %s.%s", mkString(uniqCols, ","), schema, tblName);
+ }
+
+ /**
+ * Construct load query.
+ *
+ * @param schema Database schema name.
+ * @param tblName Database table name.
+ * @param keyCols Database key columns.
+ * @param valCols Database value columns.
+ * @param keyCnt Key count.
+ * @return Load query.
+ */
+ public String loadQuery(String schema, String tblName, Collection<String> keyCols, Iterable<String> valCols,
+ int keyCnt) {
+ assert !keyCols.isEmpty();
+
+ String params = where(keyCols, keyCnt);
+
+ return String.format("SELECT %s FROM %s.%s WHERE %s", mkString(valCols, ","), schema, tblName, params);
+ }
+
+ public String insertQuery(String schema, String tblName, Collection<String> keyCols, Collection<String> valCols) {
+ Collection<String> cols = F.concat(false, keyCols, valCols);
+
+ return String.format("INSERT INTO %s.%s(%s) VALUES(%s)", schema, tblName, mkString(cols, ","),
+ repeat("?", cols.size(), "", ",", ""));
+ }
+
+ public String updateQuery(String schema, String tblName, Collection<String> keyCols, final Iterable<String> valCols) {
+ String params = mkString(valCols, new C1<String, String>() {
+ @Override public String apply(String s) {
+ return s + "=?";
+ }
+ }, "", ",", "");
+
+ return String.format("UPDATE %s.%s SET %s WHERE %s", schema, tblName, params, where(keyCols, 1));
+ }
+
+ /**
+ * @return {@code True} if database support merge operation.
+ */
+ public boolean hasMerge() {
+ return false;
+ }
+
+ /**
+ * Construct merge query.
+ * @param schema Database schema name.
+ * @param tblName Database table name.
+ * @param keyCols Database key columns.
+ * @param uniqCols Database unique columns.
+ * @return Put query.
+ */
+ public String mergeQuery(String schema, String tblName, Collection<String> keyCols, Collection<String> uniqCols) {
+ return "";
+ }
+
+ /**
+ * Construct remove query.
+ *
+ * @param schema Database schema name.
+ * @param tblName Database table name.
+ * @param keyCols Database key columns.
+ * @return Remove query.
+ */
+ public String removeQuery(String schema, String tblName, Iterable<String> keyCols) {
+ String whereParams = mkString(keyCols, new C1<String, String>() {
+ @Override public String apply(String s) {
+ return s + "=?";
+ }
+ }, "", " AND ", "");
+
+ return String.format("DELETE FROM %s.%s WHERE %s", schema, tblName, whereParams);
+ }
+
+ /**
+ * Get max query parameters count.
+ *
+ * @return Max query parameters count.
+ */
+ public int getMaxParamsCnt() {
+ return maxParamsCnt;
+ }
+
+ /**
+ * Set max query parameters count.
+ *
+ * @param maxParamsCnt Max query parameters count.
+ */
+ public void setMaxParamsCnt(int maxParamsCnt) {
+ this.maxParamsCnt = maxParamsCnt;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/79f3a5f7/modules/schema-load/src/test/java/org/gridgain/grid/cache/store/auto/AutoCacheStoreSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/test/java/org/gridgain/grid/cache/store/auto/AutoCacheStoreSelfTest.java b/modules/schema-load/src/test/java/org/gridgain/grid/cache/store/auto/AutoCacheStoreSelfTest.java
index 71abc2f..0fd4e7e 100644
--- a/modules/schema-load/src/test/java/org/gridgain/grid/cache/store/auto/AutoCacheStoreSelfTest.java
+++ b/modules/schema-load/src/test/java/org/gridgain/grid/cache/store/auto/AutoCacheStoreSelfTest.java
@@ -17,6 +17,7 @@
package org.gridgain.grid.cache.store.auto;
+import org.gridgain.grid.cache.store.auto.dialect.*;
import org.gridgain.grid.util.typedef.*;
/**
@@ -32,8 +33,10 @@ public class AutoCacheStoreSelfTest extends AbstractAutoCacheStoreSelfTest {
/**
* @return Store.
*/
- @Override protected H2PojoCacheStore store() {
- H2PojoCacheStore store = new H2PojoCacheStore();
+ @Override protected PojoCacheStore store() {
+ PojoCacheStore store = new PojoCacheStore();
+
+ store.setDialect(new H2Dialect());
store.setConnUrl("jdbc:h2:mem:test");
store.setUser("sa");