# 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 <akuznet...@gridgain.com> Authored: Mon Jan 19 09:25:33 2015 +0700 Committer: AKuznetsov <akuznet...@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");