package com.anjlab.csv2db;
import static com.anjlab.csv2db.Import.runtimeException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import com.codahale.metrics.Timer;
public class MergeRecordHandler extends AbstractInsertUpdateRecordHandler
{
protected AbstractRecordHandler insertRecordHandler;
protected PreparedStatement updateStatement;
private final Timer updateStatementTimer;
private int numberOfStatementsInBatch;
public MergeRecordHandler(
Configuration config,
Connection connection,
ScriptEngine scriptEngine,
Router router,
int threadId,
int threadCount)
throws SQLException, ScriptException
{
super(config, scriptEngine, connection, router, threadId, threadCount);
StringBuilder setClause = new StringBuilder();
for (String targetTableColumnName : getColumnNamesWithUpdateValues())
{
if (setClause.length() > 0)
{
setClause.append(", ");
}
setClause.append(targetTableColumnName).append(" = ");
ValueDefinition definition = config.getUpdateValues().get(targetTableColumnName);
if (definition.producesSQL())
{
setClause.append(definition.eval(targetTableColumnName, null, scriptEngine));
}
else
{
setClause.append("?");
}
}
for (String targetTableColumnName : getOrderedTableColumnNames())
{
if (setClause.length() > 0)
{
setClause.append(", ");
}
setClause.append(targetTableColumnName).append(" = ?");
}
StringBuilder updateClause =
new StringBuilder("UPDATE ")
.append(config.getTargetTable())
.append(" SET ")
.append(setClause)
.append(" WHERE ")
.append(buildWhereClause());
if (Import.isVerboseEnabled())
{
Import.logVerbose("UPDATE statement used: " + updateClause);
}
this.updateStatement = connection.prepareStatement(updateClause.toString());
this.insertRecordHandler = new InsertRecordHandler(
config, connection, scriptEngine, router, threadId, threadCount);
this.updateStatementTimer = Import.METRIC_REGISTRY.timer("thread-" + threadId + ".updates");
}
@Override
protected void enableBatchExecution() throws SQLException
{
super.enableBatchExecution();
checkBatchExecution(config.getBatchSize());
insertRecordHandler.enableBatchExecution();
}
@Override
protected void disableBatchExecution()
{
super.disableBatchExecution();
insertRecordHandler.disableBatchExecution();
}
@Override
protected void performInsert(Map<String, Object> nameValues)
throws SQLException, ConfigurationException, ScriptException, InterruptedException
{
insertRecordHandler.handleRecord(nameValues);
}
@Override
protected void performUpdate(Map<String, Object> nameValues)
throws ScriptException, SQLException, ConfigurationException
{
int parameterIndex = 1;
// Set parameters for the SET clause
for (String targetTableColumnName : getColumnNamesWithUpdateValues())
{
ValueDefinition definition = config.getUpdateValues().get(targetTableColumnName);
if (!definition.producesSQL())
{
Object columnValue = eval(definition, targetTableColumnName, nameValues);
if (Import.isVerboseEnabled())
{
printNameValue(targetTableColumnName, columnValue);
}
updateStatement.setObject(parameterIndex++, columnValue);
}
}
for (String targetTableColumnName : getOrderedTableColumnNames())
{
Object columnValue = transform(targetTableColumnName, nameValues);
if (Import.isVerboseEnabled())
{
printNameValue(targetTableColumnName, columnValue);
}
updateStatement.setObject(parameterIndex++, columnValue);
}
// Set parameters for the WHERE clause
for (String primaryKeyColumnName : config.getPrimaryKeys())
{
Object primaryKeyColumnValue = transform(primaryKeyColumnName, nameValues);
if (Import.isVerboseEnabled())
{
printNameValue(primaryKeyColumnName, primaryKeyColumnValue);
}
updateStatement.setObject(parameterIndex++, primaryKeyColumnValue);
}
numberOfStatementsInBatch++;
updateStatement.addBatch();
checkBatchExecution(config.getBatchSize());
}
private void checkBatchExecution(int limit) throws SQLException
{
if (batchExecutionDisabled)
{
return;
}
if (numberOfStatementsInBatch >= limit)
{
Import.measureTime(updateStatementTimer, new VoidCallable<SQLException>()
{
@Override
public void run() throws SQLException
{
updateStatement.executeBatch();
}
});
updateStatement.clearParameters();
numberOfStatementsInBatch = 0;
}
}
@Override
public void close()
{
try
{
super.executeBatch();
checkBatchExecution(0);
insertRecordHandler.close();
}
catch (Exception e)
{
throw runtimeException(e);
}
finally
{
closeQuietly(updateStatement);
super.close();
}
}
}