Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.torodb.backend.AbstractReadInterface Maven / Gradle / Ivy
/*
* ToroDB
* Copyright © 2014 8Kdata Technology (www.8kdata.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package com.torodb.backend;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.torodb.backend.ErrorHandler.Context;
import com.torodb.backend.d2r.ResultSetDocPartResult;
import com.torodb.backend.tables.MetaDocPartTable.DocPartTableFields;
import com.torodb.core.TableRef;
import com.torodb.core.TableRefFactory;
import com.torodb.core.cursors.Cursor;
import com.torodb.core.cursors.EmptyCursor;
import com.torodb.core.cursors.IteratorCursor;
import com.torodb.core.d2r.DocPartResult;
import com.torodb.core.transaction.metainf.MetaCollection;
import com.torodb.core.transaction.metainf.MetaDatabase;
import com.torodb.core.transaction.metainf.MetaDocPart;
import com.torodb.core.transaction.metainf.MetaField;
import com.torodb.kvdocument.values.KvValue;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.jooq.DSLContext;
import org.jooq.lambda.Seq;
import org.jooq.lambda.Unchecked;
import org.jooq.lambda.tuple.Tuple2;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.inject.Provider;
import javax.inject.Singleton;
/**
*
*/
@Singleton
@SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING")
public abstract class AbstractReadInterface implements ReadInterface {
private final MetaDataReadInterface metaDataReadInterface;
private final DataTypeProvider dataTypeProvider;
private final ErrorHandler errorHandler;
private final SqlHelper sqlHelper;
private final TableRefFactory tableRefFactory;
public AbstractReadInterface(MetaDataReadInterface metaDataReadInterface,
DataTypeProvider dataTypeProvider,
ErrorHandler errorHandler, SqlHelper sqlHelper, TableRefFactory tableRefFactory) {
this.metaDataReadInterface = metaDataReadInterface;
this.dataTypeProvider = dataTypeProvider;
this.errorHandler = errorHandler;
this.sqlHelper = sqlHelper;
this.tableRefFactory = tableRefFactory;
}
@Override
@SuppressFBWarnings(value = {"OBL_UNSATISFIED_OBLIGATION", "ODR_OPEN_DATABASE_RESOURCE"},
justification =
"ResultSet is wrapped in a Cursor. It's iterated and closed in caller code")
public Cursor getCollectionDidsWithFieldEqualsTo(DSLContext dsl,
MetaDatabase metaDatabase,
MetaCollection metaCol, MetaDocPart metaDocPart, MetaField metaField, KvValue> value)
throws SQLException {
assert metaDatabase.getMetaCollectionByIdentifier(metaCol.getIdentifier()) != null;
assert metaCol.getMetaDocPartByIdentifier(metaDocPart.getIdentifier()) != null;
assert metaDocPart.getMetaFieldByIdentifier(metaField.getIdentifier()) != null;
String statement = getReadCollectionDidsWithFieldEqualsToStatement(metaDatabase.getIdentifier(),
metaDocPart.getIdentifier(), metaField.getIdentifier());
Connection connection = dsl.configuration().connectionProvider().acquire();
try {
PreparedStatement preparedStatement = connection.prepareStatement(statement);
sqlHelper.setPreparedStatementValue(preparedStatement, 1, metaField.getType(), value);
return new DefaultDidCursor(errorHandler, preparedStatement.executeQuery());
} finally {
dsl.configuration().connectionProvider().release(connection);
}
}
protected abstract String getReadCollectionDidsWithFieldEqualsToStatement(String schemaName,
String rootTableName,
String columnName);
@Override
@SuppressFBWarnings(value = {"OBL_UNSATISFIED_OBLIGATION", "ODR_OPEN_DATABASE_RESOURCE"},
justification =
"ResultSet is wrapped in a Cursor. It's iterated and closed in caller code")
public Cursor getCollectionDidsWithFieldsIn(DSLContext dsl, MetaDatabase metaDatabase,
MetaCollection metaCol, MetaDocPart metaDocPart,
Multimap> valuesMultimap)
throws SQLException {
assert metaDatabase.getMetaCollectionByIdentifier(metaCol.getIdentifier()) != null;
assert metaCol.getMetaDocPartByIdentifier(metaDocPart.getIdentifier()) != null;
assert valuesMultimap.keySet().stream().allMatch(metafield -> metaDocPart
.getMetaFieldByIdentifier(metafield.getIdentifier()) != null);
if (valuesMultimap.size() > 500) {
@SuppressWarnings("checkstyle:LineLength")
Stream>, Long>>>> valuesEntriesBatchStream =
Seq.seq(valuesMultimap.entries().stream())
.zipWithIndex()
.groupBy(t -> t.v2 / 500)
.entrySet()
.stream();
Stream>>> valuesEntryBatchStreamOfStream =
valuesEntriesBatchStream
.map(e -> e.getValue()
.stream()
.map(se -> se.v1));
Stream>> valuesMultimapBatchStream =
valuesEntryBatchStreamOfStream
.map(e -> toValuesMultimap(e));
Stream> didCursorStream =
valuesMultimapBatchStream
.map(Unchecked.function(valuesMultimapBatch ->
getCollectionDidsWithFieldsInBatch(
dsl,
metaDatabase,
metaCol,
metaDocPart,
valuesMultimapBatch)));
Stream didStream = didCursorStream
.flatMap(cursor -> cursor.getRemaining().stream());
return new IteratorCursor<>(didStream.iterator());
}
return getCollectionDidsWithFieldsInBatch(dsl, metaDatabase, metaCol, metaDocPart,
valuesMultimap);
}
private Multimap> toValuesMultimap(
Stream>> valueEntryStream) {
Multimap> valuesMultimap = ArrayListMultimap.create();
valueEntryStream.forEach(e -> valuesMultimap.put(e.getKey(), e.getValue()));
return valuesMultimap;
}
@SuppressFBWarnings(value = {"OBL_UNSATISFIED_OBLIGATION", "ODR_OPEN_DATABASE_RESOURCE"},
justification =
"ResultSet is wrapped in a Cursor. It's iterated and closed in caller code")
private Cursor getCollectionDidsWithFieldsInBatch(DSLContext dsl,
MetaDatabase metaDatabase,
MetaCollection metaCol, MetaDocPart metaDocPart,
Multimap> valuesMultimap)
throws SQLException {
@SuppressWarnings("checkstyle:LineLength")
Provider>>>> valuesMultimapSortedStreamProvider =
() -> valuesMultimap.asMap().entrySet().stream()
.sorted((e1, e2) -> e1.getKey().getIdentifier().compareTo(e2.getKey().getIdentifier()));
String statement = getReadCollectionDidsWithFieldInStatement(metaDatabase.getIdentifier(),
metaDocPart.getIdentifier(), valuesMultimapSortedStreamProvider.get()
.map(e -> new Tuple2(e.getKey().getIdentifier(), e.getValue().size())));
Connection connection = dsl.configuration().connectionProvider().acquire();
try {
PreparedStatement preparedStatement = connection.prepareStatement(statement);
int parameterIndex = 1;
Iterator>>> valuesMultimapSortedIterator =
valuesMultimapSortedStreamProvider.get().iterator();
while (valuesMultimapSortedIterator.hasNext()) {
Map.Entry>> valuesMultimapEntry =
valuesMultimapSortedIterator.next();
for (KvValue> value : valuesMultimapEntry.getValue()) {
sqlHelper.setPreparedStatementValue(preparedStatement, parameterIndex, valuesMultimapEntry
.getKey().getType(), value);
parameterIndex++;
}
}
return new DefaultDidCursor(errorHandler, preparedStatement.executeQuery());
} finally {
dsl.configuration().connectionProvider().release(connection);
}
}
protected abstract String getReadCollectionDidsWithFieldInStatement(String schemaName,
String rootTableName,
Stream> valuesCountList);
@Override
@SuppressFBWarnings(value = {"OBL_UNSATISFIED_OBLIGATION", "ODR_OPEN_DATABASE_RESOURCE"},
justification = "ResultSet is wrapped in a Cursor>>. It's "
+ "iterated and closed in caller code")
public Cursor>> getCollectionDidsAndProjectionWithFieldsIn(
DSLContext dsl, MetaDatabase metaDatabase,
MetaCollection metaCol, MetaDocPart metaDocPart,
Multimap> valuesMultimap)
throws SQLException {
assert metaDatabase.getMetaCollectionByIdentifier(metaCol.getIdentifier()) != null;
assert metaCol.getMetaDocPartByIdentifier(metaDocPart.getIdentifier()) != null;
assert valuesMultimap.keySet().stream().allMatch(metafield -> metaDocPart
.getMetaFieldByIdentifier(metafield.getIdentifier()) != null);
Stream>>> valuesBatchStream =
valuesMultimap.asMap().entrySet().stream()
.map(e -> new Tuple2>>(e.getKey(), e.getValue()));
if (valuesMultimap.asMap().entrySet().stream().anyMatch(e -> e.getValue().size() > 500)) {
valuesBatchStream = valuesBatchStream
.flatMap(e -> Seq.seq(e.v2.stream())
.zipWithIndex()
.groupBy(t -> t.v2 / 500)
.entrySet()
.stream()
.map(se -> toValuesMap(e.v1, se)));
}
Stream>>> didProjectionCursorStream =
valuesBatchStream
.map(Unchecked.function(mapBatch ->
getCollectionDidsAndProjectionWithFieldsInBatch(
dsl,
metaDatabase,
metaCol,
metaDocPart,
mapBatch.v1,
mapBatch.v2)));
Stream>> didProjectionStream =
didProjectionCursorStream
.flatMap(cursor -> cursor.getRemaining().stream());
return new IteratorCursor<>(didProjectionStream.iterator());
}
@SuppressWarnings("rawtypes")
private Tuple2>> toValuesMap(MetaField metaField,
Entry, Long>>> groupedValuesMap) {
List collect = groupedValuesMap.getValue().stream()
.map(e -> (KvValue) e.v1)
.collect(Collectors.toList());
return new Tuple2>>(metaField, collect.stream()
.map(e -> (KvValue>) e)
.collect(Collectors.toList()));
}
@SuppressFBWarnings(value = {"OBL_UNSATISFIED_OBLIGATION", "ODR_OPEN_DATABASE_RESOURCE"},
justification = "ResultSet is wrapped in a Cursor>>. "
+ "It's iterated and closed in caller code")
private Cursor>> getCollectionDidsAndProjectionWithFieldsInBatch(
DSLContext dsl, MetaDatabase metaDatabase,
MetaCollection metaCol, MetaDocPart metaDocPart, MetaField metaField,
Collection> values)
throws SQLException {
String statement = getReadCollectionDidsAndProjectionWithFieldInStatement(metaDatabase
.getIdentifier(),
metaDocPart.getIdentifier(), metaField.getIdentifier(), values.size());
Connection connection = dsl.configuration().connectionProvider().acquire();
try {
PreparedStatement preparedStatement = connection.prepareStatement(statement);
int parameterIndex = 1;
for (KvValue> value : values) {
sqlHelper.setPreparedStatementValue(preparedStatement, parameterIndex, metaField.getType(),
value);
parameterIndex++;
}
return new AbstractCursor>>(errorHandler, preparedStatement
.executeQuery()) {
@Override
protected Tuple2> read(ResultSet resultSet) throws SQLException {
return new Tuple2<>(
resultSet.getInt(1),
sqlHelper.getResultSetKvValue(
metaField.getType(),
dataTypeProvider.getDataType(metaField.getType()), resultSet, 2
)
);
}
};
} finally {
dsl.configuration().connectionProvider().release(connection);
}
}
protected abstract String getReadCollectionDidsAndProjectionWithFieldInStatement(
String schemaName,
String rootTableName,
String columnName, int valuesCount);
@Override
@SuppressFBWarnings(value = {"OBL_UNSATISFIED_OBLIGATION", "ODR_OPEN_DATABASE_RESOURCE"},
justification =
"ResultSet is wrapped in a Cursor. It's iterated and closed in caller code")
public Cursor getAllCollectionDids(DSLContext dsl, MetaDatabase metaDatabase,
MetaCollection metaCollection)
throws SQLException {
MetaDocPart rootDocPart = metaCollection.getMetaDocPartByTableRef(tableRefFactory.createRoot());
if (rootDocPart == null) {
return new EmptyCursor<>();
}
String statement = getReadAllCollectionDidsStatement(metaDatabase.getIdentifier(), rootDocPart
.getIdentifier());
Connection connection = dsl.configuration().connectionProvider().acquire();
try {
PreparedStatement preparedStatement = connection.prepareStatement(statement);
return new DefaultDidCursor(errorHandler, preparedStatement.executeQuery());
} finally {
dsl.configuration().connectionProvider().release(connection);
}
}
protected abstract String getReadAllCollectionDidsStatement(String schemaName,
String rootTableName);
@Override
public long countAll(
@Nonnull DSLContext dsl,
@Nonnull MetaDatabase database,
@Nonnull MetaCollection collection
) {
MetaDocPart rootDocPart = collection.getMetaDocPartByTableRef(tableRefFactory.createRoot());
if (rootDocPart == null) {
return 0;
}
String statement = getReadCountAllStatement(database.getIdentifier(), rootDocPart
.getIdentifier());
return sqlHelper.executeStatementWithResult(dsl, statement, Context.FETCH)
.get(0).into(Long.class);
}
protected abstract String getReadCountAllStatement(String schema, String rootTableName);
@Nonnull
@Override
public List getCollectionResultSets(@Nonnull DSLContext dsl,
@Nonnull MetaDatabase metaDatabase, @Nonnull MetaCollection metaCollection,
@Nonnull Cursor didCursor, int maxSize) throws SQLException {
Collection dids = didCursor.getNextBatch(maxSize);
return getCollectionResultSets(dsl, metaDatabase, metaCollection, dids);
}
@Override
@SuppressFBWarnings(value = {"OBL_UNSATISFIED_OBLIGATION", "ODR_OPEN_DATABASE_RESOURCE"},
justification =
"ResultSet is wrapped in a DocPartResult. It's iterated and closed in caller code")
public List getCollectionResultSets(DSLContext dsl, MetaDatabase metaDatabase,
MetaCollection metaCollection, Collection dids) throws SQLException {
ArrayList result = new ArrayList<>();
Connection connection = dsl.configuration().connectionProvider().acquire();
try {
Iterator extends MetaDocPart> metaDocPartIterator = metaCollection
.streamContainedMetaDocParts()
.sorted(TableRefComparator.MetaDocPart.DESC)
.iterator();
while (metaDocPartIterator.hasNext()) {
MetaDocPart metaDocPart = metaDocPartIterator.next();
String statament = getDocPartStatament(metaDatabase, metaDocPart, dids);
PreparedStatement preparedStatement = connection.prepareStatement(statament);
result.add(new ResultSetDocPartResult(metaDataReadInterface, dataTypeProvider, errorHandler,
metaDocPart, preparedStatement.executeQuery(), sqlHelper));
}
} finally {
dsl.configuration().connectionProvider().release(connection);
}
return result;
}
protected abstract String getDocPartStatament(MetaDatabase metaDatabase, MetaDocPart metaDocPart,
Collection dids);
@Override
public int getLastRowIdUsed(DSLContext dsl, MetaDatabase metaDatabase,
MetaCollection metaCollection, MetaDocPart metaDocPart) {
String statement = getLastRowIdUsedStatement(metaDatabase, metaDocPart);
Connection connection = dsl.configuration().connectionProvider().acquire();
try (PreparedStatement preparedStatement = connection.prepareStatement(statement)) {
try (ResultSet rs = preparedStatement.executeQuery()) {
rs.next();
int maxId = rs.getInt(1);
if (rs.wasNull()) {
return -1;
}
return maxId;
}
} catch (SQLException ex) {
throw errorHandler.handleException(Context.FETCH, ex);
} finally {
dsl.configuration().connectionProvider().release(connection);
}
}
protected abstract String getLastRowIdUsedStatement(MetaDatabase metaDatabase,
MetaDocPart metaDocPart);
protected String getPrimaryKeyColumnIdentifier(TableRef tableRef) {
if (tableRef.isRoot()) {
return DocPartTableFields.DID.fieldName;
}
return DocPartTableFields.RID.fieldName;
}
}