merge
authorAlexandre Bertails <bertails@w3.org>
Sun, 03 Jan 2010 18:43:15 -0500
changeset 106 f9b231e01256
parent 105 53c4902744a2 (current diff)
parent 104 855838f67c98 (diff)
child 107 dfd77753c326
merge
src/main/scala/RDB2RDFMain.scala
src/main/scala/SQL.scala
src/test/scala/SQLTest.scala
--- a/src/main/scala/RDB2RDFMain.scala	Sun Jan 03 18:23:46 2010 -0500
+++ b/src/main/scala/RDB2RDFMain.scala	Sun Jan 03 18:43:15 2010 -0500
@@ -53,14 +53,14 @@
 
   def uriConstraint(state:R2RState, constrainMe:RelAliasAttribute, u:ObjUri, enforeForeignKeys:Boolean):R2RState = {
     // println("equiv+= " + toString(constrainMe) + "=" + value)
-    //R2RState(state.joins, state.varmap, state.exprs + RelationalExpressionEq(constrainMe,RValueTyped(SQLDatatype.INTEGER,Name(u.v.s))))
+    //R2RState(state.joins, state.varmap, state.exprs + RelationalExpressionEq(constrainMe,PrimaryExpressionTyped(SQLDatatype.INTEGER,Name(u.v.s))))
     val relvar = if (enforeForeignKeys) RelAliasAttribute(constrainMe.relalias, Attribute(Name(u.attr.s))) else constrainMe
-    R2RState(state.joins, state.varmap, state.exprs + RelationalExpressionEq(relvar,RValueTyped(SQLDatatype.INTEGER,Name(u.v.s))))
+    R2RState(state.joins, state.varmap, state.exprs + RelationalExpressionEq(PrimaryExpressionAttr(relvar),PrimaryExpressionTyped(SQLDatatype.INTEGER,Name(u.v.s))))
   }
 
   def literalConstraint(state:R2RState, constrainMe:RelAliasAttribute, lit:SparqlLiteral, dt:SQLDatatype):R2RState = {
     // println("equiv+= " + toString(attr) + "=" + lit)
-    R2RState(state.joins, state.varmap, state.exprs + RelationalExpressionEq(constrainMe,RValueTyped(dt,Name(lit.lit.lexicalForm))))    
+    R2RState(state.joins, state.varmap, state.exprs + RelationalExpressionEq(PrimaryExpressionAttr(constrainMe),PrimaryExpressionTyped(dt,Name(lit.lit.lexicalForm))))    
   }
 
   /** varConstraint
@@ -96,7 +96,7 @@
 	state // !!! what about disjoints?
       else {
 	/* Constraint against the initial binding for this variable. */
-	val constraint = RelationalExpressionEq(varToAttribute(state.varmap, v), RValueAttr(constrainMe))
+	val constraint = RelationalExpressionEq(PrimaryExpressionAttr(varToAttribute(state.varmap, v)), PrimaryExpressionAttr(constrainMe))
 	R2RState(state.joins, state.varmap, 
 		 if (varToAttributeDisjoints(state.varmap, v).size > 0) {
 		   state.exprs ++ {varToAttributeDisjoints(state.varmap, v) map ((d) => ExprDisjunction(Set(d, constraint)))}
@@ -176,7 +176,7 @@
 	      val fkaliasattr = RelAliasAttribute(oRelAlias, fkattr)
 	      val state_t = R2RState(state_subjJoin.joins + InnerJoin(AliasedResource(fkrel,oRelAlias)),
 				     state_subjJoin.varmap,
-				     state_subjJoin.exprs + RelationalExpressionEq(fkaliasattr,RValueAttr(objattr)))
+				     state_subjJoin.exprs + RelationalExpressionEq(PrimaryExpressionAttr(fkaliasattr),PrimaryExpressionAttr(objattr)))
 
 	      (fkaliasattr, fkrel, fkdt, state_t)
 	    } else {
@@ -248,8 +248,35 @@
     }
   }
 
