/*
* Database.java
* -------------
* $Id: Database.java,v 1.8 2000/11/17 05:53:49 chenli Exp $
*/
import java.util.*;
class Database {
HashSet tuples = null;
Database(HashSet tuples) {
this.tuples = tuples;
}
/**
* evaluates a query on the db and returns the results.
*/
public Relation execQuery(Query query) {
Relation sr = new Relation("sr");
for (int i = 0; i < query.getSubgoalNum(); i ++ ) {
Subgoal subgoal = query.getSubgoal(i);
// processes the subgoal on the db
Relation subgoalRel = processSubgoal(subgoal);
// process the join
sr = join(sr, subgoalRel, query.getName());
Vector usefulArgs = query.getUsefulArgs(i);
sr = sr.project(usefulArgs);
}
// set the query of the result, and compute the head of each tuple
sr.setQuery(query);
return sr;
}
/**
* processes one subgoal on a database
*/
Relation processSubgoal(Subgoal subgoal) {
String resName = subgoal.getName() + "_tmp";
// computes the schema
Vector resSchema = new Vector();
Vector subgoalSchema = subgoal.getArgs();
for (int i = 0; i < subgoalSchema.size(); i ++) {
Argument arg = (Argument) subgoalSchema.elementAt(i);
if (arg.isConst()) {
continue; // ignores constants
}
if (resSchema.contains(arg)) {
continue; // removes duplicates
}
resSchema.add(arg);
}
// finds tuples that can be unified with this subgoal
HashSet resTuples = new HashSet();
for (Iterator iter = tuples.iterator(); iter.hasNext();) {
Tuple tuple = (Tuple) iter.next();
if (!subgoal.getName().equals(tuple.getName()))
continue; // should have the same name
Vector tupleArgs = tuple.getArgs();
Vector subgoalArgs = subgoal.getArgs();
if (tupleArgs.size() != subgoalArgs.size())
UserLib.myerror("Database.processSubgoal(), wrong args!");
// tries to unify this subgoal with the tuple
Vector resTupleArgs = new Vector();
boolean unifiable = true;
Mapping phi = new Mapping();
for (int i = 0; i < subgoalArgs.size(); i ++) {
Argument tupleArg = (Argument) tupleArgs.elementAt(i);
Argument subgoalArg = (Argument) subgoalArgs.elementAt(i);
// cannot map a constant to a different constant
if (subgoalArg.isConst()) {
if (!subgoalArg.equals(tupleArg)) {
unifiable = false;
break;
}
else continue; // ignores constants in the final tuple
}
// the subgoalArg is a variable
Argument image = (Argument) phi.apply(subgoalArg);
if (image == null) { // not mapped. adds the pair
phi.put(subgoalArg, tupleArg);
resTupleArgs.add(tupleArg); // adds the first occurance to the tuple
continue;
}
if (image.equals(tupleArg)) continue;
unifiable = false; // mapped to a different value
break;
}
if (unifiable) {
HashMap mapSubgoals = new HashMap();
mapSubgoals.put(subgoal, tuple.getSubgoal()); // subgoal mapped
resTuples.add(new Tuple(subgoal.getName(),
resTupleArgs, phi, mapSubgoals));
}
}
return new Relation(resName, resSchema, resTuples);
}
/**
* processes the join of two relations
*/
Relation join(Relation rel1, Relation rel2, String resName) {
// returns the other relation if one relation's schema is empty
if (rel1.getAttrNum() == 0) return rel2;
if (rel2.getAttrNum() == 0) return rel1;
//System.out.println("rel1 = " + rel1 );
//System.out.println("rel2 = " + rel2 );
// computes the schema
Vector schema1 = (Vector) rel1.getSchema();
Vector schema2 = (Vector) rel2.getSchema();
Vector resSchema = new Vector();
for (int i = 0; i < schema1.size(); i ++) {
Argument arg = (Argument) schema1.elementAt(i);
// removes duplicates and useless args
if (!resSchema.contains(arg))
resSchema.add(arg);
}
for (int i = 0; i < schema2.size(); i ++) {
Argument arg = (Argument) schema2.elementAt(i);
// removes duplicates and useless args
if (!resSchema.contains(arg))
resSchema.add(arg);
}
// computes the tuples using a loop join
HashSet resTuples = new HashSet();
HashSet tuples1 = rel1.getTuples();
HashSet tuples2 = rel2.getTuples();
for (Iterator iter1 = tuples1.iterator(); iter1.hasNext();) {
Tuple tuple1 = (Tuple) iter1.next();
for (Iterator iter2 = tuples2.iterator(); iter2.hasNext();) {
Tuple tuple2 = (Tuple) iter2.next();
// joins two tuples
Tuple tuple = join(tuple1, schema1, tuple2, schema2, resName);
if (tuple != null) {
resTuples.add(tuple);
}
}
}
return new Relation(resName, resSchema, resTuples);
}
/**
* Joins two given tuples with their schemas,
*/
Tuple join(Tuple tuple1, Vector schema1,
Tuple tuple2, Vector schema2, String resName) {
Vector resTupleArgs = new Vector();
Vector tuple1Args = tuple1.getArgs();
Vector tuple2Args = tuple2.getArgs();
if (tuple1Args.size() != schema1.size() ||
tuple2Args.size() != schema2.size()) {
System.out.println("tuple1Args = " + tuple1Args +
"\nschema1 = " + schema1 +
"\ntuple2Args = " + tuple2Args +
"\nschema2 = " + schema2);
UserLib.myerror("Database.join(), wrong args!");
}
// processes tuple 1
for (int i = 0; i < schema1.size(); i ++) {
Argument argSchema = (Argument) schema1.elementAt(i);
Argument argValue = (Argument) tuple1Args.elementAt(i);
// checks if we have an equality comparison
int pos = schema2.indexOf(argSchema);
if (pos == -1) {
resTupleArgs.add(argValue);
continue;
}
// checks if the equality condition is satisfied
if (!argValue.equals((Argument)tuple2Args.elementAt(pos)))
return null;
resTupleArgs.add(argValue);
}
// processes tuple 2
for (int i = 0; i < schema2.size(); i ++) {
Argument argSchema = (Argument) schema2.elementAt(i);
Argument argValue = (Argument) tuple2Args.elementAt(i);
// checks if we have an equality comparison
int pos = schema1.indexOf(argSchema);
if (pos == -1) {
resTupleArgs.add(argValue);
continue;
}
// there is an equality comparison, double checks they are equal
if (!argValue.equals((Argument)tuple1Args.elementAt(pos)))
UserLib.myerror("Database.join(), wrong args!");
}
// union the two phi's
HashMap map1 = (HashMap) tuple1.getMapping().getMap();
HashMap map2 = (HashMap) tuple2.getMapping().getMap();
HashMap map = (HashMap) map1.clone();
map.putAll(map2);
Mapping phi = new Mapping(map);
// union the two mapSubgoals's
HashMap mapSubgoals1 = (HashMap) tuple1.getMapSubgoals();
HashMap mapSubgoals2 = (HashMap) tuple2.getMapSubgoals();
HashMap mapSubgoals = (HashMap) mapSubgoals1.clone();
mapSubgoals.putAll(mapSubgoals2);
return new Tuple(resName, resTupleArgs, phi, mapSubgoals);
}
public String toString() {
if (tuples == null)
return ("empty");
StringBuffer result = new StringBuffer();
for (Iterator iter = tuples.iterator(); iter.hasNext();) {
Tuple tuple = (Tuple) iter.next();
result.append(tuple.toString());
if (iter.hasNext())
result.append(", ");
}
return result.toString();
}
}