+ order independence in UNIONs
authorEric Prud'hommeaux <bertails@w3.org>
Fri, 01 Jan 2010 21:27:50 -0500
changeset 98 b9887a8a08cf
parent 97 bcaa2b088460
child 99 936f2f4836e2
+ order independence in UNIONs
src/main/scala/RDB2RDFMain.scala
src/test/scala/RDB2RDFTest.scala
--- a/src/main/scala/RDB2RDFMain.scala	Fri Jan 01 13:30:44 2010 -0500
+++ b/src/main/scala/RDB2RDFMain.scala	Fri Jan 01 21:27:50 2010 -0500
@@ -99,8 +99,7 @@
 	val constraint = RelationalExpressionEq(varToAttribute(state.varmap, v), RValueAttr(constrainMe))
 	R2RState(state.joins, state.varmap, 
 		 if (varToAttributeDisjoints(state.varmap, v).size > 0) {
-		   val s:Set[Expression] = varToAttributeDisjoints(state.varmap, v) map ((d) => ExprDisjunction(Set(d, constraint)))
-		   state.exprs ++ s
+		   state.exprs ++ {varToAttributeDisjoints(state.varmap, v) map ((d) => ExprDisjunction(Set(d, constraint)))}
 		 } else
 		   state.exprs + constraint
 	       )
@@ -320,21 +319,32 @@
 	    val varAliasAttr = RelAliasAttribute(unionAlias, Attribute(Name("A_" + v.s)))
 	    if (myState.varmap.contains(v)) {
 	      /* The variable has already been bound. */
-	      if (varToAttribute(myState.varmap, v) == varAliasAttr) {
+	      val newMap:Map[Var, SQL2RDFValueMapper] = if (varToAttribute(myState.varmap, v) == varAliasAttr) {
 		/* Same var was bound in an earlier disjoint. */
 		val oldDisjoints = varToAttributeDisjoints(myState.varmap, v)
 		// myState
-		val mapper:SQL2RDFValueMapper = disjointState.varmap(v) match {
+		Map(v -> { disjointState.varmap(v) match {
 		  case IntMapper(_, _)      => IntMapper(varAliasAttr, oldDisjoints + disjointCond)
 		  case StringMapper(_, _)   => StringMapper(varAliasAttr, oldDisjoints + disjointCond)
-		  case DateMapper(_, _)   => DateMapper(varAliasAttr, oldDisjoints + disjointCond)
+		  case DateMapper(_, _)     => DateMapper(varAliasAttr, oldDisjoints + disjointCond)
 		  case RDFNoder(rel, _, _)  => RDFNoder(rel, varAliasAttr, oldDisjoints + disjointCond)
 		  case RDFBNoder(rel, _, _) => RDFBNoder(rel, varAliasAttr, oldDisjoints + disjointCond)
+		} } )
+	      } else
+		Map()
+	      val newConstraints =
+		if (varToAttribute(outerState.varmap, v) != varAliasAttr) {
+		  /* Constraint against binding from earlier GP. */
+		  val constraint = RelationalExpressionEq(varToAttribute(outerState.varmap, v), RValueAttr(varAliasAttr))
+		  if (varToAttributeDisjoints(outerState.varmap, v).size > 0)
+		    // (union0._DISJOINT_ != 0 AND union1._DISJOINT_ != 2) OR union0.x=union1.x
+		    varToAttributeDisjoints(outerState.varmap, v) map ((d) => ExprDisjunction(Set(ExprConjunction(Set(d, disjointCond)), constraint)))
+		  else
+		    Set(ExprDisjunction(Set(disjointCond, constraint)))
+		} else {
+		  Set()
 		}
-		R2RState(myState.joins, myState.varmap + (v -> mapper), myState.exprs)
-	      } else
-		/* Constraint against the initial binding for this variable. */
-		R2RState(myState.joins, myState.varmap, myState.exprs + RelationalExpressionEq(varToAttribute(myState.varmap, v), RValueAttr(varAliasAttr)))
+	      R2RState(myState.joins, myState.varmap ++ newMap, myState.exprs ++ newConstraints)
 	    } else {
 	      /* This variable is new to the outer context. */
 	      val mapper:SQL2RDFValueMapper = disjointState.varmap(v) match {
--- a/src/test/scala/RDB2RDFTest.scala	Fri Jan 01 13:30:44 2010 -0500
+++ b/src/test/scala/RDB2RDFTest.scala	Fri Jan 01 21:27:50 2010 -0500
@@ -268,7 +268,9 @@
           WHERE R_below.manages=R_managed.id AND R_managed.lastName IS NOT NULL
                 AND R_below.manager IS NOT NULL AND R_below.id IS NOT NULL AND R_below.manages IS NOT NULL
        ) AS R_union1
- WHERE R_who.id=R_union1.A_who AND R_who.lastName="Smith" AND R_who.id IS NOT NULL
+ WHERE R_who.lastName="Smith" AND R_who.id IS NOT NULL AND
+       (R_union1._DISJOINT_!=0 OR R_who.id=R_union1.A_who) AND
+       (R_union1._DISJOINT_!=1 OR R_who.id=R_union1.A_who)
 """).get
     assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
   }
@@ -318,4 +320,100 @@
 """).get
     assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
   }
