~ big refactoring: split FeDeRate in small projects, with fine-grained dependencies
authorAlexandre Bertails <alexandre@bertails.org>
Sun, 31 Oct 2010 15:17:31 -0400
changeset 238 a5507f0ee9d8
parent 237 ad153b9f0d13
child 239 1885daa02788
~ big refactoring: split FeDeRate in small projects, with fine-grained dependencies
only the main code is concerned so far
directmapping/src/main/scala/DirectMapping.scala
project/build/RDB2RDF.scala
rdb/src/main/scala/RDB.scala
rdf/src/main/scala/RDF.scala
sparql/src/main/scala/GraphAnalyser.scala
sparql/src/main/scala/SPARQL.scala
sparql2sparql/src/main/scala/SparqlToSparql.scala
sparql2sql/src/main/scala/SparqlToSql.scala
sparqlendpoint/src/main/scala/Config.scala
sparqlendpoint/src/main/scala/Servlet.scala
sql/src/main/scala/AddOrderedSet.scala
sql/src/main/scala/SQL.scala
src/main/scala/AddOrderedSet.scala
src/main/scala/Config.scala
src/main/scala/GraphAnalyzer.scala
src/main/scala/RDF.scala
src/main/scala/SPARQL.scala
src/main/scala/SQL.scala
src/main/scala/Servlet.scala
src/main/scala/SparqlToSparql.scala
src/main/scala/SparqlToSql.scala
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping/src/main/scala/DirectMapping.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,195 @@
+package org.w3.sw.directmapping
+
+import org.w3.sw.rdb
+import org.w3.sw.rdf
+
+// to be adapted to the new RDB model
+
+// object DirectMapping {
+
+//   /** A KeyMap associates the candidate key and key values with the
+//    * node for any tuple in a unique relation. */
+//   case class KeyMap(m:Map[CandidateKey,  Map[List[CellValue], Node]]) {
+//     //def KeyMap() : KeyMap = KeyMap(Map[CandidateKey,  Map[List[CellValue], Node]]())
+//     def apply(i:CandidateKey) : Map[List[CellValue], Node] = m(i)
+//     def ++(pairs:List[(CandidateKey, List[CellValue])], n:Node):KeyMap = {
+//       val m2:Map[CandidateKey,  Map[List[CellValue], Node]] =
+// 	pairs.foldLeft(m)((m, p) => {
+// 	  if (m.get(p._1).isDefined) {
+// 	    val byKey = m(p._1)
+// 	    if (byKey.get(p._2).isDefined) {
+// 	      error("tried to set " + p._1 + p._2 + " = " + n + "(was " + byKey(p._2) + ")")
+// 	    } else {
+// 	      val im1 = byKey ++ Map[List[CellValue], Node](p._2 -> n)
+// 	      m ++ Map[CandidateKey, Map[List[CellValue], Node]](p._1 -> im1)
+// 	    }
+// 	  } else {
+// 	    m ++ Map[CandidateKey, Map[List[CellValue], Node]](p._1 -> Map(p._2 -> n))
+// 	  }
+// 	})
+//       KeyMap(m2)
+//     }
+//   }
+//   case class NodeMap(m:Map[RelName, KeyMap]) {
+//     def apply(rn:RelName) = m(rn)
+//     def ultimateReferent (rn:RelName, k:CandidateKey, vs:List[LexicalValue], db:Database) : Node = {
+//       // Issue: What if fk is a rearrangement of the pk, per issue fk-pk-order?
+//       if (db(rn).pk.isDefined && db(rn).fks.contains(db(rn).pk.get.attrs)) {
+// 	/** Table's primary key is a foreign key. */
+// 	val target = db(rn).fks(db(rn).pk.get.attrs)
+// 	ultimateReferent(target.rel, target.key, vs, db)
+//       } else
+// 	m(rn)(k)(vs)
+//     }
+//   }
+//   implicit def list2map (l:Set[(RelName, KeyMap)]):Map[RelName,KeyMap] = l.toMap
+//   implicit def list2Nmap (l:Set[(RelName, KeyMap)]):NodeMap = NodeMap(l)
+
+//   /** The direct mapping requires one parameter: the StemIRI */
+//   case class StemIRI(stem:String) {
+//     def +(path:String):IRI = IRI(stem + path)
+//   }
+
+//   /**
+//    * The mapping functions implementing
+//    * <http://www.w3.org/2001/sw/rdb2rdf/directGraph/>
+//    */
+
+//   def references (t:Tuple, r:Relation):Set[List[AttrName]] = {
+//     val allFKs:Set[List[AttrName]] = r.fks.keySet
+//     val nulllist:Set[AttrName] = t.nullAttributes(r.header)
+//     val nullFKs:Set[List[AttrName]] = allFKs.flatMap(a => {
+//       val int:Set[AttrName] = nulllist & a.toSet
+//       if (int.toList.length == 0) None else List(a)
+//     })
+
+//     /** Check to see if r's primary key is a hierarchical key.
+//      * http://www.w3.org/2001/sw/rdb2rdf/directGraph/#rule3 */
+//     if (r.pk.isDefined && r.fks.contains(r.pk.get.attrs))
+//       r.fks.keySet -- nullFKs - r.fks(r.pk.get.attrs).key.attrs
+//     else
+//       r.fks.keySet -- nullFKs
+//   }
+
+//   def scalars (t:Tuple, r:Relation):Set[AttrName] = {
+//     val allAttrs:Set[AttrName] = r.header.keySet
+//     val allFKs:Set[List[AttrName]] = r.fks.keySet
+//     val unaryFKs:Set[AttrName] = allFKs.flatMap(a => {
+//       if (a.length == 1) a else None
+//     })
+//     val nulllist:Set[AttrName] = t.nullAttributes(r.header)
+
+//     /** Check to see if r's primary key is a hierarchical key.
+//      * http://www.w3.org/2001/sw/rdb2rdf/directGraph/#rule3 */
+//     if (r.pk.isDefined && r.fks.contains(r.pk.get.attrs))
+//       allAttrs -- unaryFKs -- nulllist ++ r.fks(r.pk.get.attrs).key.attrs
+//     else
+//       allAttrs -- unaryFKs -- nulllist
+//   }
+
+//   /** The NodeMap-generating functions: */
+//   def relation2KeyMap (u:StemIRI, r:Relation) : KeyMap = {
+//     val m = KeyMap(Map[CandidateKey, Map[List[CellValue], Node]]())
+//     r.body.foldLeft(m)((m, t) => {
+//       val (pairs, node) = rdfNodeForTuple(u, t, r)
+//       m ++ (pairs, node)
+//     })
+//   }
+
+//   def rdfNodeForTuple (u:StemIRI, t:Tuple, r:Relation) : (List[(CandidateKey, List[CellValue])], Node) = {
+//     val s:Node =
+//       if (r.pk.isDefined) {
+// 	/** Table has a primkary key. */
+// 	val vs = t.lexvaluesNoNulls(r.pk.get.attrs)
+// 	nodemap(u, r.name, r.pk.get.attrs, vs)
+//       } else
+// 	/** Table has no primkary key (but has some candidate keys). */
+// 	freshbnode()
+//     (r.candidates.map(k => {
+//       val values:List[CellValue] = k.attrs.map(a => t(a))
+//       (k, values)
+//     }), s)
+//   }
+
+//   /** The triples-generating functions start with databasemap: */
+//   def directDB (u:StemIRI, db:Database) : RDFGraph = {
+//     val idxables = db.keySet filter { rn => !db(rn).candidates.isEmpty }
+//     val nodeMap = idxables map {rn => rn -> relation2KeyMap(u, db(rn))}
+//     db.keySet.flatMap(rn => directR(u, db(rn), nodeMap, db))
+//   }
+
+//   def directR (u:StemIRI, r:Relation, nodes:NodeMap, db:Database) : RDFGraph =
+//     /* flatMap.toSet assumes that no two triples from directT would be the same.
+//      * We know this because relations with candidate keys are mapped to unique
+//      * subjects, and potentially redundant rows get unique blank node subjects.
+//      */
+//     r.body.flatMap(t => directT(u, t, r, nodes, db)).toSet
+
+//   def directT (u:StemIRI, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
+//     val s:Node =
+//       if (r.candidates.size > 0) {
+// 	// Known to have at least one key, so take the first one.
+// 	val k = r.candidates(0)
+// 	val vs = t.lexvaluesNoNulls(k.attrs)
+// 	nodes.ultimateReferent(r.name, k, vs, db)
+//       } else
+// 	/** Table has no candidate keys. */
+// 	freshbnode()
+//     directS(u, s, t, r, nodes, db)
+//   }
+
+//   def directS (u:StemIRI, s:Node, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
+//     references(t, r).map(as => directN(u, s, as, r, t, nodes)) ++
+//     scalars(t, r).map(a => directL(u, r.name, s, a, r.header, t))
+//   }
+
+//   var NextBNode = 97
+//   def freshbnode () : BNode = {
+//     val ret = NextBNode
+//     NextBNode = NextBNode + 1
+//     BNode(ret.toChar.toString)
+//   }
+
+//   def directL (u:StemIRI, rn:RelName, s:Node, a:AttrName, h:Header, t:Tuple) : Triple = {
+//     val p = predicatemap (u, rn, List(a))
+//     val l = t.lexvalue(a).get
+//     val o = literalmap(l, h.sqlDatatype(a))
+//     Triple(s, p, o)
+//   }
+//   def directN (u:StemIRI, s:Node, as:List[AttrName], r:Relation, t:Tuple, nodes:NodeMap) : Triple = {
+//     val p = predicatemap (u, r.name, as)
+//     val ls:List[LexicalValue] = t.lexvaluesNoNulls(as)
+//     val target = r.fks(as)
+//     val o:Object = nodes(target.rel)(target.key)(ls)
+//     Triple(s, p, o)
+//   }
+
+//   // These implicits make nodemap and predicatemap functions prettier.
+//   implicit def relName2string (rn:RelName) = rn.n
+//   implicit def attrName2string (rn:AttrName) = rn.n
+
+//   def nodemap (u:StemIRI, rn:RelName, as:List[AttrName], ls:List[LexicalValue]) : IRI = {
+//     val pairs:List[String] = as.zip(ls).map(x => UE(x._1) + "." + UE(x._2.s))
+//     u + ("/" + UE(rn) + "/" + pairs.mkString("_") + "#_")
+//   }
+
+//   def predicatemap (u:StemIRI, rn:RelName, as:List[AttrName]) : IRI =
+//     u + ("/" + UE(rn) + "#" + as.mkString("_"))
+
+//   def XSD (d:Datatype) : IRI =
+//     d match {
+//       case RDB.Datatype.INTEGER => IRI("http://www.w3.org/2001/XMLSchema#int")
+//       case RDB.Datatype.FLOAT => IRI("http://www.w3.org/2001/XMLSchema#float")
+//       case RDB.Datatype.DATE => IRI("http://www.w3.org/2001/XMLSchema#date")
+//       case RDB.Datatype.TIME => IRI("http://www.w3.org/2001/XMLSchema#time")
+//       case RDB.Datatype.TIMESTAMP => IRI("http://www.w3.org/2001/XMLSchema#timestamp")
+//       case RDB.Datatype.CHAR => IRI("http://www.w3.org/2001/XMLSchema#char")
+//       case RDB.Datatype.VARCHAR => IRI("http://www.w3.org/2001/XMLSchema#varchar")
+//       case RDB.Datatype.STRING => IRI("http://www.w3.org/2001/XMLSchema#string")
+//     }
+
+//   def literalmap (l:LexicalValue, d:Datatype) : TypedLiteral =
+//     TypedLiteral(l.s, XSD(d))
+
+//   def UE (s:String) : String = s.replaceAll(" ", "+")
+// }
--- a/project/build/RDB2RDF.scala	Fri Oct 15 16:42:41 2010 -0400
+++ b/project/build/RDB2RDF.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -1,21 +1,41 @@
 import sbt._
 
