package unqlitego /* #cgo linux CFLAGS: -DUNQLITE_ENABLE_THREADS=1 -Wno-unused-but-set-variable #cgo darwin CFLAGS: -DUNQLITE_ENABLE_THREADS=1 #cgo windows CFLAGS: -DUNQLITE_ENABLE_THREADS=1 #include "./unqlite.h" #include */ import "C" import ( "fmt" "runtime" "unsafe" ) // UnQLiteError ... standard error for this module type UnQLiteError int func (e UnQLiteError) Error() string { s := errString[e] if s == "" { return fmt.Sprintf("errno %d", int(e)) } return s } var errString = map[UnQLiteError]string{ C.UNQLITE_LOCKERR: "Locking protocol error", C.UNQLITE_READ_ONLY: "Read only Key/Value storage engine", C.UNQLITE_CANTOPEN: "Unable to open the database file", C.UNQLITE_FULL: "Full database", C.UNQLITE_VM_ERR: "Virtual machine error", C.UNQLITE_COMPILE_ERR: "Compilation error", C.UNQLITE_DONE: "Operation done", // Not an error. C.UNQLITE_CORRUPT: "Corrupt pointer", C.UNQLITE_NOOP: "No such method", C.UNQLITE_PERM: "Permission error", C.UNQLITE_EOF: "End Of Input", C.UNQLITE_NOTIMPLEMENTED: "Method not implemented by the underlying Key/Value storage engine", C.UNQLITE_BUSY: "The database file is locked", C.UNQLITE_UNKNOWN: "Unknown configuration option", C.UNQLITE_EXISTS: "Record exists", C.UNQLITE_ABORT: "Another thread have released this instance", C.UNQLITE_INVALID: "Invalid parameter", C.UNQLITE_LIMIT: "Database limit reached", C.UNQLITE_NOTFOUND: "No such record", C.UNQLITE_LOCKED: "Forbidden Operation", C.UNQLITE_EMPTY: "Empty record", C.UNQLITE_IOERR: "IO error", C.UNQLITE_NOMEM: "Out of memory", } // Database ... type Database struct { handle *C.unqlite } // Cursor ... type Cursor struct { parent *Database handle *C.unqlite_kv_cursor } func init() { C.unqlite_lib_init() if !IsThreadSafe() { panic("unqlite library was not compiled for thread-safe option UNQLITE_ENABLE_THREADS=1") } } // NewDatabase ... func NewDatabase(filename string) (db *Database, err error) { db = &Database{} name := C.CString(filename) defer C.free(unsafe.Pointer(name)) res := C.unqlite_open(&db.handle, name, C.UNQLITE_OPEN_CREATE) if res != C.UNQLITE_OK { err = UnQLiteError(res) } if db.handle != nil { runtime.SetFinalizer(db, (*Database).Close) } return } // Close ... func (db *Database) Close() (err error) { if db.handle != nil { res := C.unqlite_close(db.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } db.handle = nil } return } // Store ... func (db *Database) Store(key, value []byte) (err error) { var k, v unsafe.Pointer if len(key) > 0 { k = unsafe.Pointer(&key[0]) } if len(value) > 0 { v = unsafe.Pointer(&value[0]) } res := C.unqlite_kv_store(db.handle, k, C.int(len(key)), v, C.unqlite_int64(len(value))) if res == C.UNQLITE_OK { return nil } return UnQLiteError(res) } // Append ... func (db *Database) Append(key, value []byte) (err error) { var k, v unsafe.Pointer if len(key) > 0 { k = unsafe.Pointer(&key[0]) } if len(value) > 0 { v = unsafe.Pointer(&value[0]) } res := C.unqlite_kv_append(db.handle, k, C.int(len(key)), v, C.unqlite_int64(len(value))) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Fetch ... func (db *Database) Fetch(key []byte) (value []byte, err error) { var k unsafe.Pointer if len(key) > 0 { k = unsafe.Pointer(&key[0]) } var n C.unqlite_int64 res := C.unqlite_kv_fetch(db.handle, k, C.int(len(key)), nil, &n) if res != C.UNQLITE_OK { err = UnQLiteError(res) return } value = make([]byte, int(n)) res = C.unqlite_kv_fetch(db.handle, k, C.int(len(key)), unsafe.Pointer(&value[0]), &n) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Delete ... func (db *Database) Delete(key []byte) (err error) { var k unsafe.Pointer if len(key) > 0 { k = unsafe.Pointer(&key[0]) } res := C.unqlite_kv_delete(db.handle, k, C.int(len(key))) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Begin ... func (db *Database) Begin() (err error) { res := C.unqlite_begin(db.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Commit ... func (db *Database) Commit() (err error) { res := C.unqlite_commit(db.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Rollback ... func (db *Database) Rollback() (err error) { res := C.unqlite_rollback(db.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // NewCursor ... func (db *Database) NewCursor() (cursor *Cursor, err error) { cursor = &Cursor{parent: db} res := C.unqlite_kv_cursor_init(db.handle, &cursor.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } runtime.SetFinalizer(cursor, (*Cursor).Close) return } // Close ... func (curs *Cursor) Close() (err error) { if curs.parent.handle != nil && curs.handle != nil { res := C.unqlite_kv_cursor_release(curs.parent.handle, curs.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } curs.handle = nil } return } // Seek ... func (curs *Cursor) Seek(key []byte) (err error) { var k unsafe.Pointer if len(key) > 0 { k = unsafe.Pointer(&key[0]) } res := C.unqlite_kv_cursor_seek(curs.handle, k, C.int(len(key)), C.UNQLITE_CURSOR_MATCH_EXACT) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // SeekLE ... func (curs *Cursor) SeekLE(key []byte) (err error) { var k unsafe.Pointer if len(key) > 0 { k = unsafe.Pointer(&key[0]) } res := C.unqlite_kv_cursor_seek(curs.handle, k, C.int(len(key)), C.UNQLITE_CURSOR_MATCH_LE) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // SeekGE ... func (curs *Cursor) SeekGE(key []byte) (err error) { var k unsafe.Pointer if len(key) > 0 { k = unsafe.Pointer(&key[0]) } res := C.unqlite_kv_cursor_seek(curs.handle, k, C.int(len(key)), C.UNQLITE_CURSOR_MATCH_GE) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // First ... func (curs *Cursor) First() (err error) { res := C.unqlite_kv_cursor_first_entry(curs.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Last ... func (curs *Cursor) Last() (err error) { res := C.unqlite_kv_cursor_last_entry(curs.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // IsValid ... func (curs *Cursor) IsValid() (ok bool) { return C.unqlite_kv_cursor_valid_entry(curs.handle) == 1 } // Next ... func (curs *Cursor) Next() (err error) { res := C.unqlite_kv_cursor_next_entry(curs.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Prev ... func (curs *Cursor) Prev() (err error) { res := C.unqlite_kv_cursor_prev_entry(curs.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Delete ... func (curs *Cursor) Delete() (err error) { res := C.unqlite_kv_cursor_delete_entry(curs.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Reset ... func (curs *Cursor) Reset() (err error) { res := C.unqlite_kv_cursor_reset(curs.handle) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Key ... func (curs *Cursor) Key() (key []byte, err error) { var n C.int res := C.unqlite_kv_cursor_key(curs.handle, nil, &n) if res != C.UNQLITE_OK { err = UnQLiteError(res) return } key = make([]byte, int(n)) res = C.unqlite_kv_cursor_key(curs.handle, unsafe.Pointer(&key[0]), &n) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Value ... func (curs *Cursor) Value() (value []byte, err error) { var n C.unqlite_int64 res := C.unqlite_kv_cursor_data(curs.handle, nil, &n) if res != C.UNQLITE_OK { err = UnQLiteError(res) return } value = make([]byte, int(n)) res = C.unqlite_kv_cursor_data(curs.handle, unsafe.Pointer(&value[0]), &n) if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // Shutdown ... func Shutdown() (err error) { res := C.unqlite_lib_shutdown() if res != C.UNQLITE_OK { err = UnQLiteError(res) } return } // IsThreadSafe ... func IsThreadSafe() bool { return C.unqlite_lib_is_threadsafe() == 1 } // Version ... func Version() string { return C.GoString(C.unqlite_lib_version()) } // Signature ... func Signature() string { return C.GoString(C.unqlite_lib_signature()) } // Ident ... func Ident() string { return C.GoString(C.unqlite_lib_ident()) } // Copyright ... func Copyright() string { return C.GoString(C.unqlite_lib_copyright()) } /* TODO: implement // Database Engine Handle int unqlite_config(unqlite *pDb,int nOp,...); // Key/Value (KV) Store Interfaces int unqlite_kv_fetch_callback(unqlite *pDb,const void *pKey, int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); int unqlite_kv_config(unqlite *pDb,int iOp,...); // Cursor Iterator Interfaces int unqlite_kv_cursor_key_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); int unqlite_kv_cursor_data_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); // Utility interfaces int unqlite_util_load_mmaped_file(const char *zFile,void **ppMap,unqlite_int64 *pFileSize); int unqlite_util_release_mmaped_file(void *pMap,unqlite_int64 iFileSize); // Global Library Management Interfaces int unqlite_lib_config(int nConfigOp,...); */