package no.priv.garshol.duke;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import no.priv.garshol.duke.utils.JDBCUtils;
/**
* An eq. class database using an RDBMS as backing.
* @since 1.0
*/
public class JDBCEquivalenceClassDatabase implements EquivalenceClassDatabase {
private Statement stmt; // set by subclass
private int nextclassid;
public JDBCEquivalenceClassDatabase(String driverklass,
String jdbcuri,
String dbtype,
Properties props) {
this.stmt = JDBCUtils.open(driverklass, jdbcuri, props);
init();
this.nextclassid = getNextClassId();
}
public int getClassCount() {
throw new UnsupportedOperationException();
}
public Iterator<Collection<String>> getClasses() {
throw new UnsupportedOperationException();
}
public Collection<String> getClass(String id) {
int clid = JDBCUtils.queryForInt(stmt, "select clid from classes " +
"where id = '" + id + "'", -1);
List ids = new ArrayList();
try {
ResultSet rs = stmt.executeQuery("select id from classes where clid = " +
clid);
try {
while (rs.next())
ids.add(rs.getString(1));
} finally {
rs.close();
}
} catch (SQLException e) {
throw new DukeException(e);
}
return ids;
}
public void addLink(String id1, String id2) {
int clid1 = getClassId(id1);
int clid2 = getClassId(id2);
if (clid1 == clid2 && clid1 != -1)
return; // we already knew
if (clid1 == -1 && clid2 == -1) {
// don't know these from before, so make a new class for them
addToClass(id1, nextclassid);
addToClass(id2, nextclassid);
nextclassid++;
} else if ((clid1 == -1 && clid2 != -1) ||
(clid1 != -1 && clid2 == -1)) {
// one of these has no class, so we add it to the class of the other
if (clid1 == -1)
addToClass(id1, clid2);
else
addToClass(id2, clid1);
} else
// we have classes for both, but they're different
merge(clid1, clid2);
}
public void commit() {
// mysql is autocommiting, so no need
}
public int getClassId(String id) {
return JDBCUtils.queryForInt(stmt, "select clid from classes " +
"where id = '" + id + "'", -1);
}
private void addToClass(String id, int clid) {
try {
stmt.executeUpdate("insert into classes values ('" + id + "', " + clid + ")");
} catch (SQLException e) {
throw new DukeException(e);
}
}
private void merge(int clid1, int clid2) {
try {
stmt.executeUpdate("update classes set clid = " + clid1 +
" where clid = " + clid2);
} catch (SQLException e) {
throw new DukeException(e);
}
}
private int getNextClassId() {
return JDBCUtils.queryForInt(stmt, "select max(clid) from classes", 0) + 1;
}
private void init() {
if (JDBCUtils.queryHasResult(stmt,
"select * from information_schema.tables " +
"where table_name = 'CLASSES'"))
return; // table exists, no problem
try {
// this table contains the equivalence classes. 'clid' has the
// ID of the class, and 'id' the ID of the record that has been
// put into the class. each 'id' should occur only once, while
// the 'clid's will occur once for each record in the class.
stmt.executeUpdate("create table classes (id varchar(100) not null, " +
" clid int not null, " +
" primary key (id, clid))");
} catch (SQLException e) {
throw new DukeException(e);
}
}
}