aboutsummaryrefslogtreecommitdiff
path: root/sqlite3.go
diff options
context:
space:
mode:
authorrittneje <rittneje@gmail.com>2019-12-17 01:58:28 -0500
committermattn <mattn.jp@gmail.com>2019-12-17 15:58:28 +0900
commitb4f5cc77d1cca1470922e916c9f775ef17d2d78f (patch)
treef4c84d072f9b184a486c9d78edbe5e0cab21e2a2 /sqlite3.go
parentMerge pull request #744 from azavorotnii/ctx_cancel (diff)
downloadgolite-b4f5cc77d1cca1470922e916c9f775ef17d2d78f.tar.gz
golite-b4f5cc77d1cca1470922e916c9f775ef17d2d78f.tar.xz
add SystemErrno to Error (#740)
* adding SystemErrno to Error, and fixing error logic when open fails * fix for old versions of libsqlite3 that do not have sqlite3_system_errno defined * fixing pre-processor logic
Diffstat (limited to 'sqlite3.go')
-rw-r--r--sqlite3.go35
1 files changed, 27 insertions, 8 deletions
diff --git a/sqlite3.go b/sqlite3.go
index 7f0e7c0..61eeff7 100644
--- a/sqlite3.go
+++ b/sqlite3.go
@@ -183,6 +183,12 @@ static int _sqlite3_limit(sqlite3* db, int limitId, int newLimit) {
return sqlite3_limit(db, limitId, newLimit);
#endif
}
+
+#if SQLITE_VERSION_NUMBER < 3012000
+static int sqlite3_system_errno(sqlite3 *db) {
+ return 0;
+}
+#endif
*/
import "C"
import (
@@ -198,6 +204,7 @@ import (
"strconv"
"strings"
"sync"
+ "syscall"
"time"
"unsafe"
)
@@ -749,15 +756,28 @@ func (c *SQLiteConn) lastError() error {
return lastError(c.db)
}
+// Note: may be called with db == nil
func lastError(db *C.sqlite3) error {
- rv := C.sqlite3_errcode(db)
+ rv := C.sqlite3_errcode(db) // returns SQLITE_NOMEM if db == nil
if rv == C.SQLITE_OK {
return nil
}
+ extrv := C.sqlite3_extended_errcode(db) // returns SQLITE_NOMEM if db == nil
+ errStr := C.GoString(C.sqlite3_errmsg(db)) // returns "out of memory" if db == nil
+
+ // https://www.sqlite.org/c3ref/system_errno.html
+ // sqlite3_system_errno is only meaningful if the error code was SQLITE_CANTOPEN,
+ // or it was SQLITE_IOERR and the extended code was not SQLITE_IOERR_NOMEM
+ var systemErrno syscall.Errno
+ if rv == C.SQLITE_CANTOPEN || (rv == C.SQLITE_IOERR && extrv != C.SQLITE_IOERR_NOMEM) {
+ systemErrno = syscall.Errno(C.sqlite3_system_errno(db))
+ }
+
return Error{
Code: ErrNo(rv),
- ExtendedCode: ErrNoExtended(C.sqlite3_extended_errcode(db)),
- err: C.GoString(C.sqlite3_errmsg(db)),
+ ExtendedCode: ErrNoExtended(extrv),
+ SystemErrno: systemErrno,
+ err: errStr,
}
}
@@ -869,10 +889,6 @@ func (c *SQLiteConn) begin(ctx context.Context) (driver.Tx, error) {
return &SQLiteTx{c}, nil
}
-func errorString(err Error) string {
- return C.GoString(C.sqlite3_errstr(C.int(err.Code)))
-}
-
// Open database and return a new connection.
//
// A pragma can take either zero or one argument.
@@ -1342,10 +1358,13 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
mutex|C.SQLITE_OPEN_READWRITE|C.SQLITE_OPEN_CREATE,
nil)
if rv != 0 {
+ // Save off the error _before_ closing the database.
+ // This is safe even if db is nil.
+ err := lastError(db)
if db != nil {
C.sqlite3_close_v2(db)
}
- return nil, Error{Code: ErrNo(rv)}
+ return nil, err
}
if db == nil {
return nil, errors.New("sqlite succeeded without returning a database")