Commit e5176627 authored by gwenn's avatar gwenn

Bind new features: sqlite3_errstr and foreign_key_check.

parent 69eefa95
......@@ -45,4 +45,5 @@ func TestBackupMisuse(t *testing.T) {
assert(t, "source and destination must be distinct", bck == nil && err != nil)
err = bck.Run(10, 0, nil)
assert(t, "misuse expected", err != nil)
//println(err.Error())
}
......@@ -68,6 +68,7 @@ func TestBlobMisuse(t *testing.T) {
bw, err := db.NewBlobReadWriter("main", "test", "content", 0)
assert(t, "error expected", bw == nil && err != nil)
//println(err.Error())
err = bw.Close()
assert(t, "error expected", err != nil)
}
......@@ -28,6 +28,7 @@ func TestInterrupt(t *testing.T) {
if err == nil {
t.Fatalf("Expected interrupt but got %v", err)
}
//println(err.Error())
if se, ok := err.(*StmtError); !ok || se.Code() != ErrInterrupt {
t.Errorf("Expected interrupt but got %#v", err)
}
......
......@@ -135,6 +135,54 @@ func (c *Conn) SetSynchronous(dbName string, mode int) error {
return c.exec(pragma(dbName, fmt.Sprintf("synchronous=%d", mode)))
}
type FkViolation struct {
Table string
Rowid int64
Parent string
Fkid int
}
// ForeignKeyCheck checks the database, or the table, for foreign key constraints that are violated
// and returns one row of output for each violation.
// Database name is optional (default is 'main').
// Table name is optional (default is all tables).
// (See http://sqlite.org/pragma.html#pragma_foreign_key_check)
func (c *Conn) ForeignKeyCheck(dbName, table string) ([]FkViolation, error) {
var pragma string
if len(dbName) == 0 {
if len(table) == 0 {
pragma = "PRAGMA foreign_key_check"
} else {
pragma = Mprintf("PRAGMA foreign_key_check(%Q)", table)
}
} else {
if len(table) == 0 {
pragma = Mprintf("PRAGMA %Q.foreign_key_check", table)
} else {
pragma = Mprintf2("PRAGMA %Q.foreign_key_check(%Q)", dbName, table)
}
}
s, err := c.prepare(pragma)
if err != nil {
return nil, err
}
defer s.finalize()
// table|rowid|parent|fkid
var violations []FkViolation = make([]FkViolation, 0, 20)
err = s.Select(func(s *Stmt) (err error) {
v := FkViolation{}
if err = s.Scan(&v.Table, &v.Rowid, &v.Parent, &v.Fkid); err != nil {
return
}
violations = append(violations, v)
return
})
if err != nil {
return nil, err
}
return violations, nil
}
func pragma(dbName, pragmaName string) string {
if len(dbName) == 0 {
return "PRAGMA " + pragmaName
......
......@@ -63,7 +63,12 @@ func (e *ConnError) Error() string { // FIXME code.Error() & e.msg are often red
type Errno int
func (e Errno) Error() string {
s := errText[e]
var s string
if e == ErrSpecific {
s = "Wrapper specific error"
} else {
s = C.GoString(C.sqlite3_errstr(C.int(e)))
}
if s == "" {
return fmt.Sprintf("errno %d", int(e))
}
......@@ -102,38 +107,6 @@ var (
ErrSpecific = Errno(-1) /* Wrapper specific error */
)
var errText = map[Errno]string{
C.SQLITE_ERROR: "SQL error or missing database",
C.SQLITE_INTERNAL: "Internal logic error in SQLite",
C.SQLITE_PERM: "Access permission denied",
C.SQLITE_ABORT: "Callback routine requested an abort",
C.SQLITE_BUSY: "The database file is locked",
C.SQLITE_LOCKED: "A table in the database is locked",
C.SQLITE_NOMEM: "A malloc() failed",
C.SQLITE_READONLY: "Attempt to write a readonly database",
C.SQLITE_INTERRUPT: "Operation terminated by sqlite3_interrupt()",
C.SQLITE_IOERR: "Some kind of disk I/O error occurred",
C.SQLITE_CORRUPT: "The database disk image is malformed",
C.SQLITE_NOTFOUND: "Unknown opcode in sqlite3_file_control()",
C.SQLITE_FULL: "Insertion failed because database is full",
C.SQLITE_CANTOPEN: "Unable to open the database file",
C.SQLITE_PROTOCOL: "Database lock protocol error",
C.SQLITE_EMPTY: "Database is empty",
C.SQLITE_SCHEMA: "The database schema changed",
C.SQLITE_TOOBIG: "String or BLOB exceeds size limit",
C.SQLITE_CONSTRAINT: "Abort due to constraint violation",
C.SQLITE_MISMATCH: "Data type mismatch",
C.SQLITE_MISUSE: "Library used incorrectly",
C.SQLITE_NOLFS: "Uses OS features not supported on host",
C.SQLITE_AUTH: "Authorization denied",
C.SQLITE_FORMAT: "Auxiliary database format error",
C.SQLITE_RANGE: "2nd parameter to sqlite3_bind out of range",
C.SQLITE_NOTADB: "File opened that is not a database file",
Row: "sqlite3_step() has another row ready",
Done: "sqlite3_step() has finished executing",
ErrSpecific: "Wrapper specific error",
}
func (c *Conn) error(rv C.int, details ...string) error {
if c == nil {
return errors.New("nil sqlite database")
......
......@@ -59,6 +59,7 @@ func TestOpen(t *testing.T) {
func TestOpenFailure(t *testing.T) {
db, err := Open("doesnotexist.sqlite", OpenReadOnly)
assert(t, "open failure expected", db == nil && err != nil)
//println(err.Error())
}
func TestEnableFKey(t *testing.T) {
......@@ -220,6 +221,7 @@ func TestReadonlyMisuse(t *testing.T) {
_, err := db.Readonly("doesnotexist")
assert(t, "error expected", err != nil)
err.Error()
//println(err.Error())
}
func TestConnSettings(t *testing.T) {
......
......@@ -232,6 +232,7 @@ func TestStmtMisuse(t *testing.T) {
s, err := db.Prepare("MISUSE")
assert(t, "error expected", s == nil && err != nil)
//println(err.Error())
err = s.Finalize()
assert(t, "error expected", err != nil)
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment