--- a/rdb/src/main/scala/RDB.scala Tue Nov 02 16:55:25 2010 -0400
+++ b/rdb/src/main/scala/RDB.scala Tue Nov 02 17:14:43 2010 -0400
@@ -14,7 +14,12 @@
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 Relation (name:RelName, header:Header, body:List[Tuple], candidates:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys) {
+ def ++ (t:Tuple):Relation = {
+ val b2:List[RDB.Tuple] = body ++ List(t)
+ Relation(name, header, b2, candidates, pk, fks)
+ }
+ }
case class Header (m:Map[AttrName, Datatype]) {
def apply (a:AttrName) = m(a)
--- a/sql/src/main/scala/SQL.scala Tue Nov 02 16:55:25 2010 -0400
+++ b/sql/src/main/scala/SQL.scala Tue Nov 02 17:14:43 2010 -0400
@@ -166,6 +166,7 @@
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 CandidateKeyDeclaration(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
@@ -177,16 +178,27 @@
"CREATE" ~ "VIEW" ~ relation ~ "AS" ~ selectORunion ^^
{ case "CREATE"~"VIEW"~relation~"AS"~defn => View(relation, defn) }
+ sealed abstract class DataDefinition
+ case class Create(rn:RDB.RelName, relation:RDB.Relation) extends DataDefinition
+ case class Insert(rn:RDB.RelName, tuple:RDB.Tuple) extends DataDefinition
+
def ddl:Parser[RDB.Database] =
- rep1sep(createtable, ";") ~ opt(";") ^^
+ rep1sep(createorinsert, ";") ~ 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)
+ p match {
+ case Create(rn:RDB.RelName, relation:RDB.Relation) => m + (rn -> relation)
+ case Insert(rn:RDB.RelName, tuple:RDB.Tuple) => m + (rn -> (m(rn) ++ tuple)) // add the tuple
+ }
}))
}
- def createtable:Parser[(RDB.RelName, RDB.Relation)] =
+ def createorinsert:Parser[DataDefinition] = (
+ createtable ^^ { case c => c }
+ | inserttable ^^ { case c => c }
+ )
+
+ def createtable:Parser[Create] =
"CREATE" ~ "TABLE" ~ relation ~ "(" ~ rep1sep(fielddescorkeydef, ",") ~ ")" ^^
{
case "CREATE"~"TABLE"~relation~"("~reldesc~")" => {
@@ -211,12 +223,26 @@
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 CandidateKeyDeclaration(key) =>
+ // @@ why doesn't [[ candidates + RDB.CandidateKey(attr.n) ]] work?
+ (pkopt, 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)
+ Create(relation, rd)
+ }
+ }
+
+ def inserttable:Parser[Insert] =
+ "INSERT" ~ "INTO" ~ relation ~ "(" ~ rep1sep(attribute, ",") ~ ")" ~ "VALUES" ~ "(" ~ rep1sep(value, ",") ~ ")" ^^
+ {
+ case "INSERT"~"INTO"~relation~"("~relnames~")"~"VALUES"~"("~values~")" => {
+ if (relnames.size != values.size)
+ error("different numbers of elements in names " + relnames + " vs. values " + values)
+ Map.empty ++ (relnames zip values)
+ Insert(relation, RDB.Tuple(Map.empty ++ (relnames zip values)))
}
}
@@ -225,12 +251,15 @@
{ case attribute~typpe~pkness => FieldDesc(attribute, typpe, pkness.isDefined) }
| "PRIMARY" ~ "KEY" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
{ case "PRIMARY"~"KEY"~"("~attributes~")" => PrimaryKeyDeclaration(RDB.CandidateKey(attributes)) }
+ | "UNIQUE" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
+ { case "UNIQUE"~"("~attributes~")" => CandidateKeyDeclaration(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 }
+ "INT" ^^ { case _ => RDB.Datatype.INTEGER } // alias for INTEGER
+ | "INTEGER" ^^ { case _ => RDB.Datatype.INTEGER }
| "DOUBLE" ^^ { case _ => RDB.Datatype.DOUBLE }
| "STRING" ^^ { case _ => RDB.Datatype.STRING }
| "DATETIME" ^^ { case _ => RDB.Datatype.DATETIME }
@@ -373,6 +402,12 @@
| "(" ~ expression ~ ")" ^^ { case "("~x~")" => x }
)
+ def value:Parser[RDB.CellValue] = (
+ int ^^ { i => RDB.LexicalValue(i) }
+ | chars ^^ { x => RDB.LexicalValue(x.substring(1, x.size - 1)) }
+ | "NULL" ^^ { case "NULL" => RDB.␀() }
+ )
+
}
case class PrettySql(select:Select) {