Start work on introducing machine-readable error codes.
This commit introduces a new type 'ErrNo', implementing the error interface. Constants for all sqlite3 error codes are provided in the new source file "error.go".
This commit is contained in:
parent
ad95f5fd3d
commit
ff8e6729ce
|
@ -0,0 +1,41 @@
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type ErrNo int
|
||||||
|
|
||||||
|
// result codes from http://www.sqlite.org/c3ref/c_abort.html
|
||||||
|
var (
|
||||||
|
ErrError error = ErrNo(1) /* SQL error or missing database */
|
||||||
|
ErrInternal error = ErrNo(2) /* Internal logic error in SQLite */
|
||||||
|
ErrPerm error = ErrNo(3) /* Access permission denied */
|
||||||
|
ErrAbort error = ErrNo(4) /* Callback routine requested an abort */
|
||||||
|
ErrBusy error = ErrNo(5) /* The database file is locked */
|
||||||
|
ErrLocked error = ErrNo(6) /* A table in the database is locked */
|
||||||
|
ErrNomem error = ErrNo(7) /* A malloc() failed */
|
||||||
|
ErrReadonly error = ErrNo(8) /* Attempt to write a readonly database */
|
||||||
|
ErrInterrupt error = ErrNo(9) /* Operation terminated by sqlite3_interrupt() */
|
||||||
|
ErrIoErr error = ErrNo(10) /* Some kind of disk I/O error occurred */
|
||||||
|
ErrCorrupt error = ErrNo(11) /* The database disk image is malformed */
|
||||||
|
ErrNotFound error = ErrNo(12) /* Unknown opcode in sqlite3_file_control() */
|
||||||
|
ErrFull error = ErrNo(13) /* Insertion failed because database is full */
|
||||||
|
ErrCantOpen error = ErrNo(14) /* Unable to open the database file */
|
||||||
|
ErrProtocol error = ErrNo(15) /* Database lock protocol error */
|
||||||
|
ErrEmpty error = ErrNo(16) /* Database is empty */
|
||||||
|
ErrSchema error = ErrNo(17) /* The database schema changed */
|
||||||
|
ErrTooBig error = ErrNo(18) /* String or BLOB exceeds size limit */
|
||||||
|
ErrConstraint error = ErrNo(19) /* Abort due to constraint violation */
|
||||||
|
ErrMismatch error = ErrNo(20) /* Data type mismatch */
|
||||||
|
ErrMisuse error = ErrNo(21) /* Library used incorrectly */
|
||||||
|
ErrNoLFS error = ErrNo(22) /* Uses OS features not supported on host */
|
||||||
|
ErrAuth error = ErrNo(23) /* Authorization denied */
|
||||||
|
ErrFormat error = ErrNo(24) /* Auxiliary database format error */
|
||||||
|
ErrRange error = ErrNo(25) /* 2nd parameter to sqlite3_bind out of range */
|
||||||
|
ErrNotADB error = ErrNo(26) /* File opened that is not a database file */
|
||||||
|
ErrNotice error = ErrNo(27) /* Notifications from sqlite3_log() */
|
||||||
|
ErrWarning error = ErrNo(28) /* Warnings from sqlite3_log() */
|
||||||
|
)
|
||||||
|
|
||||||
|
func (err ErrNo) Error() string {
|
||||||
|
return errorString(err)
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFailures(t *testing.T) {
|
||||||
|
dirName, err := ioutil.TempDir("", "sqlite3")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dirName)
|
||||||
|
|
||||||
|
dbFileName := path.Join(dirName, "test.db")
|
||||||
|
f, err := os.Create(dbFileName)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
f.Write([]byte{1, 2, 3, 4, 5})
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
db, err := sql.Open("sqlite3", dbFileName)
|
||||||
|
if err == nil {
|
||||||
|
_, err = db.Exec("drop table foo")
|
||||||
|
}
|
||||||
|
if err != ErrNotADB {
|
||||||
|
t.Error("wrong error code for corrupted DB")
|
||||||
|
}
|
||||||
|
db.Close()
|
||||||
|
}
|
26
sqlite3.go
26
sqlite3.go
|
@ -132,7 +132,7 @@ func (c *SQLiteConn) exec(cmd string) error {
|
||||||
defer C.free(unsafe.Pointer(pcmd))
|
defer C.free(unsafe.Pointer(pcmd))
|
||||||
rv := C.sqlite3_exec(c.db, pcmd, nil, nil, nil)
|
rv := C.sqlite3_exec(c.db, pcmd, nil, nil, nil)
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
return ErrNo(rv)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,10 @@ func (c *SQLiteConn) Begin() (driver.Tx, error) {
|
||||||
return &SQLiteTx{c}, nil
|
return &SQLiteTx{c}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func errorString(err ErrNo) string {
|
||||||
|
return C.GoString(C.sqlite3_errstr(C.int(err)))
|
||||||
|
}
|
||||||
|
|
||||||
// Open database and return a new connection.
|
// Open database and return a new connection.
|
||||||
// You can specify DSN string with URI filename.
|
// You can specify DSN string with URI filename.
|
||||||
// test.db
|
// test.db
|
||||||
|
@ -165,7 +169,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
C.SQLITE_OPEN_CREATE,
|
C.SQLITE_OPEN_CREATE,
|
||||||
nil)
|
nil)
|
||||||
if rv != 0 {
|
if rv != 0 {
|
||||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(db)))
|
return nil, ErrNo(rv)
|
||||||
}
|
}
|
||||||
if db == nil {
|
if db == nil {
|
||||||
return nil, errors.New("sqlite succeeded without returning a database")
|
return nil, errors.New("sqlite succeeded without returning a database")
|
||||||
|
@ -173,7 +177,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
|
|
||||||
rv = C.sqlite3_busy_timeout(db, 5000)
|
rv = C.sqlite3_busy_timeout(db, 5000)
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(db)))
|
return nil, ErrNo(rv)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SQLiteConn{db}, nil
|
return &SQLiteConn{db}, nil
|
||||||
|
@ -188,7 +192,7 @@ func (c *SQLiteConn) Close() error {
|
||||||
}
|
}
|
||||||
rv := C.sqlite3_close(c.db)
|
rv := C.sqlite3_close(c.db)
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
return errors.New("error while closing sqlite database connection")
|
return ErrNo(rv)
|
||||||
}
|
}
|
||||||
c.db = nil
|
c.db = nil
|
||||||
return nil
|
return nil
|
||||||
|
@ -202,7 +206,7 @@ func (c *SQLiteConn) Prepare(query string) (driver.Stmt, error) {
|
||||||
var perror *C.char
|
var perror *C.char
|
||||||
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &perror)
|
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &perror)
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
return nil, ErrNo(rv)
|
||||||
}
|
}
|
||||||
var t string
|
var t string
|
||||||
if perror != nil && C.strlen(perror) > 0 {
|
if perror != nil && C.strlen(perror) > 0 {
|
||||||
|
@ -222,7 +226,7 @@ func (s *SQLiteStmt) Close() error {
|
||||||
}
|
}
|
||||||
rv := C.sqlite3_finalize(s.s)
|
rv := C.sqlite3_finalize(s.s)
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
return errors.New(C.GoString(C.sqlite3_errmsg(s.c.db)))
|
return ErrNo(rv)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -235,7 +239,7 @@ func (s *SQLiteStmt) NumInput() int {
|
||||||
func (s *SQLiteStmt) bind(args []driver.Value) error {
|
func (s *SQLiteStmt) bind(args []driver.Value) error {
|
||||||
rv := C.sqlite3_reset(s.s)
|
rv := C.sqlite3_reset(s.s)
|
||||||
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
|
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
|
||||||
return errors.New(C.GoString(C.sqlite3_errmsg(s.c.db)))
|
return ErrNo(rv)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, v := range args {
|
for i, v := range args {
|
||||||
|
@ -280,7 +284,7 @@ func (s *SQLiteStmt) bind(args []driver.Value) error {
|
||||||
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
|
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
|
||||||
}
|
}
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
return errors.New(C.GoString(C.sqlite3_errmsg(s.c.db)))
|
return ErrNo(rv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -311,7 +315,7 @@ func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) {
|
||||||
}
|
}
|
||||||
rv := C.sqlite3_step(s.s)
|
rv := C.sqlite3_step(s.s)
|
||||||
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
|
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
|
||||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(s.c.db)))
|
return nil, ErrNo(rv)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &SQLiteResult{
|
res := &SQLiteResult{
|
||||||
|
@ -325,7 +329,7 @@ func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) {
|
||||||
func (rc *SQLiteRows) Close() error {
|
func (rc *SQLiteRows) Close() error {
|
||||||
rv := C.sqlite3_reset(rc.s.s)
|
rv := C.sqlite3_reset(rc.s.s)
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
return errors.New(C.GoString(C.sqlite3_errmsg(rc.s.c.db)))
|
return ErrNo(rv)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -348,7 +352,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||||
return io.EOF
|
return io.EOF
|
||||||
}
|
}
|
||||||
if rv != C.SQLITE_ROW {
|
if rv != C.SQLITE_ROW {
|
||||||
return errors.New(C.GoString(C.sqlite3_errmsg(rc.s.c.db)))
|
return ErrNo(rv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rc.decltype == nil {
|
if rc.decltype == nil {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// +build !windows
|
// +build !windows
|
||||||
|
|
||||||
package sqlite
|
package sqlite3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo pkg-config: sqlite3
|
#cgo pkg-config: sqlite3
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package sqlite
|
package sqlite3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package sqlite
|
package sqlite3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe
|
#cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe
|
||||||
|
|
Loading…
Reference in New Issue