+ INNER JOIN ... ON goes into WHERE expressions
--- a/src/main/scala/SQL.scala Mon Jan 04 15:48:21 2010 -0500
+++ b/src/main/scala/SQL.scala Mon Jan 04 17:03:53 2010 -0500
@@ -89,6 +89,9 @@
case class RelationalExpressionLt(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"
}
@@ -135,7 +138,27 @@
def select:Parser[Select] =
"SELECT" ~ attributelist ~ "FROM" ~ tablelist ~ opt(where) ^^
- { case "SELECT" ~ attributes ~ "FROM" ~ tables ~ whereexpr => Select(attributes, tables, whereexpr) }
+ {
+ case "SELECT" ~ attributes ~ "FROM" ~ tablesANDons ~ whereexpr => {
+ val t:Set[Expression] = tablesANDons._2
+ val onConjoints = tablesANDons._2.foldLeft(Set[Expression]())((set, ent) =>
+ 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(attributes, tablesANDons._1, expr)
+ }
+ }
def where:Parser[Expression] =
"WHERE" ~ expression ^^ { case "WHERE" ~ expression => expression }
@@ -171,12 +194,15 @@
def relalias:Parser[RelAlias] =
"""[a-zA-Z_]\w*""".r ^^ { x => RelAlias(Name(x)) }
- def tablelist:Parser[TableList] =
- aliasedjoin ~ rep(innerORouter) ^^ { case aj~l => TableList(AddOrderedSet(InnerJoin(aj) :: l)) }
+ def tablelist:Parser[(TableList, Set[Expression])] =
+ aliasedjoin ~ rep(innerORouter) ^^ { case aj~l => (TableList(AddOrderedSet(InnerJoin(aj) :: l.map((one) => one._1))),
+ l.foldLeft(Set[Expression]())((all, one) => all ++ one._2)) }
- def innerORouter:Parser[Join] = (
- "INNER" ~ "JOIN" ~ aliasedjoin ^^ { case "INNER"~"JOIN"~a => InnerJoin(a) }
- | "LEFT" ~ "OUTER" ~ "JOIN" ~ aliasedjoin ~ "ON" ~ expression ^^ { case l~o~j~alijoin~on~expr => LeftOuterJoin(alijoin, expr) }
+ def innerORouter:Parser[(Join, Set[Expression])] = (
+ "INNER" ~ "JOIN" ~ aliasedjoin ~ opt("ON" ~ expression) ^^
+ { case "INNER"~"JOIN"~a~o => (InnerJoin(a), { 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] =
@@ -201,6 +227,8 @@
{ case primaryexpression ~ "!=" ~ rvalue => RelationalExpressionNe(primaryexpression, rvalue) }
| primaryexpression ~ "<" ~ primaryexpression ^^
{ case primaryexpression ~ "<" ~ rvalue => RelationalExpressionLt(primaryexpression, rvalue) }
+ | primaryexpression ~ "IS" ~ "NULL" ^^
+ { case primaryexpression ~ "IS" ~ "NULL" => RelationalExpressionNull(primaryexpression) }
| primaryexpression ~ "IS" ~ "NOT" ~ "NULL" ^^
{ case primaryexpression ~ "IS" ~ "NOT" ~ "NULL" => RelationalExpressionNotNull(primaryexpression) }
| primaryexpression ^^
--- a/src/test/scala/SQLTest.scala Mon Jan 04 15:48:21 2010 -0500
+++ b/src/test/scala/SQLTest.scala Mon Jan 04 17:03:53 2010 -0500
@@ -48,6 +48,45 @@
assert(expected === (a.parseAll(a.expression, e).get))
}
+ test("parse WHERE") {
+ // AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))
+ val a = Sql()
+ val e = """
+SELECT R_emp.lastName AS A_empName
+ FROM Employee AS R_emp
+ INNER JOIN Employee AS R_manager
+ WHERE R_manager.id=R_emp.manager
+"""
+ val expected = Select(AttributeList(Set(NamedAttribute(RelAliasAttribute(RelAlias(Name("R_emp")),
+ Attribute(Name("lastName"))),
+ 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(
+ RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id")))),
+ PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager")))))))
+ assert(expected === (a.parseAll(a.select, e).get))
+ }
+
+ test("parse INNER JOIN ON") {
+ // AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))
+ val a = Sql()
+ val e = """
+SELECT R_emp.lastName AS A_empName
+ FROM Employee AS R_emp
+ INNER JOIN Employee AS R_manager ON R_manager.id=R_emp.manager
+"""
+ val expected = Select(AttributeList(Set(NamedAttribute(RelAliasAttribute(RelAlias(Name("R_emp")),
+ Attribute(Name("lastName"))),
+ 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(
+ RelationalExpressionEq(PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_manager")),Attribute(Name("id")))),
+ PrimaryExpressionAttr(RelAliasAttribute(RelAlias(Name("R_emp")),Attribute(Name("manager")))))))
+ assert(expected === (a.parseAll(a.select, e).get))
+ }
+
test("parse SQLbgp") {
// AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))
val a = Sql()