+  def varToConcat(varmap:Map[Var, SQL2RDFValueMapper], vvar:Var, stem:StemURI):Expression = {
+    varmap(vvar) match {
+      case IntMapper(relalias, _) => PrimaryExpressionAttr(relalias)
+      case StringMapper(relalias, _) => 
+	Concat(List(PrimaryExpressionTyped(SQLDatatype("String"),Name("\\\"")),
+		    PrimaryExpressionAttr(relalias),
+		    PrimaryExpressionTyped(SQLDatatype("String"),Name("\\\"^^<http://www.w3.org/2001/XMLSchema#string>"))))
+      case DateMapper(relalias, _) => PrimaryExpressionAttr(relalias)
+      case RDFNoder(relation, relalias, _) => 
+	Concat(List(PrimaryExpressionTyped(SQLDatatype("String"),Name(stem.s)),
+		    PrimaryExpressionTyped(SQLDatatype("String"),relation.n),
+		    PrimaryExpressionTyped(SQLDatatype("String"),Name("/")),
+		    PrimaryExpressionTyped(SQLDatatype("String"),relalias.attribute.n),
+		    PrimaryExpressionTyped(SQLDatatype("String"),Name(".")),
+		    PrimaryExpressionAttr(relalias),
+		    PrimaryExpressionTyped(SQLDatatype("String"),Name("#record"))))
+      case RDFBNoder(relation, relalias, _) => 
+	Concat(List(PrimaryExpressionTyped(SQLDatatype("String"),Name("_:")),
+		    PrimaryExpressionTyped(SQLDatatype("String"),relation.n),
+		    PrimaryExpressionTyped(SQLDatatype("String"),Name(".")),
+		    PrimaryExpressionTyped(SQLDatatype("String"),relalias.attribute.n),
+		    PrimaryExpressionTyped(SQLDatatype("String"),Name(".")),
+		    PrimaryExpressionAttr(relalias)))
+    }
+    
+  }
+
   def filter2expr(varmap:Map[Var, SQL2RDFValueMapper], f:SparqlPrimaryExpression):RelationalExpression = {
-    val (lTerm:Term, rTerm:Term, sqlexpr) = f match { // sqlexpr::((RelAliasAttribute,RValueAttr)=>RelationalExpression)
+    val (lTerm:Term, rTerm:Term, sqlexpr) = f match { // sqlexpr::((RelAliasAttribute,PrimaryExpressionAttr)=>RelationalExpression)
       case SparqlPrimaryExpressionEq(l, r) => (l.term, r.term, RelationalExpressionEq(_,_))
       case SparqlPrimaryExpressionLt(l, r) => (l.term, r.term, RelationalExpressionLt(_,_))
     }
@@ -263,11 +290,11 @@
 	val r = rTerm match {
 	  case TermUri(obj) => null // :ObjUri
 	  case TermVar(v) => { // :Var
-	    RValueAttr(varToAttribute(varmap, v))
+	    PrimaryExpressionAttr(varToAttribute(varmap, v))
 	  }
-	  case TermLit(lit) => null // :SparqlLiteral => RValueTyped(SQLDatatype, lit.n)
+	  case TermLit(lit) => null // :SparqlLiteral => PrimaryExpressionTyped(SQLDatatype, lit.n)
 	}
-	sqlexpr(l, r)
+	sqlexpr(PrimaryExpressionAttr(l), r)
       }
       // does not handle FILTER (7 = ?v)
       case TermLit(lit) => error("only SPARQL PrimaryExpressions with a variable on the left have been implemented: punting on " + f)
@@ -288,7 +315,7 @@
       case TriplesBlock(triplepatterns) => {
 	/* Examine each triple, updating the compilation state. */
 	val state2 = triplepatterns.foldLeft(state)((incState,s) => bindOnPredicate(db, incState, s, pk, enforeForeignKeys))
-	val nullExprs = findVars(gp) map (vvar => RelationalExpressionNotNull(varToAttribute(state2.varmap, vvar)))
+	val nullExprs = findVars(gp) map (vvar => RelationalExpressionNotNull(PrimaryExpressionAttr(varToAttribute(state2.varmap, vvar))))
 	R2RState(state2.joins, state2.varmap, state2.exprs ++ nullExprs)
       }
       case TableConjunction(list) => {
@@ -307,9 +334,9 @@
 	  val (outerState, outerDisjoints, no) = incPair
 	  val disjointState = mapGraphPattern(db, emptyState, disjoint, pk, enforeForeignKeys)
 	  val disjointVars = findVars(disjoint)
-	  val disjointNo = NamedAttribute(ConstInt("" + no), AttrAlias(Name("_DISJOINT_")))
+	  val disjointNo = NamedAttribute(PrimaryExpressionTyped(SQLDatatype.INTEGER,Name("" + no)), AttrAlias(Name("_DISJOINT_")))
 	  val disjointNoAliasAttr = RelAliasAttribute(unionAlias, Attribute(Name("_DISJOINT_")))
-	  val disjointCond = RelationalExpressionNe(disjointNoAliasAttr, RValueTyped(SQLDatatype.INTEGER,Name("" + no)))
+	  val disjointCond = RelationalExpressionNe(PrimaryExpressionAttr(disjointNoAliasAttr), PrimaryExpressionTyped(SQLDatatype.INTEGER,Name("" + no)))
 
 	  val attrlist:Set[NamedAttribute] = unionVars.foldLeft(Set(disjointNo))((attrs, v) => {
 	    val attrOrNull = if (disjointState.varmap.contains(v)) varToAttribute(disjointState.varmap, v) else ConstNULL()
@@ -345,7 +372,7 @@
 	      val newConstraints =
 		if (varToAttribute(outerState.varmap, v) != varAliasAttr) {
 		  /* Constraint against binding from earlier GP. */
-		  val constraint = RelationalExpressionEq(varToAttribute(outerState.varmap, v), RValueAttr(varAliasAttr))
+		  val constraint = RelationalExpressionEq(PrimaryExpressionAttr(varToAttribute(outerState.varmap, v)), PrimaryExpressionAttr(varAliasAttr))
 		  if (varToAttributeDisjoints(outerState.varmap, v).size > 0)
 		    // (union0._DISJOINT_ != 0 AND union1._DISJOINT_ != 2) OR union0.x=union1.x
 		    varToAttributeDisjoints(outerState.varmap, v) map ((d) => ExprDisjunction(Set(ExprConjunction(Set(d, disjointCond)), constraint)))
@@ -409,14 +436,13 @@
       	      Map()
       	    val newConstraints = {
       	      /* Constraint against binding from earlier GP. */
-      	      val constraint = RelationalExpressionEq(varToAttribute(state.varmap, v), RValueAttr(varAliasAttr))
+      	      val constraint = RelationalExpressionEq(PrimaryExpressionAttr(varToAttribute(state.varmap, v)), PrimaryExpressionAttr(varAliasAttr))
       	      if (varToAttributeDisjoints(state.varmap, v).size > 0)
       		// (leftJoin0._DISJOINT_ != 0 AND leftJoin1._DISJOINT_ != 2) OR leftJoin0.x=leftJoin1.x
       		varToAttributeDisjoints(state.varmap, v) map ((d) => ExprDisjunction(Set(d, constraint)))
       	      else
       		Set(constraint)
       	    }
-	    println("" + v + " begets " + newMap + " and " + newConstraints)
       	    R2RState(myState.joins, myState.varmap ++ newMap, myState.exprs ++ newConstraints)
       	  } else {
       	    /* This variable is new to the outer context. */
@@ -443,7 +469,7 @@
     }
   }
 
-  def apply (db:DatabaseDesc, sparql:SparqlSelect, stem:StemURI, pk:PrimaryKey, enforeForeignKeys:Boolean) : Select = {
+  def apply (db:DatabaseDesc, sparql:SparqlSelect, stem:StemURI, pk:PrimaryKey, enforeForeignKeys:Boolean, concat:Boolean) : Select = {
     val SparqlSelect(attrs, triples) = sparql
 
     /* Create an object to hold our compilation state. */
@@ -458,7 +484,11 @@
     /* Select the attributes corresponding to the variables
      * in the SPARQL SELECT.  */
     val attrlist:Set[NamedAttribute] = attrs.attributelist.foldLeft(Set[NamedAttribute]())((attrs, vvar) => 
-      attrs ++ Set(NamedAttribute(varToAttribute(r2rState.varmap, vvar), AttrAlias(Name("A_" + vvar.s)))))
+      attrs + NamedAttribute({
+	if (concat) varToConcat(r2rState.varmap, vvar, stem)
+	else varToAttribute(r2rState.varmap, vvar)
+      } , AttrAlias(Name("A_" + vvar.s))
+      ))
 
     /* Construct the generated query as an abstract syntax. */
     Select(
--- a/src/main/scala/SQL.scala	Sun Jan 03 18:23:46 2010 -0500
+++ b/src/main/scala/SQL.scala	Sun Jan 03 18:43:15 2010 -0500
@@ -5,7 +5,7 @@
 object SQLParsers extends RegexParsers {
 
   val int = """[0-9]+""".r
-  val chars = "\"[^\"]*\"".r
+  val chars = "\"([^\"\\\\\n\r]|\\\\[tbnrf\\\"'])*\"".r
 }
 
 import SQLParsers._
@@ -34,24 +34,14 @@
   // foo, bar
   override def toString = "SELECT "+(attributes mkString (",\n       "))
 }
-case class NamedAttribute(value:RelAliasAttributeORConst, attralias:AttrAlias) {
+case class NamedAttribute(value:RelAliasAttributeORExpression, attralias:AttrAlias) {
   override def toString = value + " AS " + attralias
 }
 //case class RelAttribute(relation:Relation, attribute:Attribute) c.f. ForeignKey
-sealed abstract class RelAliasAttributeORConst
-case class RelAliasAttribute(relalias:RelAlias, attribute:Attribute) extends RelAliasAttributeORConst {
+sealed abstract class RelAliasAttributeORExpression
+case class RelAliasAttribute(relalias:RelAlias, attribute:Attribute) extends RelAliasAttributeORExpression {
   override def toString = relalias + "." + attribute
 }
-sealed abstract class Const extends RelAliasAttributeORConst
-case class ConstNULL() extends Const {
-  override def toString = "NULL"
-}
-case class ConstInt(i:String) extends Const {
-  override def toString = "" + i
-}
-case class ConstChars(s:String) extends Const {
-  override def toString = "\"" + s + "\""
-}
 
 case class Attribute(n:Name) {
   override def toString = n.s /* "'" + n.s + "'" */
@@ -81,7 +71,7 @@
 case class AliasedResource(rel:RelationORSubselect, as:RelAlias) {
   override def toString = rel + " AS " + as
 }
-sealed abstract class Expression
+sealed abstract class Expression extends RelAliasAttributeORExpression
 case class ExprConjunction(exprs:Set[Expression]) extends Expression {
   override def toString = "(" + (exprs mkString (")\n       AND (")) + ")"
 }
@@ -89,25 +79,32 @@
   override def toString = "(" + (exprs mkString (") OR (")) + ")"
 }
 sealed abstract class RelationalExpression extends Expression
-case class RelationalExpressionEq(l:RelAliasAttribute, r:RValue) extends RelationalExpression {
+case class RelationalExpressionEq(l:Expression, r:Expression) extends RelationalExpression {
   override def toString = l + "=" + r
 }
-case class RelationalExpressionNe(l:RelAliasAttribute, r:RValue) extends RelationalExpression {
+case class RelationalExpressionNe(l:Expression, r:Expression) extends RelationalExpression {
   override def toString = l + "!=" + r
 }
-case class RelationalExpressionLt(l:RelAliasAttribute, r:RValue) extends RelationalExpression {
+case class RelationalExpressionLt(l:Expression, r:Expression) extends RelationalExpression {
   override def toString = l + "<" + r
 }
-case class RelationalExpressionNotNull(l:RelAliasAttribute) extends RelationalExpression {
+case class RelationalExpressionNotNull(l:Expression) extends RelationalExpression { // Expression?
   override def toString = l + " IS NOT NULL"
 }
-sealed abstract class RValue
-case class RValueAttr(fqattribute:RelAliasAttribute) extends RValue {
+sealed abstract class PrimaryExpression extends Expression
+case class PrimaryExpressionAttr(fqattribute:RelAliasAttribute) extends PrimaryExpression {
   override def toString = "" + fqattribute
 }
-case class RValueTyped(datatype:SQLDatatype, i:Name) extends RValue {
+case class PrimaryExpressionTyped(datatype:SQLDatatype, i:Name) extends PrimaryExpression {
   override def toString = i.s /* "'" + i.s + "'" */ /* + datatype */
 }
+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 Name(s:String)
 
 object Name {
@@ -146,25 +143,19 @@
     repsep(namedattribute, ",") ^^ { l => AttributeList(l.toSet) }
 
   def namedattribute:Parser[NamedAttribute] =
-    fqattributeORconst ~ "AS" ~ attralias ^^
-    { case fqattributeORconst ~ "AS" ~ attralias =>
-      NamedAttribute(fqattributeORconst, attralias) }
+    fqattributeORprimaryexpression ~ "AS" ~ attralias ^^
+    { case fqattributeORprimaryexpression ~ "AS" ~ attralias =>
+      NamedAttribute(fqattributeORprimaryexpression, attralias) }
 
-  def fqattributeORconst:Parser[RelAliasAttributeORConst] = (
+  def fqattributeORprimaryexpression:Parser[RelAliasAttributeORExpression] = (
       fqattribute ^^ { case fqattribute => fqattribute }
-    | const ^^ { case const => const }
+    | primaryexpression ^^ { case const => const }
   )
 
   def fqattribute:Parser[RelAliasAttribute] =
     relalias ~ "." ~ attribute ^^
     { case relalias ~ "." ~ attribute => RelAliasAttribute(relalias, attribute) }
 
-  def const:Parser[Const] = (
-      "NULL" ^^ { case "NULL" => ConstNULL() }
-    | int ^^ { case i => ConstInt(i) }
-    | chars ^^ { case ch => ConstChars(ch) }
-  )
-
   def attribute:Parser[Attribute] =
     """[a-zA-Z_]\w*""".r ^^ { x => Attribute(Name(x)) }
 
@@ -203,22 +194,25 @@
     { xs => if (xs.size > 1) ExprConjunction(xs.toSet) else xs(0) }
 
   def relationalexpression:Parser[Expression] = (
-      fqattribute ~ "=" ~ rvalue ^^
-      { case fqattribute ~ "=" ~ rvalue => RelationalExpressionEq(fqattribute, rvalue) }
-    | fqattribute ~ "!=" ~ rvalue ^^
-      { case fqattribute ~ "!=" ~ rvalue => RelationalExpressionNe(fqattribute, rvalue) }
-    | fqattribute ~ "<" ~ rvalue ^^
-      { case fqattribute ~ "<" ~ rvalue => RelationalExpressionLt(fqattribute, rvalue) }
-    | fqattribute ~ "IS" ~ "NOT" ~ "NULL" ^^
-      { case fqattribute ~ "IS" ~ "NOT" ~ "NULL" => RelationalExpressionNotNull(fqattribute) }
-    | "(" ~ expression ~ ")" ^^
-      { case "("~x~")" => x }
+      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 ~ "IS" ~ "NOT" ~ "NULL" ^^
+      { case primaryexpression ~ "IS" ~ "NOT" ~ "NULL" => RelationalExpressionNotNull(primaryexpression) }
+    | primaryexpression ^^
+      { case primaryexpression => primaryexpression }
   )
 
-  def rvalue:Parser[RValue] = (
-      fqattribute ^^ { RValueAttr(_) }
-    | """[0-9]+""".r ^^ { x => RValueTyped(SQLDatatype.INTEGER, Name(x)) }
-    | "\"[^\"]*\"".r  ^^ { x => RValueTyped(SQLDatatype.STRING, Name(x.substring(1, x.size - 1))) }
+  def primaryexpression:Parser[Expression] = (
+      fqattribute ^^ { PrimaryExpressionAttr(_) }
+    | int ^^ { i => PrimaryExpressionTyped(SQLDatatype.INTEGER, Name(i)) }
+    | chars  ^^ { x => PrimaryExpressionTyped(SQLDatatype.STRING, Name(x.substring(1, x.size - 1))) }
+    | "NULL" ^^ { case "NULL" => ConstNULL() }
+    | "CONCAT" ~ "(" ~ rep1sep(expression, ",") ~ ")" ^^ { case "CONCAT"~"("~expressions~")" => Concat(expressions) }
+    | "(" ~ expression ~ ")" ^^ { case "("~x~")" => x }
   )
 
 }
--- a/src/test/scala/RDB2RDFTest.scala	Sun Jan 03 18:23:46 2010 -0500
+++ b/src/test/scala/RDB2RDFTest.scala	Sun Jan 03 18:43:15 2010 -0500
@@ -45,7 +45,46 @@
             INNER JOIN Employee AS R_id18
  WHERE R_id18.id=R_emp.manager AND R_id18.id=18 AND R_emp.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true) === sqlSelect)
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, false) === sqlSelect)
+    true
+  }
+
+  test("SELECT <x> { ?sf <p> <x>} (in-SQL Nodizer)") {
+    val sparqlParser = Sparql()
+    val sparqlSelect = sparqlParser.parseAll(sparqlParser.select, """
+PREFIX empP : <http://hr.example/DB/Employee#>
+SELECT ?emp {
+?emp  empP:manager    <http://hr.example/DB/Employee/id.18#record>
+}
+""").get
+    val sqlParser = Sql()
+    val StemUrlString = "\"http://hr.example/DB/\""
+    val sqlSelect = sqlParser.parseAll(sqlParser.select, """
+SELECT CONCAT(""" + StemUrlString + """, "Employee", "/", "id", ".", R_emp.id, "#record") AS A_emp
+       FROM Employee AS R_emp
+            INNER JOIN Employee AS R_id18
+ WHERE R_id18.id=R_emp.manager AND R_id18.id=18 AND R_emp.id IS NOT NULL
+""").get
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, true) === sqlSelect)
+    true
+  }
+
+  test("SELECT <x> { ?sf <p> \"asdf\"} (in-SQL Nodizer)") {
+    val sparqlParser = Sparql()
+    val sparqlSelect = sparqlParser.parseAll(sparqlParser.select, """
+PREFIX empP : <http://hr.example/DB/Employee#>
+SELECT ?name {
+?emp  empP:lastName  ?name
+}
+""").get
+    val sqlParser = Sql()
+    val StemUrlString = "\"http://hr.example/DB/\""
+    val sqlSelect = sqlParser.parseAll(sqlParser.select, """
+SELECT CONCAT("\"", R_emp.lastName, "\"^^<http://www.w3.org/2001/XMLSchema#string>") AS A_name
+       FROM Employee AS R_emp
+ WHERE R_emp.id IS NOT NULL AND R_emp.lastName IS NOT NULL
+""").get
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, true) === sqlSelect)
     true
   }
 
@@ -64,7 +103,7 @@
             INNER JOIN Employee AS R_manager
  WHERE R_manager.id=R_id18.manager AND R_id18.id=18 AND R_manager.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true) === sqlSelect)
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, false) === sqlSelect)
     true
   }
 
