
org.nuiton.topia.service.sql.batch.actions.ReplicateTablesAction Maven / Gradle / Ivy
package org.nuiton.topia.service.sql.batch.actions;
/*
* #%L
* ObServe Toolkit :: ToPIA Extension
* %%
* Copyright (C) 2008 - 2017 IRD, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
import com.zaxxer.hikari.pool.HikariProxyConnection;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.sql.rowset.serial.SerialBlob;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.topia.persistence.metadata.TopiaMetadataEntity;
import org.nuiton.topia.service.sql.batch.tables.TopiaSqlTable;
import org.nuiton.topia.service.sql.batch.tables.TopiaSqlTables;
import org.postgresql.PGConnection;
import org.postgresql.jdbc.PgConnection;
import org.postgresql.largeobject.LargeObject;
import org.postgresql.largeobject.LargeObjectManager;
/**
* Created on 01/01/16.
*
* @author Tony Chemit - [email protected]
* @since 3.0.1
*/
public class ReplicateTablesAction extends AbstractTablesAction {
public static final String INSERT_STATEMENT = "INSERT INTO %s.%s(%s) VALUES (%%s);\n";
/**
* Logger.
*/
private static final Log log = LogFactory.getLog(ReplicateTablesAction.class);
public ReplicateTablesAction(ReplicateTablesRequest request, boolean showSql) {
super(request, showSql);
}
@Override
protected void executeOnTable(ReplicateTablesRequest request, TopiaSqlTable table, PreparedStatement readStatement) throws SQLException {
TopiaMetadataEntity metadataEntity = table.getMetadataEntity();
ResultSet readResultSet = readStatement.getResultSet();
ResultSetMetaData readResultSetMetaData = readResultSet.getMetaData();
int columnCount = readResultSetMetaData.getColumnCount();
List columnNames = getColumnNames(metadataEntity, table, readResultSet);
boolean useBlob = metadataEntity.withBlob();
boolean useOutputWriter = useOutputWriter();
boolean useOutputDb = useOutputDb();
BlobsContainer.Builder blobsBuilder = null;
if (useBlob) {
//FIXME On devrait gérer pour plusieurs colonnes
String columnName = metadataEntity.getBlobProperties().iterator().next();
blobsBuilder = BlobsContainer.builder(table.getFullyTableName(), columnName);
registerBlobsContainer(blobsBuilder);
}
PreparedStatement writeStatement = null;
String insertStatementSql = newInsertStatementSql(table, columnNames);
if (useOutputDb) {
String arguments = generateWildcardArguments(columnNames);
String sql = String.format(insertStatementSql, arguments).trim();
writeStatement = targetConnection.prepareStatement(sql);
}
int writeBatchSize = request.getWriteBatchSize();
String tableName = table.getFullyTableName();
long index = 0;
while (readResultSet.next()) {
if (log.isTraceEnabled()) {
log.trace("Copy " + readResultSet.getString(1));
}
if (useOutputDb) {
writeStatement.clearParameters();
int j = 1;
for (int i = 1; i <= columnCount; i++) {
String columnName = readResultSetMetaData.getColumnName(i);
if (columnNames.contains(columnName.toLowerCase())) {
Object object = readResultSet.getObject(i);
writeStatement.setObject(j++, object);
}
}
writeStatement.addBatch();
}
if (useOutputWriter) {
try {
String blobColumn = null;
if (useBlob) {
blobColumn = metadataEntity.getBlobProperties().iterator().next();
}
Connection connection = readStatement.getConnection();
String arguments = generateSqlArguments(readResultSet, columnNames, blobColumn, blobsBuilder, connection);
String sql = String.format(insertStatementSql, arguments);
writer.append(sql);
} catch (IOException e) {
throw new RuntimeException("Could not copyRow", e);
}
}
if ((++index % writeBatchSize) == 0) {
flush(writeStatement, writer, tableName, index);
}
}
flush(writeStatement, writer, tableName, index);
}
@Override
protected TopiaSqlTables getTables() {
return request.getTables();
}
protected String newInsertStatementSql(TopiaSqlTable table, List columnNames) {
StringBuilder columnNamesBuilder = new StringBuilder();
String blobColumn = null;
if (table.getMetadataEntity().withBlob()) {
blobColumn = table.getMetadataEntity().getBlobProperties().iterator().next();
}
for (String columnName : columnNames) {
if (!columnName.equals(blobColumn)) {
columnNamesBuilder.append(", ").append(columnName);
}
}
String sql = String.format(INSERT_STATEMENT,
table.getSchemaName(),
table.getTableName(),
columnNamesBuilder.substring(2));
if (log.isDebugEnabled()) {
log.debug("Insert sql: " + sql);
}
return sql;
}
protected String generateSqlArguments(ResultSet readResultSet,
Iterable columnNames,
String blobColumn, BlobsContainer.Builder blobsBuilder,
Connection connection) throws SQLException, IOException {
String statement = "";
for (String columnName : columnNames) {
Object columnValue = readResultSet.getObject(columnName);
if (columnName.equals(blobColumn)) {
if (columnValue == null) {
continue;
}
InputStream stream;
int size;
if (columnValue instanceof Long) {
PGConnection pgConnection;
if (connection instanceof PgConnection) {
pgConnection = (PGConnection) connection;
}
// else if (connection instanceof NewProxyConnection) {
//
// NewProxyConnection connection1 = (NewProxyConnection) connection;
// try {
// Field field = connection1.getClass().getDeclaredField("inner");
// field.setAccessible(true);
// pgConnection = (PGConnection) field.get(connection1);
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
//
// }
else if (connection instanceof HikariProxyConnection) {
HikariProxyConnection connection1 = (HikariProxyConnection) connection;
try {
Field field = connection1.getClass().getSuperclass().getDeclaredField("delegate");
field.setAccessible(true);
pgConnection = (PGConnection) field.get(connection1);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
throw new IllegalStateException("Can't know how to manage connection: " + connection);
}
LargeObjectManager lobj = pgConnection.getLargeObjectAPI();
LargeObject obj = lobj.open((long) columnValue, LargeObjectManager.READ);
size = obj.size();
stream = obj.getInputStream();
} else {
Blob blob = (Blob) columnValue;
stream = blob.getBinaryStream();
SerialBlob serialBlob = new SerialBlob(blob);
size = (int) serialBlob.length();
}
try (ByteArrayOutputStream stringWriter = new ByteArrayOutputStream(size)) {
stringWriter.write(stream);
String topiaId = readResultSet.getString("topiaId");
Objects.nonNull(topiaId);
blobsBuilder.addBlob(topiaId, stringWriter.toByteArray());
if (log.isInfoEnabled()) {
log.info("Add blob: " + topiaId);
}
}
continue;
}
if (columnValue == null) {
statement += ", NULL";
continue;
}
if (columnValue instanceof String) {
String stringValue = (String) columnValue;
statement += ", '" + stringValue.replaceAll("'", "''") + "'";
continue;
}
if (columnValue instanceof Date) {
statement += ", '" + columnValue + "'";
continue;
}
statement += ", " + columnValue;
}
return statement.substring(2);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy