more operations;
authorwenzelm
Mon, 05 Sep 2016 11:51:25 +0200
changeset 63790 3d723062dc70
parent 63789 af28929ff219
child 63791 c6cbdfaae19e
more operations; tuned;
src/Pure/General/sql.scala
src/Pure/General/sqlite.scala
--- a/src/Pure/General/sql.scala	Mon Sep 05 11:43:37 2016 +0200
+++ b/src/Pure/General/sql.scala	Mon Sep 05 11:51:25 2016 +0200
@@ -55,7 +55,8 @@
   }
 
   abstract class Column[+A] private[SQL](
-    val name: String, val strict: Boolean, val primary_key: Boolean)
+      val name: String, val strict: Boolean, val primary_key: Boolean)
+    extends Function[ResultSet, A]
   {
     def sql_name: String = quote_ident(name)
     def sql_type: String
@@ -129,6 +130,9 @@
 
   class Table private[SQL](name: String, columns: List[Column[Any]])
   {
+    private val columns_index: Map[String, Int] =
+      columns.iterator.map(_.name).zipWithIndex.toMap
+
     Library.duplicates(columns.map(_.name)) match {
       case Nil =>
       case bad => error("Duplicate column names " + commas_quote(bad) + " for table " + quote(name))
@@ -148,7 +152,21 @@
     def sql_drop(strict: Boolean): String =
       "DROP TABLE " + (if (strict) "" else "IF EXISTS ") + quote_ident(name)
 
+    def sql_insert: String =
+      "INSERT INTO " + quote_ident(name) +
+      " VALUES " + columns.map(_ => "?").mkString("(", ", ", ")")
+
     override def toString: String =
       "TABLE " + quote_ident(name) + " " + columns.map(_.toString).mkString("(", ", ", ")")
   }
+
+
+  /* results */
+
+  def iterator[A](rs: ResultSet)(get: ResultSet => A): Iterator[A] = new Iterator[A]
+  {
+    private var _next: Boolean = rs.next()
+    def hasNext: Boolean = _next
+    def next: A = { val x = get(rs); _next = rs.next(); x }
+  }
 }
--- a/src/Pure/General/sqlite.scala	Mon Sep 05 11:43:37 2016 +0200
+++ b/src/Pure/General/sqlite.scala	Mon Sep 05 11:51:25 2016 +0200
@@ -14,6 +14,15 @@
 {
   /** database connection **/
 
+  def open_database(path: Path): Database =
+  {
+    val path0 = path.expand
+    val s0 = File.platform_path(path0)
+    val s1 = if (Platform.is_windows) s0.replace('\\', '/') else s0
+    val connection = DriverManager.getConnection("jdbc:sqlite:" + s1)
+    new Database(path0, connection)
+  }
+
   class Database private [SQLite](path: Path, val connection: Connection)
   {
     override def toString: String = path.toString
@@ -35,37 +44,23 @@
       finally { connection.setAutoCommit(auto_commit) }
     }
 
-    def with_statement[A](sql: String)(body: PreparedStatement => A): A =
-    {
-      val stmt = connection.prepareStatement(sql)
-      try { body(stmt) } finally { stmt.close }
-    }
+
+    /* prepared statements */
+
+    def statement(sql: String): PreparedStatement = connection.prepareStatement(sql)
+
+    def insert_statement(table: SQL.Table): PreparedStatement = statement(table.sql_insert)
 
 
     /* tables */
 
+    def tables: List[String] =
+      SQL.iterator(connection.getMetaData.getTables(null, null, "%", null))(_.getString(3)).toList
+
     def create_table(table: SQL.Table, strict: Boolean = true, rowid: Boolean = true): Unit =
-      with_statement(table.sql_create(strict, rowid))(_.execute())
+      using(statement(table.sql_create(strict, rowid)))(_.execute())
 
     def drop_table(table: SQL.Table, strict: Boolean = true): Unit =
-      with_statement(table.sql_drop(strict))(_.execute())
-  }
-
-
-  /* open database */
-
-  def open_database(path: Path): Database =
-  {
-    val path0 = path.expand
-    val s0 = File.platform_path(path0)
-    val s1 = if (Platform.is_windows) s0.replace('\\', '/') else s0
-    val connection = DriverManager.getConnection("jdbc:sqlite:" + s1)
-    new Database(path0, connection)
-  }
-
-  def with_database[A](path: Path)(body: Database => A): A =
-  {
-    val db = open_database(path)
-    try { body(db) } finally { db.close }
+      using(statement(table.sql_drop(strict)))(_.execute())
   }
 }