@@ -86,7 +125,7 @@
             INNER JOIN Employee AS R_18
  WHERE R_18.id=R_emp.manager AND R_18.id=18 AND R_emp.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true) === sqlSelect)
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, false) === sqlSelect)
     true
   }
 
@@ -106,7 +145,7 @@
             INNER JOIN Employee AS R_emp2
  WHERE R_emp1.lastName=R_emp2.lastName AND R_emp1.id IS NOT NULL AND R_emp1.lastName IS NOT NULL AND R_emp2.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true) === sqlSelect)
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, false) === sqlSelect)
     true
   }
 
@@ -129,7 +168,7 @@
  AND R_emp.id IS NOT NULL
  AND R_manager.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true) === sqlSelect)
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, false) === sqlSelect)
   }
 
   test("transform tup1 no-enforce") {
@@ -148,7 +187,7 @@
  WHERE R_emp.manager=18 AND R_emp.lastName IS NOT NULL
  AND R_emp.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false, false) === sqlSelect)
   }
 
   test("transform tup1 enforce") {
@@ -168,7 +207,7 @@
  WHERE R_id18.id=R_emp.manager AND R_id18.id=18 AND R_emp.lastName IS NOT NULL
  AND R_emp.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true) === sqlSelect)
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, false) === sqlSelect)
   }
 
 
