+ comments
authorEric Prud'hommeaux <eric@w3.org>
Thu, 07 Jan 2010 12:32:15 -0500
changeset 121 c6a81ce5cfd6
parent 120 284c037d1728
child 122 48ae3a0f8a21
+ comments
src/main/scala/RDB2RDFMain.scala
--- a/src/main/scala/RDB2RDFMain.scala	Thu Jan 07 11:09:08 2010 -0500
+++ b/src/main/scala/RDB2RDFMain.scala	Thu Jan 07 12:32:15 2010 -0500
@@ -1,3 +1,12 @@
+/* RDB2RDF: convert SPARQL queries to sound SQL queries.
+ *
+ * Please read from the bottom -- i.e. apply calls mapGraphPattern with the root
+ * graph pattern. mapGraphPattern handles all the graph pattern types in SPARQL,
+ * effectively peforming the Convert Graph Patterns step in SPARQL 1.0 12.2.1
+ *   <http://www.w3.org/TR/rdf-sparql-query/#convertGraphPattern>
+ * with the target semantics in SQL instead of SPARQL.
+ */
+
 package w3c.sw.rdb2rdf
 
 import scala.util.parsing.combinator._
@@ -67,16 +76,7 @@
   }
 
   /** varConstraint
-   * called on triple pattern subjects and objects of type variable
-   * passed the relation name (from predicate)
-   *   if a subject, then the attribute is the primary key for relation
-   *   if an object, then passed the attribute name (from predicate)
-   * passed the relalias for this relation (e.g. _emp)
-   *
-   * schema(Employee.id) => (?emp => NodeTemplate("Employee", R_emp.id) stemURI + rel + fk(rel) + value
-   * schema(Employee.lastName) => (?lastName => RValueString(_Remp.lastName)
-   * schema(Employee.manater) => (?manager => ForeignKey("Employee", R_manager.id)
-   * 
+   * examples:
    * SELECT ?emp WHERE { ?emp emp:manager <http://hr.example/our/favorite/DB/Employee/id.18#record> ; emp:name ?name }
    * SQL Results                     SPARQL Results
    * A_emp A_name    ?emp                                                      ?name
@@ -143,6 +143,9 @@
     }
   }
 
+  /* bindOnPredicate: map a given triple to one or two joined tables, variable
+   * bindings to RelVarAttributes, and constraints if those variables were
+   * already bound. */
   def bindOnPredicate(db:sql.DatabaseDesc, stateP:R2RState, triple:sparql.TriplePattern, enforceForeignKeys:Boolean):R2RState = {
     val sparql.TriplePattern(s, p, o) = triple
     p match {
@@ -333,7 +336,8 @@
 	  Map[sparql.Var, SQL2RDFValueMapper](), 
 	  Set[sql.Expression]()
 	)
-	val unionVars = disjoints.foldLeft(Set[sparql.Var]())((mySet,disjoint) => mySet ++ findVars(disjoint)).toList
+	val unionVars = disjoints.foldLeft(Set[sparql.Var]())((mySet,disjoint) =>
+	  mySet ++ findVars(disjoint)).toList
 
 	/* Map the disjoints to subselects.
 	 * <no> is used for uniquely naming flags in the SELECTs used to
@@ -343,7 +347,8 @@
 	  val (subselects, no) = incPair
 	  val disjointState = mapGraphPattern(db, emptyState, disjoint, enforceForeignKeys)
 	  val disjointVars = findVars(disjoint)
-	  val disjointNo = sql.NamedAttribute(sql.PrimaryExpressionTyped(sql.Datatype.INTEGER,sql.Name("" + no)), sql.AttrAlias(sql.Name("_DISJOINT_")))
+	  val disjointNo = sql.NamedAttribute(sql.PrimaryExpressionTyped(sql.Datatype.INTEGER,sql.Name("" + no)),
+					      sql.AttrAlias(sql.Name("_DISJOINT_")))
 
 	  val attrlist:Set[sql.NamedAttribute] = unionVars.foldLeft(Set(disjointNo))((attrs, v) => {
 	    val attrOrNull = if (disjointState.varmap.contains(v)) varToAttribute(disjointState.varmap, v) else sql.ConstNULL()
@@ -366,14 +371,18 @@
 	 * corefs (equivalence with earlier bindings).
 	 * <no> is used for uniquely naming flags in the SELECTs used to
 	 * indicate which disjoint produced a tuple.
+	 * <state2> will have no additional tables in the TableList.
 	 */
 	val (state2, _) = disjoints.foldLeft((state, 0))((incPair,disjoint) => {
 	  val (outerState, no) = incPair
 	  val disjointState = mapGraphPattern(db, emptyState, disjoint, enforceForeignKeys)
 	  val disjointVars = findVars(disjoint)
 
-	  val disjointNoAliasAttr = sql.RelAliasAttribute(unionAlias, sql.Attribute(sql.Name("_DISJOINT_")))
-	  val disjointCond = sql.RelationalExpressionNe(sql.PrimaryExpressionAttr(disjointNoAliasAttr), sql.PrimaryExpressionTyped(sql.Datatype.INTEGER,sql.Name("" + no)))
+	  /* Create a condition to test if this OPTIONAL was matched (called
+	   * _DISJOINT_ as OPTIONAL behaves pretty much like a disjunction).
+	   */
+	  val disjointCond = sql.RelationalExpressionNe(sql.PrimaryExpressionAttr(sql.RelAliasAttribute(unionAlias, sql.Attribute(sql.Name("_DISJOINT_")))),
+							sql.PrimaryExpressionTyped(sql.Datatype.INTEGER,sql.Name("" + no)))
 	  val outerState2 = disjointVars.foldLeft(outerState)((myState, v) => {
 	    val varAliasAttr = sql.RelAliasAttribute(unionAlias, sql.Attribute(sql.Name("A_" + v.s)))
 	    if (myState.varmap.contains(v)) {
@@ -381,7 +390,6 @@
 	      val newMap:Map[sparql.Var, SQL2RDFValueMapper] = if (varToAttribute(myState.varmap, v) == varAliasAttr) {
 		/* Same var was bound in an earlier disjoint. */
 		val oldDisjoints = varToAttributeDisjoints(myState.varmap, v)
-		// myState
 		Map(v -> { disjointState.varmap(v) match {
 		  case IntMapper(_, _)      => IntMapper(varAliasAttr, oldDisjoints + disjointCond)
 		  case StringMapper(_, _)   => StringMapper(varAliasAttr, oldDisjoints + disjointCond)
@@ -394,10 +402,12 @@
 	      val newConstraints =
 		if (varToAttribute(outerState.varmap, v) != varAliasAttr) {
 		  /* Constraint against binding from earlier GP. */
-		  val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(varToAttribute(outerState.varmap, v)), sql.PrimaryExpressionAttr(varAliasAttr))
+		  val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(varToAttribute(outerState.varmap, v)),
+							      sql.PrimaryExpressionAttr(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) => sql.ExprDisjunction(Set(sql.ExprConjunction(Set(d, disjointCond)), constraint)))
+		    // (union0._DISJOINT_ != 0 OR union0.x=union1.x) AND (union1._DISJOINT_ != 2 OR union0.x=union1.x)
+		    varToAttributeDisjoints(outerState.varmap, v) map ((d) =>
+		      sql.ExprDisjunction(Set(sql.ExprConjunction(Set(d, disjointCond)), constraint)))
 		  else
 		    Set(sql.ExprDisjunction(Set(disjointCond, constraint)))
 		} else {
@@ -452,7 +462,8 @@
 	 */
       	val optionalState = mapGraphPattern(db, emptyState, gp, enforceForeignKeys)
       	val optionalVars = findVars(gp)
-	val disjointNo = sql.NamedAttribute(sql.PrimaryExpressionTyped(sql.Datatype.INTEGER,sql.Name("" + state_postLeadingTable.joins.size)), sql.AttrAlias(sql.Name("_DISJOINT_")))
+	val disjointNo = sql.NamedAttribute(sql.PrimaryExpressionTyped(sql.Datatype.INTEGER,sql.Name("" + state_postLeadingTable.joins.size)),
+					    sql.AttrAlias(sql.Name("_DISJOINT_")))
       	val leftJoinVars = findVars(gp).toList
       	val attrlist:Set[sql.NamedAttribute] = leftJoinVars.foldLeft(Set(disjointNo))((attrs, v) =>
       	  attrs ++ Set(sql.NamedAttribute(varToAttribute(optionalState.varmap, v), sql.AttrAlias(sql.Name("A_" + v.s))))
@@ -467,7 +478,8 @@
       	  }
       	)
 
-	/* Create a condition to test if this OPTIONAL was matched.
+	/* Create a condition to test if this OPTIONAL was matched (called
+	 * _DISJOINT_ as OPTIONAL behaves pretty much like a disjunction).
 	 */
 	val optionalCond = sql.RelationalExpressionNull(sql.PrimaryExpressionAttr(
 	  sql.RelAliasAttribute(leftJoinAlias, sql.Attribute(sql.Name("_DISJOINT_")))))
@@ -475,7 +487,9 @@
 	/* Bind variables to the attributes projected from the subselect; handle
 	 * corefs (equivalence with earlier bindings).
 	 */
-	val outerState2 = optionalVars.foldLeft(R2RState(state_postLeadingTable.joins, state_postLeadingTable.varmap, Set[sql.Expression]()))((myState, v) => {
+	val outerState2 = optionalVars.foldLeft(R2RState(state_postLeadingTable.joins,
+							 state_postLeadingTable.varmap,
+							 Set[sql.Expression]()))((myState, v) => {
 	  val varAliasAttr = sql.RelAliasAttribute(leftJoinAlias, sql.Attribute(sql.Name("A_" + v.s)))
 	  if (myState.varmap.contains(v)) {
 	    /* The variable has already been bound. */
@@ -494,7 +508,8 @@
 	      Map()
 	    val newConstraints = {
 	      /* Constraint against binding from earlier GP. */
-	      val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(varToAttribute(state_postLeadingTable.varmap, v)), sql.PrimaryExpressionAttr(varAliasAttr))
+	      val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(varToAttribute(state_postLeadingTable.varmap, v)),
+							  sql.PrimaryExpressionAttr(varAliasAttr))
 	      if (varToAttributeDisjoints(state_postLeadingTable.varmap, v).size > 0)
 		// (leftJoin0._DISJOINT_ IS NOT NULL AND leftJoin1._DISJOINT_ IS NOT NULL) OR leftJoin0.x=leftJoin1.x
 		varToAttributeDisjoints(state_postLeadingTable.varmap, v) map ((d) => sql.ExprDisjunction(Set(d, constraint)))