Browse files

Fix for issue #11 along with tidying up of error status handling

  • Loading branch information...
1 parent 5174223 commit d6cf7d5fb19aaca9d88f76d01194b95a25854eed @feyeleanor feyeleanor committed Feb 18, 2012
Showing with 64 additions and 76 deletions.
  1. +20 −11 database.go
  2. +22 −0 database_test.go
  3. +9 −16 query_parameter.go
  4. +13 −49 statement.go
View
31 database.go
@@ -84,6 +84,13 @@ var errText = map[Errno]string{
SAVEPOINT: "invalid or unknown savepoint identifier",
}
+func SQLiteError(code C.int) (e error) {
+ if e = Errno(code); e == OK {
+ e = nil
+ }
+ return
+}
+
// Database implements high level view of the underlying database.
type Database struct {
handle *C.sqlite3
@@ -127,9 +134,15 @@ func (db *Database) Open(flags ...int) (e error) {
for _, v := range flags {
db.Flags = db.Flags | C.int(v)
}
- if err := Errno(C.sqlite3_open_v2(C.CString(db.Filename), &db.handle, db.Flags, nil)); err != OK {
- e = err
- } else if db.handle == nil {
+
+ e = SQLiteError(C.sqlite3_open_v2(C.CString(db.Filename), &db.handle, db.Flags, nil))
+
+// if err :; err != OK {
+// e = err
+// } else if db.handle == nil {
+// e = CANTOPEN
+// }
+ if e == nil && db.handle == nil {
e = CANTOPEN
}
}
@@ -191,8 +204,8 @@ func (db *Database) Error() error {
// supplied values.
func (db *Database) Prepare(sql string, values ...interface{}) (s *Statement, e error) {
s = &Statement{db: db, timestamp: time.Now().UnixNano()}
- if rv := Errno(C.sqlite3_prepare_v2(db.handle, C.CString(sql), -1, &s.cptr, nil)); rv != OK {
- s, e = nil, rv
+ if e = SQLiteError(C.sqlite3_prepare_v2(db.handle, C.CString(sql), -1, &s.cptr, nil)); e != nil {
+ s = nil
} else {
if len(values) > 0 {
e, _ = s.BindAll(values...)
@@ -204,13 +217,9 @@ func (db *Database) Prepare(sql string, values ...interface{}) (s *Statement, e
// Execute runs the SQL statement.
func (db *Database) Execute(sql string, f ...func(*Statement, ...interface{})) (c int, e error) {
var st *Statement
- st, e = db.Prepare(sql)
- if e == nil {
+ if st, e = db.Prepare(sql); e == nil {
c, e = st.All(f...)
}
- if e == OK {
- e = nil
- }
return
}
@@ -353,7 +362,7 @@ func (db *Database) Backup(p BackupParameters) (r Reporter, e error) {
Remaining: backup.Remaining(),
}
r <- report
- if e, ok := report.Error.(Errno); ok && !(e == OK || e == BUSY || e == LOCKED) {
+ if e := report.Error; !(e == nil || e == BUSY || e == LOCKED) {
break
}
if p.Interval > 0 {
View
22 database_test.go
@@ -102,4 +102,26 @@ func TestBackup(t *testing.T) {
t.Logf("backup of %v generated %v asynchronous messages and took %vns with interval %v", db.Filename, messages, time.Now().UnixNano() - d, 100000)
}
})
+}
+
+func TestExecute(t *testing.T) {
+ t.Log("Test case for issue #11")
+ db := TransientDatabase()
+ // OPEN_FULLMUTEX, OPEN_READWRITE, OPEN_CREATE
+ if e := db.Open(0x10000, 0x02, 0x04); e != nil {
+ t.Logf("Open failed: %v", e)
+ }
+ defer db.Close()
+ if _, e := db.Execute("CREATE TABLE t(id INTEGER PRIMARY KEY ASC, unique_int INTEGER UNIQUE);"); e != nil {
+ t.Logf("Create table failed: %v", e)
+ }
+ if _, e := db.Execute("INSERT INTO t ( unique_int ) VALUES ( 1 );"); e != nil {
+ t.Logf("1. Insert failed: %v", e)
+ }
+ if _, e := db.Execute("INSERT INTO t ( unique_int ) VALUES ( 2 );"); e != nil {
+ t.Logf("2. Insert failed: %v", e)
+ }
+ if _, e := db.Execute("INSERT INTO t ( unique_int ) VALUES ( 2 );"); e == nil {
+ t.Logf("3. Insert succeeded: %v", e)
+ }
}
View
25 query_parameter.go
@@ -16,10 +16,7 @@ import (
type QueryParameter int
func (p QueryParameter) bind_blob(s *Statement, v []byte) error {
- if e := Errno(C.gosqlite3_bind_blob(s.cptr, C.int(p), unsafe.Pointer(C.CString(string(v))), C.int(len(v)))); e != OK {
- return e
- }
- return nil
+ return SQLiteError(C.gosqlite3_bind_blob(s.cptr, C.int(p), unsafe.Pointer(C.CString(string(v))), C.int(len(v))))
}
// Bind replaces the literals placed in the SQL statement with the actual
@@ -34,32 +31,28 @@ func (p QueryParameter) bind_blob(s *Statement, v []byte) error {
// In the templates above, NNN represents an integer literal, VVV represents
// an alphanumeric identifier.
func (p QueryParameter) Bind(s *Statement, value interface{}) (e error) {
- var rv Errno
switch v := value.(type) {
case nil:
- rv = Errno(C.sqlite3_bind_null(s.cptr, C.int(p)))
+ e = SQLiteError(C.sqlite3_bind_null(s.cptr, C.int(p)))
case int:
- rv = Errno(C.sqlite3_bind_int(s.cptr, C.int(p), C.int(v)))
+ e = SQLiteError(C.sqlite3_bind_int(s.cptr, C.int(p), C.int(v)))
case string:
- rv = Errno(C.gosqlite3_bind_text(s.cptr, C.int(p), C.CString(v), C.int(len(v))))
+ e = SQLiteError(C.gosqlite3_bind_text(s.cptr, C.int(p), C.CString(v), C.int(len(v))))
case int64:
- rv = Errno(C.sqlite3_bind_int64(s.cptr, C.int(p), C.sqlite3_int64(v)))
+ e = SQLiteError(C.sqlite3_bind_int64(s.cptr, C.int(p), C.sqlite3_int64(v)))
case float32:
- rv = Errno(C.sqlite3_bind_double(s.cptr, C.int(p), C.double(v)))
+ e = SQLiteError(C.sqlite3_bind_double(s.cptr, C.int(p), C.double(v)))
case float64:
- rv = Errno(C.sqlite3_bind_double(s.cptr, C.int(p), C.double(v)))
+ e = SQLiteError(C.sqlite3_bind_double(s.cptr, C.int(p), C.double(v)))
default:
buffer := new(bytes.Buffer)
encoder := gob.NewEncoder(buffer)
if encoder.Encode(value) != nil {
- rv = ENCODER
+ e = ENCODER
} else {
rawbuffer := string(buffer.Bytes())
- rv = Errno(C.gosqlite3_bind_blob(s.cptr, C.int(p), unsafe.Pointer(C.CString(rawbuffer)), C.int(len(rawbuffer))))
+ e = SQLiteError(C.gosqlite3_bind_blob(s.cptr, C.int(p), unsafe.Pointer(C.CString(rawbuffer)), C.int(len(rawbuffer))))
}
}
- if rv != OK {
- e = rv
- }
return
}
View
62 statement.go
@@ -78,62 +78,32 @@ func (s *Statement) SQLSource() (sql string) {
}
// Finalize is used to delete a prepared statement in the SQLite engine.
-func (s *Statement) Finalize() error {
- if e := Errno(C.sqlite3_finalize(s.cptr)); e != OK {
- return e
- }
- return nil
+func (s *Statement) Finalize() (e error) {
+ return SQLiteError(C.sqlite3_finalize(s.cptr))
}
// Step must be called one or more times to evaluate the statement after the
// prepared statement has been prepared.
func (s *Statement) Step(f... func(*Statement, ...interface{})) (e error) {
- r := Errno(C.sqlite3_step(s.cptr))
- switch r {
- case DONE:
- e = nil
+ switch e = SQLiteError(C.sqlite3_step(s.cptr)); e {
case ROW:
- if f != nil {
- defer func() {
- switch x := recover().(type) {
- case nil: e = ROW
- case error: e = x
- default: e = MISUSE
- }
- }()
- r := s.Row()
- for _, fn := range f {
- fn(s, r...)
- }
+ row := s.Row()
+ for _, fn := range f {
+ fn(s, row...)
}
- default:
- e = r
+ case DONE:
+ e = s.Reset()
}
return
}
// All can be used to return all rows of a prepared statement after the
// statement has been prepared.
func (s *Statement) All(f... func(*Statement, ...interface{})) (c int, e error) {
- for {
- if e = s.Step(f...); e != nil {
- if r, ok := e.(Errno); ok {
- switch r {
- case ROW:
- c++
- continue
- default:
- e = r
- break
- }
- }
- } else {
- break
- }
- }
- if e == nil {
- s.Finalize()
+ for e = s.Step(f...); e == ROW; e = s.Step(f...) {
+ c++
}
+ e = s.Finalize()
return
}
@@ -143,16 +113,10 @@ func (s *Statement) All(f... func(*Statement, ...interface{})) (c int, e error)
// Any SQL statement variables that had values bound to them retain
// their values. Use `ClearBindings` to reset the bindings.
func (s *Statement) Reset() error {
- if e := Errno(C.sqlite3_reset(s.cptr)); e != OK {
- return e
- }
- return nil
+ return SQLiteError(C.sqlite3_reset(s.cptr))
}
// ClearBindings is used to reset all parameters to NULL.
func (s *Statement) ClearBindings() error {
- if e := Errno(C.sqlite3_clear_bindings(s.cptr)); e != OK {
- return e
- }
- return nil
+ return SQLiteError(C.sqlite3_clear_bindings(s.cptr))
}

0 comments on commit d6cf7d5

Please sign in to comment.