@@ -192,7 +231,7 @@
  AND R_emp.id IS NOT NULL
  AND R_manager.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true) === sqlSelect)
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, false) === sqlSelect)
   }
 
   test("transform filter1") {
@@ -231,7 +270,7 @@
  AND R_manager.birthday IS NOT NULL
  AND R_grandManager.birthday IS NOT NULL
 """).get
-    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true) === sqlSelect)
+    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), true, false) === sqlSelect)
   }
 
   test("transform disj1") {
@@ -272,7 +311,7 @@
        (R_union1._DISJOINT_!=0 OR R_who.id=R_union1.A_who) AND
        (R_union1._DISJOINT_!=1 OR R_who.id=R_union1.A_who)
 """).get
-    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
+    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false, false) === sqlSelect)
   }
 
   test("transform assymDisj1") {
@@ -318,7 +357,7 @@
        R_union0.A_who IS NOT NULL AND
        R_union0.A_bday IS NOT NULL
 """).get
-    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
+    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false, false) === sqlSelect)
   }
 
   test("transform assymDisj1 reversed") {
@@ -366,7 +405,7 @@
        R_who.id IS NOT NULL AND
        R_who.birthday IS NOT NULL
 """).get
-    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
+    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false, false) === sqlSelect)
   }
 
   test("transform assymDisj1 interspersed") {
@@ -414,7 +453,7 @@
        R_who.id IS NOT NULL AND
        R_union1.A_bday IS NOT NULL
 """).get
-    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
+    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false, false) === sqlSelect)
   }
 
   test("transform optJoin1") {
@@ -458,7 +497,7 @@
  WHERE R_emp.lastName IS NOT NULL
    AND R_emp.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
+    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false, false) === sqlSelect)
   }
 
   test("transform nestOpt") {
@@ -499,6 +538,6 @@
              ) AS R_opt1 ON R_emp.id=R_opt1.A_emp
  WHERE R_emp.lastName IS NOT NULL AND R_emp.id IS NOT NULL
 """).get
