+ more comments
authorEric Prud'hommeaux <eric@w3.org>
Thu, 13 May 2010 14:36:55 -0400
changeset 191 b402d3939ecb
parent 190 c7bb30e943ab
child 192 2773c2007113
+ more comments
src/main/scala/SparqlToSql.scala
--- a/src/main/scala/SparqlToSql.scala	Thu May 13 11:45:03 2010 -0400
+++ b/src/main/scala/SparqlToSql.scala	Thu May 13 14:36:55 2010 -0400
@@ -390,57 +390,88 @@
 	    /** additional constraint, e.g. R_empid18.empid=18. */
 	    uriConstraint(stateP, sql.RelVarAttr(relvar, db.relationdescs(rel).primarykey.get), parseObjectURI(u))
 	  case sparql.TermVar(v) =>
+	    /** assignable binding for novel vars, new constraint for previously bound vars. */
 	    try {
 	      varConstraint(stateP, relvar, db.relationdescs(rel).primarykey, sparql.VarAssignable(v), db, rel)
 	    } catch {
 	      case e:java.util.NoSuchElementException =>
-		/** Attribute not found in database description. */
+		/** Tell user that the relation.attribute encoded in the subject was not found in the database description. */
 		throw new Exception("error processing { " + s + " " + p + " " + o + " } :db.relationdescs(" + rel + ") not found in " + db)
 	    }
-	  case sparql.TermBNode(b) => try { varConstraint(stateP, relvar, db.relationdescs(rel).primarykey, sparql.BNodeAssignable(b), db, rel) } catch {
-	    case e:java.util.NoSuchElementException =>
-	      throw new Exception("error processing { " + s + " " + p + " " + o + " } :db.relationdescs(" + rel + ") not found in " + db)
-	  }
+	  case sparql.TermBNode(b) =>
+	    /** assignable binding for novel bnodes, new constraint for previously bound bnodes. */
+	    try {
+	      varConstraint(stateP, relvar, db.relationdescs(rel).primarykey, sparql.BNodeAssignable(b), db, rel)
+	    } catch {
+	      case e:java.util.NoSuchElementException =>
+		throw new Exception("error processing { " + s + " " + p + " " + o + " } :db.relationdescs(" + rel + ") not found in " + db)
+	    }
 	  case _                 => error("illegal SPARQL subject: " + s)
 	}
+
+	/** Join rel (relation dictated by predicate) AS relvar (alias dicated by subject).
+	 * may be redundant as R2RState's joins are a set */
 	val state_subjJoin = R2RState(state_postSubj.joins + sql.InnerJoin(sql.AliasedResource(rel,relvar), None), state_postSubj.varmap, state_postSubj.exprs)
 
 	try { db.relationdescs(rel).attributes(attr) } catch {
+	  /** Tell user that the queried attribute was not found in the database description. */
 	  case e:java.util.NoSuchElementException =>
 	    throw new Exception("error processing { " + s + " " + p + " " + o + " } :db.relationdescs(" + rel + ").attributes(" + attr + ") not found in " + db)
 	}
+
+	/**
+	 * fkrel.fkattr (e.g. Employee.manager) may be a foreign key.
+	 * Calculate final relvarattr and relation.
+	 */
 	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 {
+	      /** 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 {
+	      /** 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)
 	      case sql.Value(x) => x
 	    }
 	    if (enforceForeignKeys) {
+	      /**
+	       * Create an extra join on the foreign key relvar. For instance,
+	       * <code>?task1 <http://hr.example/DB/TaskAssignments#employee> ?who</code>
+	       * where TaskAssignments.employee is a foreign key to Employee.empid
+	       * will join Employee AS R_who, constrain R_who.empid=R_task1.employee
+	       * and bind targetattr:R_who.empid. targetrel:Employee .
+	       */
 	      val oRelVar = relVarFromTerm(o)
 	      val fkaliasattr = sql.RelVarAttr(oRelVar, fkattr)
 	      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),
 										       sql.PrimaryExpressionAttr(objattr)))
-
+	      //println("enforceFKs: <code>"+s+" "+p+" "+o+"</code> where "+rel+"."+attr+" is a foreign key to "+fkrel+"."+fkattr+" will join "+fkrel+" AS "+oRelVar+", constrain "+fkaliasattr+"="+objattr+" and bind targetattr:=" + fkaliasattr + ". targetrel:=" + fkrel + " (instead of " + objattr + ", " + rel + ").")
 	      (fkaliasattr, fkrel, fkdt, state_t)
 	    } else {
+	      /**
+	       * We're not enforcing foreign keys, so just bind 
+	       * targetattr:=R_task1.employee, targetrel:=TaskAssignments.
+	       */
 	      (objattr, rel, fkdt, state_subjJoin)
 	    }
 	  }
-	  case sql.Value(dt) => (objattr, rel, dt, state_subjJoin)
+	  case sql.Value(dt) =>
+	    /** not a foreign key, so use the relvarattr and relation calculated
+	     * from the predicate. */
+	    (objattr, rel, dt, state_subjJoin)
 	}
 	o match {
 	  case sparql.TermLit(l) => literalConstraint(state_fkeys, targetattr, l, dt)
 	  case sparql.TermUri(u) => uriConstraint    (state_fkeys, targetattr, parseObjectURI(u))
 	  case sparql.TermVar(v) => varConstraint    (state_fkeys, targetattr.relvar, Some(targetattr.attribute), sparql.VarAssignable(v), db, targetrel)
-	  case sparql.TermBNode(b) => varConstraint    (state_fkeys, targetattr.relvar, Some(targetattr.attribute), sparql.BNodeAssignable(b), db, targetrel)
+	  case sparql.TermBNode(b) => varConstraint  (state_fkeys, targetattr.relvar, Some(targetattr.attribute), sparql.BNodeAssignable(b), db, targetrel)
 	}
       }
       case _                  => error("illegal SPARQL predicate: " + p)