module sqlite3
private import native_sqlite3
-import standard
+import core
# A connection to a Sqlite3 database
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
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
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`
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)
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`
# 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
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
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