-    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false) === sqlSelect)
+    assert(RDB2RDF(db2, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id"))), false, false) === sqlSelect)
   }
 }
--- a/src/test/scala/SQLTest.scala	Sun Jan 03 18:23:46 2010 -0500
+++ b/src/test/scala/SQLTest.scala	Sun Jan 03 18:43:15 2010 -0500
@@ -12,10 +12,10 @@
 R_manager.id=R_emp.manager AND R_emp.lastName IS NOT NULL AND R_manager.lastName IS NOT NULL
 """
     val expected = ExprConjunction(Set(
-      RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))),
-			     RValueAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))))),
-      RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName")))),
-      RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName"))))))
+      RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id")))),
+			     PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))))),
+      RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))))),
+      RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName")))))))
     assert(expected === (a.parseAll(a.expression, e).get))
   }
 
@@ -26,10 +26,10 @@
 R_manager.id=R_emp.manager OR R_emp.lastName IS NOT NULL OR R_manager.lastName IS NOT NULL
 """
     val expected = ExprDisjunction(Set(
-      RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))),
-			     RValueAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))))),
-      RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName")))),
-      RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName"))))))
+      RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id")))),
+			     PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))))),
+      RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))))),
+      RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName")))))))
     assert(expected === (a.parseAll(a.expression, e).get))
   }
 
