/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 2008.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.sail.rdbms.schema;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.concurrent.BlockingQueue;
import org.openrdf.sail.helpers.DefaultSailChangedEvent;
/**
* Manages a temporary table used when uploading new statements with the same
* predicate into the database.
*
* @author James Leigh
*
*/
public class TransactionTable {
private int batchSize;
private TripleTable triples;
private int addedCount;
private int removedCount;
private RdbmsTable temporary;
private Connection conn;
private TripleBatch batch;
private BlockingQueue<Batch> queue;
private DefaultSailChangedEvent sailChangedEvent;
private IdSequence ids;
private PreparedStatement insertSelect;
public void setIdSequence(IdSequence ids) {
this.ids = ids;
}
public void setQueue(BlockingQueue<Batch> queue) {
this.queue = queue;
}
public void setTemporaryTable(RdbmsTable table) {
this.temporary = table;
}
public void setConnection(Connection conn) {
this.conn = conn;
}
public TripleTable getTripleTable() {
return triples;
}
public void setTripleTable(TripleTable statements) {
this.triples = statements;
}
public void setSailChangedEvent(DefaultSailChangedEvent sailChangedEvent) {
this.sailChangedEvent = sailChangedEvent;
}
public int getBatchSize() {
return batchSize;
}
public void setBatchSize(int size) {
this.batchSize = size;
}
public void close()
throws SQLException
{
if (insertSelect != null) {
insertSelect.close();
}
temporary.close();
}
public synchronized void insert(Number ctx, Number subj, Number pred, Number obj, boolean explicit)
throws SQLException, InterruptedException
{
if (batch == null || batch.isFull() || !queue.remove(batch)) {
batch = newTripleBatch();
batch.setTable(triples);
batch.setSailChangedEvent(sailChangedEvent);
batch.setTemporary(temporary);
batch.setMaxBatchSize(getBatchSize());
batch.setBatchStatement(prepareInsert());
if (insertSelect == null) {
insertSelect = prepareInsertSelect(buildInsertSelect());
}
batch.setInsertStatement(insertSelect);
}
batch.setObject(1, ctx);
batch.setObject(2, subj);
if (temporary == null && !triples.isPredColumnPresent()) {
batch.setObject(3, obj);
batch.setObject(4, new Boolean(explicit));
} else {
batch.setObject(3, pred);
batch.setObject(4, obj);
batch.setObject(5, new Boolean(explicit));
}
batch.addBatch();
queue.put(batch);
addedCount++;
triples.getSubjTypes().add(ids.valueOf(subj));
triples.getObjTypes().add(ids.valueOf(obj));
}
public void committed()
throws SQLException
{
triples.modified(addedCount, removedCount);
addedCount = 0;
removedCount = 0;
}
public void removed(int count)
throws SQLException
{
removedCount += count;
}
public boolean isEmpty()
throws SQLException
{
return triples.isEmpty() && addedCount == 0;
}
@Override
public String toString() {
return triples.toString();
}
protected TripleBatch newTripleBatch() {
return new TripleBatch();
}
protected PreparedStatement prepareInsertSelect(String sql)
throws SQLException
{
return conn.prepareStatement(sql);
}
protected String buildInsertSelect()
throws SQLException
{
String tableName = triples.getName();
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO ").append(tableName).append("\n");
sb.append("SELECT DISTINCT ctx, subj, ");
if (triples.isPredColumnPresent()) {
sb.append("pred, ");
}
sb.append("obj, expl FROM ");
sb.append(temporary.getName()).append(" tr\n");
sb.append("WHERE NOT EXISTS (");
sb.append("SELECT ctx, subj, ");
if (triples.isPredColumnPresent()) {
sb.append("pred, ");
}
sb.append("obj, expl FROM ");
sb.append(tableName).append(" st\n");
sb.append("WHERE st.ctx = tr.ctx");
sb.append(" AND st.subj = tr.subj");
if (triples.isPredColumnPresent()) {
sb.append(" AND st.pred = tr.pred");
}
sb.append(" AND st.obj = tr.obj");
sb.append(" AND st.expl = tr.expl");
sb.append(")");
return sb.toString();
}
protected PreparedStatement prepareInsert(String sql)
throws SQLException
{
return conn.prepareStatement(sql);
}
protected String buildInsert(String tableName, boolean predColumnPresent)
throws SQLException
{
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO ").append(tableName);
sb.append(" (ctx, subj, ");
if (predColumnPresent) {
sb.append("pred, ");
}
sb.append("obj, expl)\n");
sb.append("VALUES (?, ?, ");
if (predColumnPresent) {
sb.append("?, ");
}
sb.append("?, ?)");
return sb.toString();
}
protected boolean isPredColumnPresent() {
return triples.isPredColumnPresent();
}
private PreparedStatement prepareInsert()
throws SQLException
{
if (temporary == null) {
boolean present = triples.isPredColumnPresent();
String sql = buildInsert(triples.getName(), present);
return prepareInsert(sql);
}
String sql = buildInsert(temporary.getName(), true);
return prepareInsert(sql);
}
}