factored varmap promotion handling from OPTIONAL and UNION
authorEric Prud'hommeaux <eric@w3.org>
Thu, 28 Jan 2010 21:49:59 -0500
changeset 139 a08c8fded443
parent 138 9f82ffaafe02
child 140 25e31444795b
factored varmap promotion handling from OPTIONAL and UNION
src/main/scala/RDB2RDFMain.scala
--- a/src/main/scala/RDB2RDFMain.scala	Thu Jan 28 16:07:12 2010 -0500
+++ b/src/main/scala/RDB2RDFMain.scala	Thu Jan 28 21:49:59 2010 -0500
@@ -378,6 +378,61 @@
     }
   }
 
+  /* subselectVars: Promote variables in OPTIONAL or UNION subselects to the
+   * outer varmap/expressions.
+   * <outerState> could be <myState> -- spliting roles could make proofs easier?
+   */
+  def subselectVars(myState:R2RState, v:sparql.Var, optionalAlias:sql.RelAlias,
+		    optionalCond:sql.RelationalExpression, outerState:R2RState,
+		    optionalState:R2RState, isOpt:Boolean):R2RState = {
+    val varAliasAttr = sql.RelAliasAttribute(optionalAlias, sql.Attribute(attrAliasNameFromVar(v)))
+    if (myState.varmap.contains(v)) {
+      /* The variable has already been bound. */
+      val newMap:Map[sparql.Var, SQL2RDFValueMapper] = if (varToAttribute(myState.varmap, v) == varAliasAttr) {
+	/* Same var was bound earlier. */
+	Map(v -> { myState.varmap(v) match {
+	  case IntMapper(binding)      => IntMapper(addExpr(binding, varAliasAttr, optionalCond))
+	  case StringMapper(binding)   => StringMapper(addExpr(binding, varAliasAttr, optionalCond))
+	  case DateMapper(binding)     => DateMapper(addExpr(binding, varAliasAttr, optionalCond))
+	  case RDFNoder(rel, binding)  => RDFNoder(rel, addExpr(binding, varAliasAttr, optionalCond))
+	  case RDFBNoder(rel, binding) => RDFBNoder(rel, addExpr(binding, varAliasAttr, optionalCond))
+	} } )
+      } else
+	Map()
+      val newConstraints =
+	if (varToAttribute(outerState.varmap, v) != varAliasAttr) {
+	  /* Constraint against binding from earlier GP. */
+	  val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(varAliasAttr),
+						      sql.PrimaryExpressionAttr(varToAttribute(outerState.varmap, v)))
+	  if (varToAttributeDisjoints(outerState.varmap, v).size > 0)
+	    // (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({
+		if (isOpt) Set(d, constraint)
+		else Set(sql.ExprConjunction(Set(d, optionalCond)), constraint)
+	      }))
+		else {
+		  if (isOpt) Set(constraint)
+		  else Set(sql.ExprDisjunction(Set(optionalCond, constraint)))
+		}
+	} else {
+	  Set()
+	}
+      R2RState(myState.joins, myState.varmap ++ newMap, myState.exprs ++ newConstraints)
+    } else {
+      /* This variable is new to the outer context. */
+      val p = PartialBinding(Set(BindingConstraint(optionalCond, varAliasAttr)))
+      val mapper:SQL2RDFValueMapper = optionalState.varmap(v) match {
+	case IntMapper(_)      => IntMapper(p)
+	case StringMapper(_)   => StringMapper(p)
+	case DateMapper(_)   => DateMapper(p)
+	case RDFNoder(rel, _)  => RDFNoder(rel, p)
+	case RDFBNoder(rel, _) => RDFBNoder(rel, p)
+      }
+      R2RState(myState.joins, myState.varmap + (v -> mapper), myState.exprs)
+    }
+  }
+
   def mapGraphPattern(db:sql.DatabaseDesc, state:R2RState, gp:sparql.GraphPattern, enforceForeignKeys:Boolean):R2RState = {
     gp match {
       case sparql.TableFilter(gp2:sparql.GraphPattern, expr:sparql.Expression) => {
@@ -459,49 +514,8 @@
 	   */
 	  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(attrAliasNameFromVar(v)))
-	    if (myState.varmap.contains(v)) {
-	      /* The variable has already been bound. */
-	      val newMap:Map[sparql.Var, SQL2RDFValueMapper] = if (varToAttribute(myState.varmap, v) == varAliasAttr) {
-		/* Same var was bound in an earlier disjoint. */
-		Map(v -> { myState.varmap(v) match {
-		  case IntMapper(binding)      => IntMapper(addExpr(binding, varAliasAttr, disjointCond))
-		  case StringMapper(binding)   => StringMapper(addExpr(binding, varAliasAttr, disjointCond))
-		  case DateMapper(binding)     => DateMapper(addExpr(binding, varAliasAttr, disjointCond))
-		  case RDFNoder(rel, binding)  => RDFNoder(rel, addExpr(binding, varAliasAttr, disjointCond))
-		  case RDFBNoder(rel, binding) => RDFBNoder(rel, addExpr(binding, varAliasAttr, disjointCond))
-		} } )
-	      } else
-		Map()
-	      val newConstraints =
-		if (varToAttribute(outerState.varmap, v) != varAliasAttr) {
-		  /* Constraint against binding from earlier GP. */
-		  val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(varAliasAttr),
-							      sql.PrimaryExpressionAttr(varToAttribute(outerState.varmap, v)))
-		  if (varToAttributeDisjoints(outerState.varmap, v).size > 0)
-		    // (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 {
-		  Set()
-		}
-	      R2RState(myState.joins, myState.varmap ++ newMap, myState.exprs ++ newConstraints)
-	    } else {
-	      /* This variable is new to the outer context. */
-	      val p = PartialBinding(Set(BindingConstraint(disjointCond, varAliasAttr)))
-	      val mapper:SQL2RDFValueMapper = disjointState.varmap(v) match {
-		case IntMapper(_)      => IntMapper(p)
-		case StringMapper(_)   => StringMapper(p)
-		case DateMapper(_)   => DateMapper(p)
-		case RDFNoder(rel, _)  => RDFNoder(rel, p)
-		case RDFBNoder(rel, _) => RDFBNoder(rel, p)
-	      }
-	      R2RState(myState.joins, myState.varmap + (v -> mapper), myState.exprs)
-	    }
-	  })
+	  val outerState2 = disjointVars.foldLeft(outerState)((myState, v) =>
+	      subselectVars(myState, v, unionAlias, disjointCond, outerState, disjointState, false))
 	  (outerState2, no+1)
 	})
 	val subselect = sql.Subselect(sql.Union(subselects))
