bts'd and -inConstraint
authorEric Prud'hommeaux <bertails@w3.org>
Thu, 17 Dec 2009 00:37:34 -0500
changeset 62 20b9e4d32f80
parent 61 b23f130e0024
child 63 8c92eb94d64f
bts'd and -inConstraint
src/main/scala/RDB2RDFMain.scala
src/test/scala/RDB2RDFTest.scala
--- a/src/main/scala/RDB2RDFMain.scala	Wed Dec 16 19:26:42 2009 -0500
+++ b/src/main/scala/RDB2RDFMain.scala	Thu Dec 17 00:37:34 2009 -0500
@@ -13,7 +13,7 @@
 case class Enum(relaliasattr:RelAliasAttribute) extends Binding
 
 object RDB2RDF {
-  case class R2RState(allVars:Set[Var], inConstraint:Set[Var], joins:Set[AliasedResource], varmap:Map[Var, SQL2RDFValueMapper], exprs:Set[PrimaryExpression])
+  case class R2RState(joins:Set[AliasedResource], varmap:Map[Var, SQL2RDFValueMapper], exprs:Set[PrimaryExpression])
 
   sealed abstract class SQL2RDFValueMapper(relaliasattr:RelAliasAttribute)
   case class StringMapper(relaliasattr:RelAliasAttribute) extends SQL2RDFValueMapper(relaliasattr)
@@ -113,9 +113,10 @@
   }
 
   def acc(db:DatabaseDesc, state:R2RState, triple:TriplePattern, pk:PrimaryKey):R2RState = {
-    var R2RState(allVars, inConstraint, joins, varmap, exprs) = state
+    var R2RState(joins, varmap, exprs) = state
     val TriplePattern(s, p, o) = triple
     p match {
+      case PVar(v) => error("variable predicates require tedious enumeration; too tedious for me.")
       case PUri(stem, spRel, spAttr) => {
 	val rel = Relation(Name(spRel.s))
 	val attr = Attribute(Name(spAttr.s))
@@ -133,7 +134,7 @@
 	}
 	joins += AliasedResource(rel,relalias)
 
-	val target = db.relationdescs(rel).attributes(attr) match {
+	db.relationdescs(rel).attributes(attr) match {
 	  case ForeignKey(fkrel, fkattr) => {
 	    val oRelAlias = relAliasFromO(o)
 	    val fkaliasattr = RelAliasAttribute(oRelAlias, fkattr)
@@ -164,7 +165,6 @@
 	      case OLit(l) => exprs += literalConstraint(objattr, l, dt)
 	      case OUri(u) => exprs += uriConstraint(objattr, u)
 	      case OVar(v) => {
-		allVars += v
 		// !! 2nd+ ref implies constraint
 		val binding = varConstraint(objattr, v, db, rel)
 		varmap += v -> binding
@@ -173,9 +173,22 @@
 	  }
 	}
       }
-      case PVar(v) => error("variable predicates require tedious enumeration; too tedious for me.")
+
     }
-    R2RState(allVars, inConstraint, joins, varmap, exprs)
+    R2RState(joins, varmap, exprs)
+  }
+
+  def findVars(triple:TriplePattern):Set[Var] = {
+    val TriplePattern(s, p, o) = triple
+    val varS:Set[Var] = s match {
+      case SVar(v) => Set(v)
+      case _       => Set()
+    }
+    val varO:Set[Var] = o match {
+      case OVar(v) => Set(v)
+      case _       => Set()
+    }
+    varS ++ varO
   }
 
   def varToAttribute(varmap:Map[Var, SQL2RDFValueMapper], vvar:Var):RelAliasAttribute = {
@@ -186,11 +199,8 @@
     }
   }
 