-class RDB2RDF(info: ProjectInfo) extends DefaultWebProject(info) with BSBMPlugin {
-
-  override def compileOptions = super.compileOptions ++ Seq(Unchecked, Deprecation, ExplainTypes)
-
+trait Common extends BasicScalaProject {
   val scalatools = "scala-tools" at "http://scala-tools.org/repo-snapshots"
   val scalatest = "org.scalatest" % "scalatest" % "1.2-for-scala-2.8.0.final-SNAPSHOT" % "test"
-
-  val jetty6 = "org.mortbay.jetty" % "jetty" % "6.1.14" % "test"
-  val servlet = "javax.servlet" % "servlet-api" % "2.5" % "provided" 
+  override def compileOptions = super.compileOptions ++ Seq(Unchecked, Deprecation, ExplainTypes)
+  override def defaultExcludes = super.defaultExcludes || "*~"
+}
 
-  val mysql = "mysql" % "mysql-connector-java" % "5.1.12"
+class FeDeRate(info: ProjectInfo) extends ParentProject(info) {
 
-  override def defaultExcludes = super.defaultExcludes || "*~"
+  lazy val rdb = project("rdb", "rdb", new RDB(_))
+  lazy val sql = project("sql", "sql", new SQL(_), rdb)
+  lazy val rdf = project("rdf", "rdf", new RDF(_))
+  lazy val directmapping = project("directmapping", "directmapping", new DirectMapping(_), rdb, rdf)
+  lazy val sparql = project("sparql", "sparql", new SPARQL(_), rdf)
+  lazy val sparql2sql = project("sparql2sql", "sparql2sql", new SPARQL2SQL(_), sparql, sql)
+  lazy val sparql2sparql = project("sparql2sparql", "sparql2sparql", new SPARQL2SPARQL(_), sparql)
+  lazy val sql2sql = project("sql2sql", "sql2sql", new SQL2SQL(_), sql)
+  lazy val sparqlendpoint = project("sparqlendpoint", "sparqlendpoint", new SPARQLEndPoint(_), sparql2sql)
 
-  override def webappUnmanaged = super.webappUnmanaged +++ ("src" / "main" / "resources" / "database.properties")
+  class RDB(info: ProjectInfo) extends DefaultProject(info) with Common
+  class SQL(info: ProjectInfo) extends DefaultProject(info) with Common
+  class RDF(info: ProjectInfo) extends DefaultProject(info) with Common
+  class DirectMapping(info: ProjectInfo) extends DefaultProject(info) with Common
+  class SPARQL(info: ProjectInfo) extends DefaultProject(info) with Common
+  class SPARQL2SQL(info: ProjectInfo) extends DefaultProject(info) with Common
+  class SPARQL2SPARQL(info: ProjectInfo) extends DefaultProject(info) with Common
+  class SQL2SQL(info: ProjectInfo) extends DefaultProject(info) with Common
+  class SPARQLEndPoint(info: ProjectInfo) extends DefaultWebProject(info) with Common with BSBMPlugin {
+    val jetty6 = "org.mortbay.jetty" % "jetty" % "6.1.14" % "test"
+    val servlet = "javax.servlet" % "servlet-api" % "2.5" % "provided" 
+    val mysql = "mysql" % "mysql-connector-java" % "5.1.12"
+    override def webappUnmanaged = super.webappUnmanaged +++ ("src" / "main" / "resources" / "database.properties")
+  }
 
-  val stemgraph = "w3c" %% "stemgraph" % "1.0"
+
+
+
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rdb/src/main/scala/RDB.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,95 @@
+package org.w3.sw.rdb
+
+import scala.collection.Set
+
+// Relational structure
+object RDB {
+
+  case class Database (m:Map[RelName, Relation]) {
+    def apply (rn:RelName) = m(rn)
+    def keySet () = m.keySet
+  }
+  object Database {
+    def apply (l:(Relation)*):Database =
+      Database(l.map{r => (r.name -> r)}.toMap)
+  }
+
+  case class Relation (name:RelName, header:Header, body:List[Tuple], candidates:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys)
+
+  case class Header (m:Map[AttrName, Datatype]) {
+    def apply (a:AttrName) = m(a)
+    def keySet () = m.keySet
+    def sqlDatatype (a:AttrName) : Datatype = m(a)
+    def contains (a:AttrName) : Boolean = m.contains(a)
+  }
+  object Header {
+    def apply (s:(String, Datatype)*):Header =
+      Header(s.map{p => (AttrName(p._1), p._2)}.toMap)
+  }
+  case class CandidateKey (attrs:List[AttrName])
+  object CandidateKey {
+    def apply (l:(String)*):CandidateKey =
+      CandidateKey(l.map{s => AttrName(s)}.toList)
+  }
+  implicit def cc2list (cc:CandidateKey) = cc.attrs
+
+  case class ForeignKeys (m:Map[List[AttrName], Target]) {
+    def apply (l:List[AttrName]) = m(l)
+    def keySet () = m.keySet
+    def contains (l:List[AttrName]) = m.contains(l)
+  }
+  object ForeignKeys {
+    def apply (s:(List[String], Target)*):ForeignKeys =
+      ForeignKeys(s.map{p => (p._1.map{s => AttrName(s)}, p._2)}.toMap)
+  }
+
+  case class Target (rel:RelName, key:CandidateKey)
+
+  case class Datatype(name:String) {
+    override def toString = "/* " + name + " */"
+  }
+  object Datatype {
+    val CHAR = Datatype("Char")
+    val VARCHAR = Datatype("Varchar")
+    val STRING = Datatype("String")
+    val INTEGER = Datatype("Int")
+    val FLOAT = Datatype("Float")
+    val DOUBLE = Datatype("Double")
+    val DATE = Datatype("Date")
+    val TIMESTAMP = Datatype("Timestamp")
+    val DATETIME = Datatype("Datetime")
+  }
+
+  case class Tuple (m:Map[AttrName, CellValue]) {
+    def apply (a:AttrName) = m(a)
+    def lexvalue (a:AttrName) : Option[LexicalValue] = 
+      m(a) match {
+	case ␀() => None
+	case v:LexicalValue => Some(v)
+      }
+    def lexvaluesNoNulls (as:List[AttrName]) = as.map(a => m(a).asInstanceOf[LexicalValue])
+    def nullAttributes (h:Header) : Set[(AttrName)] = {
+      h.keySet.flatMap(a =>
+	lexvalue(a) match {
+	  case None => Some(a)
+	  case _ => None
+	})
+    }
+  }
+  object Tuple {
+    def apply (s:(String, CellValue)*):Tuple =
+      Tuple(s.map{p => (AttrName(p._1), p._2)}.toMap)
+  }
+
+  abstract class CellValue
+  case class LexicalValue (s:String) extends CellValue
+  case class ␀ () extends CellValue
+
+  case class RelName(n:String) {
+    override def toString = n
+  }
+  case class AttrName(n:String) {
+    override def toString = n
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rdf/src/main/scala/RDF.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,31 @@
+package org.w3.sw.rdf
+
+import java.net.URI
+
+case class RDFTriple(s:RDFSubject, p:RDFPredicate, o:RDFObject)
+
+sealed abstract class RDFSubject()
+case class RDFSubjectUri(uri:URI) extends RDFSubject
+case class RDFSubjectBlankNode(b:BlankNode) extends RDFSubject
+
+case class RDFPredicate(uri:URI)
+
+sealed abstract class RDFObject()
+case class RDFObjectUri(uri:URI) extends RDFObject
+case class RDFObjectBlankNode(b:BlankNode) extends RDFObject
+
+case class BlankNode(debugName:String)
+
+case class RDFLiteral(lexicalForm:String, datatype:Datatype) {
+  override def toString = "\"" + lexicalForm + "\"" + datatype
+}
+case class Datatype(uri:URI) {
+  override def toString = "^^" + uri
+}
+
+object RDFLiteral {
+  val StringDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#string"))
+  val IntegerDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#integer"))
+  val DateDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#date"))
+  // val DateTimeDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#dateTime"))
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sparql/src/main/scala/GraphAnalyser.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,72 @@
+package org.w3.sw.util
+
+import scala.collection.immutable._
+
+class GraphAnalyzer[A](m:Map[A, Set[A]]) {
+
+  def reaches (from:A, to:A) = {
+    if (m.contains(from))
+      new GraphAnalyzer[A](m + (from -> (m(from) + to)))
+    else
+      new GraphAnalyzer[A](m + (from -> Set(to)))
+  }
+  def pair (l:A, r:A) = {
+    reaches(l, r).reaches(r, l)
+  }
+  def neededFor (need:Set[A], t:A, visited:Set[A]):Boolean = {
+    if (!m.contains(t))
+      error("unknown symbol: " + t)
+    var ret:Boolean = false
+    m(t).map((r) => {
+      if (visited.contains(t)) return false
+      if (need.contains(t)) return true
+      ret |= neededFor(need, r, visited + t)
+    })
+    return ret
+  }
+
+}
+
+object GraphAnalyzer {
+  def apply[A]():GraphAnalyzer[A] = GraphAnalyzer() // Map[A, Set[A]]()
+  // def apply[A](list:List[A]):GraphAnalyzer[A] = new GraphAnalyzer(list)
+  // def apply[A](args:A*):GraphAnalyzer[A] = GraphAnalyzer(args.toList)
+}
+
+// object GraphAnalyzer {
+// }
+// //def createEmptyGraphAnalyzer () = GraphAnalyzer(Map[A, Set[A]]())
+
+  // case class Reacher (b:Map[String, Map[String, Set[String]]]) {
+  //   def reaches (from:String, to:String) = {
+  //     if (b.contains(from)) {
+  // 	if (b(from).contains(to)) {
+  // 	  val back = b(from)(to) + from
+  // 	  val fore = b(from) + (to -> back)
+  // 	  val ret = Reacher(b + (from -> fore))
+  // 	  println("duplicate path from " + from + " to " + to)
+  // 	  // println("ret: " + ret)
+  // 	  ret
+  // 	} else {
+  // 	  println(from + "->" + to + " + " + this)
+  // 	  val back = Set[String](from)
+  // 	  val fore = b(from) + (to -> back)
+  // 	  val ret = Reacher(b + (from -> fore))
+  // 	  println("ret: " + ret)
+  // 	  ret
+  // 	}
+  //     } else {
+  // 	val back = Set[String](from)
+  // 	val fore = Map[String, Set[String]](to -> back)
+  // 	val ret = Reacher(b + (from -> fore))
+  // 	// println("ret: " + ret)
+  // 	ret
+  //     }
+  //   }
+  //   def pair (l:String, r:String) = {
+  //     reaches(l, r).reaches(r, l)
+  //   }
+  //   override def toString = b.toString
+  // }
+  // def createEmptyReacher () = Reacher(Map[String, Map[String, Set[String]]]())
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sparql/src/main/scala/SPARQL.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,431 @@
+package org.w3.sw.sparql
+
+import org.w3.sw.rdf._
+import scala.util.parsing.combinator._
+import java.net.URI
+
+object MyParsers extends RegexParsers {
+
+  val uri = """[a-zA-Z0-9:/#_\.\-]+""".r
+  val integer = """[0-9]+""".r
+  val name = """[a-zA-Z][a-zA-Z0-9_-]*|[a-zA-Z_][a-zA-Z0-9_]+""".r
+  var prefixes:Map[String, String] = Map()
+  var bnodes:Map[String, BNode] = Map()
+  var nextBNode = 1
+}
+
+import MyParsers._
+
+case class Select(distinct:Boolean, attrs:SparqlAttributeList, gp:GraphPattern, order:List[OrderElt], offset:Option[Int], limit:Option[Int]) {
+  override def toString =
+    "SELECT "+
+    { if (distinct) "DISTINCT " else "" }+
+    attrs+"\n"+gp+" "+
+    { if (order.size > 0) {order.map(o => o.toString).mkString("ORDER BY ", " ", " ") } else "" }+
+    { if (offset.isDefined) {"OFFSET " + offset.get + " "} else "" }+
+    { if (limit.isDefined) {"LIMIT " + limit.get + " "} else "" }
+}
+case class Construct(head:TriplesBlock, gp:GraphPattern)
+case class SparqlAttributeList(attributelist:List[Var]) {
+  override def toString = attributelist.toList.sortWith((l, r) => l.s < r.s).mkString(" ")
+}
+
+sealed abstract class GraphPattern {
+  def findVars ():Set[Var] = {
+    this match {
+      case TableFilter(gp2:GraphPattern, expr:Expression) =>
+	gp2.findVars
+
+      case TriplesBlock(triplepatterns) =>
+	/* Examine each triple, updating the compilation state. */
+	triplepatterns.foldLeft(Set[Var]())((x, y) => x ++ y.findVars)
+
+      case TableConjunction(list) =>
+	/* Examine each triple, updating the compilation state. */
+	list.foldLeft(Set[Var]())((x, y) => x ++ y.findVars)
+
+      case OptionalGraphPattern(gp2) =>
+	/* Examine each triple, updating the compilation state. */
+	gp2.findVars
+
+      case x => error("no code to handle " + x)
+    }
+  }
+  def findAssignables ():Set[Assignable] = {
+    this match {
+      case TableFilter(gp2:GraphPattern, expr:Expression) =>
+	gp2.findAssignables
+
+      case TriplesBlock(triplepatterns) =>
+	/* Examine each triple, updating the compilation state. */
+	triplepatterns.foldLeft(Set[Assignable]())((x, y) => x ++ y.findAssignables)
+
+      case TableConjunction(list) =>
+	/* Examine each triple, updating the compilation state. */
+	list.foldLeft(Set[Assignable]())((x, y) => x ++ y.findAssignables)
+
+      case OptionalGraphPattern(gp2) =>
+	/* Examine each triple, updating the compilation state. */
+	gp2.findAssignables
+
+      case x => error("no code to handle " + x)
+    }
+  }
+
+  def trim (terms:Set[Term]):GraphPattern = {
+    this match {
+      case TableFilter(gp2:GraphPattern, expr:Expression) =>
+	TableFilter(gp2.trim(terms), expr)
+
+      case TriplesBlock(triplepatterns) => {
+	val r0 = new org.w3.sw.util.GraphAnalyzer[Term](Map[Term, Set[Term]]())
+	/* Examine each triple, updating the compilation state. */
+	val r = triplepatterns.foldLeft(r0)((r, triple) => r.pair(triple.s, triple.o))
+	val useful = triplepatterns.foldLeft(Set[TriplePattern]())((s, t) => {
+	  if (r.neededFor(terms, t.s, Set(t.o)) &&
+	      r.neededFor(terms, t.o, Set(t.s))) s + t
+	  else s
+	})
+	val useful2 =
+	  if (useful.size == 0)
+	    triplepatterns.foldLeft(Set[TriplePattern]())((s, t) => {
+	      if (r.neededFor(terms, t.s, Set(t.o)) ||
+		  r.neededFor(terms, t.o, Set(t.s))) s + t
+	      else s
+	    })
+          else useful
+	TriplesBlock(useful2.toList)
+      }
+
+      case TableConjunction(list) =>
+	/* Examine each triple, updating the compilation state. */
+	TableConjunction(list.map(gp2 => gp2.trim(terms)))
+
+      case OptionalGraphPattern(gp2) =>
+	/* Examine each triple, updating the compilation state. */
+	OptionalGraphPattern(gp2.trim(terms))
+
+      case x => error("no code to handle " + x)
+    }
+  }
+
+  def simplify ():GraphPattern = {
+    this match {
+      case TableFilter(gp2:GraphPattern, expr:Expression) =>
+	TableFilter(gp2.simplify, expr)
+
+      case tb:TriplesBlock => tb
+
+      case TableConjunction(list) => {
+	/* Eliminate series of TriplesBlocks. */
+	val (conjuncts, triples) = list.foldLeft((List[GraphPattern](), List[TriplePattern]()))((pair, gp2) => {
+	  val (conj, trip) = pair
+	  val gp3 = gp2.simplify
+	  gp3 match {
+	    case TriplesBlock(triplepatterns) =>
+	      (conj, trip ++ triplepatterns)
+	    case x => {
+	      (conj ++ List(TriplesBlock(trip)), List[TriplePattern]())
+	    }
+	  }
+	})
+	val conj2 =
+	  if (triples.size > 0) conjuncts ++ List(TriplesBlock(triples))
+	  else conjuncts
+	if (conj2.size > 1) TableConjunction(conj2)
+	else if (conj2.size == 1) conj2(0)
+	else TriplesBlock(List[TriplePattern]())
+      }
+
+      case OptionalGraphPattern(gp2) =>
+	/* Examine each triple, updating the compilation state. */
+	OptionalGraphPattern(gp2.simplify)
+
+      case x => error("no code to handle " + x)
+    }
+  }
+}
+
+case class TriplesBlock(triplepatterns:List[TriplePattern]) extends GraphPattern {
+  override def toString = "{\n  " + (triplepatterns.toList.map(s => s.toString.replace("\n", "\n  ")).mkString("", " .\n  ", " .\n")) + "}"
+  override def equals (other:Any):Boolean = other match {
+    case that:TriplesBlock => (that canEqual this) && triplepatterns.toSet == that.triplepatterns.toSet
+    case _ => false
+  }
+  override def canEqual(other : Any) : Boolean = other.isInstanceOf[TriplesBlock]
+  override def hashCode:Int = 41*triplepatterns.toSet.hashCode
+}
+case class TableConjunction(gps:List[GraphPattern]) extends GraphPattern {
+  assert (!(gps exists (x => { x match { case TableConjunction(_) => true case _ => false } })))
+  override def toString = "{\n  " + (gps.toList.map(s => s.toString.replace("\n", "\n  ")).mkString("\n  ")) + "\n}\n"
+}
+case class TableDisjunction(gps:List[GraphPattern]) extends GraphPattern {
+  override def toString = "{\n  " + (gps.toList.map(s => s.toString.replace("\n", "\n  ")).mkString("\nUNION\n  ")) + "\n}\n"
+}
+case class TableFilter(gp:GraphPattern, expr:Expression) extends GraphPattern {
+  override def toString = gp.toString + "\nFILTER (" + expr.toString + ")"
+}
+case class OptionalGraphPattern(gp:GraphPattern) extends GraphPattern {
+  override def toString = "OPTIONAL " + gp.toString
+}
+case class MinusGraphPattern(gp:GraphPattern) extends GraphPattern {
+  override def toString = "MINUS " + gp.toString
+}
+case class GraphGraphPattern(gp:GraphPattern) extends GraphPattern
+
+case class TriplePattern(s:Term, p:Term, o:Term) {
+  override def toString = s + " " + p + " " + o
+  def findVars ():Set[Var] = {
+    val varS:Set[Var] = s match {
+      case TermVar(v) => Set(v)
+      case _                 => Set()
+    }
+    val varO:Set[Var] = o match {
+      case TermVar(v) => Set(v)
+      case _                 => Set()
+    }
+    varS ++ varO
+  }
+  def findAssignables ():Set[Assignable] = {
+    val varS:Set[Assignable] = s match {
+      case TermVar(v) => Set(VarAssignable(v))
+      case TermBNode(v) => Set(BNodeAssignable(v))
+      case _                 => Set()
+    }
+    val varO:Set[Assignable] = o match {
+      case TermVar(v) => Set(VarAssignable(v))
+      case TermBNode(b) => Set(BNodeAssignable(b))
+      case _                 => Set()
+    }
+    varS ++ varO
+  }
+}
+
+case class Literal(lit:RDFLiteral) {
+  override def toString = lit match {
+    case RDFLiteral(s, RDFLiteral.IntegerDatatype) => s
+    case _ => lit.toString
+  }
+}
+
+sealed abstract class Assignable { val s:String }
+
+case class VarAssignable(v:Var) extends Assignable { val s = v.s }
+case class BNodeAssignable(b:BNode) extends Assignable { val s = b.s }
+
+case class Var(s:String) {
+  override def toString = "?" + s
+}
+
+case class Uri(s:String) {
+  override def toString = "<" + s + ">"
+}
+
+case class BNode(s:String) {
+  override def toString = "_:" + s
+}
+
+case class Expression(conjuncts:List[PrimaryExpression]) {
+  override def toString = conjuncts.map(e => e.toString()).mkString(" && ")
+}
+
+sealed abstract class PrimaryExpression
+case class PrimaryExpressionEq(left:SparqlTermExpression, right:SparqlTermExpression) extends PrimaryExpression {
+  override def toString = left.toString() + " = " + right.toString
+}
+case class PrimaryExpressionLt(left:SparqlTermExpression, right:SparqlTermExpression) extends PrimaryExpression {
+  override def toString = left.toString() + " < " + right.toString
+}
+case class PrimaryExpressionGt(left:SparqlTermExpression, right:SparqlTermExpression) extends PrimaryExpression {
+  override def toString = left.toString() + " > " + right.toString
+}
+case class SparqlTermExpression(term:Term) extends PrimaryExpression {
+  override def toString = term.toString
+}
+
+case class OrderElt(desc:Boolean, expr:Expression) {
+  override def toString = { if (desc) "DESC" else "ASC" } + "(" + expr.toString + ")"
+}
+
+sealed trait Term
+case class TermUri(u:Uri) extends Term {
+  override def toString = u.toString
+}
+case class TermBNode(b:BNode) extends Term {
+  override def toString = b.toString
+}
+case class TermVar(v:Var) extends Term {
+  override def toString = v.toString
+}
+case class TermLit(lit:Literal) extends Term {
+  override def toString = lit.toString
+}
+
+
+case class Sparql() extends JavaTokenParsers {
+
+  def select:Parser[Select] =
+    rep(prefixdecls) ~ "SELECT" ~ opt("DISTINCT") ~ attributelist ~ opt("WHERE") ~ groupgraphpattern ~ opt(order) ~ opt(offset) ~ opt(limit) ^^ {
+      case x~"SELECT"~d~a~w~gp~ord~off~lim => Select(d.isDefined, a, gp, ord.getOrElse(List[OrderElt]()), off, lim)
+    }
+
+  def order:Parser[List[OrderElt]] = 
+    "ORDER" ~ "BY" ~ rep(orderelt) ^^ { case o~b~elts => elts }
+
+  def orderelt:Parser[OrderElt] = (
+      "ASC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(false, expr) }
+    | "DESC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(true, expr) }
+    | varr ^^ { case v => OrderElt(false, Expression(List(SparqlTermExpression(TermVar(v))))) }
+  )
+    
+  def offset:Parser[Int] =
+    "OFFSET" ~ integer ^^ { case o~i => i.toInt }
+
+  def limit:Parser[Int] =
+    "LIMIT" ~ integer ^^ { case o~i => i.toInt }
+
+  def construct:Parser[Construct] =
+    rep(prefixdecls) ~ "CONSTRUCT" ~ constructpattern ~ opt("WHERE") ~ groupgraphpattern ^^ { case x~"CONSTRUCT"~a~w~gp => Construct(a, gp) }
+
+  def constructpattern:Parser[TriplesBlock] =
+    "{" ~ opt(triplesblock) ~ "}" ^^ { case "{"~tbOPT~"}" => tbOPT.getOrElse(TriplesBlock(List[TriplePattern]())) }
+
+  def prefixdecls:Parser[Unit] =
+    "PREFIX" ~ name ~ ":" ~ qnameORuri ^^ { case "PREFIX"~pre~":"~u => prefixes += (pre -> u.s) }
+
+  def filter:Parser[Expression] =
+    "FILTER" ~ "(" ~ expression ~ ")" ^^ { case "FILTER"~"("~expression~")" => expression }
+
+  def expression:Parser[Expression] = 
+    repsep(primaryexpression, "&&") ^^ 
+    { Expression(_) }
+
+  def primaryexpression:Parser[PrimaryExpression] = (
+      value ~ "=" ~ value ^^
+      { case left ~ "=" ~ right => PrimaryExpressionEq(left, right) }
+    | value ~ "<" ~ value ^^
+      { case left ~ "<" ~ right => PrimaryExpressionLt(left, right) }
+    | value ~ ">" ~ value ^^
+      { case left ~ ">" ~ right => PrimaryExpressionGt(left, right) }
+    | value
+  )
+
+  def value:Parser[SparqlTermExpression] = (
+      qnameORuri ^^ { case x => SparqlTermExpression(TermUri(x)) }
+    | varr ^^ { x => SparqlTermExpression(TermVar(x)) }
+    | literal ^^ { x => SparqlTermExpression(TermLit(x)) }
+  )
+
+  def attributelist:Parser[SparqlAttributeList] =
+    rep(varr) ^^ { SparqlAttributeList(_) }
+
+  def groupgraphpattern:Parser[GraphPattern] = (
+    "{" ~ opt(triplesblock) ~ rep(graphpatternnottriplesORfilter ~ opt(triplesblock)) ~ "}" ^^
+    {
+      case "{"~tbOPT~gpntORf_tbOPT~"}" => {
+
+// case class TriplesBlock(triplepatterns:List[TriplePattern]) extends GraphPattern
+// case class TableConjunction(gps:List[GraphPattern]) extends GraphPattern
+// case class TableDisjunction(gps:List[GraphPattern]) extends GraphPattern
+// case class TableFilter(gp:GraphPattern, expr:Expression) extends GraphPattern
+// case class OptionalGraphPattern(gp:GraphPattern) extends GraphPattern
+// case class GraphGraphPattern(gp:GraphPattern) extends GraphPattern
+
+	// println("groupgraphpattern(" + tbOPT + ", " + gpntORf_tbOPT + ")")
+	val init:Option[GraphPattern] = tbOPT
+	gpntORf_tbOPT.foldLeft(init)((gp, lentry) => {//println("match: " + (gp, lentry))
+	  // print("case (" + gp + ", " + lentry + ")")
+	  (gp, lentry) match {
+	    case (Some(TableFilter(TriplesBlock(l), Expression(lexp))), ~(TableFilter(null, Expression(expr)), Some(TriplesBlock(r)))) => Some(TableFilter(TriplesBlock(l ++ r), Expression(lexp ++ expr)))
+	    case (Some(TriplesBlock(l)), ~(TableFilter(null, expr), Some(TriplesBlock(r)))) => Some(TableFilter(TriplesBlock(l ++ r), expr))
+	    case (Some(gp             ), ~(TableFilter(null, expr), None                 )) => Some(TableFilter(gp, expr))
+	    case (None,                  ~(TableFilter(null, expr), Some(TriplesBlock(r)))) => Some(TableFilter(TriplesBlock(r), expr))
+
+	    // case (None,     ~(TableConjunction(gps), None    )) => TableConjunction(gps)
+	    // case (Some(gp), ~(TableConjunction(gps), None    )) => TableConjunction(List(List(gp) ++ gps))
+	    // case (None,     ~(TableConjunction(gps), Some(tb))) => TableConjunction(List(gps ++ List(tb)))
+	    // case (Some(gp), ~(TableConjunction(gps), Some(tb))) => TableConjunction(List(List(gp) ++ gps ++ List(tb)))
+
+	    case (None                    ,  ~(x, None    )) => Some(x                                     )
+	    case (Some(TableConjunction(l)), ~(x, None    )) => Some(TableConjunction(l ++ List(    x    )))
+	    case (Some(gp                 ), ~(x, None    )) => Some(TableConjunction(     List(gp, x    )))
+	    case (None                     , ~(x, Some(tb))) => Some(TableConjunction(     List(    x, tb)))
+	    case (Some(TableConjunction(l)), ~(x, Some(tb))) => Some(TableConjunction(l ++ List(    x, tb)))
+	    case (Some(gp                 ), ~(x, Some(tb))) => Some(TableConjunction(     List(gp, x, tb)))
+
+	    case x => error("found " + x)
+	  }
+	}).get
+      }
+    }
+  )
+
+  def graphpatternnottriplesORfilter:Parser[GraphPattern] = (
+      "OPTIONAL"~groupgraphpattern ^^ { case "OPTIONAL"~ggp => OptionalGraphPattern(ggp) }
+    | "MINUS"~groupgraphpattern ^^ { case "MINUS"~ggp => MinusGraphPattern(ggp) }
+    | rep1sep(groupgraphpattern, "UNION") ^^ { x => if (x.size > 1) TableDisjunction(x) else x(0) }
+    | "GRAPH"~uri~groupgraphpattern ^^ { case "GRAPH"~u~ggp => GraphGraphPattern(ggp) }
+    | filter ^^ { x => TableFilter(null, x) }
+  )
+
+  def triplesblock:Parser[TriplesBlock] =
+    rep1sep(triplepattern, ".") ~ opt(".") ^^ { case pats~x => TriplesBlock(pats) }
+
+  def triplepattern:Parser[TriplePattern] =
+    subject ~ predicate ~ objectt ^^ { case s~p~o => TriplePattern(s, p, o) }
+
+  def subject:Parser[Term] = (
+      qnameORuri ^^ { case x => TermUri(x) }
+    | bnode ^^ { x => TermBNode(x) }
+    | varr ^^ { x => TermVar(x) }
+  )
+
+  def predicate:Parser[Term] = (
+      qnameORuri ^^ { x => TermUri(x) }
+    | "a" ^^ { x => TermUri(Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")) }
+    | varr ^^ { x => TermVar(x) }
+  )
+
+  def objectt:Parser[Term] = (
+      qnameORuri ^^ { case x => TermUri(x) }
+    | bnode ^^ { x => TermBNode(x) }
+    | varr ^^ { x => TermVar(x) }
+    | literal ^^ { x => TermLit(x) }
+  )
+
+  def qnameORuri:Parser[Uri] = (
+      "<"~uri~">" ^^ { case "<"~x~">" => Uri(x) }
+    | name~":"~name ^^ {
+      case prefix~":"~localName => try {
+	Uri(prefixes(prefix) + localName)
+      } catch {
+	case e:java.util.NoSuchElementException =>
+	  throw new Exception("unknown prefix " + prefix)
+      }
+    }
+  )
+
+  def bnode:Parser[BNode] =
+    "_:"~name ^^ { case "_:"~name => BNode(name) }
+
+  def literal:Parser[Literal] = (
+      stringLiteral~"^^"~qnameORuri ^^
+      {
+	case lit~"^^"~dt => Literal(RDFLiteral(lit.substring(1,lit.size - 1), dt.s match {
+	  case "http://www.w3.org/2001/XMLSchema#string" => RDFLiteral.StringDatatype
+	  case "http://www.w3.org/2001/XMLSchema#integer" => RDFLiteral.IntegerDatatype
+	  case "http://www.w3.org/2001/XMLSchema#date" => RDFLiteral.DateDatatype
+	  // case "http://www.w3.org/2001/XMLSchema#dateTime" => RDFLiteral.DateTimeDatatype
+	  case x => error("only programed to deal with string and integer, not " + x)
+	}))
+      }
+    | integer ^^ { l => Literal(RDFLiteral(l, RDFLiteral.IntegerDatatype)) }
+  )
+
+  def varr:Parser[Var] = "?"~ident ^^ { case "?"~x => Var(x) }
+
+}
+
+object Sparql {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sparql2sparql/src/main/scala/SparqlToSparql.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,386 @@
+/* SparqlToSparql: convert SPARQL queries to sound SQL queries.
+ *
+
+ * 
+ */
+
+package org.w3.sw.sparql2sparql
+
+import scala.util.parsing.combinator._
+import org.w3.sw.sparql
+
+case class MapTarget (term:sparql.Term, nm:Option[NodePattern])
+
+case class NodePatternMap (m:Map[sparql.Var, NodePattern]) {
+  def var2maptarget (t:sparql.Term) : MapTarget = {
+    t match {
+      case sparql.TermVar(v) => MapTarget(t, m.get(v))
+      case _ => MapTarget(t, None)
+    }
+  }
+}
+
+case class NodePattern (iface:String, direct:String)
+
+case class SparqlMap (construct:sparql.Construct, nodemap:NodePatternMap)
+
+object SparqlToSparql {
+
+  /**
+   * Some tools for making pretty output, e.g. shortening strings.
+   */
+  var RuleLabels = scala.collection.mutable.Map[String,String]()
+  var Abbreviations = scala.collection.mutable.Map[String,String]()
+  def _shorten (s:String) = {
+    val s2 = if (RuleLabels.contains(s)) RuleLabels(s)
+	     else s
+    val s3 = Abbreviations.foldLeft(s2)((s, ss) => s.replace(ss._1, ss._2))
+    s3
+  }
+
+
+  /**
+   * Substitute the terms in a triple pattern or a graph pattern with other terms.
+   */
+  def substituteTerm (changeMe:sparql.Term, from:sparql.Term, to:sparql.Term, nm:Option[NodePattern]):sparql.Term = {
+    if (changeMe == from) {
+      from match {
+	case sparql.TermVar(v) => {
+    	  if (nm.isDefined) {
+    	    val nodeMap = nm.get
+	    to match {
+    	    case sparql.TermVar(v2) => {
+    	      println("reverse map(" + v2 + ",\n            " + nodeMap.direct + ",\n            " + nodeMap.iface)
+	      to
+	    }
+    	    case sparql.TermBNode(b) => {
+    	      println("reverse map(" + b + ",\n            " + nodeMap.direct + ",\n            " + nodeMap.iface)
+	      to
+	    }
+    	    case sparql.TermUri(u) => {
+	      val s:String = u.s
+	      val r = u.s.replaceAll(nodeMap.iface, nodeMap.direct)
+	      //println("\"" + u.s + "\".replaceAll("+nodeMap.iface+", "+nodeMap.direct+") = \""+r+"\"")
+	      sparql.TermUri(sparql.Uri(u.s.replaceAll(nodeMap.iface, nodeMap.direct))) // !!! failure here should error()
+	    }
+    	    case sparql.TermLit(l) => 
+    	      error("variable " + v + " bound to literlal " + l + " but should be a node as indicated by " + nodeMap)
+	    }
+	  } else to
+	}
+	case _ => to
+      }
+    } else changeMe
+  }
+
+  def substitute (gp:sparql.GraphPattern, from:sparql.Term, target:MapTarget) = {
+    gp match {
+      case sparql.TriplesBlock(triplepatterns) => sparql.TriplesBlock(
+	triplepatterns.map((tp) => {
+	  // println("sub(" + tp.o + ", " + from + ", " + to + ") => ")
+	  // println(substituteTerm(toTerm(tp.o), tp.o, from, target.term))
+	  sparql.TriplePattern(substituteTerm(tp.s, from, target.term, target.nm),
+			       tp.p,
+			       substituteTerm(tp.o, from, target.term, target.nm))
+	}
+      ))
+      case _ => error("not implemented" + gp)
+    }
+  }
+
+  type VarMap = Map[sparql.Var, MapTarget]
+
+  def substituteGraphPattern (gp:sparql.GraphPattern, vartargetmap:VarMap, varPrefix:String):sparql.GraphPattern = {
+    /**
+     * Substitute gp (the rule body) with the variables and constants from the
+     * query which matched variables in the rule head.
+     */
+    val mapped = vartargetmap.foldLeft(gp)((incrementalGP, vartarget) => {
+      val (varr, target) = vartarget
+      val ret = substitute(incrementalGP, sparql.TermVar(varr), target)
+      //println("^^incrementalGP: " + incrementalGP + "\nvartarget: " + vartarget + "\nret: " + ret)
+      ret;
+    })
+
+    /**
+     * "Uniquely" prefix unmapped vars to void conflict with other rules.
+     */
+    // val bound = Set[sparql.Var](vartargetmap.map((vartarget) => vartarget._1))
+    val bound = vartargetmap.foldLeft(Set[sparql.Var]())((s, vartarget) => s + vartarget._1)
+    val mappedTo = vartargetmap.foldLeft(Set[sparql.Term]())((s, vartarget) => {
+      val MapTarget(term, optnp) = vartarget._2
+      (term, optnp) match {
+	case (sparql.TermUri(u), Some(np)) => {
+	  s + sparql.TermUri(sparql.Uri(u.s.replaceAll(np.iface, np.direct))) // !!! failure here should error()
+	}
+	case (_, _) => s + vartarget._2.term
+      }
+    })
+    val vars = gp.findVars
+    val diff = vars -- bound
+    diff.foldLeft(mapped)((incrementalGP, varr) => {
+      val full = substitute(incrementalGP, sparql.TermVar(varr), 
+		 MapTarget(sparql.TermVar(sparql.Var(varPrefix + varr.s)),
+			   None// !! vartargetmap(varr).nm
+			 ))
+      full.trim(mappedTo)
+    })
+  }
+  case class RuleIndex (trigger:sparql.TriplePattern, smap:SparqlMap) {
+    override def toString = "{ \"" + trigger + "\" } => {\"\n  " + _shorten(smap.construct.gp.toString).replace("\n", "\n  ") + "\n\"}"
+    def transform (tp:sparql.TriplePattern):sparql.GraphPattern = {
+      substitute(substitute(smap.construct.gp, trigger.s, smap.nodemap.var2maptarget(tp.s)),
+		 trigger.o, smap.nodemap.var2maptarget(tp.o))
+    }
+  }
+
+  /**
+   * Bindings keep track of all the ways that a particular rule has been invoked
+   * in order to cover a particular query pattern. It's a mapping from a rule to
+   * the list of "editions" (invocations) of that rule.
+   */
+  case class Bindings (b:Map[sparql.Construct, List[VarMap]]) {
+    def countEditions () = {
+      var count = 0
+      b.map((constructlist) =>
+	constructlist._2.map((_) =>
+	  count = count + 1))
+      count
+    }
+    def toGraphPattern (ident:String):sparql.GraphPattern = {
+      var conjNo = 0
+      val conjuncts = b.keySet.toList.flatMap(construct => {
+	val l = b(construct)
+	val patterns:List[sparql.GraphPattern] = l.map((vartermmap) => {
+	  val unique = ident + conjNo + "_"
+	  conjNo = conjNo + 1
+	  substituteGraphPattern(construct.gp, vartermmap, unique)
+	})
+	patterns
+      })
+
+      if (conjuncts.size == 0)
+	sparql.TriplesBlock(List[sparql.TriplePattern]())
+      else if (conjuncts.size > 1)
+	sparql.TableConjunction(conjuncts).simplify
+      else
+	conjuncts(0)
+    }
+    override def toString = "Bindings(Map(" + b.map((constructlist) => {
+      val (construct, l) = constructlist
+      "\"" + _shorten(construct.head.toString) + "\" -> List(" + l.map((vartermmap) => {
+	"Map(" + vartermmap.map((varterm) => {
+	  val (varr, term) = varterm
+	  varr.toString + ":" + term.toString
+	}) + ")"
+      }).mkString("\n    ", ",\n    ", "") + ")"
+    }).mkString("\n  ", ",\n  ", "") + "))"
+    /**
+     * Make sure a particular rule has an entry in the Bindings.
+     */
+    def ensureGraphPattern (construct:sparql.Construct) = {
+      if (b.contains(construct)) this
+      else Bindings(b + (construct -> List[VarMap]()))
+    }
+    // val varsS:Option[Bindings] = vars.maybeRebind(construct, v, tos)
+    // b:Map[sparql.Construct, List[VarMap]]
+    def mustBind (construct:sparql.Construct, nodemap:NodePatternMap, vs:sparql.Term, tos:sparql.Term, vo:sparql.Term, too:sparql.Term):Bindings = {
+      /* ridiculous traversal for the first viably matching rule edition. */
+      var matched = false
+      val existing:List[VarMap] = b(construct).map((map:VarMap) => {
+	def _matches (l:sparql.Term, r:sparql.Term):(Boolean, VarMap) = {
+	  val empty:VarMap = Map[sparql.Var, MapTarget]()
+	  (l, r) match {
+	    case (v:sparql.TermVar, x) =>
+	      // println("(v:sparql.TermVar, x)" + v.v + ":" + x)
+	      if (map.contains(v.v)) {
+		if (r == map(v.v).term) (true, empty)
+		else (false, empty)
+	      } else {
+		(true, Map[sparql.Var, MapTarget](v.v -> MapTarget(r, nodemap.m.get(v.v))))
+	      }
+	    case (x, v:sparql.TermVar) => {
+	      // println("query variable " + v + " known equal to " + x + " at compile time")
+	      (true, empty)
+	    }
+	    case (x, y) =>
+	      // println("(x, y)" + x + "?=" + y)
+	      if (x == y) (true, empty)
+	      else (false, empty)
+	  }
+	}
+	val (sMatches, sBindings) = _matches(vs, tos)
+	val (oMatches, oBindings) = _matches(vo, too)
+
+	if (sMatches & oMatches) {
+	  matched = true
+	  map ++ sBindings ++ oBindings
+	} else
+	  map
+      })
+      if (matched)
+	Bindings(b + (construct -> existing))
+      else {
+	Bindings(b.map((constructlist) => {
+	  val (oldConstr, l) = constructlist
+	  if (oldConstr == construct) {
+	    def _newBinding (l:sparql.Term, r:sparql.Term):VarMap = {
+	      val empty:VarMap = Map[sparql.Var, MapTarget]()
+	      (l, r) match {
+		case (v:sparql.TermVar, _) =>
+		  Map[sparql.Var, MapTarget](v.v -> MapTarget(r, nodemap.m.get(v.v)))
+		case (b:sparql.TermBNode, _) => {
+		  println(".. synthetic query variable " + b + "")
+		  Map[sparql.Var, MapTarget]()
+		  // println("@@ mustBind:_newBinding(BNode) + " + b)
+		  // Map(sparql.Var("bnode_" + b.b.s) -> r) // !!!
+		}
+		case (_, v:sparql.TermVar) => {
+		  println(".. query variable " + v + " known equal to " + l + " at compile time")
+		  Map[sparql.Var, MapTarget]()
+		}
+		case (_, _) => Map[sparql.Var, MapTarget]()
+	      }
+	    }
+	    val ent = _newBinding(vs, tos) ++ _newBinding(vo, too)
+	    val list = l ++ List(ent)
+	    (construct -> list)
+	  } else {
+	    (oldConstr -> l)
+	  }
+	}))
+      }
+    }
+  }
+  def createEmptyBindings () = Bindings(Map[sparql.Construct, List[VarMap]]())
+
+  case class RuleMap (rules:Map[sparql.Uri, List[RuleIndex]]) {
+    /**
+     * Recursively examine the first triple pattern in a graph pattern and add
+     * invocations to the bindings to produce that triple.
+     */
+    def transform (prove:List[sparql.TriplePattern], used:Set[sparql.TriplePattern], varsP:Bindings):Bindings = {
+      val _pad = used.foldLeft("")((s, x) => s + " ")
+      def _deepPrint (s:String):Unit = {
+	//print(used.size + ":" + _pad + s.replace("\n", "\n" + _pad) + "\n\n")
+      }
+      def _deepPrint1 (prefix:String, s:String):Unit = {
+	val p = used.size + ":" + prefix + _pad
+	//print(p + s.replace("\n", "\n" + p) + "\n\n")
+      }
+
+      val car = prove(0)
+      val cdr = prove.filterNot (_ == car)
+      _deepPrint("RuleMap.transform(" + _shorten(car.toString) + ", " + varsP.toString + ")")
+      val xform = car.p match {
+	case sparql.TermUri(u) =>
+	  // for each rule that supplies predicate u
+	  var _ruleNo = 0;
+	  rules(u).foldLeft(createEmptyBindings)((bindings, hornRule) => {
+	    val _prefix = "rule:" + _ruleNo
+	    _ruleNo = _ruleNo + 1
+	    _deepPrint1(_prefix, "trying " + _shorten(hornRule.trigger.toString))
+	    val vars = varsP.ensureGraphPattern(hornRule.smap.construct)
+	    // try matching the subject
+	    val varss:Bindings = vars.mustBind(hornRule.smap.construct, hornRule.smap.nodemap, hornRule.trigger.s, car.s, hornRule.trigger.o, car.o)
+	    val ret =
+	      if (cdr.size > 0) {
+		transform(cdr, used + car, varss)
+	      } else {
+		_deepPrint1("match!", _shorten(hornRule.trigger.toString) + "(" + _shorten(car.toString) + ") matches with " + _shorten(varss.toString))
+		varss
+	      }
+	    _deepPrint1(_prefix, _shorten(hornRule.trigger.toString) + "(" + _shorten(car.toString) + ") matches ..." + bindings.toString + ret.toString)
+
+	    /* Magic Huristics */
+	    if (bindings.countEditions == 0) {
+	      //print("choose: bindings.countEditions == 0 => " + ret + "\n\n")
+	      ret
+	    } else if (ret.countEditions == 0) {
+	      //print("choose: ret.countEditions == 0 => " + bindings + "\n\n")
+	      bindings
+	    } else if (ret.countEditions < bindings.countEditions) {
+	      //print("choose: "+ret.countEditions+" < "+bindings.countEditions+" => " + ret + "\n\n")
+	      ret
+	    } else {
+	      //print("choose: "+ret.countEditions+" > "+bindings.countEditions+" => " + bindings + "\n\n")
+	      bindings
+	    }
+	  })
+	case _ => error("not implemented: " + car.p)
+      }
+      _deepPrint("RuleMap.transform(" + _shorten(car.toString) + ") => " + _shorten(xform.toString))
+      xform
+    }
+
+    override def toString = "RuleMap(Map(" + rules.map((ent) => {
+      val (u, l) = ent
+      "\"" + _shorten(u.toString) + "\" -> List(" + l.map((hr) => {
+	_shorten(hr.toString).replace("\n", "\n    ")
+      }).mkString("\n    ", ",\n    ", "") + ")"
+    }).mkString("\n  ", ",\n  ", "") + "))"
+
+  }
+
+  def mapGraphPattern (gp:sparql.GraphPattern, ruleMap:RuleMap, ident:String):sparql.GraphPattern = {
+    gp match {
+      case sparql.TriplesBlock(tps) => {
+	val emptyBindings = createEmptyBindings
+	val b:Bindings = ruleMap.transform(tps, Set[sparql.TriplePattern](), emptyBindings)
+	//print("mapGraphPattern: " + _shorten(gp.toString) + ") => " + _shorten(b.toString) +  "\n\n")
+	val g:sparql.GraphPattern = b.toGraphPattern(ident)
+	//print("mapGraphPattern: ... instantiated: " + _shorten(g.toString) +  "\n\n")
+	g
+      }
+      case sparql.TableFilter(gp2:sparql.GraphPattern, expr:sparql.Expression) =>
+	sparql.TableFilter(mapGraphPattern(gp2, ruleMap, ident), expr)
+      case sparql.MinusGraphPattern(gp2) =>
+	sparql.MinusGraphPattern(mapGraphPattern(gp2, ruleMap, ident))
+      case sparql.OptionalGraphPattern(gp2) =>
+        sparql.OptionalGraphPattern(mapGraphPattern(gp2, ruleMap, ident))
+      case sparql.GraphGraphPattern(gp2) =>
+	sparql.GraphGraphPattern(mapGraphPattern(gp2, ruleMap, ident))
+      case sparql.TableDisjunction(l) =>
+	sparql.TableDisjunction({l.foldLeft((List[sparql.GraphPattern](), 0))((p, gp2) => {
+	  val (l, disjNo) = p
+	  (l ++ List(mapGraphPattern(gp2, ruleMap, ident + disjNo + "_")), disjNo + 1)
+	})}._1)
+      case sparql.TableConjunction(l) =>
+	sparql.TableConjunction({l.foldLeft((List[sparql.GraphPattern](), 0))((p, gp2) => {
+	  val (l, conjNo) = p
+	  (l ++ List(mapGraphPattern(gp2, ruleMap, ident + conjNo + "_")), conjNo + 1)
+	})}._1)
+    }
+  }
+
+  def apply (query:sparql.Select, maps:List[SparqlMap]) : sparql.Select = {
+    var _ruleNo = 0
+    val ruleMap = RuleMap({
+      maps.foldLeft(Map[sparql.Uri, List[RuleIndex]]())((m, sm) => {
+	val SparqlMap(rule, nodemap) = sm
+	// Register abbreviations for debugging output.
+	RuleLabels.update(rule.head.toString, "head" + _ruleNo)
+	RuleLabels.update(rule.gp.toString, "body" + _ruleNo)
+
+	_ruleNo = _ruleNo + 1
+	rule.head.triplepatterns.foldLeft(m)((m, tp) => m + ({
+	  tp.p match {
+	    case sparql.TermUri(u) => u -> {
+	      if (m.contains(u)) m(u) ++ List(RuleIndex(tp, sm))
+	      else List(RuleIndex(tp, sm))}
+	    case _ => error("not implemented: " + tp.p)
+	  }
+	}))
+      })
+    })
+    //println("ruleMap: " + ruleMap)
+    sparql.Select(
+      query.distinct,
+      query.attrs,
+      mapGraphPattern(query.gp, ruleMap, "_"),
+      query.order, query.offset, query.limit
+    )
+  }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sparql2sql/src/main/scala/SparqlToSql.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,1212 @@
+/** SparqlToSql: convert SPARQL queries to sound SQL queries.
+ * <a href="http://www.w3.org/TR/rdf-sparql-query/#sparqlDefinition">SPARQL semantics</a> defines the evalutation of an abstract query on a dataset.
+ * This object maps a SPARQL abstract query over a <a href="@@">direct graph</a> to an SQL abstract query over the constituant relations.
+ * <p/>
+ * 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
+ *   <a href="http://www.w3.org/TR/rdf-sparql-query/#convertGraphPattern">SPARQL rules for converting graph patterns</a>
+ * with the target semantics in SQL instead of SPARQL.
+ */
+
+package org.w3.sw.sparql2sql
+
+import scala.util.parsing.combinator._
+import java.net.URI
+import org.w3.sw.rdb
+import org.w3.sw.sql
+import org.w3.sw.sql.PrettySql.toPrettySql
+import org.w3.sw.rdf
+import org.w3.sw.sparql
+import org.w3.sw.util
+
+case class StemURI(s:String)
+case class PrimaryKey(attr:rdb.RDB.AttrName)
+
+sealed abstract class Binding
+case class RDFNode(relvarattr:sql.RelVarAttr) extends Binding
+case class Str(relvarattr:sql.RelVarAttr) extends Binding
+case class Int(relvarattr:sql.RelVarAttr) extends Binding
+case class Enum(relvarattr:sql.RelVarAttr) extends Binding
+
+/**
+ * Converts a SPARQL object to an SQL object equivalent over the direct graph.
+ *
+ * @see {@link org.w3.sw.sparql.Sparql Sparql}
+ * @see {@link org.w3.sw.sql.Sql#Select Sql}
+ */
+object SparqlToSql {
+  /**
+   * Accumulated state for generating an Sql object.
+   *
+   * @param joins an AddOrderedSet of SQL joins
+   * @param varmap a map from Sparql.Assignable to SQL terms
+   * @param exprs a set of accumulated SQL expressions
+   */
+  case class R2RState(joins:util.AddOrderedSet[sql.Join], varmap:Map[sparql.Assignable, SQL2RDFValueMapper], exprs:Set[sql.Expression])
+
+  /**
+   * Binding for a sparql.Variable or BNode
+   */
+  sealed abstract class FullOrPartialBinding
+  case class FullBinding(relvarattr:sql.RelVarAttr) extends FullOrPartialBinding
+  case class BindingConstraint(expr:sql.RelationalExpression, relvarattr:sql.RelVarAttr)
+
+  /**
+   * Partial binding, a variable only (so far) found in OPTIONALs or assymetric
+   * UNIONs.
+   */
+  case class PartialBinding(binders:Set[BindingConstraint]) extends FullOrPartialBinding
+
+  /**
+   * Convert a binding to an SQL expression.
+   * <p/>
+   * example return:
+   *   <code>if (g_union1._DISJOINT_ != 0, g_union1.who, if (g_union2._DISJOINT_ != 3, g_union2.who, NULL))</code>
+   * @param against binding to be expressed
+   * @return SQL expression representing that binding
+   */
+  def toExpr(against:FullOrPartialBinding):sql.Expression = {
+    against match {
+      case FullBinding(relvarattr) =>
+	sql.PrimaryExpressionAttr(relvarattr)
+      case PartialBinding(binders) =>
+	binders.toList.reverse.foldLeft(sql.ConstNULL():sql.Expression)((exp, binding) => {
+	  val BindingConstraint(expr, relvarattr) = binding
+	  sql.IfElse(expr, sql.PrimaryExpressionAttr(relvarattr), exp)
+	})
+    }
+  }
+  /**
+   * Accumulate bindings on previously bound sparql variables.
+   * @param binding previous binding
+   * @param relVarAttr SQL relvar attribute to be bound, e.g. <code>G_union1.who</code>
+   * @param expr expr binding constraint, e.g. <code>G_opt6._DISJOINT_ IS NULL</code> or <code>G_union1._DISJOINT_!=0</code>
+   * @return PartialBinding on old constraints plus expr=relVarAttr
+   */
+  def addExpr(binding:FullOrPartialBinding, relVarAttr:sql.RelVarAttr, expr:sql.RelationalExpression):FullOrPartialBinding = {
+    binding match {
+      case FullBinding(relvarattr) =>
+	error("Unexpected FullBinding to " + relvarattr + "\n" + 
+	      "because subselectVars should only find a pre-existing PartialBindings.")
+        // return binding if this codepath is needed later.
+      case PartialBinding(binders) =>
+	/**
+	 * Add a new BindingConstraint to existing one.
+	 * e.g. existing constraint: G_union1._DISJOINT_!=0,G_union1.name
+	 * add for second side of union: G_union1._DISJOINT_!=1,G_union1.name
+	 */
+	PartialBinding(binders + BindingConstraint(expr, relVarAttr))
+    }
+  }
+
+  /**
+   * SQL terms representing SPARQL variables and bnodes.
+   */
+  sealed abstract class SQL2RDFValueMapper(binding:FullOrPartialBinding)
+  case class IntMapper(binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
+  case class StringMapper(binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
+  case class DateMapper(binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
+  /**
+   * map to a URL for a tuple in the database.
+   */
+  case class RDFNoder(relation:rdb.RDB.RelName, binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
+  /**
+   * map to a blank node label for a tuple in the database.
+   */
+  case class RDFBNoder(relation:rdb.RDB.RelName, binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
+
+  /**
+   * a URL representing a tuple in a database.
+   */
+  case class NodeUri(stem:Stem, rel:Rel, attr:Attr, v:CellValue)
+
+  /**
+   * url stem to base the direct graph.
+   * <p/>
+   * e.g. http://mydb.example/theDatabase
+   */
+  case class Stem(s:String) {
+    override def toString = "" + s
+  }
+
+  /**
+   * SQL relation (table) name
+   */
+  case class Rel(s:String) {
+    override def toString = "" + s
+  }
+  /**
+   * SQL attribute (column) name
+   */
+  case class Attr(s:String) {
+    override def toString = "" + s
+  }
+  /**
+   * value in a database
+   */
+  case class CellValue(s:String)
+  /**
+   * a URL representing a predicate in a database.
+   */
+  case class PUri(stem:Stem, rel:Rel, attr:Attr) {
+    override def toString = "<" + stem + "/" + rel + "#" + attr + ">"
+  }
+  /**
+   * parse predicate URL in direct graph into stem, relation and attribute
+   * <pre>stemURI + '/' + (\w+) + '#' (\w+)</pre>
+   */
+  def parsePredicateURI(u:sparql.Uri):PUri = {
+    val x:String = u.s
+    val uri = new URI(x)
+    val path = uri.getPath().split("/").toList.filterNot(_ == "")
+    val subPath = path.slice(0, path.size - 1).mkString("/")
+    val stem = uri.getScheme() + "://" + uri.getAuthority + "/" + subPath
+    PUri(Stem(stem), Rel(path.last), Attr(uri.getFragment))
+  }
+
+  /**
+   * parse node URL in direct graph into stem, relation, attribute and value
+   * <pre>stemURI + '/' (\w+) '/' (\w+) '.' (\w+) '#record'</pre>
+   */
+  def parseObjectURI(u:sparql.Uri):NodeUri = {
+    try {
+      val x:String = u.s
+      val uri = new URI(x)
+      val path = uri.getPath().split("/").toList.filterNot(_ == "")
+      val subPath = path.slice(0, path.size - 2).mkString("/")
+      val rel = path(path.size - 2)
+      val attrPair = path(path.size-1).split("\\.")
+      val stem = uri.getScheme() + "://" + uri.getAuthority + "/" + subPath
+      assert("record" == uri.getFragment)
+      NodeUri(Stem(stem), Rel(rel), Attr(attrPair(0)), CellValue(attrPair(1)))
+    } catch {
+      case e:java.lang.IndexOutOfBoundsException =>
+	throw new Exception("unable to parse " + u + " as an object")
+    }
+  }
+  /**
+   * synthesize a relvar name from a SPARQL term.
+   * <p/>
+   * e.g. <code>?emp</code> =&gt;<code>R_emp</code>
+   * e.g. <code>&lt;http://hr.example/DB/Employee/empid.253#record&gt;</code> =&gt;<code>R_empid253</code>
+   * e.g. <code>18</code> =&gt;<code>R_18</code>
+   */
+  def relVarFromTerm(s:sparql.Term):sql.RelVar = {
+    s match {
+      case sparql.TermUri(ob) => relVarFromNode(ob)
+      case sparql.TermVar(v)  => relVarFromVar(v)
+      case sparql.TermBNode(v)  => relVarFromBNode(v)
+      case sparql.TermLit(l)  => relVarFromLiteral(l)
+    }
+  }
+
+  def relVarFromNode(u:sparql.Uri):sql.RelVar = {
+    val NodeUri(stem, rel, Attr(a), CellValue(v)) = parseObjectURI(u)
+    sql.RelVar(sql.Name("R_" + a + v))
+  }
+
+  def relVarFromLiteral(l:sparql.Literal):sql.RelVar = {
+    sql.RelVar(sql.Name("R_" + l.lit.lexicalForm))
+  }
+
+  def relVarFromVar(vr:sparql.Var):sql.RelVar = {
+    val sparql.Var(v) = vr
+    sql.RelVar(sql.Name("R_" + v))
+  }
+
+  def relVarFromBNode(vr:sparql.BNode):sql.RelVar = {
+    val sparql.BNode(b) = vr
+    sql.RelVar(sql.Name("B_" + b))
+  }
+
+  /**
+   * synthesize a SQL name from a SPARQL variable or bnode.
+   * <p/>
+   * e.g. <code>?emp</code> =&gt;<code>emp</code>
+   */
+  def attrAliasNameFromVar(v:sparql.Assignable):String = "" + v.s
+
+  /**
+   * add constraints implied by a URI
+   * @param state state to be appended
+   * @param constrainMe relvar attribute to constrain, e.g. <code>R_empid18.empid</code>
+   * @param u SparqlToSql URL object, e.g. <code>NodeUri(http://hr.example/DB,Employee,empid,CellValue(18))</code>
+   * @return state + expression for the URI
+   * <p/>
+   * <code>http://hr.example/DB/Employee/empid=18, true</code> =&gt;<code>R_emp.manager=18</code>
+   * <code>http://hr.example/DB/Employee/empid=18, false</code> =&gt;<code>R_empid18.empid=18</code>
+   * (the latter produces another join on R_empid18 in order to enforce a foreign key.)
+   * http://hr.example/DB/Employee/empid=18 has already been parsed to produce a NodeUri:
+   *   NodeUri(http://hr.example/DB,Employee,empid,CellValue(18))
+   */
+  def uriConstraint(state:R2RState, constrainMe:sql.RelVarAttr, u:NodeUri):R2RState = {
+    R2RState(state.joins,
+	     state.varmap,
+	     state.exprs + sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(constrainMe),
+						      sql.PrimaryExpressionTyped(rdb.RDB.Datatype.INTEGER,sql.Name(u.v.s))))
+  }
+
+  /**
+   * add constraints implied by a literal in a SPARQL triple pattern
+   * @param state state to be appended
+   * @param constrainMe relvar attribute to constrain, e.g. <code>R_18.empid</code>
+   * @param lit sparq.Literal, e.g. <code>18</code>
+   * @param dt sparq datatype, e.g. <code>xsd:integer</code>
+   * @return state + expression for the URI, e.g. <code>R_18.empid=18</code>
+   */
+  def literalConstraint(state:R2RState, constrainMe:sql.RelVarAttr, lit:sparql.Literal, dt:rdb.RDB.Datatype):R2RState = {
+    R2RState(state.joins,
+	     state.varmap,
+	     state.exprs + sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(constrainMe),
+						      sql.PrimaryExpressionTyped(dt,sql.Name(lit.lit.lexicalForm))))    
+  }
+
+  /** varConstraint
+   * @param state  earlier R2RState
+   * @param alias  relvar to bind, e.g. Employees AS R_emp
+   * @param optAttr  SQL attribute to bind, e.g. Employees.lastName
+   * @param v  SPARQL variable or blank node to bind
+   * @param db  database description
+   * @param rel  SQL relation to bind, e.g. Employee
+   * @return a new R2RState incorporating the new binding
+   * For example, <code>SELECT ?emp WHERE { ?emp emp:lastName ?name }</code> will call varConstraint twice:
+   * 
+   *    given: alias:=R_emp, optAttr:=lastName, v:=?name, rel:=Employee -&gt;
+   *   return: (VarAssignable(?name),StringMapper(FullBinding(R_emp.lastName)))
+   *   which maps "Smith" to "Smith"^^xsd:string
+   * 
+   *    given: alias:=R_emp, optAttr:=empid, v:=?emp, rel:=Employee -&gt;
+   *   return: (VarAssignable(?emp),RDFNoder(Employee,FullBinding(R_emp.empid)))
+   *   which maps 4 to &lt;http://hr.example/our/favorite/DB/Employee/id.4#record&gt;
+   */
+  def varConstraint(state:R2RState, alias:sql.RelVar, optAttr:Option[rdb.RDB.AttrName], v:sparql.Assignable, db:rdb.RDB.Database, rel:rdb.RDB.RelName):R2RState = {
+    val constrainMe = if (optAttr.isDefined) sql.RelVarAttr(alias, optAttr.get) else sql.RelVarAttr(alias, rdb.RDB.AttrName("_no_such_attribute"))
+    val reldesc = db(rel)
+    val boundTo = FullBinding(constrainMe)
+
+    /**
+     * Bind optAttr to an SQL generator like RDFNoder(Employee,FullBinding(R_emp.empid))
+     */
+    val binding = reldesc.pk match {
+      /** <pre>varConstraint(R_emp, Some(empid), VarAssignable(?emp), Employee) -&gt; RDFNoder(Employee,FullBinding(R_emp.empid))</pre> */
+      case Some(rdb.RDB.CandidateKey(List(rdb.RDB.AttrName(constrainMe.attribute.n)))) => RDFNoder(rel, boundTo)
+      case _ => {
+	val asKey = rdb.RDB.CandidateKey(List(constrainMe.attribute))
+	if (reldesc.fks.contains(asKey)) { // !! (0)
+	  /** varConstraint(R_patient, Some(SexDE), VarAssignable(?_0_sexEntry), Person) -&gt; RDFNoder(Person,FullBinding(R_patient.SexDE)) */
+	  val rdb.RDB.Target(fkrel, fkattr) = reldesc.fks(asKey)
+	  RDFNoder(rel, boundTo)
+	} else if (reldesc.header.contains(constrainMe.attribute)) {
+	  reldesc.header(constrainMe.attribute) match {
+	    /** varConstraint(R__0_indicDE, Some(NDC), VarAssignable(?_0_indicNDC), Medication_DE) -&gt; IntMapper(FullBinding(R__0_indicDE.NDC)) */
+	    case rdb.RDB.Datatype("Int") => IntMapper(boundTo)
+	    /** varConstraint(R_emp, Some(lastName), VarAssignable(?name), Employee) -&gt; StringMapper(FullBinding(R_emp.lastName)) */
+	    case rdb.RDB.Datatype("String") => StringMapper(boundTo)
+	    /** varConstraint(R_patient, Some(DateOfBirth), VarAssignable(?dob), Person) -&gt; DateMapper(FullBinding(R_patient.DateOfBirth)) */
+	    case rdb.RDB.Datatype("Date") => DateMapper(boundTo)
+	  }
+	} else {
+	  /** Default behavior for unknown attributes. */
+	  RDFBNoder(rel, boundTo) // @@ untested
+	} 
+      }
+    }
+
+    if (state.varmap.contains(v) && state.varmap(v) == constrainMe) {
+      /**
+       * No useful contributions for this variable.
+       * (We could re-add the binding; this case is just for clarity of behavior.)
+       */
+      state
+    } else if (state.varmap.contains(v)) {
+      /**
+       * The variable has already been bound to another attribute.
+       * Constraint against the initial binding for this variable.
+       * e.g. <code>R__0_0_indicCode.ID=R__0_0_indicCode.ID</code>
+       */
+      val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(constrainMe),
+						  sql.PrimaryExpressionAttr(varToAttribute(state.varmap, v)))
+      R2RState(state.joins, state.varmap, 
+	       if (varToAttributeDisjoints(state.varmap, v).size > 0)
+		 /**
+		  * Enumerate the set of constraints capturing all sides of a disjoint or option.
+		  * e.g. a UNION where two disjoints constrain R_who.empid=G_union0.who:
+		  * Set((G_union0._DISJOINT_!=0) OR (R_who.empid=G_union0.who),
+		  *     (G_union0._DISJOINT_!=1) OR (R_who.empid=G_union0.who))
+		  */
+		 state.exprs ++ {varToAttributeDisjoints(state.varmap, v) map ((d) => sql.ExprDisjunction(Set(d, constraint)))}
+	       else
+		 state.exprs + constraint
+	     )
+    } else {
+      /**
+       * Add binding for new variable.
+       */
+      R2RState(state.joins, state.varmap + (v -> binding), state.exprs)
+    }
+  }
+
+  def toString(relvarattr:sql.RelVarAttr) : String = {
+    relvarattr.relvar.n.s + "." + relvarattr.attribute.n
+  }
+  // def toString(mapper:SQL2RDFValueMapper) : String = {
+  //   mapper match {
+  //     case IntMapper(relvar, disjoints) => "INT: " + toString(relvar)
+  //     case StringMapper(relvar, disjoints) => "STRING: " + toString(relvar)
+  //     case DateMapper(relvar, disjoints) => "DATE: " + toString(relvar)
+  //     case RDFNoder(relation, relvar, disjoints) => "RDFNoder: " + relation.n.s + ", " + toString(relvar)
+  //     case RDFBNoder(relation, relvar, disjoints) => "RDFBNoder: " + relation.n.s + ", " + toString(relvar)
+  //   }
+  // }
+
+  def __optFirst (k:Option[rdb.RDB.CandidateKey]):Option[rdb.RDB.AttrName] =
+    k match {
+      case Some(ck) => Some(ck.attrs(0))
+      case _ => None
+    }
+
+  /**
+   * map a given triple to one or two joined tables, variable
+   * @param db  database description
+   * @param stateP  earlier R2RState
+   * @param triple  
+   * @param enforceForeignKeys  
+   * @return a new R2RState incorporating the new binding
+   * bindings to RelVarAttrs, and constraints if those variables were
+   * already bound. */
+  def bindOnPredicate(db:rdb.RDB.Database, stateP:R2RState, triple:sparql.TriplePattern, enforceForeignKeys:Boolean):R2RState = {
+    val sparql.TriplePattern(s, p, o) = triple
+    p match {
+      /** Don't deal with ?s ?p ?o . We could deal with <s> ?p ?o , but haven't yet. */
+      case sparql.TermVar(v) => error("variable predicates require tedious enumeration; too tedious for me.")
+      case sparql.TermUri(uri) => {
+	val PUri(stem, spRel, spAttr) = parsePredicateURI(uri)
+	/** The relation and attribute come from the predicate, e.g. Employee.fname =&gt; Employee and fname. */
+	val rel = rdb.RDB.RelName(spRel.s)
+	val attr = rdb.RDB.AttrName(spAttr.s)
+
+	/**
+	 * The particular join for e.g. Employee is controled by the subject.
+	 * ?emp =&gt; Employee AS emp
+	 * <Employee:18> =&gt; Employee AS Employee_18 .
+         */
+	val relvar = relVarFromTerm(s)
+	/** Synthesize relvar attribute, e.g. emp.fname. */
+	val objattr = sql.RelVarAttr(relvar, attr)
+
+	/** Accumulate joins and constraints that come from the subject */
+	val state_postSubj = s match {
+	  case sparql.TermUri(u) =>
+	    /** additional constraint, e.g. R_empid18.empid=18. */
+	    uriConstraint(stateP, sql.RelVarAttr(relvar, db(rel).pk.get.attrs(0)), parseObjectURI(u)) // !! (0)
+	  case sparql.TermVar(v) =>
+	    /** assignable binding for novel vars, new constraint for previously bound vars. */
+	    try {
+	      varConstraint(stateP, relvar, __optFirst(db(rel).pk), sparql.VarAssignable(v), db, rel) // !! (0)
+	    } catch {
+	      case e:java.util.NoSuchElementException =>
+		/** 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(" + rel + ") not found in " + db)
+	    }
+	  case sparql.TermBNode(b) =>
+	    /** assignable binding for novel bnodes, new constraint for previously bound bnodes. */
+	    try {
+	      varConstraint(stateP, relvar, __optFirst(db(rel).pk), sparql.BNodeAssignable(b), db, rel) // !! (0)
+	    } catch {
+	      case e:java.util.NoSuchElementException =>
+		throw new Exception("error processing { " + s + " " + p + " " + o + " } :db(" + 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(rel).header(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(" + rel + ").header(" + attr + ") not found in " + db)
+	}
+
+	/**
+	 * fkrel.fkattr (e.g. Employee.manager) may be a foreign key.
+	 * Calculate final relvarattr and relation.
+	 */
+	val asKey = rdb.RDB.CandidateKey(List(attr))
+	val (targetattr:sql.RelVarAttr, targetrel, dt, state_fkeys:R2RState) =
+	  if (db(rel).fks.contains(asKey)) { // !! (0)
+	    val rdb.RDB.Target(fkrel, fkattr) = db(rel).fks(asKey)
+	    try { db(fkrel).header(fkattr.attrs(0)) } catch { // !! (0)
+	      /** Foreign key relation.attribute was not found in the database description. */
+	      case e:java.util.NoSuchElementException =>
+		throw new Exception("db(" + fkrel + ").header(" + fkattr + ") not found in " + db)
+	    }
+	    val fkdt =
+	      if (db(fkrel).fks.contains(fkattr)) {
+	      /** Foreign key to something which is a foreign key. May have use
+	       * cases, but signal error until we figure out that they are. */
+		val rdb.RDB.Target(dfkrel, dfkattr) = db(fkrel).fks(fkattr)
+		error("foreign key " + rel.n + "." + attr.n + 
+		      "->" + fkrel.n + "." + fkattr.attrs(0).n +  // !! (0)
+		      "->" + dfkrel.n + "." + dfkattr.attrs(0).n) // !! (0)
+	      } else
+		db(fkrel).header(fkattr(0)) // !! (0)
+	    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.attrs(0)) // !! (0)
+	      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)
+	    }
+	  }
+	else
+	  /** not a foreign key, so use the relvarattr and relation calculated
+	   * from the predicate. */
+	  (objattr, rel, db(rel).header(attr), 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 _                  => error("illegal SPARQL predicate: " + p)
+    }
+  }
+
+  def bindingConstraintToAttribute(constraint:BindingConstraint):sql.RelVarAttr = {
+    val BindingConstraint(expr:sql.RelationalExpression, relvarattr:sql.RelVarAttr) = constraint;
+    relvarattr
+  }
+  def bindingToAttribute(binding:FullOrPartialBinding):sql.RelVarAttr = {
+    binding match {
+      case FullBinding(relvarattr:sql.RelVarAttr) => relvarattr
+      case PartialBinding(binders) => bindingConstraintToAttribute(binders.toList(0))
+    }
+  }
+  def varToAttribute(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], vvar:sparql.Assignable):sql.RelVarAttr = {
+    val mapper = try { varmap(vvar) } catch {
+      case e:java.util.NoSuchElementException =>
+	throw new Exception("mapper for variable " + vvar + " not found in " + varmap)
+    }
+    mapper match {
+      case IntMapper(binding) => bindingToAttribute(binding)
+      case StringMapper(binding) => bindingToAttribute(binding)
+      case DateMapper(binding) => bindingToAttribute(binding)
+      case RDFNoder(relation, binding) => bindingToAttribute(binding)
+      case RDFBNoder(relation, binding) =>  bindingToAttribute(binding) // error("BNode should not need relvar " + relvar)
+    }
+  }
+
+  def bindingConstraintToExpression(constraint:BindingConstraint):sql.RelationalExpression = {
+    val BindingConstraint(expr:sql.RelationalExpression, relvarattr:sql.RelVarAttr) = constraint;
+    expr
+  }
+  def bindingToDisjoints(binding:FullOrPartialBinding):Set[sql.RelationalExpression] = {
+    binding match {
+      case FullBinding(relvarattr:sql.RelVarAttr) => Set[sql.RelationalExpression]()
+      case PartialBinding(binders) => binders.map({b => bindingConstraintToExpression(b)})
+    }
+  }
+  def varToAttributeDisjoints(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], vvar:sparql.Assignable):Set[sql.RelationalExpression] = {
+    varmap(vvar) match {
+      case IntMapper(binding) => bindingToDisjoints(binding)
+      case StringMapper(binding) => bindingToDisjoints(binding)
+      case DateMapper(binding) => bindingToDisjoints(binding)
+      case RDFNoder(relation, binding) => bindingToDisjoints(binding)
+      case RDFBNoder(relation, binding) =>  bindingToDisjoints(binding) // error("BNode should not need relvar " + relvar)
+    }
+  }
+
+  /**
+   * Converts a variable bound to a URL to an SQL expression for that URL.
+   *
+   * @param  varmap  map from variable to SQL2RDFValueMapper
+   * @param  vvar    the variable to be represented
+   * @return         an SQL CONCAT expression
+   * @see            VarMap
+   */
+  def varToExpr(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], vvar:sparql.Assignable, stem:StemURI):sql.Expression = {
+    varmap(vvar) match {
+      case IntMapper(binding) => sql.PrimaryExpressionAttr(bindingToAttribute(binding))
+      case StringMapper(binding) => 
+	sql.Concat(List(sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),sql.Name("'")),
+		    sql.PrimaryExpressionAttr(bindingToAttribute(binding)),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),sql.Name("'^^<http://www.w3.org/2001/XMLSchema#string>"))))
+      case DateMapper(binding) => sql.PrimaryExpressionAttr(bindingToAttribute(binding))
+      case RDFNoder(relation, binding) => 
+	sql.Concat(List(sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),sql.Name(stem.s)),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),relation.n),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),sql.Name("/")),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),bindingToAttribute(binding).attribute.n),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),sql.Name(".")),
+		    sql.PrimaryExpressionAttr(bindingToAttribute(binding)),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),sql.Name("#record"))))
+      case RDFBNoder(relation, binding) => 
+	sql.Concat(List(sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),sql.Name("_:")),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),relation.n),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),sql.Name(".")),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),bindingToAttribute(binding).attribute.n),
+		    sql.PrimaryExpressionTyped(rdb.RDB.Datatype("String"),sql.Name(".")),
+		    sql.PrimaryExpressionAttr(bindingToAttribute(binding))))
+    }
+    
+  }
+
+  /**
+   * return an SQL PrimaryExpression for rTerm.
+   *
+   * @param  varmap  map from variable to SQL2RDFValueMapper
+   * @param  l  an SQL relvarattr for a SPARQL Assignable (variable or bnode)
+   * @param  rTerm  SPARQL term to be converted to a PrimaryExpression
+   * @param  sqlexpr  an unbound SQL relational expression, e.g. sql.RelationalExpressionEq(_,_)
+   * @return   an SQL expression on the relvarattrs to which the variables in f are bound
+   */
+  def assignable2expr(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], l:sql.RelVarAttr, rTerm:sparql.Term, sqlexpr:(sql.PrimaryExpression, sql.PrimaryExpression) => sql.RelationalExpression):sql.RelationalExpression = { // :sparql.Var
+    val r:sql.PrimaryExpression = rTerm match {
+      case sparql.TermUri(u) => error("not implemented: translating RDF URI to SQL: " + u) // :sparql.Uri
+      case sparql.TermVar(v) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.VarAssignable(v)))
+      case sparql.TermBNode(b) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.BNodeAssignable(b)))
+      case sparql.TermLit(sparql.Literal(rdf.RDFLiteral(lit,rdf.Datatype(dt)))) =>
+	sql.PrimaryExpressionTyped({
+	  dt.toString match {
+	    case "http://www.w3.org/2001/XMLSchema#string" => rdb.RDB.Datatype.STRING
+	    case "http://www.w3.org/2001/XMLSchema#integer" => rdb.RDB.Datatype.INTEGER
+	    case "http://www.w3.org/2001/XMLSchema#date" => rdb.RDB.Datatype.DATE
+	    case _ => error("unable to translate to RDF literal SQL: \"" + lit + "\"^^<" + dt + ">")
+	  }
+	}, lit)
+    }
+    sqlexpr(sql.PrimaryExpressionAttr(l), r)
+  }
+
+  /**
+   * create an SQL expression analogous to a SPARQL expression. The variables in
+   * f are expressed as the relvarattrs to which they are mapped. This function
+   * is only minimally implemented here.
+   *
+   * @param  varmap  map from variable to SQL2RDFValueMapper
+   * @param  f  SPARQL Expression
+   * @return   an SQL expression on the relvarattrs to which the variables in f are bound
+   */
+  def filter2expr(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], f:sparql.PrimaryExpression):sql.RelationalExpression = {
+
+    /** sqlexpr: an unbound RelationalExpression, i.e. a function which takes
+     * (sql.RelVarAttr, sql.PrimaryExpressionAttr) and returns an
+     * sql.RelationalExpression
+     */
+    val (lTerm:sparql.Term, rTerm:sparql.Term, sqlexpr) = f match {
+      case sparql.PrimaryExpressionEq(l, r) => (l.term, r.term, sql.RelationalExpressionEq(_,_))
+      case sparql.PrimaryExpressionLt(l, r) => (l.term, r.term, sql.RelationalExpressionLt(_,_))
+      case sparql.PrimaryExpressionGt(l, r) => (l.term, r.term, sql.RelationalExpressionGt(_,_))
+      case sparql.SparqlTermExpression(t) => error("not implemented") // (l.term, r.term, sql.PrimaryExpressionAttr(_,_))
+    }
+
+    lTerm match {
+      /** does not handle FILTER (<x> = ?v) */
+      case sparql.TermUri(obj) => error("only SPARQL PrimaryExpressions with a variable on the left have been implemented: punting on " + f)
+      /** FILTER (?v = <x> && ?v = ?x && ?v = 7) */
+      case sparql.TermVar(v) => assignable2expr(varmap, varToAttribute(varmap, sparql.VarAssignable(v)), rTerm, sqlexpr)
+      case sparql.TermBNode(b) => assignable2expr(varmap, varToAttribute(varmap, sparql.BNodeAssignable(b)), rTerm, sqlexpr)
+      /** does not handle FILTER (7 = ?v) */
+      case sparql.TermLit(lit) => error("only SPARQL PrimaryExpressions with a variable on the left have been implemented: punting on " + f)
+    }
+  }
+
+  /**
+   * Promote a variable in an OPTIONAL or UNION subselect to the outer
+   * varmap/expressions. 
+   */
+  def subselectVars(startState:R2RState, v:sparql.Assignable, optionalAlias:sql.RelVar,
+		    optionalCond:sql.RelationalExpression,
+		    outerVarmap:Map[sparql.Assignable, SQL2RDFValueMapper],
+		    nestedVarmap:Map[sparql.Assignable, SQL2RDFValueMapper],
+		    isOpt:Boolean):R2RState = {
+
+    val varAliasAttr = sql.RelVarAttr(optionalAlias, rdb.RDB.AttrName(attrAliasNameFromVar(v)))
+    if (startState.varmap.contains(v)) {
+
+      /** The variable has already been bound. */
+      val newMap:Map[sparql.Assignable, SQL2RDFValueMapper] =
+	/** If var was already bound to the same relvarattr... */
+	if (varToAttribute(startState.varmap, v) == varAliasAttr) {
+	  /**
+	   * Add new partial constraint to old partial constraints to produce a new binding.
+	   * example:
+	   *   ?name -> StringMapper(PartialBinding(Set(BindingConstraint(G_union1._DISJOINT_!=0,G_union1.name),
+           *                                            BindingConstraint(G_union1._DISJOINT_!=1,G_union1.name))))
+	   */
+	  Map(v -> {
+	    startState.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 {
+	  /** Var was bound to a different relvarattr so handle as newConstraint below. */
+	  Map()
+	}
+
+      val newConstraints =
+	if (varToAttribute(outerVarmap, v) == varAliasAttr) { // also varToAttribute(startState.varmap, v) == varAliasAttr
+	  Set()
+	} else {
+	  /** Constraint against binding from earlier graph pattern.
+	   * e.g. G_union1.who=R_who.empid */
+	  val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(varAliasAttr),
+						      sql.PrimaryExpressionAttr(varToAttribute(outerVarmap, v)))
+	  if (varToAttributeDisjoints(outerVarmap, v).size > 0) {
+	    /**
+	     * Construct a conjunction of disjunctions like:
+	     * (union0._DISJOINT_ != 0 OR union0.x=union1.x) AND (union1._DISJOINT_ != 2 OR union0.x=union1.x)
+	     */
+	    varToAttributeDisjoints(outerVarmap, v) map ((d) =>
+	      sql.ExprDisjunction({
+		if (isOpt) Set(d, constraint) // a disjunction like: G_opt1._DISJOINT_ IS NULL OR G_opt3.birthday=G_opt1.birthday
+		else Set(sql.ExprConjunction(Set(d, optionalCond)), constraint) // @@ untested code path
+	      }))
+	  } else {
+	    if (isOpt)
+	      /** just the constraint from above */
+	      Set(constraint)
+	    else
+	      /**
+	       * Above constraint applied only for this path:
+	       * for example: (G_union1._DISJOINT_!=0) OR (G_union1.who=R_who.empid)
+	       */
+	      Set(sql.ExprDisjunction(Set(optionalCond, constraint)))
+	  }
+	}
+
+      R2RState(startState.joins, startState.varmap ++ newMap, startState.exprs ++ newConstraints)
+    } else {
+      /**
+       * This variable is new to the outer context so synthesize a new partial
+       * binding à la:
+       *   ?name ->
+       *     StringMapper(PartialBinding((G_union1._DISJOINT_!=0,G_union1.name)))
+       */
+      val p = PartialBinding(Set(BindingConstraint(optionalCond, varAliasAttr)))
+      val mapper:SQL2RDFValueMapper = nestedVarmap(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(startState.joins, startState.varmap + (v -> mapper), startState.exprs)
+    }
+  }
+
+  /**
+   * Recursively add the joins, variable mappings and constraints for an SQL query implementing a graph pattern.
+   * @param db  database description.
+   * @return a new state including the subquery representing gp in a join.
+   * This is factored out of mapGraphPattern as it is used for MINUS and probably later for NOT EXISTS.
+   */
+  def synthesizeOuterJoin(initState:R2RState, gp:sparql.GraphPattern, negate:Boolean, db:rdb.RDB.Database, enforceForeignKeys:Boolean):R2RState = {
+    /** SPARQL OPTIONALs and UNIONs are treated as SQL subselects.
+     * Set up initial state for this subselect.
+     */
+    val leftJoinAlias = sql.RelVar(sql.Name("G_opt" + initState.joins.size))
+    val initDisjoints:Set[sql.Select] = Set()
+    val emptyState = R2RState(
+      util.AddOrderedSet[sql.Join](), 
+      Map[sparql.Assignable, SQL2RDFValueMapper](), 
+      Set[sql.Expression]()
+    )
+
+    /** Create the select for the nested graph pattern.
+     */
+    val nestedState = mapGraphPattern(db, emptyState, gp, enforceForeignKeys)
+    val nestedVars = gp.findVars
+    /**
+     * Select a constant as _DISJOINT_ so later constraints can be
+     * sensitive to whether a variable was bound.
+     * This matters for assymetric UNIONs and, here, OPTIONALs. Given:
+     *   Join( LeftJoin( BGP(),
+     *                   BGP( ?x :p2 ?v2 ) ),
+     *         BGP( ?y :p3 ?v2 ) )
+     * coreference constraints against ?v2 should only be enforced for
+     * tuples from the right side of this union.
+     */
+    val pathNo = sql.ProjectAttribute(sql.PrimaryExpressionTyped(rdb.RDB.Datatype.INTEGER,sql.Name("" + initState.joins.size)),
+					sql.AttrAlias(sql.Name("_DISJOINT_")))
+    val leftJoinVars = gp.findVars
+    val attrlist:Set[sql.ProjectAttribute] = leftJoinVars.map(
+      v =>
+	sql.ProjectAttribute(varToAttribute(nestedState.varmap, sparql.VarAssignable(v)),
+			   sql.AttrAlias(attrAliasNameFromVar(sparql.VarAssignable(v))))
+    ) + pathNo // add join number to selections
+    val subselect = sql.Select(
+      false,
+      sql.Projection(attrlist),
+      sql.TableList(nestedState.joins),
+      nestedState.exprs.size match {
+      	case 0 => None
+      	case 1 => Some(nestedState.exprs.toList(0))
+      	case _ => Some(sql.ExprConjunction(nestedState.exprs))
+      },
+      List[sql.OrderElt](), None, None
+    )
+
+    /** Create a condition to test if this OPTIONAL was matched (called
+     * _DISJOINT_ as OPTIONAL behaves pretty much like a disjunction).
+     */
+    val nestedCond = sql.RelationalExpressionNull(sql.PrimaryExpressionAttr(
+      sql.RelVarAttr(leftJoinAlias, rdb.RDB.AttrName("_DISJOINT_"))))
+
+    /** Bind variables to the attributes projected from the subselect;
+     * handle corefs (equivalence with earlier bindings).
+     */
+    val outerState2 =
+      nestedVars.foldLeft(
+	R2RState(initState.joins,
+		 initState.varmap,
+		 Set[sql.Expression]()))((myState, v) => 
+		   subselectVars(myState, sparql.VarAssignable(v), leftJoinAlias, nestedCond,
+				 initState.varmap, nestedState.varmap, true))
+
+    /** The final state includes the subselect as a join, the variables bound
+     * to subselect projection, and no new expresssions. The expressions
+     * derived from corefs are conditions for the LEFT OUTER JOIN.
+     */
+    val join = sql.LeftOuterJoin(sql.AliasedResource(sql.Subselect(subselect), leftJoinAlias), 
+	 outerState2.exprs.size match {
+	   case 0 =>
+	     sql.RelationalExpressionEq(sql.PrimaryExpressionTyped(rdb.RDB.Datatype.INTEGER,sql.Name("1")),
+					sql.PrimaryExpressionTyped(rdb.RDB.Datatype.INTEGER,sql.Name("1")))
+	     /** Require corefs unless we have a leading OPTIONAL. */
+	     // if (...)
+	     // else
+	     //   error ("Nested GP has no variables shared with its context; cowaredly refusing to join ON 1.")
+	   case 1 => outerState2.exprs.toList(0)
+	   case _ => sql.ExprConjunction(outerState2.exprs)
+	 }
+       )
+    val exprs =
+      if (negate) {
+	initState.exprs + sql.RelationalExpressionNull(sql.PrimaryExpressionAttr(sql.RelVarAttr(leftJoinAlias, rdb.RDB.AttrName("_DISJOINT_"))))
+      } else initState.exprs
+    R2RState(initState.joins + join, outerState2.varmap, exprs)
+  }
+
+  /**
+   * Recursively add the joins, variable mappings and constraints for an SQL query implementing a graph pattern.
+   * @param db  database description.
+   * @param state  initial set of joins, variable mappings and constraints.
+   * @param gp  the SPARQL GraphPattern to represent as SQL.
+   * @param enforceForeignKeys  if true, SPARQL triple patterns corresponding to foreign keys, e.g. <code>?who :hasParent ?parent</code>, generate a join on the referenced table.
+   * @return  a new set of joins, variable mappings and constraints.
+   * Per <a href="http://www.w3.org/TR/rdf-sparql-query/#sparqlQuery">definition of SPARQL Query</a>, SPARQL Graph Patterns are (Basic Graph Pattern, Join, LeftJoin, Filter, Union, Graph).
+   * mapGraphPattern maps each of these to an SQL abstract query (which can then be serialized as SQL and executed).
+   * 
+   */
+  def mapGraphPattern(db:rdb.RDB.Database, state:R2RState, gp:sparql.GraphPattern, enforceForeignKeys:Boolean):R2RState = {
+    gp match {
+
+      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_PatternInstanceMapping">Basic Graph Pattern Matching</a>()
+       * @param triplepatterns  set of triple patterns. Premise: all triple patterns must resolve against the direct graph.
+       * As { TP1, TP2 } == Join({ TP1 }, { TP2 }), we can view the bindOnPredicate function as partitioning triple patterns by the relvar they match.
+       * This isn't observable in the SQL query as all the triple patterns in all the conjunctions contribute to the same query.
+       */
+      case sparql.TriplesBlock(triplepatterns) => {
+	/** Examine each triple, updating the compilation state. */
+	val state2 = triplepatterns.foldLeft(state)((incState,s) => bindOnPredicate(db, incState, s, enforceForeignKeys))
+
+	/** NULLs in the database result in no triple in the Direct Graph.
+	 * Enforce this by requiring that the SQL expression to which any SPARQL variable (Assignable) is bound is NOT NULL.
+	 */
+	val nullExprs = gp.findAssignables.foldLeft(Set[sql.Expression]())((s, vvar) => {
+	  if (varToAttributeDisjoints(state2.varmap, vvar).size == 0)
+	    /** Create a NOT NULL expression for each fully bound variable. */
+	    s ++ Set(sql.RelationalExpressionNotNull(sql.PrimaryExpressionAttr(varToAttribute(state2.varmap, vvar))))
+	  else
+	    /** Variables in a partial binding can be NULL so the aren't added to the null expressions. */
+	    s
+	})
+	R2RState(state2.joins, state2.varmap, state2.exprs ++ nullExprs)
+      }
+
+      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_evalJoin">Join</a>(P1, P2)
+       * Since Join is association, we handle this as an n-ary join.
+       * @param conjoints  list of graph patterns to join.
+       */
+      case sparql.TableConjunction(conjoints) => {
+	conjoints.foldLeft(state)((incState,s) => mapGraphPattern(db, incState, s, enforceForeignKeys))
+      }
+
+      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_evalLeftJoin">LeftJoin</a>(P1, P2, F)
+       * The parser providing the SPARQL abstract query turns LeftJoin(P1, P2, F) into Join(P1, Optional(P2)), or Join(P1, Optional(Filter(P2, F))) if there is a FILTER.
+       * @param gp2  nested graph pattern (Ω in algebra)
+       */
+      case sparql.OptionalGraphPattern(gp2) => {
+	/* state_postLeadingTable: create an initial table if the first conjoint is optional.
+	 * e.g. ... FROM (SELECT 1 AS _EMPTY_) AS _EMPTY_ LEFT OUTER JOIN ...
+	 */
+	val state_postLeadingTable =
+	  if (state.joins.size == 0)
+	    /**
+	     * Leading optionals (ASK WHERE { OPTIONAL { ... } ... }) in SPARQL don't have a counterpart in SQL.
+	     * We emulate leading optionals with a leading SQL subselect which projects one solution with no selected attributes.
+	     */
+	    R2RState(state.joins + sql.InnerJoin(sql.AliasedResource(sql.Subselect(
+	      sql.Select(
+		false, 
+		sql.Projection(Set(sql.ProjectAttribute(sql.PrimaryExpressionTyped(rdb.RDB.Datatype.INTEGER,sql.Name("1")),
+							 sql.AttrAlias(sql.Name("_EMPTY_"))))),
+		sql.TableList(util.AddOrderedSet()),
+		None, List[sql.OrderElt](), None, None
+	      )), sql.RelVar(sql.Name("_EMPTY_"))), None), state.varmap, state.exprs)
+	  else
+	    state
+	/** Create an OUTER JOIN for the nested graph pattern. */
+	synthesizeOuterJoin(state_postLeadingTable, gp2, false, db, enforceForeignKeys)
+      }
+
+      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_algFilter">Filter</a>(expr, Ω)
+       * @param gp2  nested graph pattern (Ω in algebra)
+       * @param expr  boolean SPARQL expression (expr in algebra)
+       */
+      case sparql.TableFilter(gp2:sparql.GraphPattern, expr:sparql.Expression) => {
+	/** Calculate state for gp2. */
+	val state2 = mapGraphPattern(db, state, gp2, enforceForeignKeys)
+
+	/** Add constraints for all the FILTERS */
+	val filterExprs:Set[sql.RelationalExpression] =
+	  expr.conjuncts.toSet map ((x:sparql.PrimaryExpression) => filter2expr(state2.varmap, x))
+
+	R2RState(state2.joins, state2.varmap, state2.exprs ++ filterExprs)
+      }
+
+      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_evalUnion">Union</a>(P1, P2)
+       * Since Disjunction is associative, we handle this as an n-ary disjunction.
+       * @param disjoinits  list of graph patterns to concatenate.
+       */
+      case sparql.TableDisjunction(disjoints) => {
+	/**
+	 * SPARQL UNIONs are realized as SQL subselects.
+	 * Set up initial state for this subselect.
+	 */
+	val unionAlias = sql.RelVar(sql.Name("G_union" + state.joins.size)) // invent a unique name for this union.
+	val emptyState = R2RState( // create an empty state.
+	  util.AddOrderedSet[sql.Join](), 
+	  Map[sparql.Assignable, SQL2RDFValueMapper](), 
+	  Set[sql.Expression]()
+	)
+	val unionVars = disjoints.foldLeft(Set[sparql.Var]())((mySet,disjoint) =>
+	  mySet ++ disjoint.findVars).toList // all variables nested in the disjoints.
+
+	/**
+	 * Map the list of disjoints to a list of nested R2RStates, nested variable lists, and unique SQL constants identifying that disjoint.
+	 * Non-Functional var <code>number</code> is used for projecting unique
+	 * constants to indicate which disjoint produced a tuple.
+	 */
+	var number = 0
+	val nestedStates = disjoints.map(disjoint => {
+	  val disjointState = mapGraphPattern(db, emptyState, disjoint, enforceForeignKeys)
+	  val disjointVars = disjoint.findVars
+	  val uniqueConst = sql.PrimaryExpressionTyped(rdb.RDB.Datatype.INTEGER,sql.Name("" + number))
+	  number = number + 1 // non-functional, but clearer than wrapping as a parameter in a foldLeft
+	  (disjointState, disjointVars, uniqueConst)
+	})
+
+	/**
+	 * Map the list of nested R2RStates to a set of subselects.
+	 * <code>uniqueConst</code> is used for projecting a value
+	 * to indicate which disjoint produced a tuple.
+	 */
+	val subselects = nestedStates.foldLeft(Set[sql.Select]())((subselects, state) => {
+	  val (disjointState, disjointVars, uniqueConst) = state
+	  /**
+	   * Select a constant as _DISJOINT_ so later constraints can be
+	   * sensitive to whether a variable was bound.
+	   * This matters for OPTIONALs and, here, assymetric UNIONs. Given:
+	   *   Join( Union( BGP( ?x :p1 ?v1 ),
+	   *                BGP( ?x :p2 ?v1 . ?x :p2 ?v2 ) ),
+	   *         BGP( ?y :p3 ?v2 ) )
+	   * coreference constraints against ?v2 should only be enforced for
+	   * tuples from the right side of this union.
+	   */
+	  val pathNo = sql.ProjectAttribute(uniqueConst,
+					  sql.AttrAlias(sql.Name("_DISJOINT_")))
+
+	  val attrlist:Set[sql.ProjectAttribute] = unionVars.foldLeft(Set(pathNo))((attrs, v) => {
+	    val attrOrNull = if (disjointState.varmap.contains(sparql.VarAssignable(v))) varToAttribute(disjointState.varmap, sparql.VarAssignable(v)) else sql.ConstNULL()
+	    attrs ++ Set(sql.ProjectAttribute(attrOrNull, sql.AttrAlias(attrAliasNameFromVar(sparql.VarAssignable(v)))))
+	  })
+
+	  val subselect = sql.Select(
+	    false,
+	    sql.Projection(attrlist),
+	    sql.TableList(disjointState.joins),
+	    disjointState.exprs.size match {
+	      case 0 => None
+	      case 1 => Some(disjointState.exprs.toList(0))
+	      case _ => Some(sql.ExprConjunction(disjointState.exprs))
+	    }, List[sql.OrderElt](), None, None
+	  )
+	  subselects + subselect
+	})
+
+	/**
+	 * Connect the variables projected from the nested selects into the outer variable bindings and constraints.
+	 * <code>state2</code> will have no additional tables in the TableList.
+	 * <code>uniqueConst</code> is used this time to constraint coreferences between the
+	 * subselects and the outer context.
+	 */
+	val state2 = nestedStates.foldLeft(state)((outerState, state) => {
+	  val (disjointState, disjointVars, uniqueConst) = state
+
+	  /** Create a condition to test if this disjoint was matched. */
+	  val disjointCond = sql.RelationalExpressionNe(sql.PrimaryExpressionAttr(sql.RelVarAttr(unionAlias, rdb.RDB.AttrName("_DISJOINT_"))),
+							uniqueConst)
+	  val outerState2 = disjointVars.foldLeft(outerState)((myState, v) =>
+	      subselectVars(myState, sparql.VarAssignable(v), unionAlias, disjointCond, outerState.varmap, disjointState.varmap, false))
+	  number = number + 1 // non-functional, but clearer than wrapping as a parameter in a foldLeft
+	  outerState2
+	})
+	val subselect = sql.Subselect(sql.Union(subselects))
+	R2RState(state.joins + sql.InnerJoin(sql.AliasedResource(subselect,unionAlias), None), state2.varmap, state2.exprs)
+      }
+
+      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_evalGraph">Graph</a>(IRI, P)
+       * I don't know what the parser did with the IRI, but we don't know what to do with GRAPHs anyways. 
+       * @param gp2  nested graph pattern (Ω in algebra)
+       */
+      case sparql.GraphGraphPattern(gp2) => error("no code to handle GraphGraphPatterns (" + gp2 + ")")
+
+      /** Minus is from SPARQL 1.1 (in progress). This doesn't need documentation now.
+       * @param gp2  the graph pattern to subtract.
+       */
+      case sparql.MinusGraphPattern(gp2) => {
+	if (state.joins.size == 0) state
+	else synthesizeOuterJoin(state, gp2, true, db, enforceForeignKeys)
+      }
+    }
+  }
+
+  /**
+   * Default interface for SparqlToSql.
+   * @param db  database description.
+   * @param sparquery  SPARQL compile tree.
+   * @param stem  stem URI for all generated RDF URIs.
+   * @param enforceForeignKeys  if true, SPARQL triple patterns corresponding to foreign keys, e.g. ?who :hasParent ?parent , generate a join on the referenced table.
+   * @param concat  if true, keys will produce SQL functions to generate a URI, e.g. SELECT CONCAT(stemURI, table, "/", pk, ".", R_who.pk) AS who
+   * @return an SQL query corresponding to sparquery
+   */
+  def apply (db:rdb.RDB.Database, sparquery:sparql.Select, stem:StemURI, enforceForeignKeys:Boolean, concat:Boolean) : (sql.Select, Map[sparql.Assignable, SQL2RDFValueMapper]) = {
+
+    /** Create an object to hold our compilation state. */
+    val initState = R2RState(
+      util.AddOrderedSet[sql.Join](), 
+      Map[sparql.Assignable, SQL2RDFValueMapper](), 
+      Set[sql.Expression]()
+    )
+
+    /**
+     * Generate a new state with the joins, mappings to sql expressions, and
+     * constraints implicit in the SPARQL WHERE pattern.
+     */
+    val r2rState = mapGraphPattern(db, initState, sparquery.gp, enforceForeignKeys)
+
+    /**
+     * Select the attributes corresponding to the variables
+     * in the SPARQL SELECT.
+     */
+    val attrlist:Set[sql.ProjectAttribute] =
+      // This foldLeft could be a map, if i could coerce to a set afterwards.
+      sparquery.attrs.attributelist.foldLeft(Set[sql.ProjectAttribute]())((attrs, v) => {
+	val exp =
+	  if (concat)
+	    // generate CONCAT expression for keys.
+	    varToExpr(r2rState.varmap, sparql.VarAssignable(v), stem)
+	  else
+	    varToAttribute(r2rState.varmap, sparql.VarAssignable(v))
+	/** Projection alias. */
+	val as = sql.AttrAlias(attrAliasNameFromVar(sparql.VarAssignable(v)))
+	attrs + sql.ProjectAttribute(exp , as)
+      })
+
+    /** Construct the generated query as an abstract syntax. */
+    val select = sql.Select(
+      sparquery.distinct,
+      sql.Projection(attrlist),
+      sql.TableList(r2rState.joins),
+      r2rState.exprs.size match {
+	case 0 => None
+	case 1 => Some(r2rState.exprs.toList(0))
+	case _ => Some(sql.ExprConjunction(r2rState.exprs))
+      },
+      sparquery.order.map((elt:sparql.OrderElt) => {
+	sql.OrderElt(elt.desc, xxx(r2rState.varmap, elt.expr))
+      }), sparquery.offset, sparquery.limit
+    )
+    // println("r2rState.varmap: " + r2rState.varmap)
+    // println("select.expression: " + select.expression)
+    (select.makePretty, r2rState.varmap)
+  }
+
+/*
+ * vvv CLEAN THIS UP!!! vvv
+ */
+
+  def assignable2expr999(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], rTerm:sparql.Term):sql.Expression = { // :sparql.Var
+    val r:sql.PrimaryExpression = rTerm match {
+      case sparql.TermUri(u) => error("not implemented: translating RDF URI to SQL: " + u) // :sparql.Uri
+      case sparql.TermVar(v) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.VarAssignable(v)))
+      case sparql.TermBNode(b) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.BNodeAssignable(b)))
+      case sparql.TermLit(sparql.Literal(rdf.RDFLiteral(lit,rdf.Datatype(dt)))) =>
+	sql.PrimaryExpressionTyped({
+	  dt.toString match {
+	    case "http://www.w3.org/2001/XMLSchema#string" => rdb.RDB.Datatype.STRING
+	    case "http://www.w3.org/2001/XMLSchema#integer" => rdb.RDB.Datatype.INTEGER
+	    case "http://www.w3.org/2001/XMLSchema#date" => rdb.RDB.Datatype.DATE
+	    case _ => error("unable to translate to RDF literal SQL: \"" + lit + "\"^^<" + dt + ">")
+	  }
+	}, lit)
+    }
+    r
+  }
+
+  def xxx(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], from:sparql.Expression) : sql.Expression = {
+    val l = from.conjuncts.map((conj) => {
+      conj match {
+	case sparql.SparqlTermExpression(sparql.TermVar(v:sparql.Var)) =>
+	  assignable2expr999(varmap, sparql.TermVar(v))
+	case sparql.SparqlTermExpression(sparql.TermBNode(b:sparql.BNode)) =>
+	  assignable2expr999(varmap, sparql.TermBNode(b))
+	case sparql.SparqlTermExpression(sparql.TermLit(l)) =>
+	  assignable2expr999(varmap, sparql.TermLit(l))
+	case sparql.SparqlTermExpression(sparql.TermUri(u:sparql.Uri)) =>
+	  assignable2expr999(varmap, sparql.TermUri(u))
+	case e:sparql.PrimaryExpression => yyy(varmap, e)
+      }})
+    if (l.size == 1)
+      l(0)
+    else
+      sql.ExprConjunction(l.toSet)
+  }
+
+  def yyy(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], from:sparql.PrimaryExpression) : sql.Expression = {
+    from match {
+      case sparql.SparqlTermExpression(term) => assignable2expr999(varmap, term)
+      case sparql.PrimaryExpressionEq(l, r) => sql.RelationalExpressionEq(yyy(varmap, l), yyy(varmap, r))
+      case sparql.PrimaryExpressionGt(l, r) => sql.RelationalExpressionEq(yyy(varmap, l), yyy(varmap, r))
+      case sparql.PrimaryExpressionLt(l, r) => sql.RelationalExpressionEq(yyy(varmap, l), yyy(varmap, r))
+    }
+  }
+
+  /**
+   * junk that should be elsewhere
+   */
+
+  implicit def relname2relresource (rn:rdb.RDB.RelName) : sql.RelationResource = sql.RelationResource(rn)
+
+}
+
+/**
+ * Support functions to inject SparqlToSql results into an XML Results Set.
+ * @example:
+ * <pre>
+ * val xmlres:String = 
+ *   head(List[String]("emp", "name")) +
+ *   startresult +
+ *     binding("emp", "253", rdfmap, stem) +
+ *     binding("name", "Bob", rdfmap, stem) +
+ *   endresult +
+ *   startresult +
+ *     binding("emp", "258", rdfmap, stem) +
+ *     // employee 258 has no name attribute so omit this binding
+ *   endresult +
+ *   foot
+ * </pre>
+ *
+ * @see {@link org.w3.sw.sparql2sql.SparqlToSql}
+ * @see {@link http://www.w3.org/TR/2008/REC-rdf-sparql-XMLres-20080115/ XML Results Format}
+ */
+object SqlToXMLRes {
+
+  /**
+   * Create a SPARQL Results format header and begin the body (results).
+   * @param vars list of variable names to insert into the header
+   */
+  def head (vars:List[String]) : String = {
+    "<?xml version=\"1.0\"?>\n<sparql xmlns=\"http://www.w3.org/2005/sparql-results#\">\n  <head>\n" +
+    vars.map(varname => "    <variable name=\"" + varname + "\"/>\n").mkString + 
+    "  </head>\n\n  <results>\n"
+  }
+
+  /**
+   * Open a result element
+   */
+  def startresult () : String = {
+    "    <result> \n"
+  }
+
+  /**
+   * Create a binding value appropriate for <code>name</code>'s datatype.
+   * @param name name of bound variable.
+   * @param value lexical value of bound variable, may need normalization from e.g. SQL.
+   * @param varmap mapping of sparql variables to datatypes, emitted by SparqlToSql._2
+   * @param stem  stem URI for all generated RDF URIs.
+   */
+  def binding (name:String, value:String, varmap:Map[sparql.Assignable, SparqlToSql.SQL2RDFValueMapper], stem:StemURI) : String = {
+    def getattr (b:SparqlToSql.FullOrPartialBinding) : rdb.RDB.AttrName = {
+      b match {
+	case SparqlToSql.FullBinding(sql.RelVarAttr(_, attr)) =>
+	  attr
+	case SparqlToSql.PartialBinding(binders) => {
+	  val SparqlToSql.BindingConstraint(expr, sql.RelVarAttr(rv, attr)) = binders.toList(0)
+	  attr
+	}
+      }
+    }
+    val t:String = varmap(sparql.VarAssignable(sparql.Var(name))) match {
+      case SparqlToSql.RDFNoder(rel, b)  => "<uri>" + stem.s + rel + "/" + getattr(b) + "." + value + "#record</uri>"
+      case SparqlToSql.RDFBNoder(rel, b) => "<bnode>bnode_" + rel + "/" + getattr(b) + "." + value + "</bnode>"
+      case SparqlToSql.DateMapper(_)     => "<literal datatype=\"http://www.w3.org/2001/XMLSchema#date\">" + value + "</literal>"
+      case SparqlToSql.IntMapper(_)      => "<literal datatype=\"http://www.w3.org/2001/XMLSchema#integer\">" + value + "</literal>"
+      case SparqlToSql.StringMapper(_)   => "<literal datatype=\"http://www.w3.org/2001/XMLSchema#string\">" + value + "</literal>"
+    }
+    "      <binding name=\"" + name + "\">\n	" + t + "\n      </binding>\n"
+  }
+
+  /**
+   * Close a result element.
+   */
+  def endresult () : String = {
+    "    </result>\n"
+  }
+
+  /**
+   * End SPARQL Results document.
+   */
+  def foot () : String = {
+    "  </results>\n</sparql>\n"
+  }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sparqlendpoint/src/main/scala/Config.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,43 @@
+package org.w3.sw.sparqlendpoint
+
+import java.util.Properties
+import scala.io.{Source, Codec}
+
+import org.w3.sw.sql.SqlParser
+import org.w3.sw.rdb.RDB.Database
+
+trait ConfigHelper {
+
+  class P(p:Properties) {
+    def getProperty(key:String):Option[String] = 
+      try { Some(p.getProperty(key)) } catch {	case _ => None }
+  }
+  
+  def load(filename:String) = {
+    val prop = new Properties
+    prop.load(this.getClass.getResourceAsStream("/"+filename))
+    new P(prop)
+  }
+
+  def getContent(filename:String):String = {
+    val is = this.getClass.getResourceAsStream("/"+filename)
+    Source.fromInputStream(is)(Codec.UTF8).getLines().mkString("\n")
+  }
+
+}
+
+object Config extends ConfigHelper {
+
+  val rdb2rdfProp = load("rdb2rdf.properties")
+
+  val DDLParser = SqlParser()
+
+  val dbDdl = getContent("ddl.txt")
+
+  val db:org.w3.sw.rdb.RDB.Database = DDLParser.parseAll(DDLParser.ddl, dbDdl).get
+
+  val defaultSparqlQuery = getContent("default-sparql-query.txt")
+
+  val defaultStemURI = rdb2rdfProp.getProperty("default-stemuri").get
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sparqlendpoint/src/main/scala/Servlet.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,166 @@
+package org.w3.sw.sparqlendpoint
+
+import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse} 
+import scala.xml.XML
+
+import java.sql.{DriverManager, Connection, Statement, ResultSet, ResultSetMetaData}
+
+import java.sql.{Types => T}
+
+import java.net.URI
+import org.w3.sw.rdb.RDB.{RelName,AttrName}
+import org.w3.sw.sql.SqlParser
+import org.w3.sw.sparql
+import org.w3.sw.sparql.Sparql
+import org.w3.sw.sql
+import org.w3.sw.sparql2sql.{SparqlToSql,StemURI,SqlToXMLRes}
+
+object Control {
+
+  private def using[Closeable <: {def close(): Unit}, B](closeable: Closeable)(getB: Closeable => B): B =
+    try {
+      getB(closeable)
+    } finally {
+      closeable.close()
+    }
+
+  private def bmap[T](test: => Boolean)(block: => T): List[T] = {
+    val ret = new scala.collection.mutable.ListBuffer[T]
+    while(test) ret += block
+    ret.toList
+  }
+
+  /** Executes the SQL and processes the result set using the specified function. */
+  private def query[B](connection: Connection, sql: String)(process: ResultSet => B): B =
+    using (connection) { connection =>
+      using (connection.createStatement) { statement =>
+        using (statement.executeQuery(sql)) { results =>
+          process(results)
+        }
+      }
+    }
+
+  /** Executes the SQL and uses the process function to convert each row into a T. */
+  def queryEach[T](connection: Connection, sql: String)(process: ResultSet => T): List[T] =
+    query(connection, sql) { results =>
+      bmap(results.next) {
+        process(results)
+      }
+    }
+
+  def process(connection: Connection, sql: String,
+              head: List[String] => String,
+              startres: String,
+          binding: (String, String /*, Map[sparql.Assignable, SparqlToSql.SQL2RDFValueMapper], StemURI*/) => String,
+          endres: String, foot: String): String = {
+
+    query(connection, sql) { results =>
+
+      val metadata = results.getMetaData
+
+      val vars:List[String] =
+        (1 to metadata.getColumnCount) map { column => metadata.getColumnLabel(column) } toList
+
+      def processCell(rs:ResultSet, column:Int):Option[String] =
+	try {
+          val name:String = metadata.getColumnLabel(column)
+          val value:String =
+	    metadata.getColumnType(column) match {
+              case T.VARCHAR => rs.getString(column)
+              case T.INTEGER => rs.getInt(column).toString
+              case T.DATE    => rs.getDate(column).toString
+              case _         => throw new java.lang.Exception("you have to map this type!!!")
+            }
+          Some(binding(name, value))
+	} catch {
+	  case _ => None
+	}
+
+      def processRow(rs:ResultSet):String =
+        (1 to metadata.getColumnCount) flatMap { column => processCell(rs, column) } mkString ""
+
+      val rows:List[String] = bmap(results.next) {
+        processRow(results)
+      }
+
+      val body = rows map { startres + _ + endres } mkString ""
+
+      head(vars) + body + foot
+
+    }
+
+  }
+
+}
+
+
+class SparqlEndpoint extends HttpServlet {
+
+  val encoding = "utf-8"
+
+  override def doGet(request:HttpServletRequest, response:HttpServletResponse) {
+
+    request.getParameter("query") match {
+      case null | "" => processIndex(request, response)
+      case query     => processSparql(request, response, query)
+    }
+
+  }
+
+  def processSparql(request:HttpServletRequest, response:HttpServletResponse, query:String) {
+
+    val stemURI:StemURI = StemURI(Some(request.getParameter("stemuri")) getOrElse Config.defaultStemURI)
+
+    val sparqlParser = Sparql()
+
+    val sparqlSelect = sparqlParser.parseAll(sparqlParser.select, query).get
+
+    val (generated, rdfmap) = SparqlToSql(Config.db, sparqlSelect, stemURI, true, false)
+
+    Class.forName("com.mysql.jdbc.Driver").newInstance
+    val connection:Connection = DriverManager.getConnection("jdbc:mysql://localhost/rdb2rdf", "root", "")
+
+//    if (! connection.isClosed) println("Successfully connected")
+
+    val res = Control.process(connection=connection,
+			      sql=generated.toString,
+			      head=SqlToXMLRes.head(_),
+			      startres=SqlToXMLRes.startresult,
+			      binding=SqlToXMLRes.binding(_, _, rdfmap, stemURI),
+			      endres=SqlToXMLRes.endresult,
+			      foot=SqlToXMLRes.foot)
+
+    response.setContentType("text/plain; charset='" + encoding + "'")
+
+    response.getWriter.write(res)
+
+  }
+
+  def processIndex(request:HttpServletRequest, response:HttpServletResponse) {
+
+    val index =
+      <html xmlns="http://www.w3.org/1999/xhtml">
+        <head><title>RDB2RDF Sparql endpoint</title></head>
+        <body>
+          <h1>RDB2RDF Sparql endpoint</h1>
+          <form action="sparql">
+            <p>
+              StemURI: <input cols="80" name="stemuri" id="stemuri" value={ Config.defaultStemURI } /><br />
+              <textarea rows="10" cols="80" name="query" id="query">{ Config.defaultSparqlQuery }</textarea>
+              <input type="submit" />
+            </p>
+          </form>
+          <hr />
+          <address>
+            <a href="http://www.w3.org/People/Eric/">Eric Prud'hommeaux</a>, <a href="http://www.w3.org/People/Bertails/">Alexandre Bertails</a>, Jun 2010
+          </address>
+        </body>
+      </html>
+
+    response.setContentType("application/xml; charset='" + encoding + "'")
+
+    XML.write(response.getWriter, index, encoding, false, null) 
+
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sql/src/main/scala/AddOrderedSet.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,27 @@
+package org.w3.sw.util
+
+import scala.collection.immutable._
+
+// class AddOrderedSet[A](list:List[A]) extends Set[A] {
+
+//   def contains(elem: A): Boolean = list.contains(elem)
+//   def iterator: Iterator[A] = list.reverse.iterator
+//   def + (elem: A) : AddOrderedSet[A] = if (this contains elem) this else new AddOrderedSet(elem :: list)
+//   def - (elem: A) : AddOrderedSet[A] = new AddOrderedSet(list filterNot (_ == elem))
+
+// }
+
+class AddOrderedSet[A](list:List[A]) extends Set[A] {
+
+  def contains(elem: A): Boolean = list.contains(elem)
+  def iterator: Iterator[A] = list.iterator
+  def + (elem: A) : AddOrderedSet[A] = if (this contains elem) this else new AddOrderedSet(list ++ List(elem))
+  def - (elem: A) : AddOrderedSet[A] = new AddOrderedSet(list filterNot (_ == elem))
+
+}
+
+object AddOrderedSet {
+  def apply[A]():AddOrderedSet[A] = AddOrderedSet(List[A]())
+  def apply[A](list:List[A]):AddOrderedSet[A] = new AddOrderedSet(list)
+  def apply[A](args:A*):AddOrderedSet[A] = AddOrderedSet(args.toList)
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sql/src/main/scala/SQL.scala	Sun Oct 31 15:17:31 2010 -0400
@@ -0,0 +1,487 @@
+package org.w3.sw.sql
+
+import org.w3.sw.util._
+import org.w3.sw.rdb.RDB
+
+import scala.util.parsing.combinator._
+
+import scala.collection.Set
+
+object SQLParsers extends RegexParsers {
+
+  val int = """[0-9]+""".r
+  val chars = "\"([^\"\\\\\n\r]|\\\\[tbnrf\\\"'])*\"".r
+}
+
+import SQLParsers._
+
+import scala.util.parsing.combinator._
+import java.net.URI
+
+sealed abstract class RelationORSubselect
+case class Subselect(sel:SelectORUnion) extends RelationORSubselect {
+  override def toString = "(\n       " + sel.toString.replace("\n", "\n       ") + "\n                  )"
+}
+sealed abstract class SelectORUnion
+case class Select(distinct:Boolean, projection:Projection, tablelist:TableList, expression:Option[Expression], order:List[OrderElt], offset:Option[Int], limit:Option[Int]) extends SelectORUnion {
+  override def toString = 
+    "SELECT "+
+    { if (distinct) "DISTINCT " else "" }+
+    projection+"\n"+
+    tablelist+
+    { if (expression.isDefined) {"\b WHERE " + expression.get + " "} else "" }+
+    { if (order.size > 0) {order.map(o => o.toString).mkString("ORDER BY ", " ", " ") } else "" }+
+    { if (offset.isDefined) {"OFFSET " + offset + " "} else "" }+
+    { if (limit.isDefined) {"LIMIT " + limit + " "} else "" }
+}
+case class RelationResource(rn:RDB.RelName) extends RelationORSubselect {
+  override def toString = rn.toString
+}
+object foo { // doesn't work
+  implicit def relname2relationref (rn:RDB.RelName) = RelationResource(rn)
+}
+case class Union(disjoints:Set[Select]) extends SelectORUnion {
+  override def toString = "  " + (disjoints.toList.map(s => s.toString.replace("\n", "\n  ")).mkString("\nUNION\n  "))
+}
+case class Projection(attributes:Set[ProjectAttribute]) {
+  // foo, bar
+  override def toString = attributes.toList.sortWith((l, r) => l.attralias.toString < r.attralias.toString).mkString(", ")
+}
+case class ProjectAttribute(value:RelVarAttrORExpression, attralias:AttrAlias) {
+  override def toString = value + " AS " + attralias
+}
+//case class RelAttribute(relation:Relation, attribute:RDB.AttrName) c.f. ForeignKey999
+sealed abstract class RelVarAttrORExpression
+case class RelVarAttr(relvar:RelVar, attribute:RDB.AttrName) extends RelVarAttrORExpression {
+  override def toString = relvar + "." + attribute
+}
+
+case class AttrAlias(n:Name) {
+  override def toString = n.s /* "'" + n.s + "'" */
+}
+case class RelVar(n:Name) {
+  override def toString = n.s /* "'" + n.s + "'" */
+}
+case class TableList(joins:AddOrderedSet[Join]) {
+  override def toString = 
+    if (joins.size == 0) ""
+    else {
+      "  FROM " + joins.foldLeft(("", 0))(
+	(pair, entry) => (pair._1 + {
+	  if (pair._2 == 0) entry.toString.substring(19) // !!! shameless!
+	  else entry
+	}, pair._2+1))._1
+    }
+}
+
+sealed abstract class Join(res:AliasedResource)
+case class InnerJoin(res:AliasedResource, optOn:Option[Expression]) extends Join(res) {
+  override def toString = "\n       INNER JOIN " + res
+}
+case class LeftOuterJoin(res:AliasedResource, on:Expression) extends Join(res) {
+  override def toString = "\n       LEFT OUTER JOIN " + res + " ON " + on
+}
+
+case class AliasedResource(rel:RelationORSubselect, as:RelVar) {
+  override def toString = rel + " AS " + as
+}
+sealed abstract class Expression extends RelVarAttrORExpression
+case class ExprConjunction(exprs:Set[Expression]) extends Expression {
+  override def toString = "(" + (exprs.toList.sortWith((l, r) => l.toString < r.toString).mkString (")\n   AND (")) + ")"
+}
+case class ExprDisjunction(exprs:Set[Expression]) extends Expression {
+  override def toString = "(" + (exprs mkString (") OR (")) + ")"
+}
+sealed abstract class RelationalExpression extends Expression
+case class RelationalExpressionEq(l:Expression, r:Expression) extends RelationalExpression {
+  override def toString = l + "=" + r
+  /* safer operator== , but doesn't quite work yet. */
+  // override def hashCode = 41 * l.hashCode + r.hashCode
+  // override def equals(other: Any) = other match {
+  //   case that: RelationalExpressionEq =>
+  //     (that canEqual this) &&
+  //   ( ( (this.l == that.l) && (this.r == that.r) ||
+  //      (this.l == that.r) && (this.r == that.l) ) )
+  //   case _ =>
+  //     false
+  // }
+  // override def canEqual(other: Any) =
+  //   other.isInstanceOf[RelationalExpressionEq]
+
+  override def equals(that:Any) =
+    that match {
+      case RelationalExpressionEq(l1, r1) => (l == l1 && r == r1) || (r == l1 && l == r1)
+      case _ => false
+    }
+  override def hashCode =
+    if (r.hashCode < l.hashCode)
+      r.hashCode + l.hashCode
+    else
+      l.hashCode + r.hashCode
+}
+case class RelationalExpressionNe(l:Expression, r:Expression) extends RelationalExpression {
+  override def toString = l + "!=" + r
+}
+case class RelationalExpressionLt(l:Expression, r:Expression) extends RelationalExpression {
+  override def toString = l + "<" + r
+}
+case class RelationalExpressionGt(l:Expression, r:Expression) extends RelationalExpression {
+  override def toString = l + ">" + r
+}
+case class RelationalExpressionNull(l:Expression) extends RelationalExpression { // Expression?
+  override def toString = l + " IS NULL"
+}
+case class RelationalExpressionNotNull(l:Expression) extends RelationalExpression { // Expression?
+  override def toString = l + " IS NOT NULL"
+}
+sealed abstract class PrimaryExpression extends Expression
+case class PrimaryExpressionAttr(fqattribute:RelVarAttr) extends PrimaryExpression {
+  override def toString = "" + fqattribute
+}
+case class PrimaryExpressionTyped(datatype:RDB.Datatype, i:Name) extends PrimaryExpression {
+  override def toString = /* "'" + i.s + "'" */ /* + datatype */
+    datatype match {
+      case RDB.Datatype("Int") => i.s
+      case _ => "\"" + i.s + "\""
+    }
+}
+case class OrderElt(desc:Boolean, expr:Expression) {
+  override def toString = { if (desc) "DESC" else "ASC" } + "(" + expr.toString + ")"
+}
+case class ConstNULL() extends PrimaryExpression {
+  override def toString = "NULL"
+}
+case class Concat(args:List[Expression]) extends PrimaryExpression {
+  override def toString = args.mkString("CONCAT(", ", ", ")")
+}
+case class IfElse(cond:Expression, pass:Expression, fail:Expression) extends PrimaryExpression {
+  override def toString = "CONCAT(" + cond + ", " + pass +  ", " + fail + ")"
+}
+
+case class Name(s:String)
+
+object Name {
+  implicit def fromStringToName(s:String):Name = Name(s)
+}
+
+sealed abstract class FieldDescOrKeyDeclaration
+case class FieldDesc(attr:RDB.AttrName, datatype:RDB.Datatype, pkness:Boolean) extends FieldDescOrKeyDeclaration
+sealed abstract class KeyDeclaration extends FieldDescOrKeyDeclaration
+case class PrimaryKeyDeclaration(key:RDB.CandidateKey) extends KeyDeclaration
+case class ForeignKeyDeclaration(fk:List[RDB.AttrName], rel:RDB.RelName, pk:RDB.CandidateKey) extends KeyDeclaration
+case class View(rel:RDB.RelName, defn:SelectORUnion) { // sibling of RDB.Relation
+  override def toString = "CREATE VIEW " + rel + " AS\n" + defn
+}
+
+case class SqlParser() extends JavaTokenParsers {
+
+  def createview:Parser[View] = // @@@ could stick under ddl
+    "CREATE" ~ "VIEW" ~ relation ~ "AS" ~ selectORunion ^^
+  { case "CREATE"~"VIEW"~relation~"AS"~defn => View(relation, defn) }
+
+  def ddl:Parser[RDB.Database] =
+    rep1sep(createtable, ";") ~ opt(";") ^^
+  {
+    case l~x => RDB.Database(l.foldLeft(Map[RDB.RelName, RDB.Relation]())((m, p) => {
+      val (rel:RDB.RelName, desc:RDB.Relation) = p
+      m + (rel -> desc)
+    }))
+  }
+
+  def createtable:Parser[(RDB.RelName, RDB.Relation)] =
+    "CREATE" ~ "TABLE" ~ relation ~ "(" ~ rep1sep(fielddescorkeydef, ",") ~ ")" ^^
+  {
+    case "CREATE"~"TABLE"~relation~"("~reldesc~")" => {
+      val pk0:Option[RDB.CandidateKey] = None
+      val attrs0 = Map[RDB.AttrName, RDB.Datatype]()
+      val candidates0 = List[RDB.CandidateKey]()
+      val fks0 = Map[List[RDB.AttrName], RDB.Target]()
+      /* <pk>: (most recently parsed) PRIMARY KEY
+       * <attrs>: map of attribute to type (e.g. INTEGER)
+       * <fks>: map holding FOREIGN KEY relation REFERENCES attr
+       */
+      val (pk, attrs, candidates, fks) =
+	reldesc.foldLeft((pk0, attrs0, candidates0, fks0))((p, rd) => {
+	  val (pkopt, attrs, candidates, fks) = p
+	  rd match {
+	    case FieldDesc(attr, value, pkness) => {
+	      val (pkNew, candNew) =
+		if (pkness) (Some(RDB.CandidateKey(List(attr))), candidates ++ List(RDB.CandidateKey(attr.n)))
+		else (pkopt, candidates)
+	      (pkNew, attrs + (attr -> value), candNew, fks)
+	    }
+	    case PrimaryKeyDeclaration(key) =>
+	      // @@ why doesn't [[ candidates + RDB.CandidateKey(attr.n) ]] work?
+	      (Some(key), attrs, candidates ++ List(RDB.CandidateKey(key map {attr => RDB.AttrName(attr.n)})), fks)
+	    case ForeignKeyDeclaration(fk, rel, pk) =>
+	      (pkopt, attrs, candidates, fks + (fk -> RDB.Target(rel, pk)))
+	  }
+	})
+      val rd = RDB.Relation(relation, RDB.Header(attrs), List(), candidates, pk, RDB.ForeignKeys(fks))
+      (relation -> rd)
+    }
+  }
+
+  def fielddescorkeydef:Parser[FieldDescOrKeyDeclaration] = (
+      attribute ~ typpe ~ opt("PRIMARY" ~ "KEY") ^^
+      { case attribute~typpe~pkness => FieldDesc(attribute, typpe, pkness.isDefined) }
+    | "PRIMARY" ~ "KEY" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
+      { case "PRIMARY"~"KEY"~"("~attributes~")" => PrimaryKeyDeclaration(RDB.CandidateKey(attributes)) }
+    | "FOREIGN" ~ "KEY" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ~ "REFERENCES" ~ relation ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
+      { case "FOREIGN"~"KEY"~"("~fk~")"~"REFERENCES"~relation~"("~pk~")" => ForeignKeyDeclaration(fk, relation, RDB.CandidateKey(pk)) }
+  )
+
+  def typpe:Parser[RDB.Datatype] = (
+      "INT" ^^ { case _ => RDB.Datatype.INTEGER }
+    | "DOUBLE" ^^ { case _ => RDB.Datatype.DOUBLE }
+    | "STRING" ^^ { case _ => RDB.Datatype.STRING }
+    | "DATETIME" ^^ { case _ => RDB.Datatype.DATETIME }
+    | "DATE" ^^ { case _ => RDB.Datatype.DATE }
+  )
+
+  def selectORunion:Parser[SelectORUnion] =
+    rep1sep(select, "UNION") ^^ { l => if (l.size == 1) l(0) else Union(l.toSet) }
+
+  def select:Parser[Select] =
+    "SELECT" ~ opt("DISTINCT") ~ projection ~ opt(tablelist) ~ opt(where) ~ opt(order) ~ opt(offset) ~ opt(limit) ^^
+    {
+      case "SELECT" ~ distinct ~ attributes ~ tablesANDons ~ whereexpr ~ order ~ offset ~ limit => {
+	val (tables, onExpressions) =
+	  tablesANDons.getOrElse((TableList(AddOrderedSet[Join]()), Set[Expression]()))
+	val t:Set[Expression] = onExpressions
+	val onConjoints:Set[Expression] =
+	  onExpressions.foldLeft(Set[Expression]())((s, ent) =>
+	  s ++ {ent match {
+	    case ExprConjunction(l) => l
+	    case _ => Set(ent)
+	  }})
+	val conjoints = whereexpr match {
+	  case Some(ExprConjunction(l)) => onConjoints ++ l
+	  case Some(x) => onConjoints + x
+	  case _ => onConjoints
+	}
+	val expr:Option[Expression] = conjoints.size match {
+	  case 0 => None
+	  case 1 => Some(conjoints.toList(0))
+	  case _ => Some(ExprConjunction(conjoints))
+	}
+	Select(distinct.isDefined, attributes, tables, expr, order.getOrElse(List[OrderElt]()), offset, limit)
+      }
+    }
+
+  def order:Parser[List[OrderElt]] = 
+    "ORDER" ~ "BY" ~ rep(orderelt) ^^ { case o~b~elts => elts }
+
+  def orderelt:Parser[OrderElt] = (
+      "ASC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(false, expr) }
+    | "DESC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(true, expr) }
+    | fqattribute ^^ { case v => OrderElt(false, PrimaryExpressionAttr(v)) }
+  )
+    
+  def offset:Parser[Int] =
+    "OFFSET" ~ int ^^ { case o~i => i.toInt }
+
+  def limit:Parser[Int] =
+    "LIMIT" ~ int ^^ { case o~i => i.toInt }
+
+  def where:Parser[Expression] =
+    "WHERE" ~ expression ^^ { case "WHERE" ~ expression => expression }
+
+  def projection:Parser[Projection] =
+    repsep(namedattribute, ",") ^^ { l => Projection(l.toSet) }
+
+  def namedattribute:Parser[ProjectAttribute] =
+    fqattributeORprimaryexpression ~ "AS" ~ attralias ^^
+    { case fqattributeORprimaryexpression ~ "AS" ~ attralias =>
+      ProjectAttribute(fqattributeORprimaryexpression, attralias) }
+
+  def fqattributeORprimaryexpression:Parser[RelVarAttrORExpression] = (
+      fqattribute ^^ { case fqattribute => fqattribute }
+    | primaryexpression ^^ { case const => const }
+  )
+
+  def fqattribute:Parser[RelVarAttr] =
+    relvar ~ "." ~ attribute ^^
+    { case relvar ~ "." ~ attribute => RelVarAttr(relvar, attribute) }
+
+  def attribute:Parser[RDB.AttrName] =
+    """[a-zA-Z_]\w*""".r ^^ { x => RDB.AttrName(x) }
+
+  def attralias:Parser[AttrAlias] =
+    """[a-zA-Z_]\w*""".r ^^ { x => AttrAlias(Name(x)) }
+
+  def relationORsubselect:Parser[RelationORSubselect] = (
+      relation ^^ { x => RelationResource(x) }
+    | "(" ~ selectORunion ~ ")" ^^ { case "("~s~")" => Subselect(s) }
+  )
+
+  def relation:Parser[RDB.RelName] =
+    """[a-zA-Z_]\w*""".r ^^ { x => RDB.RelName(x) }
+
+  def relvar:Parser[RelVar] =
+    """[a-zA-Z_]\w*""".r ^^ { x => RelVar(Name(x)) }
+
+  def tablelist:Parser[(TableList, Set[Expression])] =
+    "FROM" ~ aliasedjoin ~ rep(innerORouter) ^^
+    { case "FROM"~aj~l => (TableList(AddOrderedSet(InnerJoin(aj, None) :: l.map((one) => one._1))), 
+			   l.foldLeft(Set[Expression]())((all, one) => all ++ one._2)) }
+
+  def innerORouter:Parser[(Join, Set[Expression])] = (
+      "INNER" ~ "JOIN" ~ aliasedjoin ~ opt("ON" ~ expression) ^^
+      { case "INNER"~"JOIN"~a~o => (InnerJoin(a, None), { if (o.isDefined) Set(o.get._2) else Set[Expression]() } ) }
+    | "LEFT" ~ "OUTER" ~ "JOIN" ~ aliasedjoin ~ "ON" ~ expression ^^
+      { case l~o~j~alijoin~on~expr => (LeftOuterJoin(alijoin, expr), Set[Expression]()) }
+  )
+
+  def aliasedjoin:Parser[AliasedResource] =
+    relationORsubselect ~ "AS" ~ relvar ^^
+    { case rel1 ~ "AS" ~ rel2 => AliasedResource(rel1, rel2) }
+
+  def expression:Parser[Expression] =
+    ORexpression ^^ { x => x }
+
+  def ORexpression:Parser[Expression] =
+    rep1sep (ANDexpression, "OR") ^^ 
+    { xs => if (xs.size > 1) ExprDisjunction(xs.toSet) else xs(0) }
+
+  def ANDexpression:Parser[Expression] =
+    rep1sep (relationalexpression, "AND") ^^ 
+    { xs => if (xs.size > 1) ExprConjunction(xs.toSet) else xs(0) }
+
+  def relationalexpression:Parser[Expression] = (
+      primaryexpression ~ "=" ~ primaryexpression ^^
+      { case primaryexpression ~ "=" ~ rvalue => RelationalExpressionEq(primaryexpression, rvalue) }
+    | primaryexpression ~ "!=" ~ primaryexpression ^^
+      { case primaryexpression ~ "!=" ~ rvalue => RelationalExpressionNe(primaryexpression, rvalue) }
+    | primaryexpression ~ "<" ~ primaryexpression ^^
+      { case primaryexpression ~ "<" ~ rvalue => RelationalExpressionLt(primaryexpression, rvalue) }
+    | primaryexpression ~ ">" ~ primaryexpression ^^
+      { case primaryexpression ~ ">" ~ rvalue => RelationalExpressionGt(primaryexpression, rvalue) }
+    | primaryexpression ~ "IS" ~ "NULL" ^^
+      { case primaryexpression ~ "IS" ~ "NULL" => RelationalExpressionNull(primaryexpression) }
+    | primaryexpression ~ "IS" ~ "NOT" ~ "NULL" ^^
+      { case primaryexpression ~ "IS" ~ "NOT" ~ "NULL" => RelationalExpressionNotNull(primaryexpression) }
+    | primaryexpression ^^
+      { case primaryexpression => primaryexpression }
+  )
+
+  def primaryexpression:Parser[Expression] = (
+      fqattribute ^^ { PrimaryExpressionAttr(_) }
+    | int ^^ { i => PrimaryExpressionTyped(RDB.Datatype.INTEGER, Name(i)) }
+    | chars  ^^ { x => PrimaryExpressionTyped(RDB.Datatype.STRING, Name(x.substring(1, x.size - 1))) }
+    | "NULL" ^^ { case "NULL" => ConstNULL() }
+    | "CONCAT" ~ "(" ~ rep1sep(expression, ",") ~ ")" ^^ { case "CONCAT"~"("~expressions~")" => Concat(expressions) }
+    | "IF" ~ "(" ~ expression ~ "," ~ expression ~ "," ~ expression ~ ")" ^^ { case "IF"~"("~c~","~p~","~f~")" => IfElse(c, p, f) }
+    | "(" ~ expression ~ ")" ^^ { case "("~x~")" => x }
+  )
+
+}
+
+case class PrettySql(select:Select) {
+  def makePretty():Select = {
+    val Select(distinct, projection, tablelist, expression, order, offset, limit) = select
+    val nullStripped =
+      if (expression.isDefined) {
+	val nonNullAttrs = PrettySql.findNonNullRelVarAttrs(expression.get)
+	PrettySql.stripNotNulls(expression.get, nonNullAttrs)
+      }
+      else None
+    val XeqXStripped =
+      if (nullStripped.isDefined) {
+	PrettySql.stripXeqX(nullStripped.get)
+      }
+      else None
+    val strippedTables = tablelist.joins.foldLeft(AddOrderedSet[Join]())((set, join) => set + {
+      join match {
+	case InnerJoin(AliasedResource(rel, as), optOn) => InnerJoin(AliasedResource({ rel match {
+	  case Subselect(s:Select) => Subselect(PrettySql(s).makePretty())
+	  case Subselect(Union(disjoints)) => Subselect(Union(disjoints.map(s => PrettySql(s).makePretty())))
+	  case r:RelationResource => r
+	}}, as), None)
+	case LeftOuterJoin(AliasedResource(rel, as), on:Expression) => LeftOuterJoin(AliasedResource({ rel match {
+	  case Subselect(s:Select) => Subselect(PrettySql(s).makePretty())
+	  case Subselect(Union(disjoints)) => Subselect(Union(disjoints.map(s => PrettySql(s).makePretty())))
+	  case r:RelationResource => r
+	}}, as), on)
+      }})
+    Select(distinct, projection, TableList(strippedTables), XeqXStripped, order, offset, limit)
+  }
+}
+
+object PrettySql {
+  def findNonNullRelVarAttrs(expr:Expression):Set[RelVarAttr] = {
+    expr match {
+      case ExprConjunction(s) => s.foldLeft(Set[RelVarAttr]())((s, e) => s ++ findNonNullRelVarAttrs(e))
+      case ExprDisjunction(s) => {
+	val l = s.toList
+	l.slice(1, l.size).foldLeft(findNonNullRelVarAttrs(l(0)))((s, e) => s & findNonNullRelVarAttrs(e))
+      }
+      case RelationalExpressionEq(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
+      case RelationalExpressionNe(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
+      case RelationalExpressionLt(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
+      case RelationalExpressionGt(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
+      case e:PrimaryExpressionTyped => Set()
+      case PrimaryExpressionAttr(a) => Set(a)
+      case e:ConstNULL => Set()
+      case e:Concat => Set()
+      case RelationalExpressionNull(a) => findNonNullRelVarAttrs(a)
+      case RelationalExpressionNotNull(a) => Set()
+      case IfElse(eef, den, els) => Set()
+    }
+  }
+  def stripNotNulls(expr:Expression, stripMe:Set[RelVarAttr]):Option[Expression] = {
+    expr match {
+      case ExprConjunction(l) => Some(ExprConjunction({l.foldLeft(Set[Expression]())((s, e) => {
+	val e2 = stripNotNulls(e,stripMe)
+	if (e2.isDefined) s + e2.get
+	else s})}))
+      case ExprDisjunction(l) => Some(ExprDisjunction({l.foldLeft(Set[Expression]())((s, e) => {
+	val e2 = stripNotNulls(e,stripMe)
+	if (e2.isDefined) s + e2.get
+	else s})}))
+      case e:RelationalExpressionEq => Some(e)
+      case e:RelationalExpressionNe => Some(e)
+      case e:RelationalExpressionLt => Some(e)
+      case e:RelationalExpressionGt => Some(e)
+      case e:PrimaryExpressionTyped => Some(e)
+      case e:PrimaryExpressionAttr => Some(e)
+      case e:ConstNULL => Some(e)
+      case e:Concat => Some(e)
+      case e:RelationalExpressionNull => Some(e)
+      case RelationalExpressionNotNull(PrimaryExpressionAttr(a)) =>
+	if (stripMe.contains(a)) None
+	else Some(RelationalExpressionNotNull(PrimaryExpressionAttr(a)))
+      case e:RelationalExpressionNotNull => Some(e)
+      case e:IfElse => Some(e)
+    }
+  }
+  def stripXeqX(expr:Expression):Option[Expression] = {
+    expr match {
+      case ExprConjunction(l) => Some(ExprConjunction({l.foldLeft(Set[Expression]())((s, e) => {
+	val e2 = stripXeqX(e)
+	if (e2.isDefined) s + e2.get
+	else s})}))
+      case ExprDisjunction(l) => Some(ExprDisjunction({l.foldLeft(Set[Expression]())((s, e) => {
+	val e2 = stripXeqX(e)
+	if (e2.isDefined) s + e2.get
+	else s})}))
+      case e:RelationalExpressionEq => {
+	val RelationalExpressionEq(l, r) = e
+	if (l == r) None
+	else Some(e)
+      }
+      case e:RelationalExpressionNe => Some(e)
+      case e:RelationalExpressionLt => Some(e)
+      case e:RelationalExpressionGt => Some(e)
+      case e:PrimaryExpressionTyped => Some(e)
+      case e:PrimaryExpressionAttr => Some(e)
+      case e:ConstNULL => Some(e)
+      case e:Concat => Some(e)
+      case e:RelationalExpressionNull => Some(e)
+      case e:RelationalExpressionNotNull => Some(e)
+      case e:IfElse => Some(e)
+    }
+  }
+  implicit def toPrettySql(select:Select) = PrettySql(select)
+}
+
--- a/src/main/scala/AddOrderedSet.scala	Fri Oct 15 16:42:41 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-package w3c.sw.util
-import scala.collection.immutable._
-
-// class AddOrderedSet[A](list:List[A]) extends Set[A] {
-
-//   def contains(elem: A): Boolean = list.contains(elem)
-//   def iterator: Iterator[A] = list.reverse.iterator
-//   def + (elem: A) : AddOrderedSet[A] = if (this contains elem) this else new AddOrderedSet(elem :: list)
-//   def - (elem: A) : AddOrderedSet[A] = new AddOrderedSet(list filterNot (_ == elem))
-
-// }
-
-class AddOrderedSet[A](list:List[A]) extends Set[A] {
-
-  def contains(elem: A): Boolean = list.contains(elem)
-  def iterator: Iterator[A] = list.iterator
-  def + (elem: A) : AddOrderedSet[A] = if (this contains elem) this else new AddOrderedSet(list ++ List(elem))
-  def - (elem: A) : AddOrderedSet[A] = new AddOrderedSet(list filterNot (_ == elem))
-
-}
-
-object AddOrderedSet {
-  def apply[A]():AddOrderedSet[A] = AddOrderedSet(List[A]())
-  def apply[A](list:List[A]):AddOrderedSet[A] = new AddOrderedSet(list)
-  def apply[A](args:A*):AddOrderedSet[A] = AddOrderedSet(args.toList)
-}
--- a/src/main/scala/Config.scala	Fri Oct 15 16:42:41 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-package org.w3.sparql2sql.servlet
-
-import java.util.Properties
-import scala.io.{Source, Codec}
-
-import w3c.sw.sql.SqlParser
-import w3c.sw.sql.RDB.Database
-
-trait ConfigHelper {
-
-  class P(p:Properties) {
-    def getProperty(key:String):Option[String] = 
-      try { Some(p.getProperty(key)) } catch {	case _ => None }
-  }
-  
-  def load(filename:String) = {
-    val prop = new Properties
-    prop.load(this.getClass.getResourceAsStream("/"+filename))
-    new P(prop)
-  }
-
-  def getContent(filename:String):String = {
-    val is = this.getClass.getResourceAsStream("/"+filename)
-    Source.fromInputStream(is)(Codec.UTF8).getLines().mkString("\n")
-  }
-
-}
-
-object Config extends ConfigHelper {
-
-  val rdb2rdfProp = load("rdb2rdf.properties")
-
-  val DDLParser = SqlParser()
-
-  val dbDdl = getContent("ddl.txt")
-
-  val db:w3c.sw.sql.RDB.Database = DDLParser.parseAll(DDLParser.ddl, dbDdl).get
-
-  val defaultSparqlQuery = getContent("default-sparql-query.txt")
-
-  val defaultStemURI = rdb2rdfProp.getProperty("default-stemuri").get
-
-}
--- a/src/main/scala/GraphAnalyzer.scala	Fri Oct 15 16:42:41 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-package w3c.sw.util
-import scala.collection.immutable._
-
-class GraphAnalyzer[A](m:Map[A, Set[A]]) {
-
-  def reaches (from:A, to:A) = {
-    if (m.contains(from))
-      new GraphAnalyzer[A](m + (from -> (m(from) + to)))
-    else
-      new GraphAnalyzer[A](m + (from -> Set(to)))
-  }
-  def pair (l:A, r:A) = {
-    reaches(l, r).reaches(r, l)
-  }
-  def neededFor (need:Set[A], t:A, visited:Set[A]):Boolean = {
-    if (!m.contains(t))
-      error("unknown symbol: " + t)
-    var ret:Boolean = false
-    m(t).map((r) => {
-      if (visited.contains(t)) return false
-      if (need.contains(t)) return true
-      ret |= neededFor(need, r, visited + t)
-    })
-    return ret
-  }
-
-}
-
-object GraphAnalyzer {
-  def apply[A]():GraphAnalyzer[A] = GraphAnalyzer() // Map[A, Set[A]]()
-  // def apply[A](list:List[A]):GraphAnalyzer[A] = new GraphAnalyzer(list)
-  // def apply[A](args:A*):GraphAnalyzer[A] = GraphAnalyzer(args.toList)
-}
-
-// object GraphAnalyzer {
-// }
-// //def createEmptyGraphAnalyzer () = GraphAnalyzer(Map[A, Set[A]]())
-
-  // case class Reacher (b:Map[String, Map[String, Set[String]]]) {
-  //   def reaches (from:String, to:String) = {
-  //     if (b.contains(from)) {
-  // 	if (b(from).contains(to)) {
-  // 	  val back = b(from)(to) + from
-  // 	  val fore = b(from) + (to -> back)
-  // 	  val ret = Reacher(b + (from -> fore))
-  // 	  println("duplicate path from " + from + " to " + to)
-  // 	  // println("ret: " + ret)
-  // 	  ret
-  // 	} else {
-  // 	  println(from + "->" + to + " + " + this)
-  // 	  val back = Set[String](from)
-  // 	  val fore = b(from) + (to -> back)
-  // 	  val ret = Reacher(b + (from -> fore))
-  // 	  println("ret: " + ret)
-  // 	  ret
-  // 	}
-  //     } else {
-  // 	val back = Set[String](from)
-  // 	val fore = Map[String, Set[String]](to -> back)
-  // 	val ret = Reacher(b + (from -> fore))
-  // 	// println("ret: " + ret)
-  // 	ret
-  //     }
-  //   }
-  //   def pair (l:String, r:String) = {
-  //     reaches(l, r).reaches(r, l)
-  //   }
-  //   override def toString = b.toString
-  // }
-  // def createEmptyReacher () = Reacher(Map[String, Map[String, Set[String]]]())
-
--- a/src/main/scala/RDF.scala	Fri Oct 15 16:42:41 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-package w3c.sw.rdf
-
-import java.net.URI
-
-case class RDFTriple(s:RDFSubject, p:RDFPredicate, o:RDFObject)
-
-sealed abstract class RDFSubject()
-case class RDFSubjectUri(uri:URI) extends RDFSubject
-case class RDFSubjectBlankNode(b:BlankNode) extends RDFSubject
-
-case class RDFPredicate(uri:URI)
-
-sealed abstract class RDFObject()
-case class RDFObjectUri(uri:URI) extends RDFObject
-case class RDFObjectBlankNode(b:BlankNode) extends RDFObject
-
-case class BlankNode(debugName:String)
-
-case class RDFLiteral(lexicalForm:String, datatype:Datatype) {
-  override def toString = "\"" + lexicalForm + "\"" + datatype
-}
-case class Datatype(uri:URI) {
-  override def toString = "^^" + uri
-}
-
-object RDFLiteral {
-  val StringDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#string"))
-  val IntegerDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#integer"))
-  val DateDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#date"))
-  // val DateTimeDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#dateTime"))
-}
--- a/src/main/scala/SPARQL.scala	Fri Oct 15 16:42:41 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,431 +0,0 @@
-package w3c.sw.sparql
-
-import w3c.sw.rdf._
-import scala.util.parsing.combinator._
-import java.net.URI
-
-object MyParsers extends RegexParsers {
-
-  val uri = """[a-zA-Z0-9:/#_\.\-]+""".r
-  val integer = """[0-9]+""".r
-  val name = """[a-zA-Z][a-zA-Z0-9_-]*|[a-zA-Z_][a-zA-Z0-9_]+""".r
-  var prefixes:Map[String, String] = Map()
-  var bnodes:Map[String, BNode] = Map()
-  var nextBNode = 1
-}
-
-import MyParsers._
-
-case class Select(distinct:Boolean, attrs:SparqlAttributeList, gp:GraphPattern, order:List[OrderElt], offset:Option[Int], limit:Option[Int]) {
-  override def toString =
-    "SELECT "+
-    { if (distinct) "DISTINCT " else "" }+
-    attrs+"\n"+gp+" "+
-    { if (order.size > 0) {order.map(o => o.toString).mkString("ORDER BY ", " ", " ") } else "" }+
-    { if (offset.isDefined) {"OFFSET " + offset.get + " "} else "" }+
-    { if (limit.isDefined) {"LIMIT " + limit.get + " "} else "" }
-}
-case class Construct(head:TriplesBlock, gp:GraphPattern)
-case class SparqlAttributeList(attributelist:List[Var]) {
-  override def toString = attributelist.toList.sortWith((l, r) => l.s < r.s).mkString(" ")
-}
-
-sealed abstract class GraphPattern {
-  def findVars ():Set[Var] = {
-    this match {
-      case TableFilter(gp2:GraphPattern, expr:Expression) =>
-	gp2.findVars
-
-      case TriplesBlock(triplepatterns) =>
-	/* Examine each triple, updating the compilation state. */
-	triplepatterns.foldLeft(Set[Var]())((x, y) => x ++ y.findVars)
-
-      case TableConjunction(list) =>
-	/* Examine each triple, updating the compilation state. */
-	list.foldLeft(Set[Var]())((x, y) => x ++ y.findVars)
-
-      case OptionalGraphPattern(gp2) =>
-	/* Examine each triple, updating the compilation state. */
-	gp2.findVars
-
-      case x => error("no code to handle " + x)
-    }
-  }
-  def findAssignables ():Set[Assignable] = {
-    this match {
-      case TableFilter(gp2:GraphPattern, expr:Expression) =>
-	gp2.findAssignables
-
-      case TriplesBlock(triplepatterns) =>
-	/* Examine each triple, updating the compilation state. */
-	triplepatterns.foldLeft(Set[Assignable]())((x, y) => x ++ y.findAssignables)
-
-      case TableConjunction(list) =>
-	/* Examine each triple, updating the compilation state. */
-	list.foldLeft(Set[Assignable]())((x, y) => x ++ y.findAssignables)
-
-      case OptionalGraphPattern(gp2) =>
-	/* Examine each triple, updating the compilation state. */
-	gp2.findAssignables
-
-      case x => error("no code to handle " + x)
-    }
-  }
-
-  def trim (terms:Set[Term]):GraphPattern = {
-    this match {
-      case TableFilter(gp2:GraphPattern, expr:Expression) =>
-	TableFilter(gp2.trim(terms), expr)
-
-      case TriplesBlock(triplepatterns) => {
-	val r0 = new w3c.sw.util.GraphAnalyzer[Term](Map[Term, Set[Term]]())
-	/* Examine each triple, updating the compilation state. */
-	val r = triplepatterns.foldLeft(r0)((r, triple) => r.pair(triple.s, triple.o))
-	val useful = triplepatterns.foldLeft(Set[TriplePattern]())((s, t) => {
-	  if (r.neededFor(terms, t.s, Set(t.o)) &&
-	      r.neededFor(terms, t.o, Set(t.s))) s + t
-	  else s
-	})
-	val useful2 =
-	  if (useful.size == 0)
-	    triplepatterns.foldLeft(Set[TriplePattern]())((s, t) => {
-	      if (r.neededFor(terms, t.s, Set(t.o)) ||
-		  r.neededFor(terms, t.o, Set(t.s))) s + t
-	      else s
-	    })
-          else useful
-	TriplesBlock(useful2.toList)
-      }
-
-      case TableConjunction(list) =>
-	/* Examine each triple, updating the compilation state. */
-	TableConjunction(list.map(gp2 => gp2.trim(terms)))
-
-      case OptionalGraphPattern(gp2) =>
-	/* Examine each triple, updating the compilation state. */
-	OptionalGraphPattern(gp2.trim(terms))
-
-      case x => error("no code to handle " + x)
-    }
-  }
-
-  def simplify ():GraphPattern = {
-    this match {
-      case TableFilter(gp2:GraphPattern, expr:Expression) =>
-	TableFilter(gp2.simplify, expr)
-
-      case tb:TriplesBlock => tb
-
-      case TableConjunction(list) => {
-	/* Eliminate series of TriplesBlocks. */
-	val (conjuncts, triples) = list.foldLeft((List[GraphPattern](), List[TriplePattern]()))((pair, gp2) => {
-	  val (conj, trip) = pair
-	  val gp3 = gp2.simplify
-	  gp3 match {
-	    case TriplesBlock(triplepatterns) =>
-	      (conj, trip ++ triplepatterns)
-	    case x => {
-	      (conj ++ List(TriplesBlock(trip)), List[TriplePattern]())
-	    }
-	  }
-	})
-	val conj2 =
-	  if (triples.size > 0) conjuncts ++ List(TriplesBlock(triples))
-	  else conjuncts
-	if (conj2.size > 1) TableConjunction(conj2)
-	else if (conj2.size == 1) conj2(0)
-	else TriplesBlock(List[TriplePattern]())
-      }
-
-      case OptionalGraphPattern(gp2) =>
-	/* Examine each triple, updating the compilation state. */
-	OptionalGraphPattern(gp2.simplify)
-
-      case x => error("no code to handle " + x)
-    }
-  }
-}
-
-case class TriplesBlock(triplepatterns:List[TriplePattern]) extends GraphPattern {
-  override def toString = "{\n  " + (triplepatterns.toList.map(s => s.toString.replace("\n", "\n  ")).mkString("", " .\n  ", " .\n")) + "}"
-  override def equals (other:Any):Boolean = other match {
-    case that:TriplesBlock => (that canEqual this) && triplepatterns.toSet == that.triplepatterns.toSet
-    case _ => false
-  }
-  override def canEqual(other : Any) : Boolean = other.isInstanceOf[TriplesBlock]
-  override def hashCode:Int = 41*triplepatterns.toSet.hashCode
-}
-case class TableConjunction(gps:List[GraphPattern]) extends GraphPattern {
-  assert (!(gps exists (x => { x match { case TableConjunction(_) => true case _ => false } })))
-  override def toString = "{\n  " + (gps.toList.map(s => s.toString.replace("\n", "\n  ")).mkString("\n  ")) + "\n}\n"
-}
-case class TableDisjunction(gps:List[GraphPattern]) extends GraphPattern {
-  override def toString = "{\n  " + (gps.toList.map(s => s.toString.replace("\n", "\n  ")).mkString("\nUNION\n  ")) + "\n}\n"
-}
-case class TableFilter(gp:GraphPattern, expr:Expression) extends GraphPattern {
-  override def toString = gp.toString + "\nFILTER (" + expr.toString + ")"
-}
-case class OptionalGraphPattern(gp:GraphPattern) extends GraphPattern {
-  override def toString = "OPTIONAL " + gp.toString
-}
-case class MinusGraphPattern(gp:GraphPattern) extends GraphPattern {
-  override def toString = "MINUS " + gp.toString
-}
-case class GraphGraphPattern(gp:GraphPattern) extends GraphPattern
-
-case class TriplePattern(s:Term, p:Term, o:Term) {
-  override def toString = s + " " + p + " " + o
-  def findVars ():Set[Var] = {
-    val varS:Set[Var] = s match {
-      case TermVar(v) => Set(v)
-      case _                 => Set()
-    }
-    val varO:Set[Var] = o match {
-      case TermVar(v) => Set(v)
-      case _                 => Set()
-    }
-    varS ++ varO
-  }
-  def findAssignables ():Set[Assignable] = {
-    val varS:Set[Assignable] = s match {
-      case TermVar(v) => Set(VarAssignable(v))
-      case TermBNode(v) => Set(BNodeAssignable(v))
-      case _                 => Set()
-    }
-    val varO:Set[Assignable] = o match {
-      case TermVar(v) => Set(VarAssignable(v))
-      case TermBNode(b) => Set(BNodeAssignable(b))
-      case _                 => Set()
-    }
-    varS ++ varO
-  }
-}
-
-case class Literal(lit:RDFLiteral) {
-  override def toString = lit match {
-    case RDFLiteral(s, RDFLiteral.IntegerDatatype) => s
-    case _ => lit.toString
-  }
-}
-
-sealed abstract class Assignable { val s:String }
-
-case class VarAssignable(v:Var) extends Assignable { val s = v.s }
-case class BNodeAssignable(b:BNode) extends Assignable { val s = b.s }
-
-case class Var(s:String) {
-  override def toString = "?" + s
-}
-
-case class Uri(s:String) {
-  override def toString = "<" + s + ">"
-}
-
-case class BNode(s:String) {
-  override def toString = "_:" + s
-}
-
-case class Expression(conjuncts:List[PrimaryExpression]) {
-  override def toString = conjuncts.map(e => e.toString()).mkString(" && ")
-}
-
-sealed abstract class PrimaryExpression
-case class PrimaryExpressionEq(left:SparqlTermExpression, right:SparqlTermExpression) extends PrimaryExpression {
-  override def toString = left.toString() + " = " + right.toString
-}
-case class PrimaryExpressionLt(left:SparqlTermExpression, right:SparqlTermExpression) extends PrimaryExpression {
-  override def toString = left.toString() + " < " + right.toString
-}
-case class PrimaryExpressionGt(left:SparqlTermExpression, right:SparqlTermExpression) extends PrimaryExpression {
-  override def toString = left.toString() + " > " + right.toString
-}
-case class SparqlTermExpression(term:Term) extends PrimaryExpression {
-  override def toString = term.toString
-}
-
-case class OrderElt(desc:Boolean, expr:Expression) {
-  override def toString = { if (desc) "DESC" else "ASC" } + "(" + expr.toString + ")"
-}
-
-sealed trait Term
-case class TermUri(u:Uri) extends Term {
-  override def toString = u.toString
-}
-case class TermBNode(b:BNode) extends Term {
-  override def toString = b.toString
-}
-case class TermVar(v:Var) extends Term {
-  override def toString = v.toString
-}
-case class TermLit(lit:Literal) extends Term {
-  override def toString = lit.toString
-}
-
-
-case class Sparql() extends JavaTokenParsers {
-
-  def select:Parser[Select] =
-    rep(prefixdecls) ~ "SELECT" ~ opt("DISTINCT") ~ attributelist ~ opt("WHERE") ~ groupgraphpattern ~ opt(order) ~ opt(offset) ~ opt(limit) ^^ {
-      case x~"SELECT"~d~a~w~gp~ord~off~lim => Select(d.isDefined, a, gp, ord.getOrElse(List[OrderElt]()), off, lim)
-    }
-
-  def order:Parser[List[OrderElt]] = 
-    "ORDER" ~ "BY" ~ rep(orderelt) ^^ { case o~b~elts => elts }
-
-  def orderelt:Parser[OrderElt] = (
-      "ASC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(false, expr) }
-    | "DESC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(true, expr) }
-    | varr ^^ { case v => OrderElt(false, Expression(List(SparqlTermExpression(TermVar(v))))) }
-  )
-    
-  def offset:Parser[Int] =
-    "OFFSET" ~ integer ^^ { case o~i => i.toInt }
-
-  def limit:Parser[Int] =
-    "LIMIT" ~ integer ^^ { case o~i => i.toInt }
-
-  def construct:Parser[Construct] =
-    rep(prefixdecls) ~ "CONSTRUCT" ~ constructpattern ~ opt("WHERE") ~ groupgraphpattern ^^ { case x~"CONSTRUCT"~a~w~gp => Construct(a, gp) }
-
-  def constructpattern:Parser[TriplesBlock] =
-    "{" ~ opt(triplesblock) ~ "}" ^^ { case "{"~tbOPT~"}" => tbOPT.getOrElse(TriplesBlock(List[TriplePattern]())) }
-
-  def prefixdecls:Parser[Unit] =
-    "PREFIX" ~ name ~ ":" ~ qnameORuri ^^ { case "PREFIX"~pre~":"~u => prefixes += (pre -> u.s) }
-
-  def filter:Parser[Expression] =
-    "FILTER" ~ "(" ~ expression ~ ")" ^^ { case "FILTER"~"("~expression~")" => expression }
-
-  def expression:Parser[Expression] = 
-    repsep(primaryexpression, "&&") ^^ 
-    { Expression(_) }
-
-  def primaryexpression:Parser[PrimaryExpression] = (
-      value ~ "=" ~ value ^^
-      { case left ~ "=" ~ right => PrimaryExpressionEq(left, right) }
-    | value ~ "<" ~ value ^^
-      { case left ~ "<" ~ right => PrimaryExpressionLt(left, right) }
-    | value ~ ">" ~ value ^^
-      { case left ~ ">" ~ right => PrimaryExpressionGt(left, right) }
-    | value
-  )
-
-  def value:Parser[SparqlTermExpression] = (
-      qnameORuri ^^ { case x => SparqlTermExpression(TermUri(x)) }
-    | varr ^^ { x => SparqlTermExpression(TermVar(x)) }
-    | literal ^^ { x => SparqlTermExpression(TermLit(x)) }
-  )
-
-  def attributelist:Parser[SparqlAttributeList] =
-    rep(varr) ^^ { SparqlAttributeList(_) }
-
-  def groupgraphpattern:Parser[GraphPattern] = (
-    "{" ~ opt(triplesblock) ~ rep(graphpatternnottriplesORfilter ~ opt(triplesblock)) ~ "}" ^^
-    {
-      case "{"~tbOPT~gpntORf_tbOPT~"}" => {
-
-// case class TriplesBlock(triplepatterns:List[TriplePattern]) extends GraphPattern
-// case class TableConjunction(gps:List[GraphPattern]) extends GraphPattern
-// case class TableDisjunction(gps:List[GraphPattern]) extends GraphPattern
-// case class TableFilter(gp:GraphPattern, expr:Expression) extends GraphPattern
-// case class OptionalGraphPattern(gp:GraphPattern) extends GraphPattern
-// case class GraphGraphPattern(gp:GraphPattern) extends GraphPattern
-
-	// println("groupgraphpattern(" + tbOPT + ", " + gpntORf_tbOPT + ")")
-	val init:Option[GraphPattern] = tbOPT
-	gpntORf_tbOPT.foldLeft(init)((gp, lentry) => {//println("match: " + (gp, lentry))
-	  // print("case (" + gp + ", " + lentry + ")")
-	  (gp, lentry) match {
-	    case (Some(TableFilter(TriplesBlock(l), Expression(lexp))), ~(TableFilter(null, Expression(expr)), Some(TriplesBlock(r)))) => Some(TableFilter(TriplesBlock(l ++ r), Expression(lexp ++ expr)))
-	    case (Some(TriplesBlock(l)), ~(TableFilter(null, expr), Some(TriplesBlock(r)))) => Some(TableFilter(TriplesBlock(l ++ r), expr))
-	    case (Some(gp             ), ~(TableFilter(null, expr), None                 )) => Some(TableFilter(gp, expr))
-	    case (None,                  ~(TableFilter(null, expr), Some(TriplesBlock(r)))) => Some(TableFilter(TriplesBlock(r), expr))
-
-	    // case (None,     ~(TableConjunction(gps), None    )) => TableConjunction(gps)
-	    // case (Some(gp), ~(TableConjunction(gps), None    )) => TableConjunction(List(List(gp) ++ gps))
-	    // case (None,     ~(TableConjunction(gps), Some(tb))) => TableConjunction(List(gps ++ List(tb)))
-	    // case (Some(gp), ~(TableConjunction(gps), Some(tb))) => TableConjunction(List(List(gp) ++ gps ++ List(tb)))
-
-	    case (None                    ,  ~(x, None    )) => Some(x                                     )
-	    case (Some(TableConjunction(l)), ~(x, None    )) => Some(TableConjunction(l ++ List(    x    )))
-	    case (Some(gp                 ), ~(x, None    )) => Some(TableConjunction(     List(gp, x    )))
-	    case (None                     , ~(x, Some(tb))) => Some(TableConjunction(     List(    x, tb)))
-	    case (Some(TableConjunction(l)), ~(x, Some(tb))) => Some(TableConjunction(l ++ List(    x, tb)))
-	    case (Some(gp                 ), ~(x, Some(tb))) => Some(TableConjunction(     List(gp, x, tb)))
-
-	    case x => error("found " + x)
-	  }
-	}).get
-      }
-    }
-  )
-
-  def graphpatternnottriplesORfilter:Parser[GraphPattern] = (
-      "OPTIONAL"~groupgraphpattern ^^ { case "OPTIONAL"~ggp => OptionalGraphPattern(ggp) }
-    | "MINUS"~groupgraphpattern ^^ { case "MINUS"~ggp => MinusGraphPattern(ggp) }
-    | rep1sep(groupgraphpattern, "UNION") ^^ { x => if (x.size > 1) TableDisjunction(x) else x(0) }
-    | "GRAPH"~uri~groupgraphpattern ^^ { case "GRAPH"~u~ggp => GraphGraphPattern(ggp) }
-    | filter ^^ { x => TableFilter(null, x) }
-  )
-
-  def triplesblock:Parser[TriplesBlock] =
-    rep1sep(triplepattern, ".") ~ opt(".") ^^ { case pats~x => TriplesBlock(pats) }
-
-  def triplepattern:Parser[TriplePattern] =
-    subject ~ predicate ~ objectt ^^ { case s~p~o => TriplePattern(s, p, o) }
-
-  def subject:Parser[Term] = (
-      qnameORuri ^^ { case x => TermUri(x) }
-    | bnode ^^ { x => TermBNode(x) }
-    | varr ^^ { x => TermVar(x) }
-  )
-
-  def predicate:Parser[Term] = (
-      qnameORuri ^^ { x => TermUri(x) }
-    | "a" ^^ { x => TermUri(Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")) }
-    | varr ^^ { x => TermVar(x) }
-  )
-
-  def objectt:Parser[Term] = (
-      qnameORuri ^^ { case x => TermUri(x) }
-    | bnode ^^ { x => TermBNode(x) }
-    | varr ^^ { x => TermVar(x) }
-    | literal ^^ { x => TermLit(x) }
-  )
-
-  def qnameORuri:Parser[Uri] = (
-      "<"~uri~">" ^^ { case "<"~x~">" => Uri(x) }
-    | name~":"~name ^^ {
-      case prefix~":"~localName => try {
-	Uri(prefixes(prefix) + localName)
-      } catch {
-	case e:java.util.NoSuchElementException =>
-	  throw new Exception("unknown prefix " + prefix)
-      }
-    }
-  )
-
-  def bnode:Parser[BNode] =
-    "_:"~name ^^ { case "_:"~name => BNode(name) }
-
-  def literal:Parser[Literal] = (
-      stringLiteral~"^^"~qnameORuri ^^
-      {
-	case lit~"^^"~dt => Literal(RDFLiteral(lit.substring(1,lit.size - 1), dt.s match {
-	  case "http://www.w3.org/2001/XMLSchema#string" => RDFLiteral.StringDatatype
-	  case "http://www.w3.org/2001/XMLSchema#integer" => RDFLiteral.IntegerDatatype
-	  case "http://www.w3.org/2001/XMLSchema#date" => RDFLiteral.DateDatatype
-	  // case "http://www.w3.org/2001/XMLSchema#dateTime" => RDFLiteral.DateTimeDatatype
-	  case x => error("only programed to deal with string and integer, not " + x)
-	}))
-      }
-    | integer ^^ { l => Literal(RDFLiteral(l, RDFLiteral.IntegerDatatype)) }
-  )
-
-  def varr:Parser[Var] = "?"~ident ^^ { case "?"~x => Var(x) }
-
-}
-
-object Sparql {
-
-}
--- a/src/main/scala/SQL.scala	Fri Oct 15 16:42:41 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,577 +0,0 @@
-package w3c.sw.sql
-import  w3c.sw.util._
-
-import scala.util.parsing.combinator._
-
-import scala.collection.Set
-
-// Relational structure
-object RDB {
-
-  case class Database (m:Map[RelName, Relation]) {
-    def apply (rn:RelName) = m(rn)
-    def keySet () = m.keySet
-  }
-  object Database {
-    def apply (l:(Relation)*):Database =
-      Database(l.map{r => (r.name -> r)}.toMap)
-  }
-
-  case class Relation (name:RelName, header:Header, body:List[Tuple], candidates:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys)
-
-  case class Header (m:Map[AttrName, Datatype]) {
-    def apply (a:AttrName) = m(a)
-    def keySet () = m.keySet
-    def sqlDatatype (a:AttrName) : Datatype = m(a)
-    def contains (a:AttrName) : Boolean = m.contains(a)
-  }
-  object Header {
-    def apply (s:(String, Datatype)*):Header =
-      Header(s.map{p => (AttrName(p._1), p._2)}.toMap)
-  }
-  case class CandidateKey (attrs:List[AttrName])
-  object CandidateKey {
-    def apply (l:(String)*):CandidateKey =
-      CandidateKey(l.map{s => AttrName(s)}.toList)
-  }
-  implicit def cc2list (cc:CandidateKey) = cc.attrs
-
-  case class ForeignKeys (m:Map[List[AttrName], Target]) {
-    def apply (l:List[AttrName]) = m(l)
-    def keySet () = m.keySet
-    def contains (l:List[AttrName]) = m.contains(l)
-  }
-  object ForeignKeys {
-    def apply (s:(List[String], Target)*):ForeignKeys =
-      ForeignKeys(s.map{p => (p._1.map{s => AttrName(s)}, p._2)}.toMap)
-  }
-
-  case class Target (rel:RelName, key:CandidateKey)
-
-  case class Datatype(name:String) {
-    override def toString = "/* " + name + " */"
-  }
-  object Datatype {
-    val CHAR = Datatype("Char")
-    val VARCHAR = Datatype("Varchar")
-    val STRING = Datatype("String")
-    val INTEGER = Datatype("Int")
-    val FLOAT = Datatype("Float")
-    val DOUBLE = Datatype("Double")
-    val DATE = Datatype("Date")
-    val TIMESTAMP = Datatype("Timestamp")
-    val DATETIME = Datatype("Datetime")
-  }
-
-  case class Tuple (m:Map[AttrName, CellValue]) {
-    def apply (a:AttrName) = m(a)
-    def lexvalue (a:AttrName) : Option[LexicalValue] = 
-      m(a) match {
-	case ␀() => None
-	case v:LexicalValue => Some(v)
-      }
-    def lexvaluesNoNulls (as:List[AttrName]) = as.map(a => m(a).asInstanceOf[LexicalValue])
-    def nullAttributes (h:Header) : Set[(AttrName)] = {
-      h.keySet.flatMap(a =>
-	lexvalue(a) match {
-	  case None => Some(a)
-	  case _ => None
-	})
-    }
-  }
-  object Tuple {
-    def apply (s:(String, CellValue)*):Tuple =
-      Tuple(s.map{p => (AttrName(p._1), p._2)}.toMap)
-  }
-
-  abstract class CellValue
-  case class LexicalValue (s:String) extends CellValue
-  case class ␀ () extends CellValue
-
-  case class RelName(n:String) {
-    override def toString = n
-  }
-  case class AttrName(n:String) {
-    override def toString = n
-  }
-
-}
-
-object SQLParsers extends RegexParsers {
-
-  val int = """[0-9]+""".r
-  val chars = "\"([^\"\\\\\n\r]|\\\\[tbnrf\\\"'])*\"".r
-}
-
-import SQLParsers._
-
-import scala.util.parsing.combinator._
-import java.net.URI
-
-sealed abstract class RelationORSubselect
-case class Subselect(sel:SelectORUnion) extends RelationORSubselect {
-  override def toString = "(\n       " + sel.toString.replace("\n", "\n       ") + "\n                  )"
-}
-sealed abstract class SelectORUnion
-case class Select(distinct:Boolean, projection:Projection, tablelist:TableList, expression:Option[Expression], order:List[OrderElt], offset:Option[Int], limit:Option[Int]) extends SelectORUnion {
-  override def toString = 
-    "SELECT "+
-    { if (distinct) "DISTINCT " else "" }+
-    projection+"\n"+
-    tablelist+
-    { if (expression.isDefined) {"\b WHERE " + expression.get + " "} else "" }+
-    { if (order.size > 0) {order.map(o => o.toString).mkString("ORDER BY ", " ", " ") } else "" }+
-    { if (offset.isDefined) {"OFFSET " + offset + " "} else "" }+
-    { if (limit.isDefined) {"LIMIT " + limit + " "} else "" }
-}
-case class RelationResource(rn:RDB.RelName) extends RelationORSubselect {
-  override def toString = rn.toString
-}
-object foo { // doesn't work
-  implicit def relname2relationref (rn:RDB.RelName) = RelationResource(rn)
-}
-case class Union(disjoints:Set[Select]) extends SelectORUnion {
-  override def toString = "  " + (disjoints.toList.map(s => s.toString.replace("\n", "\n  ")).mkString("\nUNION\n  "))
-}
-case class Projection(attributes:Set[ProjectAttribute]) {
-  // foo, bar
-  override def toString = attributes.toList.sortWith((l, r) => l.attralias.toString < r.attralias.toString).mkString(", ")
-}
-case class ProjectAttribute(value:RelVarAttrORExpression, attralias:AttrAlias) {
-  override def toString = value + " AS " + attralias
-}
-//case class RelAttribute(relation:Relation, attribute:RDB.AttrName) c.f. ForeignKey999
-sealed abstract class RelVarAttrORExpression
-case class RelVarAttr(relvar:RelVar, attribute:RDB.AttrName) extends RelVarAttrORExpression {
-  override def toString = relvar + "." + attribute
-}
-
-case class AttrAlias(n:Name) {
-  override def toString = n.s /* "'" + n.s + "'" */
-}
-case class RelVar(n:Name) {
-  override def toString = n.s /* "'" + n.s + "'" */
-}
-case class TableList(joins:AddOrderedSet[Join]) {
-  override def toString = 
-    if (joins.size == 0) ""
-    else {
-      "  FROM " + joins.foldLeft(("", 0))(
-	(pair, entry) => (pair._1 + {
-	  if (pair._2 == 0) entry.toString.substring(19) // !!! shameless!
-	  else entry
-	}, pair._2+1))._1
-    }
-}
-
-sealed abstract class Join(res:AliasedResource)
-case class InnerJoin(res:AliasedResource, optOn:Option[Expression]) extends Join(res) {
-  override def toString = "\n       INNER JOIN " + res
-}
-case class LeftOuterJoin(res:AliasedResource, on:Expression) extends Join(res) {
-  override def toString = "\n       LEFT OUTER JOIN " + res + " ON " + on
-}
-
-case class AliasedResource(rel:RelationORSubselect, as:RelVar) {
-  override def toString = rel + " AS " + as
-}
-sealed abstract class Expression extends RelVarAttrORExpression
-case class ExprConjunction(exprs:Set[Expression]) extends Expression {
-  override def toString = "(" + (exprs.toList.sortWith((l, r) => l.toString < r.toString).mkString (")\n   AND (")) + ")"
-}
-case class ExprDisjunction(exprs:Set[Expression]) extends Expression {
-  override def toString = "(" + (exprs mkString (") OR (")) + ")"
-}
-sealed abstract class RelationalExpression extends Expression
-case class RelationalExpressionEq(l:Expression, r:Expression) extends RelationalExpression {
-  override def toString = l + "=" + r
-  /* safer operator== , but doesn't quite work yet. */
-  // override def hashCode = 41 * l.hashCode + r.hashCode
-  // override def equals(other: Any) = other match {
-  //   case that: RelationalExpressionEq =>
-  //     (that canEqual this) &&
-  //   ( ( (this.l == that.l) && (this.r == that.r) ||
-  //      (this.l == that.r) && (this.r == that.l) ) )
-  //   case _ =>
-  //     false
-  // }
-  // override def canEqual(other: Any) =
-  //   other.isInstanceOf[RelationalExpressionEq]
-
-  override def equals(that:Any) =
-    that match {
-      case RelationalExpressionEq(l1, r1) => (l == l1 && r == r1) || (r == l1 && l == r1)
-      case _ => false
-    }
-  override def hashCode =
-    if (r.hashCode < l.hashCode)
-      r.hashCode + l.hashCode
-    else
-      l.hashCode + r.hashCode
-}
-case class RelationalExpressionNe(l:Expression, r:Expression) extends RelationalExpression {
-  override def toString = l + "!=" + r
-}
-case class RelationalExpressionLt(l:Expression, r:Expression) extends RelationalExpression {
-  override def toString = l + "<" + r
-}
-case class RelationalExpressionGt(l:Expression, r:Expression) extends RelationalExpression {
-  override def toString = l + ">" + r
-}
-case class RelationalExpressionNull(l:Expression) extends RelationalExpression { // Expression?
-  override def toString = l + " IS NULL"
-}
-case class RelationalExpressionNotNull(l:Expression) extends RelationalExpression { // Expression?
-  override def toString = l + " IS NOT NULL"
-}
-sealed abstract class PrimaryExpression extends Expression
-case class PrimaryExpressionAttr(fqattribute:RelVarAttr) extends PrimaryExpression {
-  override def toString = "" + fqattribute
-}
-case class PrimaryExpressionTyped(datatype:RDB.Datatype, i:Name) extends PrimaryExpression {
-  override def toString = /* "'" + i.s + "'" */ /* + datatype */
-    datatype match {
-      case RDB.Datatype("Int") => i.s
-      case _ => "\"" + i.s + "\""
-    }
-}
-case class OrderElt(desc:Boolean, expr:Expression) {
-  override def toString = { if (desc) "DESC" else "ASC" } + "(" + expr.toString + ")"
-}
-case class ConstNULL() extends PrimaryExpression {
-  override def toString = "NULL"
-}
-case class Concat(args:List[Expression]) extends PrimaryExpression {
-  override def toString = args.mkString("CONCAT(", ", ", ")")
-}
-case class IfElse(cond:Expression, pass:Expression, fail:Expression) extends PrimaryExpression {
-  override def toString = "CONCAT(" + cond + ", " + pass +  ", " + fail + ")"
-}
-
-case class Name(s:String)
-
-object Name {
-  implicit def fromStringToName(s:String):Name = Name(s)
-}
-
-sealed abstract class FieldDescOrKeyDeclaration
-case class FieldDesc(attr:RDB.AttrName, datatype:RDB.Datatype, pkness:Boolean) extends FieldDescOrKeyDeclaration
-sealed abstract class KeyDeclaration extends FieldDescOrKeyDeclaration
-case class PrimaryKeyDeclaration(key:RDB.CandidateKey) extends KeyDeclaration
-case class ForeignKeyDeclaration(fk:List[RDB.AttrName], rel:RDB.RelName, pk:RDB.CandidateKey) extends KeyDeclaration
-case class View(rel:RDB.RelName, defn:SelectORUnion) { // sibling of RDB.Relation
-  override def toString = "CREATE VIEW " + rel + " AS\n" + defn
-}
-
-case class SqlParser() extends JavaTokenParsers {
-
-  def createview:Parser[View] = // @@@ could stick under ddl
-    "CREATE" ~ "VIEW" ~ relation ~ "AS" ~ selectORunion ^^
-  { case "CREATE"~"VIEW"~relation~"AS"~defn => View(relation, defn) }
-
-  def ddl:Parser[RDB.Database] =
-    rep1sep(createtable, ";") ~ opt(";") ^^
-  {
-    case l~x => RDB.Database(l.foldLeft(Map[RDB.RelName, RDB.Relation]())((m, p) => {
-      val (rel:RDB.RelName, desc:RDB.Relation) = p
-      m + (rel -> desc)
-    }))
-  }
-
-  def createtable:Parser[(RDB.RelName, RDB.Relation)] =
-    "CREATE" ~ "TABLE" ~ relation ~ "(" ~ rep1sep(fielddescorkeydef, ",") ~ ")" ^^
-  {
-    case "CREATE"~"TABLE"~relation~"("~reldesc~")" => {
-      val pk0:Option[RDB.CandidateKey] = None
-      val attrs0 = Map[RDB.AttrName, RDB.Datatype]()
-      val candidates0 = List[RDB.CandidateKey]()
-      val fks0 = Map[List[RDB.AttrName], RDB.Target]()
-      /* <pk>: (most recently parsed) PRIMARY KEY
-       * <attrs>: map of attribute to type (e.g. INTEGER)
-       * <fks>: map holding FOREIGN KEY relation REFERENCES attr
-       */
-      val (pk, attrs, candidates, fks) =
-	reldesc.foldLeft((pk0, attrs0, candidates0, fks0))((p, rd) => {
-	  val (pkopt, attrs, candidates, fks) = p
-	  rd match {
-	    case FieldDesc(attr, value, pkness) => {
-	      val (pkNew, candNew) =
-		if (pkness) (Some(RDB.CandidateKey(List(attr))), candidates ++ List(RDB.CandidateKey(attr.n)))
-		else (pkopt, candidates)
-	      (pkNew, attrs + (attr -> value), candNew, fks)
-	    }
-	    case PrimaryKeyDeclaration(key) =>
-	      // @@ why doesn't [[ candidates + RDB.CandidateKey(attr.n) ]] work?
-	      (Some(key), attrs, candidates ++ List(RDB.CandidateKey(key map {attr => RDB.AttrName(attr.n)})), fks)
-	    case ForeignKeyDeclaration(fk, rel, pk) =>
-	      (pkopt, attrs, candidates, fks + (fk -> RDB.Target(rel, pk)))
-	  }
-	})
-      val rd = RDB.Relation(relation, RDB.Header(attrs), List(), candidates, pk, RDB.ForeignKeys(fks))
-      (relation -> rd)
-    }
-  }
-
-  def fielddescorkeydef:Parser[FieldDescOrKeyDeclaration] = (
-      attribute ~ typpe ~ opt("PRIMARY" ~ "KEY") ^^
-      { case attribute~typpe~pkness => FieldDesc(attribute, typpe, pkness.isDefined) }
-    | "PRIMARY" ~ "KEY" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
-      { case "PRIMARY"~"KEY"~"("~attributes~")" => PrimaryKeyDeclaration(RDB.CandidateKey(attributes)) }
-    | "FOREIGN" ~ "KEY" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ~ "REFERENCES" ~ relation ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
-      { case "FOREIGN"~"KEY"~"("~fk~")"~"REFERENCES"~relation~"("~pk~")" => ForeignKeyDeclaration(fk, relation, RDB.CandidateKey(pk)) }
-  )
-
-  def typpe:Parser[RDB.Datatype] = (
-      "INT" ^^ { case _ => RDB.Datatype.INTEGER }
-    | "DOUBLE" ^^ { case _ => RDB.Datatype.DOUBLE }
-    | "STRING" ^^ { case _ => RDB.Datatype.STRING }
-    | "DATETIME" ^^ { case _ => RDB.Datatype.DATETIME }
-    | "DATE" ^^ { case _ => RDB.Datatype.DATE }
-  )
-
-  def selectORunion:Parser[SelectORUnion] =
-    rep1sep(select, "UNION") ^^ { l => if (l.size == 1) l(0) else Union(l.toSet) }
-
-  def select:Parser[Select] =
-    "SELECT" ~ opt("DISTINCT") ~ projection ~ opt(tablelist) ~ opt(where) ~ opt(order) ~ opt(offset) ~ opt(limit) ^^
-    {
-      case "SELECT" ~ distinct ~ attributes ~ tablesANDons ~ whereexpr ~ order ~ offset ~ limit => {
-	val (tables, onExpressions) =
-	  tablesANDons.getOrElse((TableList(AddOrderedSet[Join]()), Set[Expression]()))
-	val t:Set[Expression] = onExpressions
-	val onConjoints:Set[Expression] =
-	  onExpressions.foldLeft(Set[Expression]())((s, ent) =>
-	  s ++ {ent match {
-	    case ExprConjunction(l) => l
-	    case _ => Set(ent)
-	  }})
-	val conjoints = whereexpr match {
-	  case Some(ExprConjunction(l)) => onConjoints ++ l
-	  case Some(x) => onConjoints + x
-	  case _ => onConjoints
-	}
-	val expr:Option[Expression] = conjoints.size match {
-	  case 0 => None
-	  case 1 => Some(conjoints.toList(0))
-	  case _ => Some(ExprConjunction(conjoints))
-	}
-	Select(distinct.isDefined, attributes, tables, expr, order.getOrElse(List[OrderElt]()), offset, limit)
-      }
-    }
-
-  def order:Parser[List[OrderElt]] = 
-    "ORDER" ~ "BY" ~ rep(orderelt) ^^ { case o~b~elts => elts }
-
-  def orderelt:Parser[OrderElt] = (
-      "ASC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(false, expr) }
-    | "DESC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(true, expr) }
-    | fqattribute ^^ { case v => OrderElt(false, PrimaryExpressionAttr(v)) }
-  )
-    
-  def offset:Parser[Int] =
-    "OFFSET" ~ int ^^ { case o~i => i.toInt }
-
-  def limit:Parser[Int] =
-    "LIMIT" ~ int ^^ { case o~i => i.toInt }
-
-  def where:Parser[Expression] =
-    "WHERE" ~ expression ^^ { case "WHERE" ~ expression => expression }
-
-  def projection:Parser[Projection] =
-    repsep(namedattribute, ",") ^^ { l => Projection(l.toSet) }
-
-  def namedattribute:Parser[ProjectAttribute] =
-    fqattributeORprimaryexpression ~ "AS" ~ attralias ^^
-    { case fqattributeORprimaryexpression ~ "AS" ~ attralias =>
-      ProjectAttribute(fqattributeORprimaryexpression, attralias) }
-
-  def fqattributeORprimaryexpression:Parser[RelVarAttrORExpression] = (
-      fqattribute ^^ { case fqattribute => fqattribute }
-    | primaryexpression ^^ { case const => const }
-  )
-
-  def fqattribute:Parser[RelVarAttr] =
-    relvar ~ "." ~ attribute ^^
-    { case relvar ~ "." ~ attribute => RelVarAttr(relvar, attribute) }
-
-  def attribute:Parser[RDB.AttrName] =
-    """[a-zA-Z_]\w*""".r ^^ { x => RDB.AttrName(x) }
-
-  def attralias:Parser[AttrAlias] =
-    """[a-zA-Z_]\w*""".r ^^ { x => AttrAlias(Name(x)) }
-
-  def relationORsubselect:Parser[RelationORSubselect] = (
-      relation ^^ { x => RelationResource(x) }
-    | "(" ~ selectORunion ~ ")" ^^ { case "("~s~")" => Subselect(s) }
-  )
-
-  def relation:Parser[RDB.RelName] =
-    """[a-zA-Z_]\w*""".r ^^ { x => RDB.RelName(x) }
-
-  def relvar:Parser[RelVar] =
-    """[a-zA-Z_]\w*""".r ^^ { x => RelVar(Name(x)) }
-
-  def tablelist:Parser[(TableList, Set[Expression])] =
-    "FROM" ~ aliasedjoin ~ rep(innerORouter) ^^
-    { case "FROM"~aj~l => (TableList(AddOrderedSet(InnerJoin(aj, None) :: l.map((one) => one._1))), 
-			   l.foldLeft(Set[Expression]())((all, one) => all ++ one._2)) }
-
-  def innerORouter:Parser[(Join, Set[Expression])] = (
-      "INNER" ~ "JOIN" ~ aliasedjoin ~ opt("ON" ~ expression) ^^
-      { case "INNER"~"JOIN"~a~o => (InnerJoin(a, None), { if (o.isDefined) Set(o.get._2) else Set[Expression]() } ) }
-    | "LEFT" ~ "OUTER" ~ "JOIN" ~ aliasedjoin ~ "ON" ~ expression ^^
-      { case l~o~j~alijoin~on~expr => (LeftOuterJoin(alijoin, expr), Set[Expression]()) }
-  )
-
-  def aliasedjoin:Parser[AliasedResource] =
-    relationORsubselect ~ "AS" ~ relvar ^^
-    { case rel1 ~ "AS" ~ rel2 => AliasedResource(rel1, rel2) }
-
-  def expression:Parser[Expression] =
-    ORexpression ^^ { x => x }
-
-  def ORexpression:Parser[Expression] =
-    rep1sep (ANDexpression, "OR") ^^ 
-    { xs => if (xs.size > 1) ExprDisjunction(xs.toSet) else xs(0) }
-
-  def ANDexpression:Parser[Expression] =
-    rep1sep (relationalexpression, "AND") ^^ 
-    { xs => if (xs.size > 1) ExprConjunction(xs.toSet) else xs(0) }
-
-  def relationalexpression:Parser[Expression] = (
-      primaryexpression ~ "=" ~ primaryexpression ^^
-      { case primaryexpression ~ "=" ~ rvalue => RelationalExpressionEq(primaryexpression, rvalue) }
-    | primaryexpression ~ "!=" ~ primaryexpression ^^
-      { case primaryexpression ~ "!=" ~ rvalue => RelationalExpressionNe(primaryexpression, rvalue) }
-    | primaryexpression ~ "<" ~ primaryexpression ^^
-      { case primaryexpression ~ "<" ~ rvalue => RelationalExpressionLt(primaryexpression, rvalue) }
-    | primaryexpression ~ ">" ~ primaryexpression ^^
-      { case primaryexpression ~ ">" ~ rvalue => RelationalExpressionGt(primaryexpression, rvalue) }
-    | primaryexpression ~ "IS" ~ "NULL" ^^
-      { case primaryexpression ~ "IS" ~ "NULL" => RelationalExpressionNull(primaryexpression) }
-    | primaryexpression ~ "IS" ~ "NOT" ~ "NULL" ^^
-      { case primaryexpression ~ "IS" ~ "NOT" ~ "NULL" => RelationalExpressionNotNull(primaryexpression) }
-    | primaryexpression ^^
-      { case primaryexpression => primaryexpression }
-  )
-
-  def primaryexpression:Parser[Expression] = (
-      fqattribute ^^ { PrimaryExpressionAttr(_) }
-    | int ^^ { i => PrimaryExpressionTyped(RDB.Datatype.INTEGER, Name(i)) }
-    | chars  ^^ { x => PrimaryExpressionTyped(RDB.Datatype.STRING, Name(x.substring(1, x.size - 1))) }
-    | "NULL" ^^ { case "NULL" => ConstNULL() }
-    | "CONCAT" ~ "(" ~ rep1sep(expression, ",") ~ ")" ^^ { case "CONCAT"~"("~expressions~")" => Concat(expressions) }
-    | "IF" ~ "(" ~ expression ~ "," ~ expression ~ "," ~ expression ~ ")" ^^ { case "IF"~"("~c~","~p~","~f~")" => IfElse(c, p, f) }
-    | "(" ~ expression ~ ")" ^^ { case "("~x~")" => x }
-  )
-
-}
-
-case class PrettySql(select:Select) {
-  def makePretty():Select = {
-    val Select(distinct, projection, tablelist, expression, order, offset, limit) = select
-    val nullStripped =
-      if (expression.isDefined) {
-	val nonNullAttrs = PrettySql.findNonNullRelVarAttrs(expression.get)
-	PrettySql.stripNotNulls(expression.get, nonNullAttrs)
-      }
-      else None
-    val XeqXStripped =
-      if (nullStripped.isDefined) {
-	PrettySql.stripXeqX(nullStripped.get)
-      }
-      else None
-    val strippedTables = tablelist.joins.foldLeft(AddOrderedSet[Join]())((set, join) => set + {
-      join match {
-	case InnerJoin(AliasedResource(rel, as), optOn) => InnerJoin(AliasedResource({ rel match {
-	  case Subselect(s:Select) => Subselect(PrettySql(s).makePretty())
-	  case Subselect(Union(disjoints)) => Subselect(Union(disjoints.map(s => PrettySql(s).makePretty())))
-	  case r:RelationResource => r
-	}}, as), None)
-	case LeftOuterJoin(AliasedResource(rel, as), on:Expression) => LeftOuterJoin(AliasedResource({ rel match {
-	  case Subselect(s:Select) => Subselect(PrettySql(s).makePretty())
-	  case Subselect(Union(disjoints)) => Subselect(Union(disjoints.map(s => PrettySql(s).makePretty())))
-	  case r:RelationResource => r
-	}}, as), on)
-      }})
-    Select(distinct, projection, TableList(strippedTables), XeqXStripped, order, offset, limit)
-  }
-}
-
-object PrettySql {
-  def findNonNullRelVarAttrs(expr:Expression):Set[RelVarAttr] = {
-    expr match {
-      case ExprConjunction(s) => s.foldLeft(Set[RelVarAttr]())((s, e) => s ++ findNonNullRelVarAttrs(e))
-      case ExprDisjunction(s) => {
-	val l = s.toList
-	l.slice(1, l.size).foldLeft(findNonNullRelVarAttrs(l(0)))((s, e) => s & findNonNullRelVarAttrs(e))
-      }
-      case RelationalExpressionEq(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
-      case RelationalExpressionNe(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
-      case RelationalExpressionLt(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
-      case RelationalExpressionGt(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
-      case e:PrimaryExpressionTyped => Set()
-      case PrimaryExpressionAttr(a) => Set(a)
-      case e:ConstNULL => Set()
-      case e:Concat => Set()
-      case RelationalExpressionNull(a) => findNonNullRelVarAttrs(a)
-      case RelationalExpressionNotNull(a) => Set()
-      case IfElse(eef, den, els) => Set()
-    }
-  }
-  def stripNotNulls(expr:Expression, stripMe:Set[RelVarAttr]):Option[Expression] = {
-    expr match {
-      case ExprConjunction(l) => Some(ExprConjunction({l.foldLeft(Set[Expression]())((s, e) => {
-	val e2 = stripNotNulls(e,stripMe)
-	if (e2.isDefined) s + e2.get
-	else s})}))
-      case ExprDisjunction(l) => Some(ExprDisjunction({l.foldLeft(Set[Expression]())((s, e) => {
-	val e2 = stripNotNulls(e,stripMe)
-	if (e2.isDefined) s + e2.get
-	else s})}))
-      case e:RelationalExpressionEq => Some(e)
-      case e:RelationalExpressionNe => Some(e)
-      case e:RelationalExpressionLt => Some(e)
-      case e:RelationalExpressionGt => Some(e)
-      case e:PrimaryExpressionTyped => Some(e)
-      case e:PrimaryExpressionAttr => Some(e)
-      case e:ConstNULL => Some(e)
-      case e:Concat => Some(e)
-      case e:RelationalExpressionNull => Some(e)
-      case RelationalExpressionNotNull(PrimaryExpressionAttr(a)) =>
-	if (stripMe.contains(a)) None
-	else Some(RelationalExpressionNotNull(PrimaryExpressionAttr(a)))
-      case e:RelationalExpressionNotNull => Some(e)
-      case e:IfElse => Some(e)
-    }
-  }
-  def stripXeqX(expr:Expression):Option[Expression] = {
-    expr match {
-      case ExprConjunction(l) => Some(ExprConjunction({l.foldLeft(Set[Expression]())((s, e) => {
-	val e2 = stripXeqX(e)
-	if (e2.isDefined) s + e2.get
-	else s})}))
-      case ExprDisjunction(l) => Some(ExprDisjunction({l.foldLeft(Set[Expression]())((s, e) => {
-	val e2 = stripXeqX(e)
-	if (e2.isDefined) s + e2.get
-	else s})}))
-      case e:RelationalExpressionEq => {
-	val RelationalExpressionEq(l, r) = e
-	if (l == r) None
-	else Some(e)
-      }
-      case e:RelationalExpressionNe => Some(e)
-      case e:RelationalExpressionLt => Some(e)
-      case e:RelationalExpressionGt => Some(e)
-      case e:PrimaryExpressionTyped => Some(e)
-      case e:PrimaryExpressionAttr => Some(e)
-      case e:ConstNULL => Some(e)
-      case e:Concat => Some(e)
-      case e:RelationalExpressionNull => Some(e)
-      case e:RelationalExpressionNotNull => Some(e)
-      case e:IfElse => Some(e)
-    }
-  }
-  implicit def toPrettySql(select:Select) = PrettySql(select)
-}
-
--- a/src/main/scala/Servlet.scala	Fri Oct 15 16:42:41 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-package org.w3.sparql2sql.servlet
-
-import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse} 
-import scala.xml.XML
-
-import java.sql.{DriverManager, Connection, Statement, ResultSet, ResultSetMetaData}
-
-import java.sql.{Types => T}
-
-import java.net.URI
-import w3c.sw.sql.RDB.{RelName,AttrName}
-import w3c.sw.sql.SqlParser
-import w3c.sw.sparql
-import w3c.sw.sparql.Sparql
-import w3c.sw.sql
-import w3c.sw.sparql2sql.{SparqlToSql,StemURI,SqlToXMLRes}
-
-object Control {
-
-  private def using[Closeable <: {def close(): Unit}, B](closeable: Closeable)(getB: Closeable => B): B =
-    try {
-      getB(closeable)
-    } finally {
-      closeable.close()
-    }
-
-  private def bmap[T](test: => Boolean)(block: => T): List[T] = {
-    val ret = new scala.collection.mutable.ListBuffer[T]
-    while(test) ret += block
-    ret.toList
-  }
-
-  /** Executes the SQL and processes the result set using the specified function. */
-  private def query[B](connection: Connection, sql: String)(process: ResultSet => B): B =
-    using (connection) { connection =>
-      using (connection.createStatement) { statement =>
-        using (statement.executeQuery(sql)) { results =>
-          process(results)
-        }
-      }
-    }
-
-  /** Executes the SQL and uses the process function to convert each row into a T. */
-  def queryEach[T](connection: Connection, sql: String)(process: ResultSet => T): List[T] =
-    query(connection, sql) { results =>
-      bmap(results.next) {
-        process(results)
-      }
-    }
-
-  def process(connection: Connection, sql: String,
-              head: List[String] => String,
-              startres: String,
-          binding: (String, String /*, Map[sparql.Assignable, SparqlToSql.SQL2RDFValueMapper], StemURI*/) => String,
-          endres: String, foot: String): String = {
-
-    query(connection, sql) { results =>
-
-      val metadata = results.getMetaData
-
-      val vars:List[String] =
-        (1 to metadata.getColumnCount) map { column => metadata.getColumnLabel(column) } toList
-
-      def processCell(rs:ResultSet, column:Int):Option[String] =
-	try {
-          val name:String = metadata.getColumnLabel(column)
-          val value:String =
-	    metadata.getColumnType(column) match {
-              case T.VARCHAR => rs.getString(column)
-              case T.INTEGER => rs.getInt(column).toString
-              case T.DATE    => rs.getDate(column).toString
-              case _         => throw new java.lang.Exception("you have to map this type!!!")
-            }
-          Some(binding(name, value))
-	} catch {
-	  case _ => None
-	}
-
-      def processRow(rs:ResultSet):String =
-        (1 to metadata.getColumnCount) flatMap { column => processCell(rs, column) } mkString ""
-
-      val rows:List[String] = bmap(results.next) {
-        processRow(results)
-      }
-
-      val body = rows map { startres + _ + endres } mkString ""
-
-      head(vars) + body + foot
-
-    }
-
-  }
-
-}
-
-
-class SparqlEndpoint extends HttpServlet {
-
-  val encoding = "utf-8"
-
-  override def doGet(request:HttpServletRequest, response:HttpServletResponse) {
-
-    request.getParameter("query") match {
-      case null | "" => processIndex(request, response)
-      case query     => processSparql(request, response, query)
-    }
-
-  }
-
-  def processSparql(request:HttpServletRequest, response:HttpServletResponse, query:String) {
-
-    val stemURI:StemURI = StemURI(Some(request.getParameter("stemuri")) getOrElse Config.defaultStemURI)
-
-    val sparqlParser = Sparql()
-
-    val sparqlSelect = sparqlParser.parseAll(sparqlParser.select, query).get
-
-    val (generated, rdfmap) = SparqlToSql(Config.db, sparqlSelect, stemURI, true, false)
-
-    Class.forName("com.mysql.jdbc.Driver").newInstance
-    val connection:Connection = DriverManager.getConnection("jdbc:mysql://localhost/rdb2rdf", "root", "")
-
-//    if (! connection.isClosed) println("Successfully connected")
-
-    val res = Control.process(connection=connection,
-			      sql=generated.toString,
-			      head=SqlToXMLRes.head(_),
-			      startres=SqlToXMLRes.startresult,
-			      binding=SqlToXMLRes.binding(_, _, rdfmap, stemURI),
-			      endres=SqlToXMLRes.endresult,
-			      foot=SqlToXMLRes.foot)
-
-    response.setContentType("text/plain; charset='" + encoding + "'")
-
-    response.getWriter.write(res)
-
-  }
-
-  def processIndex(request:HttpServletRequest, response:HttpServletResponse) {
-
-    val index =
-      <html xmlns="http://www.w3.org/1999/xhtml">
-        <head><title>RDB2RDF Sparql endpoint</title></head>
-        <body>
-          <h1>RDB2RDF Sparql endpoint</h1>
-          <form action="sparql">
-            <p>
-              StemURI: <input cols="80" name="stemuri" id="stemuri" value={ Config.defaultStemURI } /><br />
-              <textarea rows="10" cols="80" name="query" id="query">{ Config.defaultSparqlQuery }</textarea>
-              <input type="submit" />
-            </p>
-          </form>
-          <hr />
-          <address>
-            <a href="http://www.w3.org/People/Eric/">Eric Prud'hommeaux</a>, <a href="http://www.w3.org/People/Bertails/">Alexandre Bertails</a>, Jun 2010
-          </address>
-        </body>
-      </html>
-
-    response.setContentType("application/xml; charset='" + encoding + "'")
-
-    XML.write(response.getWriter, index, encoding, false, null) 
-
-  }
-
-}
--- a/src/main/scala/SparqlToSparql.scala	Fri Oct 15 16:42:41 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,386 +0,0 @@
-/* SparqlToSparql: convert SPARQL queries to sound SQL queries.
- *
-
- * 
- */
-
-package w3c.sw.sparql2sparql
-
-import scala.util.parsing.combinator._
-import w3c.sw.sparql
-
-case class MapTarget (term:sparql.Term, nm:Option[NodePattern])
-
-case class NodePatternMap (m:Map[sparql.Var, NodePattern]) {
-  def var2maptarget (t:sparql.Term) : MapTarget = {
-    t match {
-      case sparql.TermVar(v) => MapTarget(t, m.get(v))
-      case _ => MapTarget(t, None)
-    }
-  }
-}
-
-case class NodePattern (iface:String, direct:String)
-
-case class SparqlMap (construct:sparql.Construct, nodemap:NodePatternMap)
-
-object SparqlToSparql {
-
-  /**
-   * Some tools for making pretty output, e.g. shortening strings.
-   */
-  var RuleLabels = scala.collection.mutable.Map[String,String]()
-  var Abbreviations = scala.collection.mutable.Map[String,String]()
-  def _shorten (s:String) = {
-    val s2 = if (RuleLabels.contains(s)) RuleLabels(s)
-	     else s
-    val s3 = Abbreviations.foldLeft(s2)((s, ss) => s.replace(ss._1, ss._2))
-    s3
-  }
-
-
-  /**
-   * Substitute the terms in a triple pattern or a graph pattern with other terms.
-   */
-  def substituteTerm (changeMe:sparql.Term, from:sparql.Term, to:sparql.Term, nm:Option[NodePattern]):sparql.Term = {
-    if (changeMe == from) {
-      from match {
-	case sparql.TermVar(v) => {
-    	  if (nm.isDefined) {
-    	    val nodeMap = nm.get
-	    to match {
-    	    case sparql.TermVar(v2) => {
-    	      println("reverse map(" + v2 + ",\n            " + nodeMap.direct + ",\n            " + nodeMap.iface)
-	      to
-	    }
-    	    case sparql.TermBNode(b) => {
-    	      println("reverse map(" + b + ",\n            " + nodeMap.direct + ",\n            " + nodeMap.iface)
-	      to
-	    }
-    	    case sparql.TermUri(u) => {
-	      val s:String = u.s
-	      val r = u.s.replaceAll(nodeMap.iface, nodeMap.direct)
-	      //println("\"" + u.s + "\".replaceAll("+nodeMap.iface+", "+nodeMap.direct+") = \""+r+"\"")
-	      sparql.TermUri(sparql.Uri(u.s.replaceAll(nodeMap.iface, nodeMap.direct))) // !!! failure here should error()
-	    }
-    	    case sparql.TermLit(l) => 
-    	      error("variable " + v + " bound to literlal " + l + " but should be a node as indicated by " + nodeMap)
-	    }
-	  } else to
-	}
-	case _ => to
-      }
-    } else changeMe
-  }
-
-  def substitute (gp:sparql.GraphPattern, from:sparql.Term, target:MapTarget) = {
-    gp match {
-      case sparql.TriplesBlock(triplepatterns) => sparql.TriplesBlock(
-	triplepatterns.map((tp) => {
-	  // println("sub(" + tp.o + ", " + from + ", " + to + ") => ")
-	  // println(substituteTerm(toTerm(tp.o), tp.o, from, target.term))
-	  sparql.TriplePattern(substituteTerm(tp.s, from, target.term, target.nm),
-			       tp.p,
-			       substituteTerm(tp.o, from, target.term, target.nm))
-	}
-      ))
-      case _ => error("not implemented" + gp)
-    }
-  }
-
-  type VarMap = Map[sparql.Var, MapTarget]
-
-  def substituteGraphPattern (gp:sparql.GraphPattern, vartargetmap:VarMap, varPrefix:String):sparql.GraphPattern = {
-    /**
-     * Substitute gp (the rule body) with the variables and constants from the
-     * query which matched variables in the rule head.
-     */
-    val mapped = vartargetmap.foldLeft(gp)((incrementalGP, vartarget) => {
-      val (varr, target) = vartarget
-      val ret = substitute(incrementalGP, sparql.TermVar(varr), target)
-      //println("^^incrementalGP: " + incrementalGP + "\nvartarget: " + vartarget + "\nret: " + ret)
-      ret;
-    })
-
-    /**
-     * "Uniquely" prefix unmapped vars to void conflict with other rules.
-     */
-    // val bound = Set[sparql.Var](vartargetmap.map((vartarget) => vartarget._1))
-    val bound = vartargetmap.foldLeft(Set[sparql.Var]())((s, vartarget) => s + vartarget._1)
-    val mappedTo = vartargetmap.foldLeft(Set[sparql.Term]())((s, vartarget) => {
-      val MapTarget(term, optnp) = vartarget._2
-      (term, optnp) match {
-	case (sparql.TermUri(u), Some(np)) => {
-	  s + sparql.TermUri(sparql.Uri(u.s.replaceAll(np.iface, np.direct))) // !!! failure here should error()
-	}
-	case (_, _) => s + vartarget._2.term
-      }
-    })
-    val vars = gp.findVars
-    val diff = vars -- bound
-    diff.foldLeft(mapped)((incrementalGP, varr) => {
-      val full = substitute(incrementalGP, sparql.TermVar(varr), 
-		 MapTarget(sparql.TermVar(sparql.Var(varPrefix + varr.s)),
-			   None// !! vartargetmap(varr).nm
-			 ))
-      full.trim(mappedTo)
-    })
-  }
-  case class RuleIndex (trigger:sparql.TriplePattern, smap:SparqlMap) {
-    override def toString = "{ \"" + trigger + "\" } => {\"\n  " + _shorten(smap.construct.gp.toString).replace("\n", "\n  ") + "\n\"}"
-    def transform (tp:sparql.TriplePattern):sparql.GraphPattern = {
-      substitute(substitute(smap.construct.gp, trigger.s, smap.nodemap.var2maptarget(tp.s)),
-		 trigger.o, smap.nodemap.var2maptarget(tp.o))
-    }
-  }
-
-  /**
-   * Bindings keep track of all the ways that a particular rule has been invoked
-   * in order to cover a particular query pattern. It's a mapping from a rule to
-   * the list of "editions" (invocations) of that rule.
-   */
-  case class Bindings (b:Map[sparql.Construct, List[VarMap]]) {
-    def countEditions () = {
-      var count = 0
-      b.map((constructlist) =>
-	constructlist._2.map((_) =>
-	  count = count + 1))
-      count
-    }
-    def toGraphPattern (ident:String):sparql.GraphPattern = {
-      var conjNo = 0
-      val conjuncts = b.keySet.toList.flatMap(construct => {
-	val l = b(construct)
-	val patterns:List[sparql.GraphPattern] = l.map((vartermmap) => {
-	  val unique = ident + conjNo + "_"
-	  conjNo = conjNo + 1
-	  substituteGraphPattern(construct.gp, vartermmap, unique)
-	})
-	patterns
-      })
-
-      if (conjuncts.size == 0)
-	sparql.TriplesBlock(List[sparql.TriplePattern]())
-      else if (conjuncts.size > 1)
-	sparql.TableConjunction(conjuncts).simplify
-      else
-	conjuncts(0)
-    }
-    override def toString = "Bindings(Map(" + b.map((constructlist) => {
-      val (construct, l) = constructlist
-      "\"" + _shorten(construct.head.toString) + "\" -> List(" + l.map((vartermmap) => {
-	"Map(" + vartermmap.map((varterm) => {
-	  val (varr, term) = varterm
-	  varr.toString + ":" + term.toString
-	}) + ")"
-      }).mkString("\n    ", ",\n    ", "") + ")"
-    }).mkString("\n  ", ",\n  ", "") + "))"
-    /**
-     * Make sure a particular rule has an entry in the Bindings.
-     */
-    def ensureGraphPattern (construct:sparql.Construct) = {
-      if (b.contains(construct)) this
-      else Bindings(b + (construct -> List[VarMap]()))
-    }
-    // val varsS:Option[Bindings] = vars.maybeRebind(construct, v, tos)
-    // b:Map[sparql.Construct, List[VarMap]]
-    def mustBind (construct:sparql.Construct, nodemap:NodePatternMap, vs:sparql.Term, tos:sparql.Term, vo:sparql.Term, too:sparql.Term):Bindings = {
-      /* ridiculous traversal for the first viably matching rule edition. */
-      var matched = false
-      val existing:List[VarMap] = b(construct).map((map:VarMap) => {
-	def _matches (l:sparql.Term, r:sparql.Term):(Boolean, VarMap) = {
-	  val empty:VarMap = Map[sparql.Var, MapTarget]()
-	  (l, r) match {
-	    case (v:sparql.TermVar, x) =>
-	      // println("(v:sparql.TermVar, x)" + v.v + ":" + x)
-	      if (map.contains(v.v)) {
-		if (r == map(v.v).term) (true, empty)
-		else (false, empty)
-	      } else {
-		(true, Map[sparql.Var, MapTarget](v.v -> MapTarget(r, nodemap.m.get(v.v))))
-	      }
-	    case (x, v:sparql.TermVar) => {
-	      // println("query variable " + v + " known equal to " + x + " at compile time")
-	      (true, empty)
-	    }
-	    case (x, y) =>
-	      // println("(x, y)" + x + "?=" + y)
-	      if (x == y) (true, empty)
-	      else (false, empty)
-	  }
-	}
-	val (sMatches, sBindings) = _matches(vs, tos)
-	val (oMatches, oBindings) = _matches(vo, too)
-
-	if (sMatches & oMatches) {
-	  matched = true
-	  map ++ sBindings ++ oBindings
-	} else
-	  map
-      })
-      if (matched)
-	Bindings(b + (construct -> existing))
-      else {
-	Bindings(b.map((constructlist) => {
-	  val (oldConstr, l) = constructlist
-	  if (oldConstr == construct) {
-	    def _newBinding (l:sparql.Term, r:sparql.Term):VarMap = {
-	      val empty:VarMap = Map[sparql.Var, MapTarget]()
-	      (l, r) match {
-		case (v:sparql.TermVar, _) =>
-		  Map[sparql.Var, MapTarget](v.v -> MapTarget(r, nodemap.m.get(v.v)))
-		case (b:sparql.TermBNode, _) => {
-		  println(".. synthetic query variable " + b + "")
-		  Map[sparql.Var, MapTarget]()
-		  // println("@@ mustBind:_newBinding(BNode) + " + b)
-		  // Map(sparql.Var("bnode_" + b.b.s) -> r) // !!!
-		}
-		case (_, v:sparql.TermVar) => {
-		  println(".. query variable " + v + " known equal to " + l + " at compile time")
-		  Map[sparql.Var, MapTarget]()
-		}
-		case (_, _) => Map[sparql.Var, MapTarget]()
-	      }
-	    }
-	    val ent = _newBinding(vs, tos) ++ _newBinding(vo, too)
-	    val list = l ++ List(ent)
-	    (construct -> list)
-	  } else {
-	    (oldConstr -> l)
-	  }
-	}))
-      }
-    }
-  }
-  def createEmptyBindings () = Bindings(Map[sparql.Construct, List[VarMap]]())
-
-  case class RuleMap (rules:Map[sparql.Uri, List[RuleIndex]]) {
-    /**
-     * Recursively examine the first triple pattern in a graph pattern and add
-     * invocations to the bindings to produce that triple.
-     */
-    def transform (prove:List[sparql.TriplePattern], used:Set[sparql.TriplePattern], varsP:Bindings):Bindings = {
-      val _pad = used.foldLeft("")((s, x) => s + " ")
-      def _deepPrint (s:String):Unit = {
-	//print(used.size + ":" + _pad + s.replace("\n", "\n" + _pad) + "\n\n")
-      }
-      def _deepPrint1 (prefix:String, s:String):Unit = {
-	val p = used.size + ":" + prefix + _pad
-	//print(p + s.replace("\n", "\n" + p) + "\n\n")
-      }
-
-      val car = prove(0)
-      val cdr = prove.filterNot (_ == car)
-      _deepPrint("RuleMap.transform(" + _shorten(car.toString) + ", " + varsP.toString + ")")
-      val xform = car.p match {
-	case sparql.TermUri(u) =>
-	  // for each rule that supplies predicate u
-	  var _ruleNo = 0;
-	  rules(u).foldLeft(createEmptyBindings)((bindings, hornRule) => {
-	    val _prefix = "rule:" + _ruleNo
-	    _ruleNo = _ruleNo + 1
-	    _deepPrint1(_prefix, "trying " + _shorten(hornRule.trigger.toString))
-	    val vars = varsP.ensureGraphPattern(hornRule.smap.construct)
-	    // try matching the subject
-	    val varss:Bindings = vars.mustBind(hornRule.smap.construct, hornRule.smap.nodemap, hornRule.trigger.s, car.s, hornRule.trigger.o, car.o)
-	    val ret =
-	      if (cdr.size > 0) {
-		transform(cdr, used + car, varss)
-	      } else {
-		_deepPrint1("match!", _shorten(hornRule.trigger.toString) + "(" + _shorten(car.toString) + ") matches with " + _shorten(varss.toString))
-		varss
-	      }
-	    _deepPrint1(_prefix, _shorten(hornRule.trigger.toString) + "(" + _shorten(car.toString) + ") matches ..." + bindings.toString + ret.toString)
-
-	    /* Magic Huristics */
-	    if (bindings.countEditions == 0) {
-	      //print("choose: bindings.countEditions == 0 => " + ret + "\n\n")
-	      ret
-	    } else if (ret.countEditions == 0) {
-	      //print("choose: ret.countEditions == 0 => " + bindings + "\n\n")
-	      bindings
-	    } else if (ret.countEditions < bindings.countEditions) {
-	      //print("choose: "+ret.countEditions+" < "+bindings.countEditions+" => " + ret + "\n\n")
-	      ret
-	    } else {
-	      //print("choose: "+ret.countEditions+" > "+bindings.countEditions+" => " + bindings + "\n\n")
-	      bindings
-	    }
-	  })
-	case _ => error("not implemented: " + car.p)
-      }
-      _deepPrint("RuleMap.transform(" + _shorten(car.toString) + ") => " + _shorten(xform.toString))
-      xform
-    }
-
-    override def toString = "RuleMap(Map(" + rules.map((ent) => {
-      val (u, l) = ent
-      "\"" + _shorten(u.toString) + "\" -> List(" + l.map((hr) => {
-	_shorten(hr.toString).replace("\n", "\n    ")
-      }).mkString("\n    ", ",\n    ", "") + ")"
-    }).mkString("\n  ", ",\n  ", "") + "))"
-
-  }
-
-  def mapGraphPattern (gp:sparql.GraphPattern, ruleMap:RuleMap, ident:String):sparql.GraphPattern = {
-    gp match {
-      case sparql.TriplesBlock(tps) => {
-	val emptyBindings = createEmptyBindings
-	val b:Bindings = ruleMap.transform(tps, Set[sparql.TriplePattern](), emptyBindings)
-	//print("mapGraphPattern: " + _shorten(gp.toString) + ") => " + _shorten(b.toString) +  "\n\n")
-	val g:sparql.GraphPattern = b.toGraphPattern(ident)
-	//print("mapGraphPattern: ... instantiated: " + _shorten(g.toString) +  "\n\n")
-	g
-      }
-      case sparql.TableFilter(gp2:sparql.GraphPattern, expr:sparql.Expression) =>
-	sparql.TableFilter(mapGraphPattern(gp2, ruleMap, ident), expr)
-      case sparql.MinusGraphPattern(gp2) =>
-	sparql.MinusGraphPattern(mapGraphPattern(gp2, ruleMap, ident))
-      case sparql.OptionalGraphPattern(gp2) =>
-        sparql.OptionalGraphPattern(mapGraphPattern(gp2, ruleMap, ident))
-      case sparql.GraphGraphPattern(gp2) =>
-	sparql.GraphGraphPattern(mapGraphPattern(gp2, ruleMap, ident))
-      case sparql.TableDisjunction(l) =>
-	sparql.TableDisjunction({l.foldLeft((List[sparql.GraphPattern](), 0))((p, gp2) => {
-	  val (l, disjNo) = p
-	  (l ++ List(mapGraphPattern(gp2, ruleMap, ident + disjNo + "_")), disjNo + 1)
-	})}._1)
-      case sparql.TableConjunction(l) =>
-	sparql.TableConjunction({l.foldLeft((List[sparql.GraphPattern](), 0))((p, gp2) => {
-	  val (l, conjNo) = p
-	  (l ++ List(mapGraphPattern(gp2, ruleMap, ident + conjNo + "_")), conjNo + 1)
-	})}._1)
-    }
-  }
-
-  def apply (query:sparql.Select, maps:List[SparqlMap]) : sparql.Select = {
-    var _ruleNo = 0
-    val ruleMap = RuleMap({
-      maps.foldLeft(Map[sparql.Uri, List[RuleIndex]]())((m, sm) => {
-	val SparqlMap(rule, nodemap) = sm
-	// Register abbreviations for debugging output.
-	RuleLabels.update(rule.head.toString, "head" + _ruleNo)
-	RuleLabels.update(rule.gp.toString, "body" + _ruleNo)
-
-	_ruleNo = _ruleNo + 1
-	rule.head.triplepatterns.foldLeft(m)((m, tp) => m + ({
-	  tp.p match {
-	    case sparql.TermUri(u) => u -> {
-	      if (m.contains(u)) m(u) ++ List(RuleIndex(tp, sm))
-	      else List(RuleIndex(tp, sm))}
-	    case _ => error("not implemented: " + tp.p)
-	  }
-	}))
-      })
-    })
-    //println("ruleMap: " + ruleMap)
-    sparql.Select(
-      query.distinct,
-      query.attrs,
-      mapGraphPattern(query.gp, ruleMap, "_"),
-      query.order, query.offset, query.limit
-    )
-  }
-
-}
-
--- a/src/main/scala/SparqlToSql.scala	Fri Oct 15 16:42:41 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1211 +0,0 @@
-/** SparqlToSql: convert SPARQL queries to sound SQL queries.
- * <a href="http://www.w3.org/TR/rdf-sparql-query/#sparqlDefinition">SPARQL semantics</a> defines the evalutation of an abstract query on a dataset.
- * This object maps a SPARQL abstract query over a <a href="@@">direct graph</a> to an SQL abstract query over the constituant relations.
- * <p/>
- * 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
- *   <a href="http://www.w3.org/TR/rdf-sparql-query/#convertGraphPattern">SPARQL rules for converting graph patterns</a>
- * with the target semantics in SQL instead of SPARQL.
- */
-
-package w3c.sw.sparql2sql
-
-import scala.util.parsing.combinator._
-import java.net.URI
-import w3c.sw.sql
-import w3c.sw.sql.PrettySql.toPrettySql
-import w3c.sw.rdf
-import w3c.sw.sparql
-import w3c.sw.util
-
-case class StemURI(s:String)
-case class PrimaryKey(attr:sql.RDB.AttrName)
-
-sealed abstract class Binding
-case class RDFNode(relvarattr:sql.RelVarAttr) extends Binding
-case class Str(relvarattr:sql.RelVarAttr) extends Binding
-case class Int(relvarattr:sql.RelVarAttr) extends Binding
-case class Enum(relvarattr:sql.RelVarAttr) extends Binding
-
-/**
- * Converts a SPARQL object to an SQL object equivalent over the direct graph.
- *
- * @see {@link w3c.sw.sparql.Sparql Sparql}
- * @see {@link w3c.sw.sql.Sql#Select Sql}
- */
-object SparqlToSql {
-  /**
-   * Accumulated state for generating an Sql object.
-   *
-   * @param joins an AddOrderedSet of SQL joins
-   * @param varmap a map from Sparql.Assignable to SQL terms
-   * @param exprs a set of accumulated SQL expressions
-   */
-  case class R2RState(joins:util.AddOrderedSet[sql.Join], varmap:Map[sparql.Assignable, SQL2RDFValueMapper], exprs:Set[sql.Expression])
-
-  /**
-   * Binding for a sparql.Variable or BNode
-   */
-  sealed abstract class FullOrPartialBinding
-  case class FullBinding(relvarattr:sql.RelVarAttr) extends FullOrPartialBinding
-  case class BindingConstraint(expr:sql.RelationalExpression, relvarattr:sql.RelVarAttr)
-
-  /**
-   * Partial binding, a variable only (so far) found in OPTIONALs or assymetric
-   * UNIONs.
-   */
-  case class PartialBinding(binders:Set[BindingConstraint]) extends FullOrPartialBinding
-
-  /**
-   * Convert a binding to an SQL expression.
-   * <p/>
-   * example return:
-   *   <code>if (g_union1._DISJOINT_ != 0, g_union1.who, if (g_union2._DISJOINT_ != 3, g_union2.who, NULL))</code>
-   * @param against binding to be expressed
-   * @return SQL expression representing that binding
-   */
-  def toExpr(against:FullOrPartialBinding):sql.Expression = {
-    against match {
-      case FullBinding(relvarattr) =>
-	sql.PrimaryExpressionAttr(relvarattr)
-      case PartialBinding(binders) =>
-	binders.toList.reverse.foldLeft(sql.ConstNULL():sql.Expression)((exp, binding) => {
-	  val BindingConstraint(expr, relvarattr) = binding
-	  sql.IfElse(expr, sql.PrimaryExpressionAttr(relvarattr), exp)
-	})
-    }
-  }
-  /**
-   * Accumulate bindings on previously bound sparql variables.
-   * @param binding previous binding
-   * @param relVarAttr SQL relvar attribute to be bound, e.g. <code>G_union1.who</code>
-   * @param expr expr binding constraint, e.g. <code>G_opt6._DISJOINT_ IS NULL</code> or <code>G_union1._DISJOINT_!=0</code>
-   * @return PartialBinding on old constraints plus expr=relVarAttr
-   */
-  def addExpr(binding:FullOrPartialBinding, relVarAttr:sql.RelVarAttr, expr:sql.RelationalExpression):FullOrPartialBinding = {
-    binding match {
-      case FullBinding(relvarattr) =>
-	error("Unexpected FullBinding to " + relvarattr + "\n" + 
-	      "because subselectVars should only find a pre-existing PartialBindings.")
-        // return binding if this codepath is needed later.
-      case PartialBinding(binders) =>
-	/**
-	 * Add a new BindingConstraint to existing one.
-	 * e.g. existing constraint: G_union1._DISJOINT_!=0,G_union1.name
-	 * add for second side of union: G_union1._DISJOINT_!=1,G_union1.name
-	 */
-	PartialBinding(binders + BindingConstraint(expr, relVarAttr))
-    }
-  }
-
-  /**
-   * SQL terms representing SPARQL variables and bnodes.
-   */
-  sealed abstract class SQL2RDFValueMapper(binding:FullOrPartialBinding)
-  case class IntMapper(binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
-  case class StringMapper(binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
-  case class DateMapper(binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
-  /**
-   * map to a URL for a tuple in the database.
-   */
-  case class RDFNoder(relation:sql.RDB.RelName, binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
-  /**
-   * map to a blank node label for a tuple in the database.
-   */
-  case class RDFBNoder(relation:sql.RDB.RelName, binding:FullOrPartialBinding) extends SQL2RDFValueMapper(binding)
-
-  /**
-   * a URL representing a tuple in a database.
-   */
-  case class NodeUri(stem:Stem, rel:Rel, attr:Attr, v:CellValue)
-
-  /**
-   * url stem to base the direct graph.
-   * <p/>
-   * e.g. http://mydb.example/theDatabase
-   */
-  case class Stem(s:String) {
-    override def toString = "" + s
-  }
-
-  /**
-   * SQL relation (table) name
-   */
-  case class Rel(s:String) {
-    override def toString = "" + s
-  }
-  /**
-   * SQL attribute (column) name
-   */
-  case class Attr(s:String) {
-    override def toString = "" + s
-  }
-  /**
-   * value in a database
-   */
-  case class CellValue(s:String)
-  /**
-   * a URL representing a predicate in a database.
-   */
-  case class PUri(stem:Stem, rel:Rel, attr:Attr) {
-    override def toString = "<" + stem + "/" + rel + "#" + attr + ">"
-  }
-  /**
-   * parse predicate URL in direct graph into stem, relation and attribute
-   * <pre>stemURI + '/' + (\w+) + '#' (\w+)</pre>
-   */
-  def parsePredicateURI(u:sparql.Uri):PUri = {
-    val x:String = u.s
-    val uri = new URI(x)
-    val path = uri.getPath().split("/").toList.filterNot(_ == "")
-    val subPath = path.slice(0, path.size - 1).mkString("/")
-    val stem = uri.getScheme() + "://" + uri.getAuthority + "/" + subPath
-    PUri(Stem(stem), Rel(path.last), Attr(uri.getFragment))
-  }
-
-  /**
-   * parse node URL in direct graph into stem, relation, attribute and value
-   * <pre>stemURI + '/' (\w+) '/' (\w+) '.' (\w+) '#record'</pre>
-   */
-  def parseObjectURI(u:sparql.Uri):NodeUri = {
-    try {
-      val x:String = u.s
-      val uri = new URI(x)
-      val path = uri.getPath().split("/").toList.filterNot(_ == "")
-      val subPath = path.slice(0, path.size - 2).mkString("/")
-      val rel = path(path.size - 2)
-      val attrPair = path(path.size-1).split("\\.")
-      val stem = uri.getScheme() + "://" + uri.getAuthority + "/" + subPath
-      assert("record" == uri.getFragment)
-      NodeUri(Stem(stem), Rel(rel), Attr(attrPair(0)), CellValue(attrPair(1)))
-    } catch {
-      case e:java.lang.IndexOutOfBoundsException =>
-	throw new Exception("unable to parse " + u + " as an object")
-    }
-  }
-  /**
-   * synthesize a relvar name from a SPARQL term.
-   * <p/>
-   * e.g. <code>?emp</code> =&gt;<code>R_emp</code>
-   * e.g. <code>&lt;http://hr.example/DB/Employee/empid.253#record&gt;</code> =&gt;<code>R_empid253</code>
-   * e.g. <code>18</code> =&gt;<code>R_18</code>
-   */
-  def relVarFromTerm(s:sparql.Term):sql.RelVar = {
-    s match {
-      case sparql.TermUri(ob) => relVarFromNode(ob)
-      case sparql.TermVar(v)  => relVarFromVar(v)
-      case sparql.TermBNode(v)  => relVarFromBNode(v)
-      case sparql.TermLit(l)  => relVarFromLiteral(l)
-    }
-  }
-
-  def relVarFromNode(u:sparql.Uri):sql.RelVar = {
-    val NodeUri(stem, rel, Attr(a), CellValue(v)) = parseObjectURI(u)
-    sql.RelVar(sql.Name("R_" + a + v))
-  }
-
-  def relVarFromLiteral(l:sparql.Literal):sql.RelVar = {
-    sql.RelVar(sql.Name("R_" + l.lit.lexicalForm))
-  }
-
-  def relVarFromVar(vr:sparql.Var):sql.RelVar = {
-    val sparql.Var(v) = vr
-    sql.RelVar(sql.Name("R_" + v))
-  }
-
-  def relVarFromBNode(vr:sparql.BNode):sql.RelVar = {
-    val sparql.BNode(b) = vr
-    sql.RelVar(sql.Name("B_" + b))
-  }
-
-  /**
-   * synthesize a SQL name from a SPARQL variable or bnode.
-   * <p/>
-   * e.g. <code>?emp</code> =&gt;<code>emp</code>
-   */
-  def attrAliasNameFromVar(v:sparql.Assignable):String = "" + v.s
-
-  /**
-   * add constraints implied by a URI
-   * @param state state to be appended
-   * @param constrainMe relvar attribute to constrain, e.g. <code>R_empid18.empid</code>
-   * @param u SparqlToSql URL object, e.g. <code>NodeUri(http://hr.example/DB,Employee,empid,CellValue(18))</code>
-   * @return state + expression for the URI
-   * <p/>
-   * <code>http://hr.example/DB/Employee/empid=18, true</code> =&gt;<code>R_emp.manager=18</code>
-   * <code>http://hr.example/DB/Employee/empid=18, false</code> =&gt;<code>R_empid18.empid=18</code>
-   * (the latter produces another join on R_empid18 in order to enforce a foreign key.)
-   * http://hr.example/DB/Employee/empid=18 has already been parsed to produce a NodeUri:
-   *   NodeUri(http://hr.example/DB,Employee,empid,CellValue(18))
-   */
-  def uriConstraint(state:R2RState, constrainMe:sql.RelVarAttr, u:NodeUri):R2RState = {
-    R2RState(state.joins,
-	     state.varmap,
-	     state.exprs + sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(constrainMe),
-						      sql.PrimaryExpressionTyped(sql.RDB.Datatype.INTEGER,sql.Name(u.v.s))))
-  }
-
-  /**
-   * add constraints implied by a literal in a SPARQL triple pattern
-   * @param state state to be appended
-   * @param constrainMe relvar attribute to constrain, e.g. <code>R_18.empid</code>
-   * @param lit sparq.Literal, e.g. <code>18</code>
-   * @param dt sparq datatype, e.g. <code>xsd:integer</code>
-   * @return state + expression for the URI, e.g. <code>R_18.empid=18</code>
-   */
-  def literalConstraint(state:R2RState, constrainMe:sql.RelVarAttr, lit:sparql.Literal, dt:sql.RDB.Datatype):R2RState = {
-    R2RState(state.joins,
-	     state.varmap,
-	     state.exprs + sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(constrainMe),
-						      sql.PrimaryExpressionTyped(dt,sql.Name(lit.lit.lexicalForm))))    
-  }
-
-  /** varConstraint
-   * @param state  earlier R2RState
-   * @param alias  relvar to bind, e.g. Employees AS R_emp
-   * @param optAttr  SQL attribute to bind, e.g. Employees.lastName
-   * @param v  SPARQL variable or blank node to bind
-   * @param db  database description
-   * @param rel  SQL relation to bind, e.g. Employee
-   * @return a new R2RState incorporating the new binding
-   * For example, <code>SELECT ?emp WHERE { ?emp emp:lastName ?name }</code> will call varConstraint twice:
-   * 
-   *    given: alias:=R_emp, optAttr:=lastName, v:=?name, rel:=Employee -&gt;
-   *   return: (VarAssignable(?name),StringMapper(FullBinding(R_emp.lastName)))
-   *   which maps "Smith" to "Smith"^^xsd:string
-   * 
-   *    given: alias:=R_emp, optAttr:=empid, v:=?emp, rel:=Employee -&gt;
-   *   return: (VarAssignable(?emp),RDFNoder(Employee,FullBinding(R_emp.empid)))
-   *   which maps 4 to &lt;http://hr.example/our/favorite/DB/Employee/id.4#record&gt;
-   */
-  def varConstraint(state:R2RState, alias:sql.RelVar, optAttr:Option[sql.RDB.AttrName], v:sparql.Assignable, db:sql.RDB.Database, rel:sql.RDB.RelName):R2RState = {
-    val constrainMe = if (optAttr.isDefined) sql.RelVarAttr(alias, optAttr.get) else sql.RelVarAttr(alias, sql.RDB.AttrName("_no_such_attribute"))
-    val reldesc = db(rel)
-    val boundTo = FullBinding(constrainMe)
-
-    /**
-     * Bind optAttr to an SQL generator like RDFNoder(Employee,FullBinding(R_emp.empid))
-     */
-    val binding = reldesc.pk match {
-      /** <pre>varConstraint(R_emp, Some(empid), VarAssignable(?emp), Employee) -&gt; RDFNoder(Employee,FullBinding(R_emp.empid))</pre> */
-      case Some(sql.RDB.CandidateKey(List(sql.RDB.AttrName(constrainMe.attribute.n)))) => RDFNoder(rel, boundTo)
-      case _ => {
-	val asKey = sql.RDB.CandidateKey(List(constrainMe.attribute))
-	if (reldesc.fks.contains(asKey)) { // !! (0)
-	  /** varConstraint(R_patient, Some(SexDE), VarAssignable(?_0_sexEntry), Person) -&gt; RDFNoder(Person,FullBinding(R_patient.SexDE)) */
-	  val sql.RDB.Target(fkrel, fkattr) = reldesc.fks(asKey)
-	  RDFNoder(rel, boundTo)
-	} else if (reldesc.header.contains(constrainMe.attribute)) {
-	  reldesc.header(constrainMe.attribute) match {
-	    /** varConstraint(R__0_indicDE, Some(NDC), VarAssignable(?_0_indicNDC), Medication_DE) -&gt; IntMapper(FullBinding(R__0_indicDE.NDC)) */
-	    case sql.RDB.Datatype("Int") => IntMapper(boundTo)
-	    /** varConstraint(R_emp, Some(lastName), VarAssignable(?name), Employee) -&gt; StringMapper(FullBinding(R_emp.lastName)) */
-	    case sql.RDB.Datatype("String") => StringMapper(boundTo)
-	    /** varConstraint(R_patient, Some(DateOfBirth), VarAssignable(?dob), Person) -&gt; DateMapper(FullBinding(R_patient.DateOfBirth)) */
-	    case sql.RDB.Datatype("Date") => DateMapper(boundTo)
-	  }
-	} else {
-	  /** Default behavior for unknown attributes. */
-	  RDFBNoder(rel, boundTo) // @@ untested
-	} 
-      }
-    }
-
-    if (state.varmap.contains(v) && state.varmap(v) == constrainMe) {
-      /**
-       * No useful contributions for this variable.
-       * (We could re-add the binding; this case is just for clarity of behavior.)
-       */
-      state
-    } else if (state.varmap.contains(v)) {
-      /**
-       * The variable has already been bound to another attribute.
-       * Constraint against the initial binding for this variable.
-       * e.g. <code>R__0_0_indicCode.ID=R__0_0_indicCode.ID</code>
-       */
-      val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(constrainMe),
-						  sql.PrimaryExpressionAttr(varToAttribute(state.varmap, v)))
-      R2RState(state.joins, state.varmap, 
-	       if (varToAttributeDisjoints(state.varmap, v).size > 0)
-		 /**
-		  * Enumerate the set of constraints capturing all sides of a disjoint or option.
-		  * e.g. a UNION where two disjoints constrain R_who.empid=G_union0.who:
-		  * Set((G_union0._DISJOINT_!=0) OR (R_who.empid=G_union0.who),
-		  *     (G_union0._DISJOINT_!=1) OR (R_who.empid=G_union0.who))
-		  */
-		 state.exprs ++ {varToAttributeDisjoints(state.varmap, v) map ((d) => sql.ExprDisjunction(Set(d, constraint)))}
-	       else
-		 state.exprs + constraint
-	     )
-    } else {
-      /**
-       * Add binding for new variable.
-       */
-      R2RState(state.joins, state.varmap + (v -> binding), state.exprs)
-    }
-  }
-
-  def toString(relvarattr:sql.RelVarAttr) : String = {
-    relvarattr.relvar.n.s + "." + relvarattr.attribute.n
-  }
-  // def toString(mapper:SQL2RDFValueMapper) : String = {
-  //   mapper match {
-  //     case IntMapper(relvar, disjoints) => "INT: " + toString(relvar)
-  //     case StringMapper(relvar, disjoints) => "STRING: " + toString(relvar)
-  //     case DateMapper(relvar, disjoints) => "DATE: " + toString(relvar)
-  //     case RDFNoder(relation, relvar, disjoints) => "RDFNoder: " + relation.n.s + ", " + toString(relvar)
-  //     case RDFBNoder(relation, relvar, disjoints) => "RDFBNoder: " + relation.n.s + ", " + toString(relvar)
-  //   }
-  // }
-
-  def __optFirst (k:Option[sql.RDB.CandidateKey]):Option[sql.RDB.AttrName] =
-    k match {
-      case Some(ck) => Some(ck.attrs(0))
-      case _ => None
-    }
-
-  /**
-   * map a given triple to one or two joined tables, variable
-   * @param db  database description
-   * @param stateP  earlier R2RState
-   * @param triple  
-   * @param enforceForeignKeys  
-   * @return a new R2RState incorporating the new binding
-   * bindings to RelVarAttrs, and constraints if those variables were
-   * already bound. */
-  def bindOnPredicate(db:sql.RDB.Database, stateP:R2RState, triple:sparql.TriplePattern, enforceForeignKeys:Boolean):R2RState = {
-    val sparql.TriplePattern(s, p, o) = triple
-    p match {
-      /** Don't deal with ?s ?p ?o . We could deal with <s> ?p ?o , but haven't yet. */
-      case sparql.TermVar(v) => error("variable predicates require tedious enumeration; too tedious for me.")
-      case sparql.TermUri(uri) => {
-	val PUri(stem, spRel, spAttr) = parsePredicateURI(uri)
-	/** The relation and attribute come from the predicate, e.g. Employee.fname =&gt; Employee and fname. */
-	val rel = sql.RDB.RelName(spRel.s)
-	val attr = sql.RDB.AttrName(spAttr.s)
-
-	/**
-	 * The particular join for e.g. Employee is controled by the subject.
-	 * ?emp =&gt; Employee AS emp
-	 * <Employee:18> =&gt; Employee AS Employee_18 .
-         */
-	val relvar = relVarFromTerm(s)
-	/** Synthesize relvar attribute, e.g. emp.fname. */
-	val objattr = sql.RelVarAttr(relvar, attr)
-
-	/** Accumulate joins and constraints that come from the subject */
-	val state_postSubj = s match {
-	  case sparql.TermUri(u) =>
-	    /** additional constraint, e.g. R_empid18.empid=18. */
-	    uriConstraint(stateP, sql.RelVarAttr(relvar, db(rel).pk.get.attrs(0)), parseObjectURI(u)) // !! (0)
-	  case sparql.TermVar(v) =>
-	    /** assignable binding for novel vars, new constraint for previously bound vars. */
-	    try {
-	      varConstraint(stateP, relvar, __optFirst(db(rel).pk), sparql.VarAssignable(v), db, rel) // !! (0)
-	    } catch {
-	      case e:java.util.NoSuchElementException =>
-		/** 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(" + rel + ") not found in " + db)
-	    }
-	  case sparql.TermBNode(b) =>
-	    /** assignable binding for novel bnodes, new constraint for previously bound bnodes. */
-	    try {
-	      varConstraint(stateP, relvar, __optFirst(db(rel).pk), sparql.BNodeAssignable(b), db, rel) // !! (0)
-	    } catch {
-	      case e:java.util.NoSuchElementException =>
-		throw new Exception("error processing { " + s + " " + p + " " + o + " } :db(" + 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(rel).header(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(" + rel + ").header(" + attr + ") not found in " + db)
-	}
-
-	/**
-	 * fkrel.fkattr (e.g. Employee.manager) may be a foreign key.
-	 * Calculate final relvarattr and relation.
-	 */
-	val asKey = sql.RDB.CandidateKey(List(attr))
-	val (targetattr:sql.RelVarAttr, targetrel, dt, state_fkeys:R2RState) =
-	  if (db(rel).fks.contains(asKey)) { // !! (0)
-	    val sql.RDB.Target(fkrel, fkattr) = db(rel).fks(asKey)
-	    try { db(fkrel).header(fkattr.attrs(0)) } catch { // !! (0)
-	      /** Foreign key relation.attribute was not found in the database description. */
-	      case e:java.util.NoSuchElementException =>
-		throw new Exception("db(" + fkrel + ").header(" + fkattr + ") not found in " + db)
-	    }
-	    val fkdt =
-	      if (db(fkrel).fks.contains(fkattr)) {
-	      /** Foreign key to something which is a foreign key. May have use
-	       * cases, but signal error until we figure out that they are. */
-		val sql.RDB.Target(dfkrel, dfkattr) = db(fkrel).fks(fkattr)
-		error("foreign key " + rel.n + "." + attr.n + 
-		      "->" + fkrel.n + "." + fkattr.attrs(0).n +  // !! (0)
-		      "->" + dfkrel.n + "." + dfkattr.attrs(0).n) // !! (0)
-	      } else
-		db(fkrel).header(fkattr(0)) // !! (0)
-	    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.attrs(0)) // !! (0)
-	      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)
-	    }
-	  }
-	else
-	  /** not a foreign key, so use the relvarattr and relation calculated
-	   * from the predicate. */
-	  (objattr, rel, db(rel).header(attr), 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 _                  => error("illegal SPARQL predicate: " + p)
-    }
-  }
-
-  def bindingConstraintToAttribute(constraint:BindingConstraint):sql.RelVarAttr = {
-    val BindingConstraint(expr:sql.RelationalExpression, relvarattr:sql.RelVarAttr) = constraint;
-    relvarattr
-  }
-  def bindingToAttribute(binding:FullOrPartialBinding):sql.RelVarAttr = {
-    binding match {
-      case FullBinding(relvarattr:sql.RelVarAttr) => relvarattr
-      case PartialBinding(binders) => bindingConstraintToAttribute(binders.toList(0))
-    }
-  }
-  def varToAttribute(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], vvar:sparql.Assignable):sql.RelVarAttr = {
-    val mapper = try { varmap(vvar) } catch {
-      case e:java.util.NoSuchElementException =>
-	throw new Exception("mapper for variable " + vvar + " not found in " + varmap)
-    }
-    mapper match {
-      case IntMapper(binding) => bindingToAttribute(binding)
-      case StringMapper(binding) => bindingToAttribute(binding)
-      case DateMapper(binding) => bindingToAttribute(binding)
-      case RDFNoder(relation, binding) => bindingToAttribute(binding)
-      case RDFBNoder(relation, binding) =>  bindingToAttribute(binding) // error("BNode should not need relvar " + relvar)
-    }
-  }
-
-  def bindingConstraintToExpression(constraint:BindingConstraint):sql.RelationalExpression = {
-    val BindingConstraint(expr:sql.RelationalExpression, relvarattr:sql.RelVarAttr) = constraint;
-    expr
-  }
-  def bindingToDisjoints(binding:FullOrPartialBinding):Set[sql.RelationalExpression] = {
-    binding match {
-      case FullBinding(relvarattr:sql.RelVarAttr) => Set[sql.RelationalExpression]()
-      case PartialBinding(binders) => binders.map({b => bindingConstraintToExpression(b)})
-    }
-  }
-  def varToAttributeDisjoints(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], vvar:sparql.Assignable):Set[sql.RelationalExpression] = {
-    varmap(vvar) match {
-      case IntMapper(binding) => bindingToDisjoints(binding)
-      case StringMapper(binding) => bindingToDisjoints(binding)
-      case DateMapper(binding) => bindingToDisjoints(binding)
-      case RDFNoder(relation, binding) => bindingToDisjoints(binding)
-      case RDFBNoder(relation, binding) =>  bindingToDisjoints(binding) // error("BNode should not need relvar " + relvar)
-    }
-  }
-
-  /**
-   * Converts a variable bound to a URL to an SQL expression for that URL.
-   *
-   * @param  varmap  map from variable to SQL2RDFValueMapper
-   * @param  vvar    the variable to be represented
-   * @return         an SQL CONCAT expression
-   * @see            VarMap
-   */
-  def varToExpr(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], vvar:sparql.Assignable, stem:StemURI):sql.Expression = {
-    varmap(vvar) match {
-      case IntMapper(binding) => sql.PrimaryExpressionAttr(bindingToAttribute(binding))
-      case StringMapper(binding) => 
-	sql.Concat(List(sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),sql.Name("'")),
-		    sql.PrimaryExpressionAttr(bindingToAttribute(binding)),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),sql.Name("'^^<http://www.w3.org/2001/XMLSchema#string>"))))
-      case DateMapper(binding) => sql.PrimaryExpressionAttr(bindingToAttribute(binding))
-      case RDFNoder(relation, binding) => 
-	sql.Concat(List(sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),sql.Name(stem.s)),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),relation.n),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),sql.Name("/")),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),bindingToAttribute(binding).attribute.n),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),sql.Name(".")),
-		    sql.PrimaryExpressionAttr(bindingToAttribute(binding)),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),sql.Name("#record"))))
-      case RDFBNoder(relation, binding) => 
-	sql.Concat(List(sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),sql.Name("_:")),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),relation.n),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),sql.Name(".")),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),bindingToAttribute(binding).attribute.n),
-		    sql.PrimaryExpressionTyped(sql.RDB.Datatype("String"),sql.Name(".")),
-		    sql.PrimaryExpressionAttr(bindingToAttribute(binding))))
-    }
-    
-  }
-
-  /**
-   * return an SQL PrimaryExpression for rTerm.
-   *
-   * @param  varmap  map from variable to SQL2RDFValueMapper
-   * @param  l  an SQL relvarattr for a SPARQL Assignable (variable or bnode)
-   * @param  rTerm  SPARQL term to be converted to a PrimaryExpression
-   * @param  sqlexpr  an unbound SQL relational expression, e.g. sql.RelationalExpressionEq(_,_)
-   * @return   an SQL expression on the relvarattrs to which the variables in f are bound
-   */
-  def assignable2expr(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], l:sql.RelVarAttr, rTerm:sparql.Term, sqlexpr:(sql.PrimaryExpression, sql.PrimaryExpression) => sql.RelationalExpression):sql.RelationalExpression = { // :sparql.Var
-    val r:sql.PrimaryExpression = rTerm match {
-      case sparql.TermUri(u) => error("not implemented: translating RDF URI to SQL: " + u) // :sparql.Uri
-      case sparql.TermVar(v) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.VarAssignable(v)))
-      case sparql.TermBNode(b) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.BNodeAssignable(b)))
-      case sparql.TermLit(sparql.Literal(rdf.RDFLiteral(lit,rdf.Datatype(dt)))) =>
-	sql.PrimaryExpressionTyped({
-	  dt.toString match {
-	    case "http://www.w3.org/2001/XMLSchema#string" => sql.RDB.Datatype.STRING
-	    case "http://www.w3.org/2001/XMLSchema#integer" => sql.RDB.Datatype.INTEGER
-	    case "http://www.w3.org/2001/XMLSchema#date" => sql.RDB.Datatype.DATE
-	    case _ => error("unable to translate to RDF literal SQL: \"" + lit + "\"^^<" + dt + ">")
-	  }
-	}, lit)
-    }
-    sqlexpr(sql.PrimaryExpressionAttr(l), r)
-  }
-
-  /**
-   * create an SQL expression analogous to a SPARQL expression. The variables in
-   * f are expressed as the relvarattrs to which they are mapped. This function
-   * is only minimally implemented here.
-   *
-   * @param  varmap  map from variable to SQL2RDFValueMapper
-   * @param  f  SPARQL Expression
-   * @return   an SQL expression on the relvarattrs to which the variables in f are bound
-   */
-  def filter2expr(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], f:sparql.PrimaryExpression):sql.RelationalExpression = {
-
-    /** sqlexpr: an unbound RelationalExpression, i.e. a function which takes
-     * (sql.RelVarAttr, sql.PrimaryExpressionAttr) and returns an
-     * sql.RelationalExpression
-     */
-    val (lTerm:sparql.Term, rTerm:sparql.Term, sqlexpr) = f match {
-      case sparql.PrimaryExpressionEq(l, r) => (l.term, r.term, sql.RelationalExpressionEq(_,_))
-      case sparql.PrimaryExpressionLt(l, r) => (l.term, r.term, sql.RelationalExpressionLt(_,_))
-      case sparql.PrimaryExpressionGt(l, r) => (l.term, r.term, sql.RelationalExpressionGt(_,_))
-      case sparql.SparqlTermExpression(t) => error("not implemented") // (l.term, r.term, sql.PrimaryExpressionAttr(_,_))
-    }
-
-    lTerm match {
-      /** does not handle FILTER (<x> = ?v) */
-      case sparql.TermUri(obj) => error("only SPARQL PrimaryExpressions with a variable on the left have been implemented: punting on " + f)
-      /** FILTER (?v = <x> && ?v = ?x && ?v = 7) */
-      case sparql.TermVar(v) => assignable2expr(varmap, varToAttribute(varmap, sparql.VarAssignable(v)), rTerm, sqlexpr)
-      case sparql.TermBNode(b) => assignable2expr(varmap, varToAttribute(varmap, sparql.BNodeAssignable(b)), rTerm, sqlexpr)
-      /** does not handle FILTER (7 = ?v) */
-      case sparql.TermLit(lit) => error("only SPARQL PrimaryExpressions with a variable on the left have been implemented: punting on " + f)
-    }
-  }
-
-  /**
-   * Promote a variable in an OPTIONAL or UNION subselect to the outer
-   * varmap/expressions. 
-   */
-  def subselectVars(startState:R2RState, v:sparql.Assignable, optionalAlias:sql.RelVar,
-		    optionalCond:sql.RelationalExpression,
-		    outerVarmap:Map[sparql.Assignable, SQL2RDFValueMapper],
-		    nestedVarmap:Map[sparql.Assignable, SQL2RDFValueMapper],
-		    isOpt:Boolean):R2RState = {
-
-    val varAliasAttr = sql.RelVarAttr(optionalAlias, sql.RDB.AttrName(attrAliasNameFromVar(v)))
-    if (startState.varmap.contains(v)) {
-
-      /** The variable has already been bound. */
-      val newMap:Map[sparql.Assignable, SQL2RDFValueMapper] =
-	/** If var was already bound to the same relvarattr... */
-	if (varToAttribute(startState.varmap, v) == varAliasAttr) {
-	  /**
-	   * Add new partial constraint to old partial constraints to produce a new binding.
-	   * example:
-	   *   ?name -> StringMapper(PartialBinding(Set(BindingConstraint(G_union1._DISJOINT_!=0,G_union1.name),
-           *                                            BindingConstraint(G_union1._DISJOINT_!=1,G_union1.name))))
-	   */
-	  Map(v -> {
-	    startState.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 {
-	  /** Var was bound to a different relvarattr so handle as newConstraint below. */
-	  Map()
-	}
-
-      val newConstraints =
-	if (varToAttribute(outerVarmap, v) == varAliasAttr) { // also varToAttribute(startState.varmap, v) == varAliasAttr
-	  Set()
-	} else {
-	  /** Constraint against binding from earlier graph pattern.
-	   * e.g. G_union1.who=R_who.empid */
-	  val constraint = sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(varAliasAttr),
-						      sql.PrimaryExpressionAttr(varToAttribute(outerVarmap, v)))
-	  if (varToAttributeDisjoints(outerVarmap, v).size > 0) {
-	    /**
-	     * Construct a conjunction of disjunctions like:
-	     * (union0._DISJOINT_ != 0 OR union0.x=union1.x) AND (union1._DISJOINT_ != 2 OR union0.x=union1.x)
-	     */
-	    varToAttributeDisjoints(outerVarmap, v) map ((d) =>
-	      sql.ExprDisjunction({
-		if (isOpt) Set(d, constraint) // a disjunction like: G_opt1._DISJOINT_ IS NULL OR G_opt3.birthday=G_opt1.birthday
-		else Set(sql.ExprConjunction(Set(d, optionalCond)), constraint) // @@ untested code path
-	      }))
-	  } else {
-	    if (isOpt)
-	      /** just the constraint from above */
-	      Set(constraint)
-	    else
-	      /**
-	       * Above constraint applied only for this path:
-	       * for example: (G_union1._DISJOINT_!=0) OR (G_union1.who=R_who.empid)
-	       */
-	      Set(sql.ExprDisjunction(Set(optionalCond, constraint)))
-	  }
-	}
-
-      R2RState(startState.joins, startState.varmap ++ newMap, startState.exprs ++ newConstraints)
-    } else {
-      /**
-       * This variable is new to the outer context so synthesize a new partial
-       * binding à la:
-       *   ?name ->
-       *     StringMapper(PartialBinding((G_union1._DISJOINT_!=0,G_union1.name)))
-       */
-      val p = PartialBinding(Set(BindingConstraint(optionalCond, varAliasAttr)))
-      val mapper:SQL2RDFValueMapper = nestedVarmap(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(startState.joins, startState.varmap + (v -> mapper), startState.exprs)
-    }
-  }
-
-  /**
-   * Recursively add the joins, variable mappings and constraints for an SQL query implementing a graph pattern.
-   * @param db  database description.
-   * @return a new state including the subquery representing gp in a join.
-   * This is factored out of mapGraphPattern as it is used for MINUS and probably later for NOT EXISTS.
-   */
-  def synthesizeOuterJoin(initState:R2RState, gp:sparql.GraphPattern, negate:Boolean, db:sql.RDB.Database, enforceForeignKeys:Boolean):R2RState = {
-    /** SPARQL OPTIONALs and UNIONs are treated as SQL subselects.
-     * Set up initial state for this subselect.
-     */
-    val leftJoinAlias = sql.RelVar(sql.Name("G_opt" + initState.joins.size))
-    val initDisjoints:Set[sql.Select] = Set()
-    val emptyState = R2RState(
-      util.AddOrderedSet[sql.Join](), 
-      Map[sparql.Assignable, SQL2RDFValueMapper](), 
-      Set[sql.Expression]()
-    )
-
-    /** Create the select for the nested graph pattern.
-     */
-    val nestedState = mapGraphPattern(db, emptyState, gp, enforceForeignKeys)
-    val nestedVars = gp.findVars
-    /**
-     * Select a constant as _DISJOINT_ so later constraints can be
-     * sensitive to whether a variable was bound.
-     * This matters for assymetric UNIONs and, here, OPTIONALs. Given:
-     *   Join( LeftJoin( BGP(),
-     *                   BGP( ?x :p2 ?v2 ) ),
-     *         BGP( ?y :p3 ?v2 ) )
-     * coreference constraints against ?v2 should only be enforced for
-     * tuples from the right side of this union.
-     */
-    val pathNo = sql.ProjectAttribute(sql.PrimaryExpressionTyped(sql.RDB.Datatype.INTEGER,sql.Name("" + initState.joins.size)),
-					sql.AttrAlias(sql.Name("_DISJOINT_")))
-    val leftJoinVars = gp.findVars
-    val attrlist:Set[sql.ProjectAttribute] = leftJoinVars.map(
-      v =>
-	sql.ProjectAttribute(varToAttribute(nestedState.varmap, sparql.VarAssignable(v)),
-			   sql.AttrAlias(attrAliasNameFromVar(sparql.VarAssignable(v))))
-    ) + pathNo // add join number to selections
-    val subselect = sql.Select(
-      false,
-      sql.Projection(attrlist),
-      sql.TableList(nestedState.joins),
-      nestedState.exprs.size match {
-      	case 0 => None
-      	case 1 => Some(nestedState.exprs.toList(0))
-      	case _ => Some(sql.ExprConjunction(nestedState.exprs))
-      },
-      List[sql.OrderElt](), None, None
-    )
-
-    /** Create a condition to test if this OPTIONAL was matched (called
-     * _DISJOINT_ as OPTIONAL behaves pretty much like a disjunction).
-     */
-    val nestedCond = sql.RelationalExpressionNull(sql.PrimaryExpressionAttr(
-      sql.RelVarAttr(leftJoinAlias, sql.RDB.AttrName("_DISJOINT_"))))
-
-    /** Bind variables to the attributes projected from the subselect;
-     * handle corefs (equivalence with earlier bindings).
-     */
-    val outerState2 =
-      nestedVars.foldLeft(
-	R2RState(initState.joins,
-		 initState.varmap,
-		 Set[sql.Expression]()))((myState, v) => 
-		   subselectVars(myState, sparql.VarAssignable(v), leftJoinAlias, nestedCond,
-				 initState.varmap, nestedState.varmap, true))
-
-    /** The final state includes the subselect as a join, the variables bound
-     * to subselect projection, and no new expresssions. The expressions
-     * derived from corefs are conditions for the LEFT OUTER JOIN.
-     */
-    val join = sql.LeftOuterJoin(sql.AliasedResource(sql.Subselect(subselect), leftJoinAlias), 
-	 outerState2.exprs.size match {
-	   case 0 =>
-	     sql.RelationalExpressionEq(sql.PrimaryExpressionTyped(sql.RDB.Datatype.INTEGER,sql.Name("1")),
-					sql.PrimaryExpressionTyped(sql.RDB.Datatype.INTEGER,sql.Name("1")))
-	     /** Require corefs unless we have a leading OPTIONAL. */
-	     // if (...)
-	     // else
-	     //   error ("Nested GP has no variables shared with its context; cowaredly refusing to join ON 1.")
-	   case 1 => outerState2.exprs.toList(0)
-	   case _ => sql.ExprConjunction(outerState2.exprs)
-	 }
-       )
-    val exprs =
-      if (negate) {
-	initState.exprs + sql.RelationalExpressionNull(sql.PrimaryExpressionAttr(sql.RelVarAttr(leftJoinAlias, sql.RDB.AttrName("_DISJOINT_"))))
-      } else initState.exprs
-    R2RState(initState.joins + join, outerState2.varmap, exprs)
-  }
-
-  /**
-   * Recursively add the joins, variable mappings and constraints for an SQL query implementing a graph pattern.
-   * @param db  database description.
-   * @param state  initial set of joins, variable mappings and constraints.
-   * @param gp  the SPARQL GraphPattern to represent as SQL.
-   * @param enforceForeignKeys  if true, SPARQL triple patterns corresponding to foreign keys, e.g. <code>?who :hasParent ?parent</code>, generate a join on the referenced table.
-   * @return  a new set of joins, variable mappings and constraints.
-   * Per <a href="http://www.w3.org/TR/rdf-sparql-query/#sparqlQuery">definition of SPARQL Query</a>, SPARQL Graph Patterns are (Basic Graph Pattern, Join, LeftJoin, Filter, Union, Graph).
-   * mapGraphPattern maps each of these to an SQL abstract query (which can then be serialized as SQL and executed).
-   * 
-   */
-  def mapGraphPattern(db:sql.RDB.Database, state:R2RState, gp:sparql.GraphPattern, enforceForeignKeys:Boolean):R2RState = {
-    gp match {
-
-      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_PatternInstanceMapping">Basic Graph Pattern Matching</a>()
-       * @param triplepatterns  set of triple patterns. Premise: all triple patterns must resolve against the direct graph.
-       * As { TP1, TP2 } == Join({ TP1 }, { TP2 }), we can view the bindOnPredicate function as partitioning triple patterns by the relvar they match.
-       * This isn't observable in the SQL query as all the triple patterns in all the conjunctions contribute to the same query.
-       */
-      case sparql.TriplesBlock(triplepatterns) => {
-	/** Examine each triple, updating the compilation state. */
-	val state2 = triplepatterns.foldLeft(state)((incState,s) => bindOnPredicate(db, incState, s, enforceForeignKeys))
-
-	/** NULLs in the database result in no triple in the Direct Graph.
-	 * Enforce this by requiring that the SQL expression to which any SPARQL variable (Assignable) is bound is NOT NULL.
-	 */
-	val nullExprs = gp.findAssignables.foldLeft(Set[sql.Expression]())((s, vvar) => {
-	  if (varToAttributeDisjoints(state2.varmap, vvar).size == 0)
-	    /** Create a NOT NULL expression for each fully bound variable. */
-	    s ++ Set(sql.RelationalExpressionNotNull(sql.PrimaryExpressionAttr(varToAttribute(state2.varmap, vvar))))
-	  else
-	    /** Variables in a partial binding can be NULL so the aren't added to the null expressions. */
-	    s
-	})
-	R2RState(state2.joins, state2.varmap, state2.exprs ++ nullExprs)
-      }
-
-      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_evalJoin">Join</a>(P1, P2)
-       * Since Join is association, we handle this as an n-ary join.
-       * @param conjoints  list of graph patterns to join.
-       */
-      case sparql.TableConjunction(conjoints) => {
-	conjoints.foldLeft(state)((incState,s) => mapGraphPattern(db, incState, s, enforceForeignKeys))
-      }
-
-      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_evalLeftJoin">LeftJoin</a>(P1, P2, F)
-       * The parser providing the SPARQL abstract query turns LeftJoin(P1, P2, F) into Join(P1, Optional(P2)), or Join(P1, Optional(Filter(P2, F))) if there is a FILTER.
-       * @param gp2  nested graph pattern (Ω in algebra)
-       */
-      case sparql.OptionalGraphPattern(gp2) => {
-	/* state_postLeadingTable: create an initial table if the first conjoint is optional.
-	 * e.g. ... FROM (SELECT 1 AS _EMPTY_) AS _EMPTY_ LEFT OUTER JOIN ...
-	 */
-	val state_postLeadingTable =
-	  if (state.joins.size == 0)
-	    /**
-	     * Leading optionals (ASK WHERE { OPTIONAL { ... } ... }) in SPARQL don't have a counterpart in SQL.
-	     * We emulate leading optionals with a leading SQL subselect which projects one solution with no selected attributes.
-	     */
-	    R2RState(state.joins + sql.InnerJoin(sql.AliasedResource(sql.Subselect(
-	      sql.Select(
-		false, 
-		sql.Projection(Set(sql.ProjectAttribute(sql.PrimaryExpressionTyped(sql.RDB.Datatype.INTEGER,sql.Name("1")),
-							 sql.AttrAlias(sql.Name("_EMPTY_"))))),
-		sql.TableList(util.AddOrderedSet()),
-		None, List[sql.OrderElt](), None, None
-	      )), sql.RelVar(sql.Name("_EMPTY_"))), None), state.varmap, state.exprs)
-	  else
-	    state
-	/** Create an OUTER JOIN for the nested graph pattern. */
-	synthesizeOuterJoin(state_postLeadingTable, gp2, false, db, enforceForeignKeys)
-      }
-
-      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_algFilter">Filter</a>(expr, Ω)
-       * @param gp2  nested graph pattern (Ω in algebra)
-       * @param expr  boolean SPARQL expression (expr in algebra)
-       */
-      case sparql.TableFilter(gp2:sparql.GraphPattern, expr:sparql.Expression) => {
-	/** Calculate state for gp2. */
-	val state2 = mapGraphPattern(db, state, gp2, enforceForeignKeys)
-
-	/** Add constraints for all the FILTERS */
-	val filterExprs:Set[sql.RelationalExpression] =
-	  expr.conjuncts.toSet map ((x:sparql.PrimaryExpression) => filter2expr(state2.varmap, x))
-
-	R2RState(state2.joins, state2.varmap, state2.exprs ++ filterExprs)
-      }
-
-      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_evalUnion">Union</a>(P1, P2)
-       * Since Disjunction is associative, we handle this as an n-ary disjunction.
-       * @param disjoinits  list of graph patterns to concatenate.
-       */
-      case sparql.TableDisjunction(disjoints) => {
-	/**
-	 * SPARQL UNIONs are realized as SQL subselects.
-	 * Set up initial state for this subselect.
-	 */
-	val unionAlias = sql.RelVar(sql.Name("G_union" + state.joins.size)) // invent a unique name for this union.
-	val emptyState = R2RState( // create an empty state.
-	  util.AddOrderedSet[sql.Join](), 
-	  Map[sparql.Assignable, SQL2RDFValueMapper](), 
-	  Set[sql.Expression]()
-	)
-	val unionVars = disjoints.foldLeft(Set[sparql.Var]())((mySet,disjoint) =>
-	  mySet ++ disjoint.findVars).toList // all variables nested in the disjoints.
-
-	/**
-	 * Map the list of disjoints to a list of nested R2RStates, nested variable lists, and unique SQL constants identifying that disjoint.
-	 * Non-Functional var <code>number</code> is used for projecting unique
-	 * constants to indicate which disjoint produced a tuple.
-	 */
-	var number = 0
-	val nestedStates = disjoints.map(disjoint => {
-	  val disjointState = mapGraphPattern(db, emptyState, disjoint, enforceForeignKeys)
-	  val disjointVars = disjoint.findVars
-	  val uniqueConst = sql.PrimaryExpressionTyped(sql.RDB.Datatype.INTEGER,sql.Name("" + number))
-	  number = number + 1 // non-functional, but clearer than wrapping as a parameter in a foldLeft
-	  (disjointState, disjointVars, uniqueConst)
-	})
-
-	/**
-	 * Map the list of nested R2RStates to a set of subselects.
-	 * <code>uniqueConst</code> is used for projecting a value
-	 * to indicate which disjoint produced a tuple.
-	 */
-	val subselects = nestedStates.foldLeft(Set[sql.Select]())((subselects, state) => {
-	  val (disjointState, disjointVars, uniqueConst) = state
-	  /**
-	   * Select a constant as _DISJOINT_ so later constraints can be
-	   * sensitive to whether a variable was bound.
-	   * This matters for OPTIONALs and, here, assymetric UNIONs. Given:
-	   *   Join( Union( BGP( ?x :p1 ?v1 ),
-	   *                BGP( ?x :p2 ?v1 . ?x :p2 ?v2 ) ),
-	   *         BGP( ?y :p3 ?v2 ) )
-	   * coreference constraints against ?v2 should only be enforced for
-	   * tuples from the right side of this union.
-	   */
-	  val pathNo = sql.ProjectAttribute(uniqueConst,
-					  sql.AttrAlias(sql.Name("_DISJOINT_")))
-
-	  val attrlist:Set[sql.ProjectAttribute] = unionVars.foldLeft(Set(pathNo))((attrs, v) => {
-	    val attrOrNull = if (disjointState.varmap.contains(sparql.VarAssignable(v))) varToAttribute(disjointState.varmap, sparql.VarAssignable(v)) else sql.ConstNULL()
-	    attrs ++ Set(sql.ProjectAttribute(attrOrNull, sql.AttrAlias(attrAliasNameFromVar(sparql.VarAssignable(v)))))
-	  })
-
-	  val subselect = sql.Select(
-	    false,
-	    sql.Projection(attrlist),
-	    sql.TableList(disjointState.joins),
-	    disjointState.exprs.size match {
-	      case 0 => None
-	      case 1 => Some(disjointState.exprs.toList(0))
-	      case _ => Some(sql.ExprConjunction(disjointState.exprs))
-	    }, List[sql.OrderElt](), None, None
-	  )
-	  subselects + subselect
-	})
-
-	/**
-	 * Connect the variables projected from the nested selects into the outer variable bindings and constraints.
-	 * <code>state2</code> will have no additional tables in the TableList.
-	 * <code>uniqueConst</code> is used this time to constraint coreferences between the
-	 * subselects and the outer context.
-	 */
-	val state2 = nestedStates.foldLeft(state)((outerState, state) => {
-	  val (disjointState, disjointVars, uniqueConst) = state
-
-	  /** Create a condition to test if this disjoint was matched. */
-	  val disjointCond = sql.RelationalExpressionNe(sql.PrimaryExpressionAttr(sql.RelVarAttr(unionAlias, sql.RDB.AttrName("_DISJOINT_"))),
-							uniqueConst)
-	  val outerState2 = disjointVars.foldLeft(outerState)((myState, v) =>
-	      subselectVars(myState, sparql.VarAssignable(v), unionAlias, disjointCond, outerState.varmap, disjointState.varmap, false))
-	  number = number + 1 // non-functional, but clearer than wrapping as a parameter in a foldLeft
-	  outerState2
-	})
-	val subselect = sql.Subselect(sql.Union(subselects))
-	R2RState(state.joins + sql.InnerJoin(sql.AliasedResource(subselect,unionAlias), None), state2.varmap, state2.exprs)
-      }
-
-      /** <a href="http://www.w3.org/TR/rdf-sparql-query/#defn_evalGraph">Graph</a>(IRI, P)
-       * I don't know what the parser did with the IRI, but we don't know what to do with GRAPHs anyways. 
-       * @param gp2  nested graph pattern (Ω in algebra)
-       */
-      case sparql.GraphGraphPattern(gp2) => error("no code to handle GraphGraphPatterns (" + gp2 + ")")
-
-      /** Minus is from SPARQL 1.1 (in progress). This doesn't need documentation now.
-       * @param gp2  the graph pattern to subtract.
-       */
-      case sparql.MinusGraphPattern(gp2) => {
-	if (state.joins.size == 0) state
-	else synthesizeOuterJoin(state, gp2, true, db, enforceForeignKeys)
-      }
-    }
-  }
-
-  /**
-   * Default interface for SparqlToSql.
-   * @param db  database description.
-   * @param sparquery  SPARQL compile tree.
-   * @param stem  stem URI for all generated RDF URIs.
-   * @param enforceForeignKeys  if true, SPARQL triple patterns corresponding to foreign keys, e.g. ?who :hasParent ?parent , generate a join on the referenced table.
-   * @param concat  if true, keys will produce SQL functions to generate a URI, e.g. SELECT CONCAT(stemURI, table, "/", pk, ".", R_who.pk) AS who
-   * @return an SQL query corresponding to sparquery
-   */
-  def apply (db:sql.RDB.Database, sparquery:sparql.Select, stem:StemURI, enforceForeignKeys:Boolean, concat:Boolean) : (sql.Select, Map[sparql.Assignable, SQL2RDFValueMapper]) = {
-
-    /** Create an object to hold our compilation state. */
-    val initState = R2RState(
-      util.AddOrderedSet[sql.Join](), 
-      Map[sparql.Assignable, SQL2RDFValueMapper](), 
-      Set[sql.Expression]()
-    )
-
-    /**
-     * Generate a new state with the joins, mappings to sql expressions, and
-     * constraints implicit in the SPARQL WHERE pattern.
-     */
-    val r2rState = mapGraphPattern(db, initState, sparquery.gp, enforceForeignKeys)
-
-    /**
-     * Select the attributes corresponding to the variables
-     * in the SPARQL SELECT.
-     */
-    val attrlist:Set[sql.ProjectAttribute] =
-      // This foldLeft could be a map, if i could coerce to a set afterwards.
-      sparquery.attrs.attributelist.foldLeft(Set[sql.ProjectAttribute]())((attrs, v) => {
-	val exp =
-	  if (concat)
-	    // generate CONCAT expression for keys.
-	    varToExpr(r2rState.varmap, sparql.VarAssignable(v), stem)
-	  else
-	    varToAttribute(r2rState.varmap, sparql.VarAssignable(v))
-	/** Projection alias. */
-	val as = sql.AttrAlias(attrAliasNameFromVar(sparql.VarAssignable(v)))
-	attrs + sql.ProjectAttribute(exp , as)
-      })
-
-    /** Construct the generated query as an abstract syntax. */
-    val select = sql.Select(
-      sparquery.distinct,
-      sql.Projection(attrlist),
-      sql.TableList(r2rState.joins),
-      r2rState.exprs.size match {
-	case 0 => None
-	case 1 => Some(r2rState.exprs.toList(0))
-	case _ => Some(sql.ExprConjunction(r2rState.exprs))
-      },
-      sparquery.order.map((elt:sparql.OrderElt) => {
-	sql.OrderElt(elt.desc, xxx(r2rState.varmap, elt.expr))
-      }), sparquery.offset, sparquery.limit
-    )
-    // println("r2rState.varmap: " + r2rState.varmap)
-    // println("select.expression: " + select.expression)
-    (select.makePretty, r2rState.varmap)
-  }
-
-/*
- * vvv CLEAN THIS UP!!! vvv
- */
-
-  def assignable2expr999(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], rTerm:sparql.Term):sql.Expression = { // :sparql.Var
-    val r:sql.PrimaryExpression = rTerm match {
-      case sparql.TermUri(u) => error("not implemented: translating RDF URI to SQL: " + u) // :sparql.Uri
-      case sparql.TermVar(v) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.VarAssignable(v)))
-      case sparql.TermBNode(b) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.BNodeAssignable(b)))
-      case sparql.TermLit(sparql.Literal(rdf.RDFLiteral(lit,rdf.Datatype(dt)))) =>
-	sql.PrimaryExpressionTyped({
-	  dt.toString match {
-	    case "http://www.w3.org/2001/XMLSchema#string" => sql.RDB.Datatype.STRING
-	    case "http://www.w3.org/2001/XMLSchema#integer" => sql.RDB.Datatype.INTEGER
-	    case "http://www.w3.org/2001/XMLSchema#date" => sql.RDB.Datatype.DATE
-	    case _ => error("unable to translate to RDF literal SQL: \"" + lit + "\"^^<" + dt + ">")
-	  }
-	}, lit)
-    }
-    r
-  }
-
-  def xxx(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], from:sparql.Expression) : sql.Expression = {
-    val l = from.conjuncts.map((conj) => {
-      conj match {
-	case sparql.SparqlTermExpression(sparql.TermVar(v:sparql.Var)) =>
-	  assignable2expr999(varmap, sparql.TermVar(v))
-	case sparql.SparqlTermExpression(sparql.TermBNode(b:sparql.BNode)) =>
-	  assignable2expr999(varmap, sparql.TermBNode(b))
-	case sparql.SparqlTermExpression(sparql.TermLit(l)) =>
-	  assignable2expr999(varmap, sparql.TermLit(l))
-	case sparql.SparqlTermExpression(sparql.TermUri(u:sparql.Uri)) =>
-	  assignable2expr999(varmap, sparql.TermUri(u))
-	case e:sparql.PrimaryExpression => yyy(varmap, e)
-      }})
-    if (l.size == 1)
-      l(0)
-    else
-      sql.ExprConjunction(l.toSet)
-  }
-
-  def yyy(varmap:Map[sparql.Assignable, SQL2RDFValueMapper], from:sparql.PrimaryExpression) : sql.Expression = {
-    from match {
-      case sparql.SparqlTermExpression(term) => assignable2expr999(varmap, term)
-      case sparql.PrimaryExpressionEq(l, r) => sql.RelationalExpressionEq(yyy(varmap, l), yyy(varmap, r))
-      case sparql.PrimaryExpressionGt(l, r) => sql.RelationalExpressionEq(yyy(varmap, l), yyy(varmap, r))
-      case sparql.PrimaryExpressionLt(l, r) => sql.RelationalExpressionEq(yyy(varmap, l), yyy(varmap, r))
-    }
-  }
-
-  /**
-   * junk that should be elsewhere
-   */
-
-  implicit def relname2relresource (rn:sql.RDB.RelName) : sql.RelationResource = sql.RelationResource(rn)
-
-}
-
-/**
- * Support functions to inject SparqlToSql results into an XML Results Set.
- * @example:
- * <pre>
- * val xmlres:String = 
- *   head(List[String]("emp", "name")) +
- *   startresult +
- *     binding("emp", "253", rdfmap, stem) +
- *     binding("name", "Bob", rdfmap, stem) +
- *   endresult +
- *   startresult +
- *     binding("emp", "258", rdfmap, stem) +
- *     // employee 258 has no name attribute so omit this binding
- *   endresult +
- *   foot
- * </pre>
- *
- * @see {@link w3c.sw.sparql2sql.SparqlToSql}
- * @see {@link http://www.w3.org/TR/2008/REC-rdf-sparql-XMLres-20080115/ XML Results Format}
- */
-object SqlToXMLRes {
-
-  /**
-   * Create a SPARQL Results format header and begin the body (results).
-   * @param vars list of variable names to insert into the header
-   */
-  def head (vars:List[String]) : String = {
-    "<?xml version=\"1.0\"?>\n<sparql xmlns=\"http://www.w3.org/2005/sparql-results#\">\n  <head>\n" +
-    vars.map(varname => "    <variable name=\"" + varname + "\"/>\n").mkString + 
-    "  </head>\n\n  <results>\n"
-  }
-
-  /**
-   * Open a result element
-   */
-  def startresult () : String = {
-    "    <result> \n"
-  }
-
-  /**
-   * Create a binding value appropriate for <code>name</code>'s datatype.
-   * @param name name of bound variable.
-   * @param value lexical value of bound variable, may need normalization from e.g. SQL.
-   * @param varmap mapping of sparql variables to datatypes, emitted by SparqlToSql._2
-   * @param stem  stem URI for all generated RDF URIs.
-   */
-  def binding (name:String, value:String, varmap:Map[sparql.Assignable, SparqlToSql.SQL2RDFValueMapper], stem:StemURI) : String = {
-    def getattr (b:SparqlToSql.FullOrPartialBinding) : sql.RDB.AttrName = {
-      b match {
-	case SparqlToSql.FullBinding(sql.RelVarAttr(_, attr)) =>
-	  attr
-	case SparqlToSql.PartialBinding(binders) => {
-	  val SparqlToSql.BindingConstraint(expr, sql.RelVarAttr(rv, attr)) = binders.toList(0)
-	  attr
-	}
-      }
-    }
-    val t:String = varmap(sparql.VarAssignable(sparql.Var(name))) match {
-      case SparqlToSql.RDFNoder(rel, b)  => "<uri>" + stem.s + rel + "/" + getattr(b) + "." + value + "#record</uri>"
-      case SparqlToSql.RDFBNoder(rel, b) => "<bnode>bnode_" + rel + "/" + getattr(b) + "." + value + "</bnode>"
-      case SparqlToSql.DateMapper(_)     => "<literal datatype=\"http://www.w3.org/2001/XMLSchema#date\">" + value + "</literal>"
-      case SparqlToSql.IntMapper(_)      => "<literal datatype=\"http://www.w3.org/2001/XMLSchema#integer\">" + value + "</literal>"
-      case SparqlToSql.StringMapper(_)   => "<literal datatype=\"http://www.w3.org/2001/XMLSchema#string\">" + value + "</literal>"
-    }
-    "      <binding name=\"" + name + "\">\n	" + t + "\n      </binding>\n"
-  }
-
-  /**
-   * Close a result element.
-   */
-  def endresult () : String = {
-    "    </result>\n"
-  }
-
-  /**
-   * End SPARQL Results document.
-   */
-  def foot () : String = {
-    "  </results>\n</sparql>\n"
-  }
-
-}
-