loader: build_module_importation invalidates the mmodule on errors
[nit.git] / lib / sqlite3 / native_sqlite3.nit
index 10cb886..6419ea8 100644 (file)
@@ -22,6 +22,11 @@ in "C header" `{
        #include <sqlite3.h>
 `}
 
+redef class Sys
+       # Last error raised when calling `Sqlite3::open`
+       var sqlite_open_error: nullable Sqlite3Code = null
+end
+
 extern class Sqlite3Code `{int`}
        new ok `{ return SQLITE_OK; `} #         0   /* Successful result */
        fun is_ok: Bool `{ return recv == SQLITE_OK; `}
@@ -89,6 +94,7 @@ extern class NativeStatement `{sqlite3_stmt*`}
                return NativeString_to_s(ret);
        `}
 
+       # Number of bytes in the blob or string at row `i`
        fun column_bytes(i: Int) : Int `{
                return sqlite3_column_bytes(recv, i);
        `}
@@ -101,15 +107,12 @@ extern class NativeStatement `{sqlite3_stmt*`}
                return sqlite3_column_int(recv, i);
        `}
 
-       fun column_text(i: Int) : String import NativeString.to_s `{
-               char * ret = (char *) sqlite3_column_text(recv, i);
-               if( ret == NULL ){
-                       ret = "";
-               }
-               return NativeString_to_s(ret);
+       fun column_text(i: Int): NativeString `{
+               return (char *)sqlite3_column_text(recv, i);
        `}
 
-       fun column_type(i: Int) : Int `{
+       # Type of the entry at row `i`
+       fun column_type(i: Int): DataType `{
                return sqlite3_column_type(recv, i);
        `}
 
@@ -130,12 +133,18 @@ end
 extern class NativeSqlite3 `{sqlite3 *`}
 
        # Open a connection to a database in UTF-8
-       new open(filename: String) import String.to_cstring `{
+       new open(filename: String) import String.to_cstring, set_sys_sqlite_open_error `{
                sqlite3 *self = NULL;
-               sqlite3_open(String_to_cstring(filename), &self);
+               int err = sqlite3_open(String_to_cstring(filename), &self);
+               NativeSqlite3_set_sys_sqlite_open_error(self, (void*)(long)err);
+               // The previous cast is a hack, using non pointers in extern classes is not
+               // yet in the spec of the FFI.
                return self;
        `}
 
+       # Utility method to set `Sys.sqlite_open_error`
+       private fun set_sys_sqlite_open_error(err: Sqlite3Code) do sys.sqlite_open_error = err
+
        # Has this DB been correctly opened?
        #
        # To know if it has been closed or interrupted, you must check for errors with `error`.
@@ -144,7 +153,16 @@ extern class NativeSqlite3 `{sqlite3 *`}
        fun destroy do close
 
        # Close this connection
-       fun close `{ sqlite3_close_v2(recv); `}
+       fun close `{
+#if SQLITE_VERSION_NUMBER >= 3007014
+               sqlite3_close_v2(recv);
+#else
+               // A program using the older version should not rely on the garbage-collector
+               // to close its connections. They must be closed manually after the associated
+               // prepare statements have been finalized.
+               sqlite3_close(recv);
+#endif
+       `}
 
        # Execute a SQL statement
        fun exec(sql: String): Sqlite3Code import String.to_cstring `{
@@ -169,3 +187,14 @@ extern class NativeSqlite3 `{sqlite3 *`}
                return sqlite3_errcode(recv);
        `}
 end
+
+# Sqlite data types
+extern class DataType `{ int `}
+       fun is_integer: Bool `{ return recv == SQLITE_INTEGER; `}
+       fun is_float: Bool `{ return recv == SQLITE_FLOAT; `}
+       fun is_blob: Bool `{ return recv == SQLITE_BLOB; `}
+       fun is_null: Bool `{ return recv == SQLITE_NULL; `}
+       fun is_text: Bool `{ return recv == SQLITE_TEXT; `}
+
+       fun to_i: Int `{ return recv; `}
+end