-  def filter(exprsP:Set[PrimaryExpression], inConstraintP:Set[Var], varmap:Map[Var, SQL2RDFValueMapper], f:SparqlPrimaryExpression):Tuple2[Set[PrimaryExpression], Set[Var]] = {
+  def filter(exprsP:Set[PrimaryExpression], varmap:Map[Var, SQL2RDFValueMapper], f:SparqlPrimaryExpression):Set[PrimaryExpression] = {
     var exprs = exprsP
-    var inConstraint = inConstraintP
-    // var f = SparqlPrimaryExpressionEq
-    // val e:SparqlPrimaryExpression = f(SparqlTermExpression(Term(TermVar(Var("a")))), SparqlTermExpression(Term(TermVar(Var("a")))))
     val tup:Tuple3[Term, Term, String] = f match {
       case SparqlPrimaryExpressionEq(l, r) => (l.term, r.term, "==")
       case SparqlPrimaryExpressionLt(l, r) => (l.term, r.term, "<")
@@ -198,12 +208,10 @@
     tup._1 match {
       case TermUri(obj) => error("only SPARQL PrimaryExpressions with a variable on the left have been implemented: punting on " + f)
       case TermVar(v) => { // :Var
-	inConstraint += v
 	val l = varToAttribute(varmap, v)
 	val r = tup._2 match {
 	  case TermUri(obj) => null // :ObjUri
 	  case TermVar(v) => { // :Var
-	    inConstraint += v
 	    RValueAttr(varToAttribute(varmap, v))
 	  }
 	  case TermLit(lit) => null // :SparqlLiteral => RValueTyped(SQLDatatype, lit.n)
@@ -212,27 +220,21 @@
 	  case "==" => exprs += PrimaryExpressionEq(l, r)
 	  case _ => exprs += PrimaryExpressionLt(l, r)
 	}
-	(exprs, inConstraint)
+	exprs
       }
       case TermLit(lit) => error("only SPARQL PrimaryExpressions with a variable on the left have been implemented: punting on " + f)
     } 
   }
 
-  def nullGuard(exprs:Set[PrimaryExpression], inConstraint:Set[Var], varmap:Map[Var, SQL2RDFValueMapper], vvar:Var):Set[PrimaryExpression] = {
+  def nullGuard(exprs:Set[PrimaryExpression], varmap:Map[Var, SQL2RDFValueMapper], vvar:Var):Set[PrimaryExpression] = {
     var ret = exprs
-    inConstraint contains(vvar) match {
-      case false => {
-	val mapper:SQL2RDFValueMapper = varmap(vvar)
-	val aattr = mapper match {
-	  case StringMapper(relalias) => relalias
-	  case IntMapper(relalias) => relalias
-	  case RDFNoder(relation, relalias) => relalias
-	}
-	ret += PrimaryExpressionNotNull(aattr)
-      }
-      case true => 
+    val mapper:SQL2RDFValueMapper = varmap(vvar)
+    val aattr = mapper match {
+      case StringMapper(relalias) => relalias
+      case IntMapper(relalias) => relalias
+      case RDFNoder(relation, relalias) => relalias
     }
-    ret
+    ret + PrimaryExpressionNotNull(aattr)
   }
 
   def apply (db:DatabaseDesc, sparql:SparqlSelect, stem:StemURI, pk:PrimaryKey) : Select = {
@@ -240,8 +242,6 @@
 
     /* Create an object to hold our compilation state. */
     var r2rState = R2RState(
-      Set[Var](), 
-      Set[Var](), 
       Set[AliasedResource](), 
       Map[Var, SQL2RDFValueMapper](), 
       Set[PrimaryExpression]()
@@ -257,25 +257,22 @@
       NamedAttribute(varToAttribute(r2rState.varmap, vvar), AttrAlias(Name("A_" + vvar.s)))
     )
 
-    var exprs:Set[PrimaryExpression] = r2rState.exprs
-    var inConstraint:Set[Var] = r2rState.inConstraint
-
     /* Add constraints for all the FILTERS */
-    triples.filter.conjuncts.foreach(f => {
-	val pair = filter(exprs, inConstraint, r2rState.varmap, f)
-	exprs = pair._1
-	inConstraint = pair._2
-      })
 
-    /* Add null guards for attributes associated with variables which
-     * are not optional and have not been used in constraints. */
-    r2rState.allVars.foreach(s => exprs = nullGuard(exprs, inConstraint, r2rState.varmap, s))
+    def it(exprs:Set[PrimaryExpression], primaryExpr:SparqlPrimaryExpression) = {
+      filter(exprs, r2rState.varmap, primaryExpr)
+    }
+
+    val exprs = triples.filter.conjuncts.foldLeft(r2rState.exprs)(it(_, _))
+
+    val allVars:Set[Var] = triples.triplepatterns.foldLeft(Set[Var]())((x, y) => x ++ findVars(y))
+    val exprWithNull = allVars.foldLeft(exprs)((exprs,s) => nullGuard(exprs, r2rState.varmap, s))
 
     /* Construct the generated query as an abstract syntax. */
     Select(
       AttributeList(attrlist),
       TableList(r2rState.joins),
-      Expression(exprs)
+      Expression(exprWithNull)
     )
   }
 }
--- a/src/test/scala/RDB2RDFTest.scala	Wed Dec 16 19:26:42 2009 -0500
+++ b/src/test/scala/RDB2RDFTest.scala	Thu Dec 17 00:37:34 2009 -0500
@@ -43,7 +43,7 @@
 SELECT R_emp.id AS A_emp
        FROM Employee AS R_emp
             INNER JOIN Employee AS R_id18
- WHERE R_id18.id=R_emp.manager AND R_id18.id=18
+ WHERE R_id18.id=R_emp.manager AND R_id18.id=18 AND R_emp.id IS NOT NULL
 """).get
     assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id")))) === sqlSelect)
     true
@@ -63,7 +63,7 @@
 SELECT R_emp.id AS A_emp
        FROM Employee AS R_emp
             INNER JOIN Employee AS R_18
- WHERE R_18.id=R_emp.manager AND R_18.id=18
+ WHERE R_18.id=R_emp.manager AND R_18.id=18 AND R_emp.id IS NOT NULL
 """).get
     assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id")))) === sqlSelect)
     true
@@ -84,6 +84,8 @@
        FROM Employee AS R_emp
             INNER JOIN Employee AS R_manager
  WHERE R_manager.id=R_emp.manager AND R_emp.lastName IS NOT NULL AND R_manager.lastName IS NOT NULL
+ AND R_emp.id IS NOT NULL
+ AND R_manager.id IS NOT NULL
 """).get
     assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id")))) === sqlSelect)
   }
@@ -102,6 +104,7 @@
        FROM Employee AS R_emp
             INNER JOIN Employee AS R_id18
  WHERE R_id18.id=R_emp.manager AND R_id18.id=18 AND R_emp.lastName IS NOT NULL
+ AND R_emp.id IS NOT NULL
 """).get
     assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id")))) === sqlSelect)
   }