@@ -40,10 +40,10 @@
 ( R_manager.id=R_emp.manager OR R_emp.lastName IS NOT NULL OR R_manager.lastName IS NOT NULL )
 """
     val expected = ExprDisjunction(Set(
-      RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))),
-			     RValueAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))))),
-      RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName")))),
-      RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName"))))))
+      RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id")))),
+			     PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))))),
+      RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))))),
+      RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName")))))))
     assert(expected === (a.parseAll(a.expression, e).get))
   }
 
@@ -65,10 +65,10 @@
 			  TableList(AddOrderedSet(InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))),
 					InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_manager")))))),
 			  Some(ExprConjunction(Set(
-			    RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))),
-						RValueAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))))),
-			    RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName")))),
-			    RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName"))))))))
+			    RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id")))),
+						   PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))))),
+			    RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))))),
+			    RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName")))))))))
     assert(expected === (a.parseAll(a.select, e).get))
   }
 
@@ -83,9 +83,9 @@
 									      Attribute(Name("lastName"))),
 							    AttrAlias(Name("A_empName"))))),
 			  TableList(AddOrderedSet(InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))))),
-			  Some(ExprConjunction(Set(RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))),
-							      RValueTyped(SQLDatatype.INTEGER,Name("18"))),
-					  RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))))))))
+			  Some(ExprConjunction(Set(RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager")))),
+									  PrimaryExpressionTyped(SQLDatatype.INTEGER,Name("18"))),
+					  RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName")))))))))
     assert(expected === (a.parseAll(a.select, e).get))
   }
 
@@ -102,11 +102,11 @@
 							    AttrAlias(Name("A_empName"))))),
 			  TableList(AddOrderedSet(InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))),
 					InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_manager")))))),
-			  Some(ExprConjunction(Set(RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager"))),
-							      RValueAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))))),
-					  RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName"))),
-							      RValueTyped(SQLDatatype.STRING,Name("Johnson"))),
-					  RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))))))))
+			  Some(ExprConjunction(Set(RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager")))),
+									  PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))))),
+					  RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName")))),
+								 PrimaryExpressionTyped(SQLDatatype.STRING,Name("Johnson"))),
+					  RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName")))))))))
     assert(expected === (a.parseAll(a.select, e).get))
   }
 
@@ -134,20 +134,20 @@
 					InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_manager")))),
 					InnerJoin(AliasedResource(Relation(Name("Manage")),RelAlias(Name("R_upper")))),
 					InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_grandManager")))))),
-			  Some(ExprConjunction(Set(RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_lower")),Attribute(Name("manages"))),
-							     RValueAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("id"))))),
-					 RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))),
-							     RValueAttr(RelAliasAttribute(RelAlias(Name("R_lower")),Attribute(Name("manager"))))),
-					 RelationalExpressionLt(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("birthday"))),
-							     RValueAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("birthday"))))),
-					 RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_upper")),Attribute(Name("manages"))),
-							     RValueAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))))),
-					 RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_grandManager")),Attribute(Name("id"))),
-							     RValueAttr(RelAliasAttribute(RelAlias(Name("R_upper")),Attribute(Name("manager"))))),
-					 RelationalExpressionLt(RelAliasAttribute(RelAlias(Name("R_grandManager")),Attribute(Name("birthday"))),
-							     RValueAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("birthday"))))),
-					 RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName")))),
-					 RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_grandManager")),Attribute(Name("lastName"))))))))
+			  Some(ExprConjunction(Set(RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_lower")),Attribute(Name("manages")))),
+									  PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("id"))))),
+					 RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id")))),
+								PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_lower")),Attribute(Name("manager"))))),
+					 RelationalExpressionLt(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("birthday")))),
+								PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("birthday"))))),
+					 RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_upper")),Attribute(Name("manages")))),
+								PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))))),
+					 RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_grandManager")),Attribute(Name("id")))),
+								PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_upper")),Attribute(Name("manager"))))),
+					 RelationalExpressionLt(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_grandManager")),Attribute(Name("birthday")))),
+								PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("birthday"))))),
+					 RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))))),
+					 RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_grandManager")),Attribute(Name("lastName")))))))))
     assert(expected === (a.parseAll(a.select, e).get))
   }
 
@@ -181,9 +181,9 @@
 						   InnerJoin(AliasedResource(Relation(Name("Manage")),RelAlias(Name("R_above")))),
 						   InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_manager"))))
 						 )), 
-						 Some(ExprConjunction(Set(RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("manager"))),
-										    RValueAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))))),
-								RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName")))))))), 
+						 Some(ExprConjunction(Set(RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("manager")))),
+												 PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id"))))),
+								RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("lastName"))))))))), 
 					  Select(AttributeList(Set(NamedAttribute(RelAliasAttribute(RelAlias(Name("R_managed")), Attribute(Name("lastName"))),
 										  AttrAlias(Name("A_name"))), 
 								   NamedAttribute(RelAliasAttribute(RelAlias(Name("R_below")), Attribute(Name("manager"))),
@@ -192,14 +192,14 @@
 						   InnerJoin(AliasedResource(Relation(Name("Manage")),RelAlias(Name("R_below")))),
 						   InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_managed"))))
 						 )), 
-						 Some(ExprConjunction(Set(RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_below")),Attribute(Name("manages"))),
-										    RValueAttr(RelAliasAttribute(RelAlias(Name("R_managed")),Attribute(Name("id"))))),
-								RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_managed")),Attribute(Name("lastName"))))))))))),
+						 Some(ExprConjunction(Set(RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_below")),Attribute(Name("manages")))),
+												 PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_managed")),Attribute(Name("id"))))),
+								RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_managed")),Attribute(Name("lastName")))))))))))),
 							RelAlias(Name("R_union1")))))), 
-			  Some(ExprConjunction(Set(RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_union1")),Attribute(Name("A_who"))),
-							     RValueAttr(RelAliasAttribute(RelAlias(Name("R_who")),Attribute(Name("id"))))),
-					 RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_who")),Attribute(Name("lastName"))),
-							     RValueTyped(SQLDatatype.STRING,Name("Smith")))))))
+			  Some(ExprConjunction(Set(RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_union1")),Attribute(Name("A_who")))),
+									  PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_who")),Attribute(Name("id"))))),
+					 RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_who")),Attribute(Name("lastName")))),
+								PrimaryExpressionTyped(SQLDatatype.STRING,Name("Smith")))))))
     assert(expected === (a.parseAll(a.select, e).get))
   }
 
@@ -217,7 +217,27 @@
 							    AttrAlias(Name("A_bday"))))),
 			  TableList(AddOrderedSet(InnerJoin(AliasedResource(Relation(Name("Manage")),RelAlias(Name("R_above")))))),
 			  Some(
-			    RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("id"))))))
+			    RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("id")))))))
+    assert(expected === (a.parseAll(a.select, e).get))
+  }
+
+  test("parse CONCAT") {
+    val a = Sql()
+    val QuotedBaseURI = "\"http://hr.example/DB/\""
+    val e = """
+SELECT CONCAT(""" + QuotedBaseURI + """, "Employee", "/", "id", ".", R_emp.id, "#record") AS A_emp
+       FROM Employee AS R_emp
+"""
+    val expected = Select(AttributeList(Set(NamedAttribute(Concat(List(PrimaryExpressionTyped(SQLDatatype("String"),Name("http://hr.example/DB/")),
+								       PrimaryExpressionTyped(SQLDatatype("String"),Name("Employee")),
+								       PrimaryExpressionTyped(SQLDatatype("String"),Name("/")),
+								       PrimaryExpressionTyped(SQLDatatype("String"),Name("id")),
+								       PrimaryExpressionTyped(SQLDatatype("String"),Name(".")),
+								       PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("id")))),
+								       PrimaryExpressionTyped(SQLDatatype("String"),Name("#record")))),
+							    AttrAlias(Name("A_emp"))))),
+			  TableList(AddOrderedSet(InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))))),
+			  None)
     assert(expected === (a.parseAll(a.select, e).get))
   }
 
@@ -236,12 +256,12 @@
 			  TableList(AddOrderedSet(InnerJoin(AliasedResource(Relation(Name("Manage")),RelAlias(Name("R_above")))))),
 			  Some(
 			    ExprDisjunction(Set(
-			      RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("id")))),
+			      RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("id"))))),
 			      ExprConjunction(Set(
-				RelationalExpressionLt(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("id"))),
-						       RValueTyped(SQLDatatype.INTEGER,Name("5"))),
-				RelationalExpressionLt(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("id"))),
-						       RValueTyped(SQLDatatype.INTEGER,Name("3")))
+				RelationalExpressionLt(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("id")))),
+						       PrimaryExpressionTyped(SQLDatatype.INTEGER,Name("5"))),
+				RelationalExpressionLt(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("id")))),
+						       PrimaryExpressionTyped(SQLDatatype.INTEGER,Name("3")))
 			      ))))))
     assert(expected === (a.parseAll(a.select, e).get))
   }
@@ -262,12 +282,11 @@
 							    AttrAlias(Name("A_manageName"))))),
 			  TableList(AddOrderedSet(InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))),
 					LeftOuterJoin(AliasedResource(Relation(Name("Manage")),RelAlias(Name("R_mang"))),
-						      RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_mang")),Attribute(Name("emp"))),
-									     RValueAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("id"))))
-
+						      RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_mang")),Attribute(Name("emp")))),
+									     PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("id"))))
 									   )))),
 			  Some(
-			      RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))))
+			      RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName")))))
 			    ))
     assert(expected === (a.parseAll(a.select, e).get))
   }
@@ -293,9 +312,9 @@
 				    TableList(AddOrderedSet(InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))))),
 				    None)),
 			     RelAlias(Name("R_mang"))),
-					 RelationalExpressionEq(RelAliasAttribute(RelAlias(Name("R_mang")),Attribute(Name("emp"))),
-								RValueAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("id")))))))),
-	     Some(RelationalExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))))))
+					 RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_mang")),Attribute(Name("emp")))),
+								PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("id")))))))),
+	     Some(RelationalExpressionNotNull(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName")))))))
     assert(expected === (a.parseAll(a.select, e).get))
   }