| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- package sqlite3
- import (
- "errors"
- "strings"
- "github.com/ncruces/go-sqlite3/internal/util"
- )
- // Error wraps an SQLite Error Code.
- //
- // https://sqlite.org/c3ref/errcode.html
- type Error struct {
- msg string
- sql string
- code res_t
- }
- // Code returns the primary error code for this error.
- //
- // https://sqlite.org/rescode.html
- func (e *Error) Code() ErrorCode {
- return ErrorCode(e.code)
- }
- // ExtendedCode returns the extended error code for this error.
- //
- // https://sqlite.org/rescode.html
- func (e *Error) ExtendedCode() ExtendedErrorCode {
- return xErrorCode(e.code)
- }
- // Error implements the error interface.
- func (e *Error) Error() string {
- var b strings.Builder
- b.WriteString(util.ErrorCodeString(uint32(e.code)))
- if e.msg != "" {
- b.WriteString(": ")
- b.WriteString(e.msg)
- }
- return b.String()
- }
- // Is tests whether this error matches a given [ErrorCode] or [ExtendedErrorCode].
- //
- // It makes it possible to do:
- //
- // 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
- }
- // 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
- }
- // Temporary returns true for [BUSY] errors.
- func (e *Error) Temporary() bool {
- return e.Code() == BUSY
- }
- // Timeout returns true for [BUSY_TIMEOUT] errors.
- func (e *Error) Timeout() bool {
- return e.ExtendedCode() == BUSY_TIMEOUT
- }
- // SQL returns the SQL starting at the token that triggered a syntax error.
- func (e *Error) SQL() string {
- return e.sql
- }
- // Error implements the error interface.
- func (e ErrorCode) Error() string {
- return util.ErrorCodeString(uint32(e))
- }
- // Temporary returns true for [BUSY] errors.
- func (e ErrorCode) Temporary() bool {
- return e == BUSY || e == INTERRUPT
- }
- // ExtendedCode returns the extended error code for this error.
- func (e ErrorCode) ExtendedCode() ExtendedErrorCode {
- return xErrorCode(e)
- }
- // Error implements the error interface.
- func (e ExtendedErrorCode) Error() string {
- return util.ErrorCodeString(uint32(e))
- }
- // 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)
- }
- // 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
- }
- // Temporary returns true for [BUSY] errors.
- func (e ExtendedErrorCode) Temporary() bool {
- return ErrorCode(e) == BUSY || ErrorCode(e) == INTERRUPT
- }
- // Timeout returns true for [BUSY_TIMEOUT] errors.
- func (e ExtendedErrorCode) Timeout() bool {
- return e == BUSY_TIMEOUT
- }
- // Code returns the primary error code for this error.
- func (e ExtendedErrorCode) Code() ErrorCode {
- return ErrorCode(e)
- }
- func errorCode(err error, def ErrorCode) (msg string, code res_t) {
- switch code := err.(type) {
- case nil:
- return "", _OK
- case ErrorCode:
- return "", res_t(code)
- case xErrorCode:
- return "", res_t(code)
- case *Error:
- return code.msg, res_t(code.code)
- }
- var ecode ErrorCode
- var xcode xErrorCode
- switch {
- case errors.As(err, &xcode):
- code = res_t(xcode)
- case errors.As(err, &ecode):
- code = res_t(ecode)
- default:
- code = res_t(def)
- }
- return err.Error(), code
- }
|