mirror of
https://github.com/glebarez/go-sqlite.git
synced 2025-10-04 23:42:40 +08:00
driver: return error strings for constraint errors
In conn.step, use conn.errstr which gets the error from sqlite instead of looking up the result code in the ErrorCodeString map. This changes the code 5 (SQLITE_BUSY) message slightly, including "database is locked" as returned my errstr. "SQLITE_BUSY" is still added to the message. Fixes #73
This commit is contained in:
57
all_test.go
57
all_test.go
@@ -1880,7 +1880,7 @@ func TestIssue66(t *testing.T) {
|
|||||||
// think that's correct (jnml).
|
// think that's correct (jnml).
|
||||||
|
|
||||||
t.Logf("insert 2: %v", err)
|
t.Logf("insert 2: %v", err)
|
||||||
if !strings.Contains(err.Error(), "SQLITE_BUSY") {
|
if !strings.Contains(err.Error(), "database is locked (5) (SQLITE_BUSY)") {
|
||||||
t.Fatalf("insert 2: %v", err)
|
t.Fatalf("insert 2: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2010,3 +2010,58 @@ func testIssue65(t *testing.T, db *sql.DB, canFail bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://gitlab.com/cznic/sqlite/-/issues/73
|
||||||
|
func TestConstraintPrimaryKeyError(t *testing.T) {
|
||||||
|
db, err := sql.Open(driverName, "file::memory:")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS hash (hashval TEXT PRIMARY KEY NOT NULL)`)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.Exec("INSERT INTO hash (hashval) VALUES (?)", "somehashval")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.Exec("INSERT INTO hash (hashval) VALUES (?)", "somehashval")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("wanted error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs, want := err.Error(), "constraint failed: UNIQUE constraint failed: hash.hashval (1555)"; errs != want {
|
||||||
|
t.Fatalf("got error string %q, want %q", errs, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConstraintUniqueError(t *testing.T) {
|
||||||
|
db, err := sql.Open(driverName, "file::memory:")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS hash (hashval TEXT UNIQUE)`)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.Exec("INSERT INTO hash (hashval) VALUES (?)", "somehashval")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.Exec("INSERT INTO hash (hashval) VALUES (?)", "somehashval")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("wanted error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs, want := err.Error(), "constraint failed: UNIQUE constraint failed: hash.hashval (2067)"; errs != want {
|
||||||
|
t.Fatalf("got error string %q, want %q", errs, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
11
sqlite.go
11
sqlite.go
@@ -11,7 +11,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
@@ -883,7 +882,7 @@ func (c *conn) step(pstmt uintptr) (int, error) {
|
|||||||
|
|
||||||
return int(rc), nil
|
return int(rc), nil
|
||||||
default:
|
default:
|
||||||
return int(rc), errors.New(ErrorCodeString[int(rc)])
|
return int(rc), c.errstr(rc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1225,11 +1224,15 @@ func (c *conn) errstr(rc int32) error {
|
|||||||
p := sqlite3.Xsqlite3_errstr(c.tls, rc)
|
p := sqlite3.Xsqlite3_errstr(c.tls, rc)
|
||||||
str := libc.GoString(p)
|
str := libc.GoString(p)
|
||||||
p = sqlite3.Xsqlite3_errmsg(c.tls, c.db)
|
p = sqlite3.Xsqlite3_errmsg(c.tls, c.db)
|
||||||
|
var s string
|
||||||
|
if rc == sqlite3.SQLITE_BUSY {
|
||||||
|
s = " (SQLITE_BUSY)"
|
||||||
|
}
|
||||||
switch msg := libc.GoString(p); {
|
switch msg := libc.GoString(p); {
|
||||||
case msg == str:
|
case msg == str:
|
||||||
return &Error{msg: fmt.Sprintf("%s (%v)", str, rc), code: int(rc)}
|
return &Error{msg: fmt.Sprintf("%s (%v)%s", str, rc, s), code: int(rc)}
|
||||||
default:
|
default:
|
||||||
return &Error{msg: fmt.Sprintf("%s: %s (%v)", str, msg, rc), code: int(rc)}
|
return &Error{msg: fmt.Sprintf("%s: %s (%v)%s", str, msg, rc, s), code: int(rc)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user