forked from mirror/go-sqlite3
Merge pull request #91 from robertknight/rob-extended_err_info
Provide more specific error messages
This commit is contained in:
commit
8d3a4e0ee8
16
error.go
16
error.go
|
@ -4,6 +4,12 @@ import "C"
|
||||||
|
|
||||||
type ErrNo int
|
type ErrNo int
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
Code ErrNo /* The error code returned by SQLite */
|
||||||
|
err string /* The error string returned by sqlite3_errmsg(),
|
||||||
|
this usually contains more specific details. */
|
||||||
|
}
|
||||||
|
|
||||||
// result codes from http://www.sqlite.org/c3ref/c_abort.html
|
// result codes from http://www.sqlite.org/c3ref/c_abort.html
|
||||||
var (
|
var (
|
||||||
ErrError error = ErrNo(1) /* SQL error or missing database */
|
ErrError error = ErrNo(1) /* SQL error or missing database */
|
||||||
|
@ -37,5 +43,13 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (err ErrNo) Error() string {
|
func (err ErrNo) Error() string {
|
||||||
return errorString(err)
|
return Error{Code: err}.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err Error) Error() string {
|
||||||
|
if err.err != "" {
|
||||||
|
return err.err
|
||||||
|
} else {
|
||||||
|
return errorString(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFailures(t *testing.T) {
|
func TestCorruptDbErrors(t *testing.T) {
|
||||||
dirName, err := ioutil.TempDir("", "sqlite3")
|
dirName, err := ioutil.TempDir("", "sqlite3")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -27,7 +27,9 @@ func TestFailures(t *testing.T) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_, err = db.Exec("drop table foo")
|
_, err = db.Exec("drop table foo")
|
||||||
}
|
}
|
||||||
if err != ErrNotADB {
|
|
||||||
|
sqliteErr := err.(Error)
|
||||||
|
if sqliteErr.Code != ErrNotADB {
|
||||||
t.Error("wrong error code for corrupted DB")
|
t.Error("wrong error code for corrupted DB")
|
||||||
}
|
}
|
||||||
if err.Error() == "" {
|
if err.Error() == "" {
|
||||||
|
@ -35,3 +37,28 @@ func TestFailures(t *testing.T) {
|
||||||
}
|
}
|
||||||
db.Close()
|
db.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSqlLogicErrors(t *testing.T) {
|
||||||
|
dirName, err := ioutil.TempDir("", "sqlite3")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dirName)
|
||||||
|
|
||||||
|
dbFileName := path.Join(dirName, "test.db")
|
||||||
|
db, err := sql.Open("sqlite3", dbFileName)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.Exec("CREATE TABLE Foo (id INT PRIMARY KEY)")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectedErr = "table Foo already exists"
|
||||||
|
_, err = db.Exec("CREATE TABLE Foo (id INT PRIMARY KEY)")
|
||||||
|
if err.Error() != expectedErr {
|
||||||
|
t.Errorf("Unexpected error: %s, expected %s", err.Error(), expectedErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
32
sqlite3.go
32
sqlite3.go
|
@ -138,6 +138,12 @@ func (c *SQLiteConn) AutoCommit() bool {
|
||||||
return int(C.sqlite3_get_autocommit(c.db)) != 0
|
return int(C.sqlite3_get_autocommit(c.db)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *SQLiteConn) lastError() Error {
|
||||||
|
return Error{Code: ErrNo(C.sqlite3_errcode(c.db)),
|
||||||
|
err: C.GoString(C.sqlite3_errmsg(c.db)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Execer & Queryer currently disabled
|
// TODO: Execer & Queryer currently disabled
|
||||||
// https://github.com/mattn/go-sqlite3/issues/82
|
// https://github.com/mattn/go-sqlite3/issues/82
|
||||||
//// Implements Execer
|
//// Implements Execer
|
||||||
|
@ -205,7 +211,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 ErrNo(rv)
|
return c.lastError()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -218,8 +224,8 @@ func (c *SQLiteConn) Begin() (driver.Tx, error) {
|
||||||
return &SQLiteTx{c}, nil
|
return &SQLiteTx{c}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func errorString(err ErrNo) string {
|
func errorString(err Error) string {
|
||||||
return C.GoString(C.sqlite3_errstr(C.int(err)))
|
return C.GoString(C.sqlite3_errstr(C.int(err.Code)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open database and return a new connection.
|
// Open database and return a new connection.
|
||||||
|
@ -242,7 +248,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, ErrNo(rv)
|
return nil, Error{Code: 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")
|
||||||
|
@ -250,7 +256,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, ErrNo(rv)
|
return nil, Error{Code: ErrNo(rv)}
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := &SQLiteConn{db}
|
conn := &SQLiteConn{db}
|
||||||
|
@ -295,7 +301,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
func (c *SQLiteConn) Close() error {
|
func (c *SQLiteConn) Close() error {
|
||||||
rv := C.sqlite3_close_v2(c.db)
|
rv := C.sqlite3_close_v2(c.db)
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
return ErrNo(rv)
|
return c.lastError()
|
||||||
}
|
}
|
||||||
c.db = nil
|
c.db = nil
|
||||||
return nil
|
return nil
|
||||||
|
@ -309,7 +315,7 @@ func (c *SQLiteConn) Prepare(query string) (driver.Stmt, error) {
|
||||||
var tail *C.char
|
var tail *C.char
|
||||||
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
|
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
return nil, ErrNo(rv)
|
return nil, c.lastError()
|
||||||
}
|
}
|
||||||
var t string
|
var t string
|
||||||
if tail != nil && C.strlen(tail) > 0 {
|
if tail != nil && C.strlen(tail) > 0 {
|
||||||
|
@ -329,7 +335,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 ErrNo(rv)
|
return s.c.lastError()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -342,7 +348,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 ErrNo(rv)
|
return s.c.lastError()
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, v := range args {
|
for i, v := range args {
|
||||||
|
@ -387,7 +393,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 ErrNo(rv)
|
return s.c.lastError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -418,7 +424,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, ErrNo(rv)
|
return nil, s.c.lastError()
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &SQLiteResult{
|
res := &SQLiteResult{
|
||||||
|
@ -435,7 +441,7 @@ 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 ErrNo(rv)
|
return rc.s.c.lastError()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -460,7 +466,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||||
if rv != C.SQLITE_ROW {
|
if rv != C.SQLITE_ROW {
|
||||||
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 ErrNo(rv)
|
return rc.s.c.lastError()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue