707 lines
22 KiB
Java
707 lines
22 KiB
Java
import java.sql.*;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
|
|
|
|
/**
|
|
* @author Lublena
|
|
*
|
|
*/
|
|
public class Chaser
|
|
{
|
|
private Connection dbConnection;
|
|
private Statement sqlStatement;
|
|
|
|
/**
|
|
* Name of the template relation
|
|
*/
|
|
private String templateRelName;
|
|
/**
|
|
* Name of the mapping relation
|
|
*/
|
|
private String mappingRelName;
|
|
/**
|
|
* Name of the components relation
|
|
*/
|
|
private String compRelName;
|
|
/**
|
|
* Name of the world relation
|
|
*/
|
|
private String worldRelName;
|
|
|
|
/**
|
|
* Number of pairs of components that were merged during the chasing phase.
|
|
*/
|
|
public int merged;
|
|
|
|
/**
|
|
* Constructs a new chaser and initializes database connection.
|
|
* @param aDatabase Name of the database
|
|
* @param aUser Username
|
|
* @param aPassword Pasword
|
|
* @param aTemplateRelName Name of the template relation
|
|
* @param aMappingRelName Name of the mapping relation
|
|
* @param aCompRelName Name of the components relation
|
|
* @param aWorldRelName Name of the world relation
|
|
*/
|
|
public Chaser(String aDatabase, String aUser, String aPassword,
|
|
String aTemplateRelName, String aMappingRelName, String aCompRelName,
|
|
String aWorldRelName)
|
|
{
|
|
init(aDatabase, aUser, aPassword);
|
|
templateRelName = aTemplateRelName;
|
|
mappingRelName = aMappingRelName;
|
|
compRelName = aCompRelName;
|
|
worldRelName = aWorldRelName;
|
|
merged = 0;
|
|
}
|
|
|
|
/**
|
|
* Initializes database connection.
|
|
* @param aDatabase Name of the database to connect to
|
|
* @param aUser Username
|
|
* @param aPassword Password
|
|
*/
|
|
private void init(String aDatabase, String aUser, String aPassword)
|
|
{
|
|
try
|
|
{
|
|
Class.forName("org.postgresql.Driver"); //load the driver
|
|
|
|
dbConnection = DriverManager.getConnection("jdbc:postgresql:" + aDatabase,
|
|
aUser, aPassword);
|
|
sqlStatement = dbConnection.createStatement();
|
|
}
|
|
catch (SQLException e)
|
|
{
|
|
System.out.println("Could not connect to the database!");
|
|
e.printStackTrace();
|
|
return;
|
|
}
|
|
catch (ClassNotFoundException e)
|
|
{
|
|
System.out.println("Could not load database driver!");
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Closes connection to the database.
|
|
*
|
|
*/
|
|
public void closeConnection()
|
|
{
|
|
try
|
|
{
|
|
sqlStatement.close();
|
|
dbConnection.close();
|
|
}
|
|
catch (SQLException e)
|
|
{
|
|
// Ignore
|
|
return;
|
|
}
|
|
}
|
|
|
|
private boolean applyFD(FDependency aFD)
|
|
{
|
|
// TODO: Implement
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Enforces an equality-generating dependency on the database by deleting invalid
|
|
* worlds.
|
|
* @param aEQD An equality-generating dependency to enforce
|
|
* @return True if the dependency was successfully enforced,
|
|
* false if the database was inconsistent.
|
|
*/
|
|
private boolean applyEQD(EQDependency aEQD)
|
|
{
|
|
// Find tuples that do not satisfy the dependency
|
|
//ArrayList<Term> terms = aEQD.getTerms();
|
|
//ArrayList<Term> rterms = aEQD.getRTerms();
|
|
|
|
//ArrayList terms = aEQD.getTerms();
|
|
ArrayList rterms = aEQD.getRTerms();
|
|
|
|
|
|
Term t = (Term) rterms.get(0);
|
|
StringBuffer leftArrayBuilder = new StringBuffer("'{\"" + t.left + "\"");
|
|
StringBuffer opArrayBuilder = new StringBuffer("'{\"" + t.op + "\"");
|
|
StringBuffer rightArrayBuilder = new StringBuffer("'{\"" + t.right + "\"");
|
|
|
|
// Construct the left, op and right arrays needed for the call to project_select
|
|
for (int i = 1; i < rterms.size(); ++i)
|
|
{
|
|
Term term = (Term) rterms.get(i);
|
|
leftArrayBuilder.append(",\"" + term.left + "\"");
|
|
opArrayBuilder.append(",\"" + term.op + "\"");
|
|
rightArrayBuilder.append(",\"" + term.right + "\"");
|
|
}
|
|
|
|
leftArrayBuilder.append("}'");
|
|
opArrayBuilder.append("}'");
|
|
rightArrayBuilder.append("}'");
|
|
|
|
// Construct command for retrieving the rows not satisfying the given dependency
|
|
StringBuffer commandBuilder = new StringBuffer("select project_select(");
|
|
commandBuilder.append("'" + templateRelName + "','" + mappingRelName + "','" +
|
|
compRelName + "','" + worldRelName + "',");
|
|
commandBuilder.append("'eqRel', 'eqMap', 'eqComp', 'eqWorld', ");
|
|
commandBuilder.append(leftArrayBuilder.toString() + "," + leftArrayBuilder.toString() + ",");
|
|
commandBuilder.append(opArrayBuilder.toString() + "," + rightArrayBuilder.toString() + ")");
|
|
|
|
String command = commandBuilder.toString();
|
|
|
|
//String command = constructStatement(rterms);
|
|
|
|
try
|
|
{
|
|
//System.out.println("Executing query " + commandBuilder.toString());
|
|
sqlStatement.execute(command);
|
|
|
|
StringBuffer sql = new StringBuffer("SELECT cid, hid FROM " + mappingRelName);
|
|
sql.append(" WHERE tid = ? AND Col = ?;");
|
|
|
|
PreparedStatement holePropertiesStatement = dbConnection.prepareStatement(sql.toString());
|
|
//Statement statement = dbConnection.createStatement();
|
|
|
|
ResultSet rs = sqlStatement.executeQuery("SELECT * FROM eqRel");
|
|
|
|
//ResultSet rs = sqlStatement.executeQuery(command);
|
|
|
|
// Prepare ArrayList that will hold information for the bulk operations
|
|
ArrayList bulkDeleteInfo = new ArrayList();
|
|
ArrayList bulkMergeInfo = new ArrayList();
|
|
|
|
int s = 0;
|
|
while (rs.next())
|
|
{
|
|
s++;
|
|
/*ArrayList<String> compIDs = new ArrayList<String>();
|
|
ArrayList<String> holeIDs = new ArrayList<String>();
|
|
ArrayList<Integer> inds = new ArrayList<Integer>(); // indexes of terms that are not true in all worlds
|
|
*/
|
|
ArrayList compIDs = new ArrayList();
|
|
ArrayList holeIDs = new ArrayList();
|
|
ArrayList inds = new ArrayList(); // indexes of terms that are not true in all worlds
|
|
ArrayList invalidTerms = new ArrayList();
|
|
|
|
ArrayList columns = aEQD.getColumns();
|
|
|
|
for (int i = 0; i < columns.size(); ++i)
|
|
{
|
|
String col = columns.get(i).toString();
|
|
// The current column contains a hole
|
|
String val = rs.getString(col);
|
|
if (val == null)
|
|
{
|
|
continue;
|
|
}
|
|
if (val.equals("-1"))
|
|
{
|
|
// Retrieve the cid and hid for the hole
|
|
holePropertiesStatement.setInt(1, rs.getInt("tid"));
|
|
holePropertiesStatement.setString(2, col);
|
|
|
|
ResultSet cidhid = holePropertiesStatement.executeQuery();
|
|
if (cidhid.next())
|
|
{
|
|
String cid = cidhid.getString("cid");
|
|
String hid = cidhid.getString("hid");
|
|
compIDs.add(cid);
|
|
holeIDs.add(hid);
|
|
inds.add(new Integer(i));
|
|
invalidTerms.add(rterms.get(i));
|
|
}
|
|
else
|
|
{
|
|
// System.out.println(holePropertiesStatement.toString());
|
|
System.out.println("Warning: No info found for the current hole (" + rs.getInt("tid")
|
|
+ ", " + col + ").");
|
|
//return false;
|
|
}
|
|
} // end if (rs.getObject(col) == null)
|
|
} // end for(int i = 0; i < columns.size; ++i)
|
|
|
|
// Database is inconsistent
|
|
if (compIDs.isEmpty())
|
|
{
|
|
System.out.println("Incosistent database. Aborting...");
|
|
return false;
|
|
}
|
|
if (compIDs.size() == 1)
|
|
{
|
|
bulkDeleteInfo.add(new InvalidInfo(compIDs.get(0),
|
|
holeIDs.get(0), invalidTerms.get(0)));
|
|
}
|
|
else // More than one component involved - merge
|
|
{
|
|
// !!!Dirty fix - there are exactly two components to merge,
|
|
// which are independent of the components in the rest of the tuples
|
|
// TODO: Figure out what to do when this is not the case
|
|
|
|
String c1 = compIDs.get(0).toString();
|
|
String c2 = compIDs.get(1).toString();
|
|
|
|
String h1 = holeIDs.get(0).toString();
|
|
String h2 = holeIDs.get(1).toString();
|
|
|
|
Term t1 = (Term) invalidTerms.get(0);
|
|
Term t2 = (Term) invalidTerms.get(1);
|
|
|
|
String c = c1 + "x" + c2;
|
|
bulkMergeInfo.add(new InvalidInfoPair(c,c1,c2,h1,h2,t1,t2));
|
|
}
|
|
} // end while(rs.next)
|
|
|
|
System.out.println("Size of intermediate results: " + s);
|
|
// Perform bulk operations
|
|
Statement bulkStatement = dbConnection.createStatement();
|
|
if (!bulkDeleteInfo.isEmpty())
|
|
{
|
|
bulkDelete(bulkStatement, bulkDeleteInfo);
|
|
}
|
|
if (!bulkMergeInfo.isEmpty())
|
|
{
|
|
bulkMerge(bulkStatement, bulkMergeInfo);
|
|
}
|
|
// Drop intermediate results
|
|
try
|
|
{
|
|
sqlStatement.executeUpdate("DROP TABLE eqRel; DROP TABLE eqMap; DROP TABLE eqComp;");
|
|
sqlStatement.executeUpdate("DROP TABLE eqWorld;");
|
|
}
|
|
catch (SQLException e)
|
|
{
|
|
// Ignore
|
|
}
|
|
|
|
}
|
|
catch (SQLException e)
|
|
{
|
|
System.out.println("Error occured when chasing dependency " + aEQD.toString());
|
|
e.printStackTrace();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
/**
|
|
* Updates the entries in the mapping and components tables after the components
|
|
* in the given ArrayList have been merged.
|
|
* @param statement The Statement used to perform the updates.
|
|
* @param oldCompIDs ArrayList of component IDs that have been merged.
|
|
* @param newCompID Name of the new component that replaced the old ones.
|
|
*/
|
|
private void updateTables(Statement statement, ArrayList oldCompIDs, String newCompID)
|
|
throws SQLException
|
|
{
|
|
StringBuffer sb = new StringBuffer("('" + oldCompIDs.get(0) + "'");
|
|
|
|
for (int i = 1; i < oldCompIDs.size(); ++i)
|
|
{
|
|
sb.append(",'" + oldCompIDs.get(i).toString() + "'");
|
|
}
|
|
sb.append(")");
|
|
String st = "DELETE FROM " + compRelName + " WHERE cid IN " + sb.toString();
|
|
// System.out.println(st);
|
|
statement.executeUpdate(st);
|
|
st = "UPDATE " + mappingRelName + " SET cid = '" + newCompID + "' WHERE cid IN " + sb.toString();
|
|
statement.executeUpdate(st);
|
|
}
|
|
/**
|
|
* Deletes all worlds in a component that do not satisfy the given conjunctive formula.
|
|
* @param statement The Statement used to perform the updates.
|
|
* @param comp The name of the component to filter.
|
|
* @param rterms A conjunction of terms.
|
|
* @param holeIDs IDs of the holes that corespond to the column names in the formula.
|
|
* @param inds Indices of the terms that should be taken into account when filtering.
|
|
* @throws SQLException
|
|
*/
|
|
private void deleteInvalid(Statement statement, String comp, ArrayList rterms, ArrayList holeIDs, ArrayList inds)
|
|
throws SQLException
|
|
{
|
|
StringBuffer delSQL = new StringBuffer();
|
|
if (holeIDs.size() == 1)
|
|
{
|
|
delSQL.append("CREATE TABLE INVALID AS SELECT cid, wid FROM " + compRelName);
|
|
delSQL.append(" WHERE cid = '" + comp + "'");
|
|
delSQL.append(" AND hid = '" + holeIDs.get(0).toString() + "'");
|
|
int i = (new Integer(inds.get(0).toString())).intValue();
|
|
String op = ((Term) rterms.get(i)).op;
|
|
String c = ((Term) rterms.get(i)).right;
|
|
// System.out.println("Deleting Values " + op + " " + c);
|
|
delSQL.append(" AND Value " + op + " " + c);
|
|
statement.executeUpdate(delSQL.toString());
|
|
delSQL.delete(0, delSQL.length());
|
|
delSQL.append("DELETE FROM " + compRelName + " WHERE oid IN (SELECT c.oid FROM INVALID NATURAL JOIN ");
|
|
delSQL.append(compRelName + " AS c)");
|
|
statement.executeUpdate(delSQL.toString());
|
|
}
|
|
else
|
|
{
|
|
StringBuffer fromClause = new StringBuffer(compRelName + " C0");
|
|
StringBuffer cond1 = new StringBuffer("C0.cid = '" + comp +
|
|
"' AND C0.hid = '" + holeIDs.get(0) + "'");
|
|
int ind = (new Integer(inds.get(0).toString())).intValue();
|
|
Term t = (Term) rterms.get(ind);
|
|
StringBuffer cond2 = new StringBuffer("C0.Value " + t.op + " " +
|
|
t.right);
|
|
StringBuffer cond3 = new StringBuffer();
|
|
|
|
for (int i = 1; i < holeIDs.size(); ++i)
|
|
{
|
|
fromClause.append("," + compRelName + " C" + i);
|
|
cond1.append(" AND C" + i + ".cid = '" + comp +
|
|
"' AND C" + i + ".hid = '" + holeIDs.get(i) + "'");
|
|
ind = (new Integer(inds.get(i).toString())).intValue();
|
|
t = (Term) rterms.get(ind);
|
|
cond2.append(" AND C" + i + ".Value " + t.op + " " +
|
|
t.right);
|
|
cond3.append(" AND C" + (i-1) + ".wid = C" + i + ".wid");
|
|
}
|
|
|
|
String st = "CREATE TABLE INVALID AS SELECT c0.cid,c0.wid FROM " + fromClause.toString() +
|
|
" WHERE " + cond1.toString() + " AND " + cond2.toString() + cond3.toString();
|
|
|
|
statement.executeUpdate(st);
|
|
st = "DELETE FROM " + compRelName + " WHERE oid in (SELECT c.oid FROM INVALID NATURAL JOIN " +
|
|
compRelName + " AS c);";
|
|
// System.out.println(st);
|
|
statement.executeUpdate(st);
|
|
} // end else
|
|
|
|
// Delete intermediate results
|
|
statement.executeUpdate("DROP TABLE INVALID;");
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Performs a bulk delete to remove inconsistencies from the database
|
|
* @param invalid ArrayList of InvalidInfo items, denoting which worlds in which components
|
|
* @param statement Statement to execute the SQL commands with
|
|
* should be deleted.
|
|
*/
|
|
private void bulkDelete(Statement statement, ArrayList invalid) throws SQLException
|
|
{
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
int size = invalid.size();
|
|
int j;
|
|
int n;
|
|
int i = 0;
|
|
while (i < size)
|
|
{
|
|
j = i;
|
|
n = i + 250;
|
|
if (n > size)
|
|
{
|
|
n = size;
|
|
}
|
|
for (; j < n; ++j)
|
|
{
|
|
InvalidInfo info = (InvalidInfo) invalid.get(j);
|
|
if (j > i)
|
|
{
|
|
sb.append(" OR ");
|
|
}
|
|
sb.append("(cid = '" + info.cid + "' AND hid = '" + info.hid + "'");
|
|
sb.append(" AND Value " + info.t.op + " '" + info.t.right + "')");
|
|
}
|
|
|
|
// Create table of invalid worlds
|
|
String createInvalid = "CREATE TABLE Invalid AS SELECT cid,wid FROM " + compRelName
|
|
+ " WHERE " + sb.toString();
|
|
statement.executeUpdate(createInvalid);
|
|
|
|
String delete = "DELETE FROM " + compRelName
|
|
+ " WHERE oid IN (SELECT c.oid FROM Invalid NATURAL JOIN " + compRelName + " AS c);";
|
|
statement.executeUpdate(delete);
|
|
// Drop table of invalid worlds
|
|
statement.executeUpdate("DROP TABLE Invalid;");
|
|
|
|
i += (n-i);
|
|
sb.delete(0, sb.length());
|
|
}
|
|
}
|
|
|
|
|
|
private String generateDelete(InvalidInfoPair info)
|
|
{
|
|
StringBuffer sb = new StringBuffer();
|
|
sb.append("(c1.cid = '" + info.c + "'" + " AND c1.hid ='" + info.h1 + "'");
|
|
sb.append(" AND c1.Value " + info.t1.op + " '" + info.t1.right + "'");
|
|
sb.append(" AND c2.hid = '" + info.h2 + "'");
|
|
sb.append(" AND c2.Value " + info.t2.op + " '" + info.t2.right + "')");
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Performs a bulk merge of given pairs of components.
|
|
* @param statement
|
|
* @param mergeInfo
|
|
* @throws SQLException
|
|
*/
|
|
private void bulkMerge(Statement statement, ArrayList mergeInfo) throws SQLException
|
|
{
|
|
int size = mergeInfo.size();
|
|
int i = 0;
|
|
int n;
|
|
int j;
|
|
|
|
while (i < size)
|
|
{
|
|
StringBuffer sb1 = new StringBuffer();
|
|
sb1.append("CREATE TABLE Invalid AS SELECT c1.cid,c1.wid FROM ");
|
|
sb1.append(compRelName + " AS c1 JOIN " + compRelName
|
|
+ " AS c2 ON(c1.cid = c2.cid AND c1.wid = c2.wid)");
|
|
sb1.append(" WHERE ");
|
|
|
|
n = i + 250;
|
|
if (n > size)
|
|
{
|
|
n = size;
|
|
}
|
|
j = i;
|
|
for (;j < n; ++j)
|
|
{
|
|
InvalidInfoPair info = (InvalidInfoPair) mergeInfo.get(j);
|
|
|
|
// The components were already merged
|
|
if (info.c1.equals(info.c2))
|
|
{
|
|
info.c = info.c1;
|
|
}
|
|
else
|
|
{
|
|
System.out.println("Merging " + info.c1 + " and " + info.c2);
|
|
// Merge components
|
|
StringBuffer sb2 = new StringBuffer("INSERT INTO " + compRelName + " ");
|
|
sb2.append("SELECT '" + info.c + "',c1.hid,c1.wid || c2.wid,c1.Value FROM " + compRelName + " c1," + compRelName + " c2 ");
|
|
sb2.append("WHERE c1.cid = '" + info.c1 + "' AND c2.cid = '" + info.c2 +
|
|
"' AND c2.hid = '" + info.h2 + "'");
|
|
statement.addBatch(sb2.toString());
|
|
sb2.delete(0, sb2.length());
|
|
sb2.append("INSERT INTO " + compRelName + " ");
|
|
sb2.append("SELECT '" + info.c + "',c2.hid,c1.wid || c2.wid,c2.Value FROM " + compRelName + " c1," + compRelName + " c2 ");
|
|
sb2.append("WHERE c1.cid = '" + info.c1 + "' AND c2.cid = '" + info.c2 + "' AND c1.hid = '" + info.h1 + "'");
|
|
statement.addBatch(sb2.toString());
|
|
// Delete old component entries
|
|
statement.addBatch("DELETE FROM " + compRelName + " WHERE cid IN ('" + info.c1 + "','" + info.c2 + "')");
|
|
|
|
// Update mapping relation
|
|
statement.addBatch("UPDATE " + mappingRelName + " SET cid = '" + info.c
|
|
+ "' WHERE cid IN ('" + info.c1 + "','" + info.c2 + "')");
|
|
merged ++;
|
|
}
|
|
|
|
// Delete worlds not satisfying the dependency
|
|
if (j > i)
|
|
{
|
|
sb1.append(" OR ");
|
|
}
|
|
sb1.append(generateDelete(info));
|
|
}
|
|
|
|
// Perform merging of components
|
|
statement.executeBatch();
|
|
|
|
// Create table of invalid worlds
|
|
statement.clearBatch();
|
|
//System.out.println(sb1.toString());
|
|
statement.executeUpdate(sb1.toString());
|
|
|
|
String delete = "DELETE FROM " + compRelName
|
|
+ " WHERE oid IN (SELECT c.oid FROM Invalid NATURAL JOIN " + compRelName + " AS c);";
|
|
statement.executeUpdate(delete);
|
|
|
|
// Drop table of invalid worlds
|
|
statement.executeUpdate("DROP TABLE Invalid;");
|
|
|
|
i += (n - i);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Merges two given components into one and returns the name of the new component.
|
|
* @param statement The statement used to perform the updates.
|
|
* @param cid1 Name of the first component to merge.
|
|
* @param cid2 Name of the second component to merge.
|
|
* @param hid1 ID of a hole in the first component.
|
|
* @param hid2 ID of a hole in the second component.
|
|
* @return Name of the new component.
|
|
*/
|
|
private String mergeComponents(Statement statement, String cid1, String cid2, String hid1, String hid2)
|
|
throws SQLException
|
|
{
|
|
System.out.println("Merging " + cid1 + " and " + cid2);
|
|
// c1 and c2 were already merged or are the same component
|
|
if (cid1.indexOf(cid2) != -1 || cid2.indexOf(cid1) != -1)
|
|
{
|
|
System.out.println("Already merged!");
|
|
return cid1;
|
|
}
|
|
String comp = cid1 + "x" + cid2;
|
|
//System.out.println("done");
|
|
StringBuffer sb = new StringBuffer("INSERT INTO " + compRelName + " ");
|
|
sb.append("SELECT '" + comp + "',c1.hid,c1.wid || c2.wid,c1.Value FROM " + compRelName + " c1," + compRelName + " c2 ");
|
|
sb.append("WHERE c1.cid = '" + cid1 + "' AND c2.cid = '" + cid2 + "' AND c2.hid = '" + hid2 + "'");
|
|
statement.executeUpdate(sb.toString());
|
|
|
|
sb.delete(0, sb.length());
|
|
|
|
sb.append("INSERT INTO " + compRelName + " ");
|
|
sb.append("SELECT '" + comp + "',c2.hid,c1.wid || c2.wid,c2.Value FROM " + compRelName + " c1," + compRelName + " c2 ");
|
|
sb.append("WHERE c1.cid = '" + cid1 + "' AND c2.cid = '" + cid2 + "' AND c1.hid = '" + hid1 + "'");
|
|
statement.executeUpdate(sb.toString());
|
|
// Update mapping and components tables
|
|
//ArrayList<String> oldCompIDs = new ArrayList<String>();
|
|
ArrayList oldCompIDs = new ArrayList();
|
|
oldCompIDs.add(cid1);
|
|
oldCompIDs.add(cid2);
|
|
updateTables(statement, oldCompIDs, comp);
|
|
merged++;
|
|
return comp;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param terms
|
|
* @return
|
|
*/
|
|
private String constructStatement(ArrayList terms)
|
|
{
|
|
String result;
|
|
StringBuffer selClause = new StringBuffer("SELECT TID, ");
|
|
StringBuffer cond = new StringBuffer(" WHERE ");
|
|
|
|
for (int i = 0; i < terms.size(); ++i)
|
|
{
|
|
Term t = (Term) terms.get(i);
|
|
if (i > 0)
|
|
{
|
|
selClause.append(",");
|
|
cond.append(" AND ");
|
|
}
|
|
selClause.append(t.left);
|
|
cond.append("(" + t.left + " " + t.op + " " + t.right + " OR ");
|
|
cond.append("(" + t.left + " IS NULL AND EXISTS (");
|
|
cond.append(" SELECT '1' FROM " + mappingRelName + " f," + compRelName + " c ");
|
|
cond.append(" WHERE r.tid = f.tid AND f.col = '" + t.left + "' AND f.hid = c.hid");
|
|
cond.append(" AND c.value " + t.op + " " + t.right);
|
|
cond.append(")))");
|
|
}
|
|
|
|
result = selClause.toString() + " FROM " + templateRelName + " r " + cond;
|
|
return result;
|
|
}
|
|
|
|
public boolean chase(ArrayList aDependencies)
|
|
{
|
|
while(true)
|
|
{
|
|
for (int i = 0; i < aDependencies.size(); ++i)
|
|
{
|
|
Dependency d = (Dependency) aDependencies.get(i);
|
|
System.out.println("Chasing " + d.toString());
|
|
|
|
// Functional dependency
|
|
if (d.type == 0)
|
|
{
|
|
if (applyFD((FDependency) d) == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
// Equlaity-generating dependency
|
|
else if (d.type == 1)
|
|
{
|
|
if (applyEQD((EQDependency) d) == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
// TODO: Only break if nothing was changed in the last iteration
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the IDs of all component and for each component
|
|
* one of the holes defined in it.
|
|
* @param statement Statement used to perform the query.
|
|
* @return HashMap of (component ID, hole ID) pairs.
|
|
* @throws SQLException
|
|
*/
|
|
private HashMap getCompIDs(Statement statement) throws SQLException
|
|
{
|
|
HashMap result = new HashMap();
|
|
String sql = "SELECT cid,hid FROM " + mappingRelName + " WHERE Rel = '"
|
|
+ templateRelName + "';";
|
|
ResultSet rs = statement.executeQuery(sql);
|
|
while (rs.next())
|
|
{
|
|
result.put(rs.getString("cid"), rs.getString("hid"));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Encapsulates the information needed to delete invalid worlds, such as component ID,
|
|
* hole ID and a condition that should be fulfilled in all worlds.
|
|
* @author Lublena
|
|
*
|
|
*/
|
|
class InvalidInfo
|
|
{
|
|
public String cid;
|
|
public String hid;
|
|
public Term t;
|
|
|
|
public InvalidInfo(String aCid, String aHid, Term aTerm)
|
|
{
|
|
cid = aCid;
|
|
hid = aHid;
|
|
t = aTerm;
|
|
}
|
|
|
|
public InvalidInfo(Object aCid, Object aHid, Object aTerm)
|
|
{
|
|
cid = aCid.toString();
|
|
hid = aHid.toString();
|
|
t = (Term) aTerm;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Encapsulates the information needed to merge two components and
|
|
* delete invalid worlds with respect to a conjunctive formula of two conditions.
|
|
* @author Lublena
|
|
*/
|
|
class InvalidInfoPair
|
|
{
|
|
String c;
|
|
String c1;
|
|
String c2;
|
|
String h1;
|
|
String h2;
|
|
Term t1;
|
|
Term t2;
|
|
|
|
public InvalidInfoPair(String c, String c1, String c2, String h1, String h2, Term t1, Term t2)
|
|
{
|
|
this.c = c;
|
|
this.c1 = c1;
|
|
this.c2 = c2;
|
|
this.h1 = h1;
|
|
this.h2 = h2;
|
|
this.t1 = t1;
|
|
this.t2 = t2;
|
|
}
|
|
}
|
|
}
|