// Copyright (C) 2019 Yasuhiro Matsumoto . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. // +build cgo package sqlite3 import ( "database/sql" "io/ioutil" "os" "path" "testing" ) func TestSimpleError(t *testing.T) { e := ErrError.Error() if e != "SQL logic error or missing database" && e != "SQL logic error" { t.Error("wrong error code: " + e) } } func TestCorruptDbErrors(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") } sqliteErr := err.(Error) if sqliteErr.Code != ErrNotADB { t.Error("wrong error code for corrupted DB") } if err.Error() == "" { t.Error("wrong error string for corrupted DB") } 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) } defer db.Close() _, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)") if err != nil { t.Error(err) } const expectedErr = "table Foo already exists" _, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)") if err.Error() != expectedErr { t.Errorf("Unexpected error: %s, expected %s", err.Error(), expectedErr) } } func TestExtendedErrorCodes_ForeignKey(t *testing.T) { dirName, err := ioutil.TempDir("", "sqlite3-err") 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) } defer db.Close() _, err = db.Exec("PRAGMA foreign_keys=ON;") if err != nil { t.Errorf("PRAGMA foreign_keys=ON: %v", err) } _, err = db.Exec(`CREATE TABLE Foo ( id INTEGER PRIMARY KEY AUTOINCREMENT, value INTEGER NOT NULL, ref INTEGER NULL REFERENCES Foo (id), UNIQUE(value) );`) if err != nil { t.Error(err) } _, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (100, 100);") if err == nil { t.Error("No error!") } else { sqliteErr := err.(Error) if sqliteErr.Code != ErrConstraint { t.Errorf("Wrong basic error code: %d != %d", sqliteErr.Code, ErrConstraint) } if sqliteErr.ExtendedCode != ErrConstraintForeignKey { t.Errorf("Wrong extended error code: %d != %d", sqliteErr.ExtendedCode, ErrConstraintForeignKey) } } } func TestExtendedErrorCodes_NotNull(t *testing.T) { dirName, err := ioutil.TempDir("", "sqlite3-err") 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) } defer db.Close() _, err = db.Exec("PRAGMA foreign_keys=ON;") if err != nil { t.Errorf("PRAGMA foreign_keys=ON: %v", err) } _, err = db.Exec(`CREATE TABLE Foo ( id INTEGER PRIMARY KEY AUTOINCREMENT, value INTEGER NOT NULL, ref INTEGER NULL REFERENCES Foo (id), UNIQUE(value) );`) if err != nil { t.Error(err) } res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);") if err != nil { t.Fatalf("Creating first row: %v", err) } id, err := res.LastInsertId() if err != nil { t.Fatalf("Retrieving last insert id: %v", err) } _, err = db.Exec("INSERT INTO Foo (ref) VALUES (?);", id) if err == nil { t.Error("No error!") } else { sqliteErr := err.(Error) if sqliteErr.Code != ErrConstraint { t.Errorf("Wrong basic error code: %d != %d", sqliteErr.Code, ErrConstraint) } if sqliteErr.ExtendedCode != ErrConstraintNotNull { t.Errorf("Wrong extended error code: %d != %d", sqliteErr.ExtendedCode, ErrConstraintNotNull) } } } func TestExtendedErrorCodes_Unique(t *testing.T) { dirName, err := ioutil.TempDir("", "sqlite3-err") 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) } defer db.Close() _, err = db.Exec("PRAGMA foreign_keys=ON;") if err != nil { t.Errorf("PRAGMA foreign_keys=ON: %v", err) } _, err = db.Exec(`CREATE TABLE Foo ( id INTEGER PRIMARY KEY AUTOINCREMENT, value INTEGER NOT NULL, ref INTEGER NULL REFERENCES Foo (id), UNIQUE(value) );`) if err != nil { t.Error(err) } res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);") if err != nil { t.Fatalf("Creating first row: %v", err) } id, err := res.LastInsertId() if err != nil { t.Fatalf("Retrieving last insert id: %v", err) } _, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (?, 100);", id) if err == nil { t.Error("No error!") } else { sqliteErr := err.(Error) if sqliteErr.Code != ErrConstraint { t.Errorf("Wrong basic error code: %d != %d", sqliteErr.Code, ErrConstraint) } if sqliteErr.ExtendedCode != ErrConstraintUnique { t.Errorf("Wrong extended error code: %d != %d", sqliteErr.ExtendedCode, ErrConstraintUnique) } extended := sqliteErr.Code.Extend(3).Error() expected := "constraint failed" if extended != expected { t.Errorf("Wrong basic error code: %q != %q", extended, expected) } } } func TestError_SystemErrno(t *testing.T) { _, n, _ := Version() if n < 3012000 { t.Skip("sqlite3_system_errno requires sqlite3 >= 3.12.0") } // open a non-existent database in read-only mode so we get an IO error. db, err := sql.Open("sqlite3", "file:nonexistent.db?mode=ro") if err != nil { t.Fatal(err) } defer db.Close() err = db.Ping() if err == nil { t.Fatal("expected error pinging read-only non-existent database, but got nil") } serr, ok := err.(Error) if !ok { t.Fatalf("expected error to be of type Error, but got %[1]T %[1]v", err) } if serr.SystemErrno == 0 { t.Fatal("expected SystemErrno to be set") } if !os.IsNotExist(serr.SystemErrno) { t.Errorf("expected SystemErrno to be a not exists error, but got %v", serr.SystemErrno) } }