--- a/src/main/scala/SQL.scala Fri Oct 15 11:23:10 2010 -0400
+++ b/src/main/scala/SQL.scala Fri Oct 15 12:21:49 2010 -0400
@@ -257,7 +257,7 @@
sealed abstract class ValueDescription
case class Value(datatype:Datatype) extends ValueDescription
-case class ForeignKey(rel:RDB.RelName, attr:RDB.AttrName) extends ValueDescription
+case class ForeignKey(rel:RDB.RelName, attr:RDB.CandidateKey) extends ValueDescription
case class DatabaseDesc(relationdescs:Map[RDB.RelName,RelationDesc])
object DatabaseDesc {
@@ -265,12 +265,12 @@
DatabaseDesc(rs.map{r => (r.name -> r)}.toMap)
}
// case class Relation (name:RDB.RelName, header:RDB.Header, body:List[RDB.Tuple], candidates:List[RDB.CandidateKey], pk:Option[RDB.CandidateKey], fks:RDB.ForeignKeys)
-case class RelationDesc(name:RDB.RelName, attributes:Map[RDB.AttrName, ValueDescription], body:List[RDB.Tuple], candidates:List[RDB.CandidateKey], pk:Option[RDB.AttrName])
+case class RelationDesc(name:RDB.RelName, attributes:Map[RDB.AttrName, ValueDescription], body:List[RDB.Tuple], candidates:List[RDB.CandidateKey], pk:Option[RDB.CandidateKey])
sealed abstract class FieldDescOrKeyDeclaration
case class FieldDesc(attr:RDB.AttrName, value:Value, pkness:Boolean) extends FieldDescOrKeyDeclaration
sealed abstract class KeyDeclaration extends FieldDescOrKeyDeclaration
-case class PrimaryKeyDeclaration(attr:RDB.AttrName) extends KeyDeclaration
-case class ForeignKeyDeclaration(fk:RDB.AttrName, rel:RDB.RelName, pk:RDB.AttrName) extends KeyDeclaration
+case class PrimaryKeyDeclaration(key:RDB.CandidateKey) extends KeyDeclaration
+case class ForeignKeyDeclaration(fk:List[RDB.AttrName], rel:RDB.RelName, pk:RDB.CandidateKey) extends KeyDeclaration
case class View(rel:RDB.RelName, defn:SelectORUnion) { // sibling of RelationDesc
override def toString = "CREATE VIEW " + rel + " AS\n" + defn
}
@@ -294,10 +294,10 @@
"CREATE" ~ "TABLE" ~ relation ~ "(" ~ rep1sep(fielddescorkeydef, ",") ~ ")" ^^
{
case "CREATE"~"TABLE"~relation~"("~reldesc~")" => {
- val pk0:Option[RDB.AttrName] = None
+ val pk0:Option[RDB.CandidateKey] = None
val attrs0 = Map[RDB.AttrName, ValueDescription]()
val candidates0 = List[RDB.CandidateKey]()
- val fks0 = Map[RDB.AttrName, ForeignKey]()
+ val fks0 = Map[List[RDB.AttrName], ForeignKey]()
/* <pk>: (most recently parsed) PRIMARY KEY
* <attrs>: map of attribute to type (e.g. INTEGER)
* <fks>: map holding FOREIGN KEY relation REFERENCES attr
@@ -308,13 +308,13 @@
rd match {
case FieldDesc(attr, value, pkness) => {
val (pkNew, candNew) =
- if (pkness) (Some(attr), candidates ++ List(RDB.CandidateKey(attr.n)))
+ if (pkness) (Some(RDB.CandidateKey(List(attr))), candidates ++ List(RDB.CandidateKey(attr.n)))
else (pkopt, candidates)
(pkNew, attrs + (attr -> value), candNew, fks)
}
- case PrimaryKeyDeclaration(attr) =>
+ case PrimaryKeyDeclaration(key) =>
// @@ why doesn't [[ candidates + RDB.CandidateKey(attr.n) ]] work?
- (Some(attr), attrs, candidates ++ List(RDB.CandidateKey(attr.n)), fks)
+ (Some(key), attrs, candidates ++ List(RDB.CandidateKey(key map {attr => RDB.AttrName(attr.n)})), fks)
case ForeignKeyDeclaration(fk, rel, pk) =>
(pkopt, attrs, candidates, fks + (fk -> ForeignKey(rel, pk)))
}
@@ -324,7 +324,8 @@
*/
val attrs2 = attrs.map(x => {
val (attr:RDB.AttrName, value:Value) = x
- if (fks.contains(attr)) (attr -> fks(attr))
+ val asKey = RDB.CandidateKey(List(attr))
+ if (fks.contains(asKey)) (attr -> fks(asKey))
else (attr -> value)
})
val rd = RelationDesc(relation, attrs2, List(), candidates, pk)
@@ -335,10 +336,10 @@
def fielddescorkeydef:Parser[FieldDescOrKeyDeclaration] = (
attribute ~ typpe ~ opt("PRIMARY" ~ "KEY") ^^
{ case attribute~typpe~pkness => FieldDesc(attribute, typpe, pkness.isDefined) }
- | "PRIMARY" ~ "KEY" ~ "(" ~ attribute ~ ")" ^^
- { case "PRIMARY"~"KEY"~"("~attribute~")" => PrimaryKeyDeclaration(attribute) }
- | "FOREIGN" ~ "KEY" ~ "(" ~ attribute ~ ")" ~ "REFERENCES" ~ relation ~ "(" ~ attribute ~ ")" ^^
- { case "FOREIGN"~"KEY"~"("~fk~")"~"REFERENCES"~relation~"("~pk~")" => ForeignKeyDeclaration(fk, relation, pk) }
+ | "PRIMARY" ~ "KEY" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
+ { case "PRIMARY"~"KEY"~"("~attributes~")" => PrimaryKeyDeclaration(RDB.CandidateKey(attributes)) }
+ | "FOREIGN" ~ "KEY" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ~ "REFERENCES" ~ relation ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
+ { case "FOREIGN"~"KEY"~"("~fk~")"~"REFERENCES"~relation~"("~pk~")" => ForeignKeyDeclaration(fk, relation, RDB.CandidateKey(pk)) }
)
def typpe:Parser[Value] = (
--- a/src/main/scala/SparqlToSql.scala Fri Oct 15 11:23:10 2010 -0400
+++ b/src/main/scala/SparqlToSql.scala Fri Oct 15 12:21:49 2010 -0400
@@ -289,7 +289,7 @@
*/
val binding = reldesc.pk match {
/** <pre>varConstraint(R_emp, Some(empid), VarAssignable(?emp), Employee) -> RDFNoder(Employee,FullBinding(R_emp.empid))</pre> */
- case Some(sql.RDB.AttrName(constrainMe.attribute.n)) => RDFNoder(rel, boundTo)
+ case Some(sql.RDB.CandidateKey(List(sql.RDB.AttrName(constrainMe.attribute.n)))) => RDFNoder(rel, boundTo)
case _ => {
if (reldesc.attributes.contains(constrainMe.attribute)) {
@@ -357,6 +357,12 @@
// }
// }
+ def __optFirst (k:Option[sql.RDB.CandidateKey]):Option[sql.RDB.AttrName] =
+ k match {
+ case Some(ck) => Some(ck.attrs(0))
+ case _ => None
+ }
+
/**
* map a given triple to one or two joined tables, variable
* @param db database description
@@ -390,11 +396,11 @@
val state_postSubj = s match {
case sparql.TermUri(u) =>
/** additional constraint, e.g. R_empid18.empid=18. */
- uriConstraint(stateP, sql.RelVarAttr(relvar, db.relationdescs(rel).pk.get), parseObjectURI(u))
+ uriConstraint(stateP, sql.RelVarAttr(relvar, db.relationdescs(rel).pk.get.attrs(0)), parseObjectURI(u)) // !! (0)
case sparql.TermVar(v) =>
/** assignable binding for novel vars, new constraint for previously bound vars. */
try {
- varConstraint(stateP, relvar, db.relationdescs(rel).pk, sparql.VarAssignable(v), db, rel)
+ varConstraint(stateP, relvar, __optFirst(db.relationdescs(rel).pk), sparql.VarAssignable(v), db, rel) // !! (0)
} catch {
case e:java.util.NoSuchElementException =>
/** Tell user that the relation.attribute encoded in the subject was not found in the database description. */
@@ -403,7 +409,7 @@
case sparql.TermBNode(b) =>
/** assignable binding for novel bnodes, new constraint for previously bound bnodes. */
try {
- varConstraint(stateP, relvar, db.relationdescs(rel).pk, sparql.BNodeAssignable(b), db, rel)
+ varConstraint(stateP, relvar, __optFirst(db.relationdescs(rel).pk), sparql.BNodeAssignable(b), db, rel) // !! (0)
} catch {
case e:java.util.NoSuchElementException =>
throw new Exception("error processing { " + s + " " + p + " " + o + " } :db.relationdescs(" + rel + ") not found in " + db)
@@ -427,17 +433,17 @@
*/
val (targetattr:sql.RelVarAttr, targetrel, dt, state_fkeys:R2RState) = db.relationdescs(rel).attributes(attr) match {
case sql.ForeignKey(fkrel, fkattr) => {
- try { db.relationdescs(fkrel).attributes(fkattr) } catch {
+ try { db.relationdescs(fkrel).attributes(fkattr.attrs(0)) } catch { // !! (0)
/** Foreign key relation.attribute was not found in the database description. */
case e:java.util.NoSuchElementException =>
throw new Exception("db.relationdescs(" + fkrel + ").attributes(" + fkattr + ") not found in " + db)
}
- val fkdt = db.relationdescs(fkrel).attributes(fkattr) match {
+ val fkdt = db.relationdescs(fkrel).attributes(fkattr.attrs(0)) match { // !! (0)
/** Foreign key to something which is a foreign key. May have use
* cases, but signal error until we figure out that they are. */
case sql.ForeignKey(dfkrel, dfkattr) => error("foreign key " + rel.n + "." + attr.n +
- "->" + fkrel.n + "." + fkattr.n +
- "->" + dfkrel.n + "." + dfkattr.n)
+ "->" + fkrel.n + "." + fkattr.attrs(0).n + // !! (0)
+ "->" + dfkrel.n + "." + dfkattr.attrs(0).n) // !! (0)
case sql.Value(x) => x
}
if (enforceForeignKeys) {
@@ -449,7 +455,7 @@
* and bind targetattr:R_who.empid. targetrel:Employee .
*/
val oRelVar = relVarFromTerm(o)
- val fkaliasattr = sql.RelVarAttr(oRelVar, fkattr)
+ val fkaliasattr = sql.RelVarAttr(oRelVar, fkattr.attrs(0)) // !! (0)
val state_t = R2RState(state_subjJoin.joins + sql.InnerJoin(sql.AliasedResource(fkrel,oRelVar), None),
state_subjJoin.varmap,
state_subjJoin.exprs + sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(fkaliasattr),
--- a/src/test/scala/SQLTest.scala Fri Oct 15 11:23:10 2010 -0400
+++ b/src/test/scala/SQLTest.scala Fri Oct 15 12:21:49 2010 -0400
@@ -436,7 +436,7 @@
Map(RDB.AttrName("ID") -> Value(Datatype.INTEGER)),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID"))))
+ Option(RDB.CandidateKey("ID"))))
assert(expected === (a.parseAll(a.ddl, e).get))
}
@@ -452,7 +452,7 @@
RDB.AttrName("EnterpriseEntryID") -> Value(Datatype.INTEGER)),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID"))))
+ Option(RDB.CandidateKey("ID"))))
assert(expected === (a.parseAll(a.ddl, e).get))
}
@@ -468,7 +468,7 @@
RDB.AttrName("EnterpriseEntryID") -> Value(Datatype.INTEGER)),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID"))))
+ Option(RDB.CandidateKey("ID"))))
assert(expected === (a.parseAll(a.ddl, e).get))
}
@@ -484,16 +484,16 @@
Map(RDB.AttrName("ID") -> Value(Datatype.INTEGER),
RDB.AttrName("MiddleName") -> Value(Datatype.STRING),
RDB.AttrName("DateOfBirth") -> Value(Datatype.DATE),
- RDB.AttrName("SexDE") -> ForeignKey(RDB.RelName("Sex_DE"), RDB.AttrName("ID"))),
+ RDB.AttrName("SexDE") -> ForeignKey(RDB.RelName("Sex_DE"), RDB.CandidateKey("ID"))),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID"))),
+ Option(RDB.CandidateKey("ID"))),
RelationDesc("Sex_DE",
Map(RDB.AttrName("ID") -> Value(Datatype.INTEGER),
RDB.AttrName("EntryName") -> Value(Datatype.STRING)),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID")))
+ Option(RDB.CandidateKey("ID")))
)
assert(expected === (a.parseAll(a.ddl, e).get))
}
@@ -513,44 +513,44 @@
Map(RDB.AttrName("ID") -> Value(Datatype.INTEGER),
RDB.AttrName("MiddleName") -> Value(Datatype.STRING),
RDB.AttrName("DateOfBirth") -> Value(Datatype.DATE),
- RDB.AttrName("SexDE") -> ForeignKey(RDB.RelName("Sex_DE"), RDB.AttrName("ID"))),
+ RDB.AttrName("SexDE") -> ForeignKey(RDB.RelName("Sex_DE"), RDB.CandidateKey("ID"))),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID"))),
+ Option(RDB.CandidateKey("ID"))),
RelationDesc("Sex_DE",
Map(RDB.AttrName("ID") -> Value(Datatype.INTEGER),
RDB.AttrName("EntryName") -> Value(Datatype.STRING)),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID"))),
+ Option(RDB.CandidateKey("ID"))),
RelationDesc("Item_Medication",
Map(RDB.AttrName("ID") -> Value(Datatype.INTEGER),
- RDB.AttrName("PatientID") -> ForeignKey(RDB.RelName("Person"), RDB.AttrName("ID")),
+ RDB.AttrName("PatientID") -> ForeignKey(RDB.RelName("Person"), RDB.CandidateKey("ID")),
RDB.AttrName("PerformedDTTM") -> Value(Datatype.DATE),
RDB.AttrName("EntryName") -> Value(Datatype.STRING)),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID"))),
+ Option(RDB.CandidateKey("ID"))),
RelationDesc("Medication",
Map(RDB.AttrName("ID") -> Value(Datatype.INTEGER),
- RDB.AttrName("ItemID") -> ForeignKey(RDB.RelName("Item_Medication"), RDB.AttrName("ID")),
- RDB.AttrName("MedDictDE") -> ForeignKey(RDB.RelName("Medication_DE"), RDB.AttrName("ID"))),
+ RDB.AttrName("ItemID") -> ForeignKey(RDB.RelName("Item_Medication"), RDB.CandidateKey("ID")),
+ RDB.AttrName("MedDictDE") -> ForeignKey(RDB.RelName("Medication_DE"), RDB.CandidateKey("ID"))),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID"))),
+ Option(RDB.CandidateKey("ID"))),
RelationDesc("Medication_DE",
Map(RDB.AttrName("ID") -> Value(Datatype.INTEGER),
RDB.AttrName("NDC") -> Value(Datatype.INTEGER)),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID"))),
+ Option(RDB.CandidateKey("ID"))),
RelationDesc("NDCcodes",
Map(RDB.AttrName("ID") -> Value(Datatype.INTEGER),
RDB.AttrName("NDC") -> Value(Datatype.INTEGER),
RDB.AttrName("ingredient") -> Value(Datatype.INTEGER)),
List(),
List(RDB.CandidateKey("ID")),
- Option(RDB.AttrName("ID")))
+ Option(RDB.CandidateKey("ID")))
)
assert(expected === (a.parseAll(a.ddl, e).get))
}