niti: simply use `cc` as compiler
[nit.git] / lib / sqlite3 / sqlite3.nit
index 6856d9d..62fe8e5 100644 (file)
@@ -20,7 +20,7 @@
 module sqlite3
 
 private import native_sqlite3
-import standard
+import core
 
 # A connection to a Sqlite3 database
 class Sqlite3DB
@@ -35,13 +35,15 @@ class Sqlite3DB
        # Open a connection to the database file at `path`
        init open(path: Text)
        do
-               native_connection = new NativeSqlite3.open(path.to_s)
+               init(new NativeSqlite3.open(path.to_cstring))
                if native_connection.is_valid then is_open = true
        end
 
        # Close this connection to the DB and all open statements
        fun close
        do
+               if not is_open then return
+
                is_open = false
 
                # close open statements
@@ -105,20 +107,37 @@ class Sqlite3DB
                if err.is_ok then return null
                return err.to_s
        end
+
+       # Returns the id for the last successful insert on the current connection.
+       fun last_insert_rowid: Int do return native_connection.last_insert_rowid
 end
 
-# A prepared Sqlite3 statement, created from `Sqlite3DB::prepare` or `Sqlite3DB::select`
+# Prepared Sqlite3 statement
+#
+# Instances of this class are created from `Sqlite3DB::prepare` and
+# its shortcuts: `create_table`, `insert`, `replace` and `select`.
+# The results should be explored with an `iterator`,
+# and each call to `iterator` resets the request.
+# If `close_with_iterator` the iterator calls `close`
+# on this request upon finishing.
 class Statement
        private var native_statement: NativeStatement
 
-       private init(ns: NativeStatement) do self.native_statement = ns
-
        # Is this statement usable?
        var is_open = true
 
+       # Should any `iterator` close this statement on `Iterator::finish`?
+       #
+       # If `true`, the default, any `StatementIterator` created by calls to
+       # `iterator` invokes `close` on this request when finished iterating.
+       # Otherwise, `close` must be called manually.
+       var close_with_iterator = true is writable
+
        # Close and finalize this statement
        fun close
        do
+               if not is_open then return
+
                is_open = false
                native_statement.finalize
        end
@@ -127,17 +146,15 @@ class Statement
        fun iterator: StatementIterator
        do
                native_statement.reset
-               native_statement.step
                return new StatementIterator(self)
        end
 end
 
+# A row from a `Statement`
 class StatementRow
        # Statement linked to `self`
        var statement: Statement
 
-       private init(s: Statement) do self.statement = s
-
        # Number of entries in this row
        #
        # require: `self.statement.is_open`
@@ -159,16 +176,10 @@ class StatementEntry
 
        private var index: Int
 
-       private init(s: Statement, i: Int)
-       do
-               self.statement = s
-               self.index = i
-       end
-
        # Name of the column
        #
        # require: `self.statement.is_open`
-       fun name: String is cached do
+       var name: String is lazy do
                assert statement_closed: statement.is_open
 
                return statement.native_statement.column_name(index)
@@ -228,7 +239,7 @@ class StatementEntry
 
                var native_string = statement.native_statement.column_text(index)
                if native_string.address_is_null then return ""
-               return native_string.to_s
+               return native_string.to_s_with_copy
        end
 
        # Get this entry as `Blob`
@@ -256,15 +267,15 @@ class StatementIterator
        # Statement linked to `self`
        var statement: Statement
 
-       private init(s: Statement)
+       init
        do
-               self.statement = s
-               self.item = new StatementRow(s)
+               self.item = new StatementRow(statement)
+               self.is_ok = statement.native_statement.step.is_row
        end
 
-       redef var item: StatementRow
+       redef var item: StatementRow is noinit
 
-       redef var is_ok = true
+       redef var is_ok is noinit
 
        # require: `self.statement.is_open`
        redef fun next
@@ -283,22 +294,26 @@ class StatementIterator
                        is_ok = false
                end
        end
+
+       redef fun finish do if statement.close_with_iterator then statement.close
 end
 
 # A data type supported by Sqlite3
 interface Sqlite3Data end
 
 redef universal Int super Sqlite3Data end
+
 redef universal Float super Sqlite3Data end
+
 redef class String
        super Sqlite3Data
 
-       # Return `self` between `'`s and escaping any extra `'`
+       # Return `self` between `'`s, escaping `\` and `'`
        #
        #     assert "'; DROP TABLE students".to_sql_string == "'''; DROP TABLE students'"
        fun to_sql_string: String
        do
-               return "'{self.replace('\'', "''")}'"
+               return "'{self.replace('\\', "\\\\").replace('\'', "''")}'"
        end
 end
 
@@ -306,12 +321,9 @@ end
 class Blob
        super Sqlite3Data
 
-       private init(pointer: Pointer, length: Int)
-       do
-               self.pointer = pointer
-               self.length = length
-       end
-
+       # Pointer to the beginning of the blob
        var pointer: Pointer
+
+       # Size of the blob
        var length: Int
 end