@@ -122,6 +125,8 @@
   FROM Employee AS R_emp
        INNER JOIN Employee AS R_manager
 WHERE R_manager.id=R_emp.manager AND R_manager.lastName="Johnson" AND R_emp.lastName IS NOT NULL
+ AND R_emp.id IS NOT NULL
+ AND R_manager.id IS NOT NULL
 """).get
     assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id")))) === sqlSelect)
   }
@@ -151,6 +156,14 @@
        INNER JOIN Manage AS R_upper
        INNER JOIN Employee AS R_grandManager
  WHERE R_emp.id=R_lower.manages AND R_manager.id=R_lower.manager AND R_manager.id=R_upper.manages AND R_grandManager.id=R_upper.manager AND R_manager.birthday < R_emp.birthday AND R_grandManager.birthday < R_manager.birthday AND R_emp.lastName IS NOT NULL AND R_grandManager.lastName IS NOT NULL
+ AND R_emp.id IS NOT NULL
+ AND R_lower.id IS NOT NULL
+ AND R_manager.id IS NOT NULL
+ AND R_upper.id IS NOT NULL
+ AND R_grandManager.id IS NOT NULL
+ AND R_emp.birthday IS NOT NULL
+ AND R_manager.birthday IS NOT NULL
+ AND R_grandManager.birthday IS NOT NULL
 """).get
     assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id")))) === sqlSelect)
   }