--- a/src/main/scala/RDB2RDFMain.scala Sat Jan 02 16:33:28 2010 -0500
+++ b/src/main/scala/RDB2RDFMain.scala Sat Jan 02 18:34:46 2010 -0500
@@ -361,12 +361,87 @@
})
(outerState2, outerDisjoints ++ Set(subselect), no+1)
})
- val union = Subselect(Union(disjoints))
- R2RState(state.joins + InnerJoin(AliasedResource(union,unionAlias)), state2.varmap, state2.exprs)
+ val subselect = Subselect(Union(disjoints))
+ R2RState(state.joins + InnerJoin(AliasedResource(subselect,unionAlias)), state2.varmap, state2.exprs)
}
- case OptionalGraphPattern(gp) => {
- state
- }
+ // case OptionalGraphPattern(gp) => {
+ // val leftJoinAlias = RelAlias(Name("R_leftJoin" + state.joins.size))
+ // val initDisjoints:Set[Select] = Set()
+ // val emptyState = R2RState(
+ // Set[Join](),
+ // Map[Var, SQL2RDFValueMapper](),
+ // Set[Expression]()
+ // )
+ // val leftJoinVars = list.foldLeft(Set[Var]())((mySet,disjoint) => mySet ++ findVars(disjoint)).toList
+ // val (state2, disjoints, count) = list.foldLeft((state, initDisjoints, 0))((incPair,disjoint) => {
+ // 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 disjointNoAliasAttr = RelAliasAttribute(leftJoinAlias, Attribute(Name("_DISJOINT_")))
+ // val disjointCond = RelationalExpressionNe(disjointNoAliasAttr, RValueTyped(SQLDatatype.INTEGER,Name("" + no)))
+
+ // val attrlist:Set[NamedAttribute] = leftJoinVars.foldLeft(Set(disjointNo))((attrs, v) => {
+ // val attrOrNull = if (disjointState.varmap.contains(v)) varToAttribute(disjointState.varmap, v) else ConstNULL()
+ // attrs ++ Set(NamedAttribute(attrOrNull, AttrAlias(Name("A_" + v.s))))
+ // })
+
+ // val subselect = Select(
+ // AttributeList(attrlist),
+ // TableList(disjointState.joins),
+ // disjointState.exprs.size match {
+ // case 0 => None
+ // case 1 => Some(disjointState.exprs.toList(0))
+ // case _ => Some(ExprConjunction(disjointState.exprs))
+ // }
+ // )
+ // val outerState2 = disjointVars.foldLeft(outerState)((myState, v) => {
+ // val varAliasAttr = RelAliasAttribute(leftJoinAlias, Attribute(Name("A_" + v.s)))
+ // if (myState.varmap.contains(v)) {
+ // /* The variable has already been bound. */
+ // val newMap:Map[Var, SQL2RDFValueMapper] = if (varToAttribute(myState.varmap, v) == varAliasAttr) {
+ // /* Same var was bound in an earlier disjoint. */
+ // val oldDisjoints = varToAttributeDisjoints(myState.varmap, v)
+ // // myState
+ // Map(v -> { disjointState.varmap(v) match {
+ // case IntMapper(_, _) => IntMapper(varAliasAttr, oldDisjoints + disjointCond)
+ // case StringMapper(_, _) => StringMapper(varAliasAttr, oldDisjoints + disjointCond)
+ // case DateMapper(_, _) => DateMapper(varAliasAttr, oldDisjoints + disjointCond)
+ // case RDFNoder(rel, _, _) => RDFNoder(rel, varAliasAttr, oldDisjoints + disjointCond)
+ // case RDFBNoder(rel, _, _) => RDFBNoder(rel, varAliasAttr, oldDisjoints + disjointCond)
+ // } } )
+ // } else
+ // Map()
+ // val newConstraints =
+ // if (varToAttribute(outerState.varmap, v) != varAliasAttr) {
+ // /* Constraint against binding from earlier GP. */
+ // val constraint = RelationalExpressionEq(varToAttribute(outerState.varmap, v), RValueAttr(varAliasAttr))
+ // if (varToAttributeDisjoints(outerState.varmap, v).size > 0)
+ // // (leftJoin0._DISJOINT_ != 0 AND leftJoin1._DISJOINT_ != 2) OR leftJoin0.x=leftJoin1.x
+ // varToAttributeDisjoints(outerState.varmap, v) map ((d) => ExprDisjunction(Set(ExprConjunction(Set(d, disjointCond)), constraint)))
+ // else
+ // Set(ExprDisjunction(Set(disjointCond, constraint)))
+ // } else {
+ // Set()
+ // }
+ // R2RState(myState.joins, myState.varmap ++ newMap, myState.exprs ++ newConstraints)
+ // } else {
+ // /* This variable is new to the outer context. */
+ // val mapper:SQL2RDFValueMapper = disjointState.varmap(v) match {
+ // case IntMapper(_, _) => IntMapper(varAliasAttr, Set(disjointCond))
+ // case StringMapper(_, _) => StringMapper(varAliasAttr, Set(disjointCond))
+ // case DateMapper(_, _) => DateMapper(varAliasAttr, Set(disjointCond))
+ // case RDFNoder(rel, _, _) => RDFNoder(rel, varAliasAttr, Set(disjointCond))
+ // case RDFBNoder(rel, _, _) => RDFBNoder(rel, varAliasAttr, Set(disjointCond))
+ // }
+ // R2RState(myState.joins, myState.varmap + (v -> mapper), myState.exprs)
+ // }
+ // })
+ // (outerState2, outerDisjoints ++ Set(subselect), no+1)
+ // })
+ // val subselect = Subselect(Union(disjoints))
+ // R2RState(state.joins + InnerJoin(AliasedResource(subselect,unionAlias)), state2.varmap, state2.exprs)
+ // }
case x => error("no code to handle " + x)
}
}
--- a/src/main/scala/SQL.scala Sat Jan 02 16:33:28 2010 -0500
+++ b/src/main/scala/SQL.scala Sat Jan 02 18:34:46 2010 -0500
@@ -13,15 +13,23 @@
import scala.util.parsing.combinator._
import java.net.URI
-case class Union(disjoints:Set[Select]) {
- override def toString = (disjoints mkString ("\nUNION\n"))
+sealed abstract class RelationORSubselect
+case class Subselect(sel:SelectORUnion) extends RelationORSubselect {
+ override def toString = "(\n" + sel + "\n )"
}
-case class Select(attributelist:AttributeList, tablelist:TableList, expression:Option[Expression]) {
+sealed abstract class SelectORUnion
+case class Select(attributelist:AttributeList, tablelist:TableList, expression:Option[Expression]) extends SelectORUnion {
override def toString = expression match {
case Some(expr) => attributelist+"\n"+tablelist+"\n WHERE "+expr
case None => attributelist+"\n"+tablelist
}
}
+case class Relation(n:Name) extends RelationORSubselect {
+ override def toString = n.s /* "'" + n.s + "'" */
+}
+case class Union(disjoints:Set[Select]) extends SelectORUnion {
+ override def toString = "\n" + (disjoints mkString ("\nUNION\n")) + "\n)"
+}
case class AttributeList(attributes:Set[NamedAttribute]) {
// foo, bar
override def toString = "SELECT "+(attributes mkString (",\n "))
@@ -34,7 +42,7 @@
case class RelAliasAttribute(relalias:RelAlias, attribute:Attribute) extends RelAliasAttributeORConst {
override def toString = relalias + "." + attribute
}
-sealed abstract class Const extends RelAliasAttributeORConst
+sealed abstract class Const extends RelAliasAttributeORConst
case class ConstNULL() extends Const {
override def toString = "NULL"
}
@@ -51,23 +59,24 @@
case class AttrAlias(n:Name) {
override def toString = n.s /* "'" + n.s + "'" */
}
-sealed abstract class RelationORSubselect
-case class Relation(n:Name) extends RelationORSubselect {
- override def toString = n.s /* "'" + n.s + "'" */
-}
-case class Subselect(union:Union) extends RelationORSubselect {
- override def toString = "\n" + union + "\n)"
-}
case class RelAlias(n:Name) {
override def toString = n.s /* "'" + n.s + "'" */
}
case class TableList(joins:Set[Join]) {
- override def toString = " FROM " + (joins mkString ("\n INNER JOIN "))
+ override def toString = " 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) extends Join(res)
-case class LeftOuterJoin(res:AliasedResource, on:Expression) extends Join(res)
+case class InnerJoin(res:AliasedResource) 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
+}
case class AliasedResource(rel:RelationORSubselect, as:RelAlias) {
override def toString = rel + " AS " + as
@@ -123,8 +132,8 @@
case class Sql() extends JavaTokenParsers {
- def union:Parser[Union] =
- repsep(select, "UNION") ^^ { l => Union(l.toSet) }
+ def selectORunion:Parser[SelectORUnion] =
+ rep1sep(select, "UNION") ^^ { l => if (l.size == 1) l(0) else Union(l.toSet) }
def select:Parser[Select] =
"SELECT" ~ attributelist ~ "FROM" ~ tablelist ~ opt(where) ^^
@@ -164,7 +173,7 @@
def relationORsubselect:Parser[RelationORSubselect] = (
"""[a-zA-Z_]\w*""".r ^^ { x => Relation(Name(x)) }
- | "(" ~ union ~ ")" ^^ { case "("~s~")" => Subselect(s) }
+ | "(" ~ selectORunion ~ ")" ^^ { case "("~s~")" => Subselect(s) }
)
def relalias:Parser[RelAlias] =
--- a/src/test/scala/SQLTest.scala Sat Jan 02 16:33:28 2010 -0500
+++ b/src/test/scala/SQLTest.scala Sat Jan 02 18:34:46 2010 -0500
@@ -272,5 +272,32 @@
assert(expected === (a.parseAll(a.select, e).get))
}
+ test("parse LEFT OUTER SELECT") {
+ val a = Sql()
+ val e = """
+SELECT R_emp.lastName AS A_empName, R_mang.manageName AS A_manageName
+ FROM Employee AS R_emp
+ LEFT OUTER JOIN (
+ SELECT R_emp.lastName AS A_empName, R_mang.manageName AS A_manageName
+ FROM Employee AS R_emp
+ ) AS R_mang ON R_mang.emp=R_emp.id
+ WHERE R_emp.lastName IS NOT NULL
+"""
+ val expected =
+ Select(AttributeList(Set(NamedAttribute(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))),AttrAlias(Name("A_empName"))),
+ NamedAttribute(RelAliasAttribute(RelAlias(Name("R_mang")),Attribute(Name("manageName"))),AttrAlias(Name("A_manageName"))))),
+ TableList(Set(InnerJoin(AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))),
+ LeftOuterJoin(AliasedResource(
+ Subselect(Select(AttributeList(Set(NamedAttribute(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("lastName"))),AttrAlias(Name("A_empName"))),
+ NamedAttribute(RelAliasAttribute(RelAlias(Name("R_mang")),Attribute(Name("manageName"))),AttrAlias(Name("A_manageName"))))),
+ TableList(Set(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"))))))
+ assert(expected === (a.parseAll(a.select, e).get))
+ }
+
}