Files
sqlite3/error.go

179 lines
3.8 KiB
Go
Raw Normal View History

2023-01-12 13:43:35 +00:00
package sqlite3
import (
2023-11-16 01:16:38 +00:00
"errors"
2023-01-12 13:43:35 +00:00
"strings"
2023-05-18 16:00:34 +01:00
"github.com/ncruces/go-sqlite3/internal/util"
2023-01-12 13:43:35 +00:00
)
2023-02-09 16:40:48 +00:00
// Error wraps an SQLite Error Code.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/errcode.html
2023-01-12 13:43:35 +00:00
type Error struct {
2025-10-15 16:22:36 +01:00
sys error
2023-02-09 16:40:48 +00:00
msg string
2023-02-10 16:42:49 +00:00
sql string
2025-01-21 01:42:57 +00:00
code res_t
2023-01-12 13:43:35 +00:00
}
2023-02-09 16:40:48 +00:00
// Code returns the primary error code for this error.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/rescode.html
2023-02-09 16:40:48 +00:00
func (e *Error) Code() ErrorCode {
return ErrorCode(e.code)
}
// ExtendedCode returns the extended error code for this error.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/rescode.html
2023-02-09 16:40:48 +00:00
func (e *Error) ExtendedCode() ExtendedErrorCode {
2025-03-28 11:51:45 +00:00
return xErrorCode(e.code)
2023-02-09 16:40:48 +00:00
}
// Error implements the error interface.
2023-01-21 00:33:46 +00:00
func (e *Error) Error() string {
2023-01-12 13:43:35 +00:00
var b strings.Builder
2025-10-15 16:22:36 +01:00
b.WriteString(util.ErrorCodeString(e.code))
2023-01-12 13:43:35 +00:00
if e.msg != "" {
2023-12-06 15:39:26 +00:00
b.WriteString(": ")
2023-01-12 13:43:35 +00:00
b.WriteString(e.msg)
}
return b.String()
}
2023-01-19 14:31:32 +00:00
2025-10-15 16:22:36 +01:00
// Unwrap returns the underlying operating system error
// that caused the I/O error or failure to open a file.
//
// https://sqlite.org/c3ref/system_errno.html
func (e *Error) Unwrap() error {
return e.sys
}
2023-02-25 15:11:07 +00:00
// Is tests whether this error matches a given [ErrorCode] or [ExtendedErrorCode].
//
2023-03-01 10:34:08 +00:00
// It makes it possible to do:
2023-02-25 15:11:07 +00:00
//
// if errors.Is(err, sqlite3.BUSY) {
// // ... handle BUSY
// }
func (e *Error) Is(err error) bool {
switch c := err.(type) {
case ErrorCode:
return c == e.Code()
case ExtendedErrorCode:
return c == e.ExtendedCode()
}
return false
}
2023-06-30 12:25:07 +01:00
// As converts this error to an [ErrorCode] or [ExtendedErrorCode].
func (e *Error) As(err any) bool {
switch c := err.(type) {
case *ErrorCode:
*c = e.Code()
return true
case *ExtendedErrorCode:
*c = e.ExtendedCode()
return true
}
return false
}
2023-02-20 13:38:03 +00:00
// Temporary returns true for [BUSY] errors.
func (e *Error) Temporary() bool {
2025-04-08 12:41:46 +01:00
return e.Code() == BUSY || e.Code() == INTERRUPT
2023-02-20 13:38:03 +00:00
}
2023-02-25 15:11:07 +00:00
// Timeout returns true for [BUSY_TIMEOUT] errors.
func (e *Error) Timeout() bool {
return e.ExtendedCode() == BUSY_TIMEOUT
}
2023-02-10 16:42:49 +00:00
// SQL returns the SQL starting at the token that triggered a syntax error.
func (e *Error) SQL() string {
return e.sql
}
2023-02-25 15:11:07 +00:00
// Error implements the error interface.
func (e ErrorCode) Error() string {
2025-10-15 16:22:36 +01:00
return util.ErrorCodeString(e)
}
// As converts this error to an [ExtendedErrorCode].
func (e ErrorCode) As(err any) bool {
c, ok := err.(*xErrorCode)
if ok {
*c = xErrorCode(e)
}
return ok
2023-02-25 15:11:07 +00:00
}
// Temporary returns true for [BUSY] errors.
func (e ErrorCode) Temporary() bool {
2025-03-28 11:51:45 +00:00
return e == BUSY || e == INTERRUPT
2023-02-25 15:11:07 +00:00
}
2024-11-06 11:45:20 +00:00
// ExtendedCode returns the extended error code for this error.
func (e ErrorCode) ExtendedCode() ExtendedErrorCode {
2025-03-28 11:51:45 +00:00
return xErrorCode(e)
2024-11-06 11:45:20 +00:00
}
2023-02-25 15:11:07 +00:00
// Error implements the error interface.
func (e ExtendedErrorCode) Error() string {
2025-10-15 16:22:36 +01:00
return util.ErrorCodeString(e)
2023-02-25 15:11:07 +00:00
}
// Is tests whether this error matches a given [ErrorCode].
func (e ExtendedErrorCode) Is(err error) bool {
c, ok := err.(ErrorCode)
return ok && c == ErrorCode(e)
}
2023-06-30 12:25:07 +01:00
// As converts this error to an [ErrorCode].
func (e ExtendedErrorCode) As(err any) bool {
c, ok := err.(*ErrorCode)
if ok {
*c = ErrorCode(e)
}
return ok
}
2023-02-25 15:11:07 +00:00
// Temporary returns true for [BUSY] errors.
func (e ExtendedErrorCode) Temporary() bool {
2025-03-28 11:51:45 +00:00
return ErrorCode(e) == BUSY || ErrorCode(e) == INTERRUPT
2023-02-25 15:11:07 +00:00
}
// Timeout returns true for [BUSY_TIMEOUT] errors.
func (e ExtendedErrorCode) Timeout() bool {
return e == BUSY_TIMEOUT
}
2023-11-16 01:16:38 +00:00
2024-11-06 11:45:20 +00:00
// Code returns the primary error code for this error.
func (e ExtendedErrorCode) Code() ErrorCode {
return ErrorCode(e)
}
2025-01-21 01:42:57 +00:00
func errorCode(err error, def ErrorCode) (msg string, code res_t) {
2023-11-21 13:40:55 +00:00
switch code := err.(type) {
2024-01-11 02:18:12 +00:00
case nil:
return "", _OK
2023-11-21 13:40:55 +00:00
case ErrorCode:
2025-01-21 01:42:57 +00:00
return "", res_t(code)
2024-01-11 02:18:12 +00:00
case xErrorCode:
2025-01-21 01:42:57 +00:00
return "", res_t(code)
2023-12-05 16:11:56 +00:00
case *Error:
2025-01-21 01:42:57 +00:00
return code.msg, res_t(code.code)
2023-11-21 13:40:55 +00:00
}
2023-11-16 01:16:38 +00:00
var xcode xErrorCode
2025-10-15 16:22:36 +01:00
if errors.As(err, &xcode) {
2025-01-21 01:42:57 +00:00
code = res_t(xcode)
2025-10-15 16:22:36 +01:00
} else {
2025-01-21 01:42:57 +00:00
code = res_t(def)
2023-11-16 01:16:38 +00:00
}
2023-11-21 13:40:55 +00:00
return err.Error(), code
2023-11-16 01:16:38 +00:00
}