@@ -563,48 +577,13 @@
 	/* 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 varAliasAttr = sql.RelAliasAttribute(leftJoinAlias, sql.Attribute(attrAliasNameFromVar(v)))
-	  if (myState.varmap.contains(v)) {
-	    /* The variable has already been bound. */
-	    val newMap:Map[sparql.Var, SQL2RDFValueMapper] = if (varToAttribute(myState.varmap, v) == varAliasAttr) {
-	      /* Same var was bound in an earlier optional. */
-	      // myState
-	      Map(v -> { myState.varmap(v) match {
-		case IntMapper(binding)      => IntMapper(addExpr(binding, varAliasAttr, optionalCond))
-		case StringMapper(binding)   => StringMapper(addExpr(binding, varAliasAttr, optionalCond))
-		case DateMapper(binding)     => DateMapper(addExpr(binding, varAliasAttr, optionalCond))
-		case RDFNoder(rel, binding)  => RDFNoder(rel, addExpr(binding, varAliasAttr, optionalCond))
-		case RDFBNoder(rel, binding) => RDFBNoder(rel, addExpr(binding, varAliasAttr, optionalCond))
-	      } } )
-	    } else
-	      Map()
-	    val newConstraints = {
-	      /* Constraint against binding from earlier GP. */
-	      val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(varAliasAttr),
-							  sql.PrimaryExpressionAttr(varToAttribute(state_postLeadingTable.varmap, v)))
-	      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)))
-	      else
-		Set(constraint)
-	    }
-	    R2RState(myState.joins, myState.varmap ++ newMap, myState.exprs ++ newConstraints)
-	  } else {
-	    /* This variable is new to the outer context. */
-	      val p = PartialBinding(Set(BindingConstraint(optionalCond, varAliasAttr)))
-	    val mapper:SQL2RDFValueMapper = optionalState.varmap(v) match {
-	      case IntMapper(binding)      => IntMapper(p)
-	      case StringMapper(binding)   => StringMapper(p)
-	      case DateMapper(binding)   => DateMapper(p)
-	      case RDFNoder(rel, binding)  => RDFNoder(rel, p)
-	      case RDFBNoder(rel, binding) => RDFBNoder(rel, p)
-	    }
-	    R2RState(myState.joins, myState.varmap + (v -> mapper), myState.exprs)
-	  }
-	})
+	val outerState2 =
+	  optionalVars.foldLeft(
+	    R2RState(state_postLeadingTable.joins,
+		     state_postLeadingTable.varmap,
+		     Set[sql.Expression]()))((myState, v) => 
+		       subselectVars(myState, v, leftJoinAlias, optionalCond,
+				     state_postLeadingTable, optionalState, true))
 
 	/* The final state includes the subselect as a join, the variables bound
 	 * to subselect projection, and no new expresssions. The expressions