error.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package sqlite3
  2. import (
  3. "errors"
  4. "strings"
  5. "github.com/ncruces/go-sqlite3/internal/util"
  6. )
  7. // Error wraps an SQLite Error Code.
  8. //
  9. // https://sqlite.org/c3ref/errcode.html
  10. type Error struct {
  11. msg string
  12. sql string
  13. code res_t
  14. }
  15. // Code returns the primary error code for this error.
  16. //
  17. // https://sqlite.org/rescode.html
  18. func (e *Error) Code() ErrorCode {
  19. return ErrorCode(e.code)
  20. }
  21. // ExtendedCode returns the extended error code for this error.
  22. //
  23. // https://sqlite.org/rescode.html
  24. func (e *Error) ExtendedCode() ExtendedErrorCode {
  25. return xErrorCode(e.code)
  26. }
  27. // Error implements the error interface.
  28. func (e *Error) Error() string {
  29. var b strings.Builder
  30. b.WriteString(util.ErrorCodeString(uint32(e.code)))
  31. if e.msg != "" {
  32. b.WriteString(": ")
  33. b.WriteString(e.msg)
  34. }
  35. return b.String()
  36. }
  37. // Is tests whether this error matches a given [ErrorCode] or [ExtendedErrorCode].
  38. //
  39. // It makes it possible to do:
  40. //
  41. // if errors.Is(err, sqlite3.BUSY) {
  42. // // ... handle BUSY
  43. // }
  44. func (e *Error) Is(err error) bool {
  45. switch c := err.(type) {
  46. case ErrorCode:
  47. return c == e.Code()
  48. case ExtendedErrorCode:
  49. return c == e.ExtendedCode()
  50. }
  51. return false
  52. }
  53. // As converts this error to an [ErrorCode] or [ExtendedErrorCode].
  54. func (e *Error) As(err any) bool {
  55. switch c := err.(type) {
  56. case *ErrorCode:
  57. *c = e.Code()
  58. return true
  59. case *ExtendedErrorCode:
  60. *c = e.ExtendedCode()
  61. return true
  62. }
  63. return false
  64. }
  65. // Temporary returns true for [BUSY] errors.
  66. func (e *Error) Temporary() bool {
  67. return e.Code() == BUSY
  68. }
  69. // Timeout returns true for [BUSY_TIMEOUT] errors.
  70. func (e *Error) Timeout() bool {
  71. return e.ExtendedCode() == BUSY_TIMEOUT
  72. }
  73. // SQL returns the SQL starting at the token that triggered a syntax error.
  74. func (e *Error) SQL() string {
  75. return e.sql
  76. }
  77. // Error implements the error interface.
  78. func (e ErrorCode) Error() string {
  79. return util.ErrorCodeString(uint32(e))
  80. }
  81. // Temporary returns true for [BUSY] errors.
  82. func (e ErrorCode) Temporary() bool {
  83. return e == BUSY || e == INTERRUPT
  84. }
  85. // ExtendedCode returns the extended error code for this error.
  86. func (e ErrorCode) ExtendedCode() ExtendedErrorCode {
  87. return xErrorCode(e)
  88. }
  89. // Error implements the error interface.
  90. func (e ExtendedErrorCode) Error() string {
  91. return util.ErrorCodeString(uint32(e))
  92. }
  93. // Is tests whether this error matches a given [ErrorCode].
  94. func (e ExtendedErrorCode) Is(err error) bool {
  95. c, ok := err.(ErrorCode)
  96. return ok && c == ErrorCode(e)
  97. }
  98. // As converts this error to an [ErrorCode].
  99. func (e ExtendedErrorCode) As(err any) bool {
  100. c, ok := err.(*ErrorCode)
  101. if ok {
  102. *c = ErrorCode(e)
  103. }
  104. return ok
  105. }
  106. // Temporary returns true for [BUSY] errors.
  107. func (e ExtendedErrorCode) Temporary() bool {
  108. return ErrorCode(e) == BUSY || ErrorCode(e) == INTERRUPT
  109. }
  110. // Timeout returns true for [BUSY_TIMEOUT] errors.
  111. func (e ExtendedErrorCode) Timeout() bool {
  112. return e == BUSY_TIMEOUT
  113. }
  114. // Code returns the primary error code for this error.
  115. func (e ExtendedErrorCode) Code() ErrorCode {
  116. return ErrorCode(e)
  117. }
  118. func errorCode(err error, def ErrorCode) (msg string, code res_t) {
  119. switch code := err.(type) {
  120. case nil:
  121. return "", _OK
  122. case ErrorCode:
  123. return "", res_t(code)
  124. case xErrorCode:
  125. return "", res_t(code)
  126. case *Error:
  127. return code.msg, res_t(code.code)
  128. }
  129. var ecode ErrorCode
  130. var xcode xErrorCode
  131. switch {
  132. case errors.As(err, &xcode):
  133. code = res_t(xcode)
  134. case errors.As(err, &ecode):
  135. code = res_t(ecode)
  136. default:
  137. code = res_t(def)
  138. }
  139. return err.Error(), code
  140. }