+
+  test("transform assymDisj1 reversed") {
+    val sparqlParser = Sparql()
+    val sparqlSelect = sparqlParser.parseAll(sparqlParser.select, """
+PREFIX empP : <http://hr.example/DB/Employee#>
+PREFIX manP : <http://hr.example/DB/Manage#>
+PREFIX xsd : <http://www.w3.org/2001/XMLSchema#>
+SELECT ?name
+       {
+         ?who empP:lastName "Smith"^^xsd:string .
+         ?who empP:birthday ?bday
+         { ?above   manP:manages ?who .
+           ?above   manP:manager ?manager .
+           ?manager empP:lastName  ?name }
+         UNION
+         { ?below   manP:manager ?who .
+           ?below   manP:manages ?managed .
+           ?managed empP:lastName  ?name .
+           ?managed empP:birthday  ?bday } 
+       }
+""").get
+    val sqlParser = Sql()
+    val sqlSelect = sqlParser.parseAll(sqlParser.select, """
+SELECT R_union1.A_name AS A_name
+  FROM Employee AS R_who
+       INNER JOIN ( SELECT 0 AS _DISJOINT_, R_above.manager AS A_manager, R_manager.lastName AS A_name, R_above.id AS A_above, 
+                NULL AS A_below, NULL AS A_bday, R_above.manages AS A_who, NULL AS A_managed
+                FROM Manage AS R_above
+                INNER JOIN Employee AS R_manager
+          WHERE R_above.manager IS NOT NULL AND R_above.manager=R_manager.id AND R_above.id IS NOT NULL
+                AND R_above.manages IS NOT NULL AND R_manager.lastName IS NOT NULL
+       UNION
+         SELECT 1 AS _DISJOINT_, NULL AS A_manager, R_managed.lastName AS A_name, NULL AS A_above, 
+                R_below.id AS A_below, R_managed.birthday AS A_bday, R_below.manager AS A_who, R_below.manages AS A_managed
+                FROM Manage AS R_below
+                INNER JOIN Employee AS R_managed
+          WHERE R_managed.birthday IS NOT NULL AND R_below.manager IS NOT NULL AND R_below.id IS NOT NULL
+                AND R_below.manages=R_managed.id AND R_below.manages IS NOT NULL AND R_managed.lastName IS NOT NULL
+       ) AS R_union1
+ WHERE R_who.lastName="Smith" AND
+       (R_union1._DISJOINT_!=0 OR R_who.id=R_union1.A_who) AND
+       (R_union1._DISJOINT_!=1 OR R_who.id=R_union1.A_who) AND
+       (R_union1._DISJOINT_!=1 OR R_who.birthday=R_union1.A_bday) AND
+       R_who.id IS NOT NULL AND
+       R_who.birthday IS NOT NULL
+""").get
+    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
+  }
+
+  test("transform assymDisj1 interspersed") {
+    val sparqlParser = Sparql()
+    val sparqlSelect = sparqlParser.parseAll(sparqlParser.select, """
+PREFIX empP : <http://hr.example/DB/Employee#>
+PREFIX manP : <http://hr.example/DB/Manage#>
+PREFIX xsd : <http://www.w3.org/2001/XMLSchema#>
+SELECT ?name
+       {
+         ?who empP:lastName "Smith"^^xsd:string
+         { ?above   manP:manages ?who .
+           ?above   manP:manager ?manager .
+           ?manager empP:lastName  ?name }
+         UNION
+         { ?below   manP:manager ?who .
+           ?below   manP:manages ?managed .
+           ?managed empP:lastName  ?name .
+           ?managed empP:birthday  ?bday } 
+         ?who empP:birthday ?bday
+       }
+""").get
+    val sqlParser = Sql()
+    val sqlSelect = sqlParser.parseAll(sqlParser.select, """
+SELECT R_union1.A_name AS A_name
+  FROM Employee AS R_who
+       INNER JOIN ( SELECT 0 AS _DISJOINT_, R_above.manager AS A_manager, R_manager.lastName AS A_name, R_above.id AS A_above, 
+                NULL AS A_below, NULL AS A_bday, R_above.manages AS A_who, NULL AS A_managed
+                FROM Manage AS R_above
+                INNER JOIN Employee AS R_manager
+          WHERE R_above.manager IS NOT NULL AND R_above.manager=R_manager.id AND R_above.id IS NOT NULL
+                AND R_above.manages IS NOT NULL AND R_manager.lastName IS NOT NULL
+       UNION
+         SELECT 1 AS _DISJOINT_, NULL AS A_manager, R_managed.lastName AS A_name, NULL AS A_above, 
+                R_below.id AS A_below, R_managed.birthday AS A_bday, R_below.manager AS A_who, R_below.manages AS A_managed
+                FROM Manage AS R_below
+                INNER JOIN Employee AS R_managed
+          WHERE R_managed.birthday IS NOT NULL AND R_below.manager IS NOT NULL AND R_below.id IS NOT NULL
+                AND R_below.manages=R_managed.id AND R_below.manages IS NOT NULL AND R_managed.lastName IS NOT NULL
+       ) AS R_union1
+ WHERE R_who.lastName="Smith" AND
+       (R_union1._DISJOINT_!=0 OR R_who.id=R_union1.A_who) AND
+       (R_union1._DISJOINT_!=1 OR R_who.id=R_union1.A_who) AND
+       (R_union1._DISJOINT_!=1 OR R_union1.A_bday=R_who.birthday) AND
+       R_who.id IS NOT NULL AND
+       R_union1.A_bday IS NOT NULL
+""").get
+    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
+  }
 }