package org.opencb.opencga.storage.hadoop.variant.index.annotation; import com.google.common.base.Function; import org.apache.phoenix.schema.types.PDataType; import org.apache.phoenix.schema.types.PhoenixArray; import org.apache.phoenix.util.UpsertExecutor; import org.opencb.opencga.storage.hadoop.variant.index.phoenix.PhoenixHelper.Column; import org.opencb.opencga.storage.hadoop.variant.index.phoenix.VariantPhoenixHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.sql.Array; import java.sql.Connection; import java.sql.SQLException; import java.util.*; import java.util.stream.Collectors; import static org.apache.phoenix.monitoring.GlobalClientMetrics.GLOBAL_MUTATION_SQL_COUNTER; /** * Created on 24/10/16. * * @author Jacobo Coll <jacobo167@gmail.com> */ public class VariantAnnotationUpsertExecutor extends UpsertExecutor<Map<Column, ?>, Object> { private static final Logger LOG = LoggerFactory.getLogger(VariantAnnotationUpsertExecutor.class); private final List<Column> columnList; public VariantAnnotationUpsertExecutor(Connection conn, String tableName) { this(conn, tableName, Arrays.stream(VariantPhoenixHelper.VariantColumn.values()).collect(Collectors.toList())); } public VariantAnnotationUpsertExecutor(Connection conn, String tableName, List<Column> columnList) { this(conn, tableName, columnList, new UpsertListener<Map<Column, ?>>() { @Override public void upsertDone(long upsertCount) { // System.out.println("upsertCount = " + upsertCount); } @Override public void errorOnRecord(Map<Column, ?> columnMap, Throwable e) { LOG.error("ERROR LOADING: " + columnMap, e); if (e instanceof Exception) { throw new RuntimeException(e); } } }); } public VariantAnnotationUpsertExecutor(Connection conn, String tableName, List<Column> columnList, UpsertListener<Map<Column, ?>> upsertListener) { super(conn, tableName, columnList.stream().map(Column::toColumnInfo).collect(Collectors.toList()), upsertListener); this.columnList = columnList; try { conn.setAutoCommit(true); } catch (SQLException e) { // Impossible? throw new RuntimeException(e); } } @Override protected void execute(Map<Column, ?> map) { try { for (int fieldIndex = 0; fieldIndex < columnList.size(); fieldIndex++) { Column column = columnList.get(fieldIndex); Object sqlValue; sqlValue = map.get(column); if (sqlValue != null) { if (column.getPDataType().isArrayType()) { if (sqlValue instanceof Collection) { sqlValue = toArray(column.getPDataType(), (Collection) sqlValue); } else { throw new IllegalArgumentException("Column " + column + " is not a collection " + sqlValue); } } preparedStatement.setObject(fieldIndex + 1, sqlValue); } else { preparedStatement.setNull(fieldIndex + 1, dataTypes.get(fieldIndex).getSqlType()); } } preparedStatement.execute(); LOG.debug("preparedStatement.getUpdateCount() = " + preparedStatement.getUpdateCount()); upsertListener.upsertDone(++upsertCount); } catch (RuntimeException | SQLException e) { if (LOG.isDebugEnabled()) { // Even though this is an error we only log it with debug logging because we're notifying the // listener, and it can do its own logging if needed LOG.debug("Error on variant " + map, e); } upsertListener.errorOnRecord(map, e); } } private Array toArray(PDataType elementDataType, Collection<?> input) { if (elementDataType.isArrayType()) { elementDataType = PDataType.arrayBaseType(elementDataType); } return new PhoenixArray(elementDataType, input.toArray(new Object[input.size()])); } @Override protected Function<Object, Object> createConversionFunction(PDataType dataType) { // return input -> dataType.toObject(input, dataType); return input -> input; } @Override public void close() throws IOException { super.close(); try { conn.commit(); } catch (SQLException e) { throw new IOException(e); } LOG.debug("GLOBAL_MUTATION_SQL_COUNTER = " + GLOBAL_MUTATION_SQL_COUNTER.getMetric().getTotalSum()); } // void putDynamicColumns(Map<Column, ?> map) { // EnumSet<VariantPhoenixHelper.VariantColumn> variantColumns = EnumSet.allOf(VariantPhoenixHelper.VariantColumn.class); // // } }