terror.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // Copyright 2015 PingCAP, Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package terror
  14. import (
  15. "fmt"
  16. "strconv"
  17. "strings"
  18. "sync"
  19. "github.com/pingcap/errors"
  20. "github.com/pingcap/log"
  21. "github.com/pingcap/parser/mysql"
  22. "go.uber.org/zap"
  23. )
  24. // ErrCode represents a specific error type in a error class.
  25. // Same error code can be used in different error classes.
  26. type ErrCode int
  27. const (
  28. // Executor error codes.
  29. // CodeUnknown is for errors of unknown reason.
  30. CodeUnknown ErrCode = -1
  31. // CodeExecResultIsEmpty indicates execution result is empty.
  32. CodeExecResultIsEmpty ErrCode = 3
  33. // Expression error codes.
  34. // CodeMissConnectionID indicates connection id is missing.
  35. CodeMissConnectionID ErrCode = 1
  36. // Special error codes.
  37. // CodeResultUndetermined indicates the sql execution result is undetermined.
  38. CodeResultUndetermined ErrCode = 2
  39. )
  40. // ErrClass represents a class of errors.
  41. type ErrClass int
  42. type Error = errors.Error
  43. // Error classes.
  44. var (
  45. ClassAutoid = RegisterErrorClass(1, "autoid")
  46. ClassDDL = RegisterErrorClass(2, "ddl")
  47. ClassDomain = RegisterErrorClass(3, "domain")
  48. ClassEvaluator = RegisterErrorClass(4, "evaluator")
  49. ClassExecutor = RegisterErrorClass(5, "executor")
  50. ClassExpression = RegisterErrorClass(6, "expression")
  51. ClassAdmin = RegisterErrorClass(7, "admin")
  52. ClassKV = RegisterErrorClass(8, "kv")
  53. ClassMeta = RegisterErrorClass(9, "meta")
  54. ClassOptimizer = RegisterErrorClass(10, "planner")
  55. ClassParser = RegisterErrorClass(11, "parser")
  56. ClassPerfSchema = RegisterErrorClass(12, "perfschema")
  57. ClassPrivilege = RegisterErrorClass(13, "privilege")
  58. ClassSchema = RegisterErrorClass(14, "schema")
  59. ClassServer = RegisterErrorClass(15, "server")
  60. ClassStructure = RegisterErrorClass(16, "structure")
  61. ClassVariable = RegisterErrorClass(17, "variable")
  62. ClassXEval = RegisterErrorClass(18, "xeval")
  63. ClassTable = RegisterErrorClass(19, "table")
  64. ClassTypes = RegisterErrorClass(20, "types")
  65. ClassGlobal = RegisterErrorClass(21, "global")
  66. ClassMockTikv = RegisterErrorClass(22, "mocktikv")
  67. ClassJSON = RegisterErrorClass(23, "json")
  68. ClassTiKV = RegisterErrorClass(24, "tikv")
  69. ClassSession = RegisterErrorClass(25, "session")
  70. ClassPlugin = RegisterErrorClass(26, "plugin")
  71. ClassUtil = RegisterErrorClass(27, "util")
  72. // Add more as needed.
  73. )
  74. var errClass2Desc = make(map[ErrClass]string)
  75. var rfcCode2errClass = newCode2ErrClassMap()
  76. type code2ErrClassMap struct {
  77. data sync.Map
  78. }
  79. func newCode2ErrClassMap() *code2ErrClassMap {
  80. return &code2ErrClassMap{
  81. data: sync.Map{},
  82. }
  83. }
  84. func (m *code2ErrClassMap) Get(key string) (ErrClass, bool) {
  85. ret, have := m.data.Load(key)
  86. return ret.(ErrClass), have
  87. }
  88. func (m *code2ErrClassMap) Put(key string, err ErrClass) {
  89. m.data.Store(key, err)
  90. }
  91. // RegisterErrorClass registers new error class for terror.
  92. func RegisterErrorClass(classCode int, desc string) ErrClass {
  93. errClass := ErrClass(classCode)
  94. if _, exists := errClass2Desc[errClass]; exists {
  95. panic(fmt.Sprintf("duplicate register ClassCode %d - %s", classCode, desc))
  96. }
  97. errClass2Desc[errClass] = desc
  98. return errClass
  99. }
  100. // String implements fmt.Stringer interface.
  101. func (ec ErrClass) String() string {
  102. if s, exists := errClass2Desc[ec]; exists {
  103. return s
  104. }
  105. return strconv.Itoa(int(ec))
  106. }
  107. // EqualClass returns true if err is *Error with the same class.
  108. func (ec ErrClass) EqualClass(err error) bool {
  109. e := errors.Cause(err)
  110. if e == nil {
  111. return false
  112. }
  113. if te, ok := e.(*Error); ok {
  114. rfcCode := te.RFCCode()
  115. if index := strings.Index(string(rfcCode), ":"); index > 0 {
  116. if class, has := rfcCode2errClass.Get(string(rfcCode)[:index]); has {
  117. return class == ec
  118. }
  119. }
  120. }
  121. return false
  122. }
  123. // NotEqualClass returns true if err is not *Error with the same class.
  124. func (ec ErrClass) NotEqualClass(err error) bool {
  125. return !ec.EqualClass(err)
  126. }
  127. func (ec ErrClass) initError(code ErrCode) string {
  128. clsMap, ok := ErrClassToMySQLCodes[ec]
  129. if !ok {
  130. clsMap = make(map[ErrCode]struct{})
  131. ErrClassToMySQLCodes[ec] = clsMap
  132. }
  133. clsMap[code] = struct{}{}
  134. class := errClass2Desc[ec]
  135. rfcCode := fmt.Sprintf("%s:%d", class, code)
  136. rfcCode2errClass.Put(class, ec)
  137. return rfcCode
  138. }
  139. // New defines an *Error with an error code and an error message.
  140. // Usually used to create base *Error.
  141. // Attention:
  142. // this method is not goroutine-safe and
  143. // usually be used in global variable initializer
  144. //
  145. // Deprecated: use NewStd or NewStdErr instead.
  146. func (ec ErrClass) New(code ErrCode, message string) *Error {
  147. rfcCode := ec.initError(code)
  148. err := errors.Normalize(message, errors.MySQLErrorCode(int(code)), errors.RFCCodeText(rfcCode))
  149. return err
  150. }
  151. // NewStdErr defines an *Error with an error code, an error
  152. // message and workaround to create standard error.
  153. func (ec ErrClass) NewStdErr(code ErrCode, message *mysql.ErrMessage) *Error {
  154. rfcCode := ec.initError(code)
  155. err := errors.Normalize(message.Raw, errors.RedactArgs(message.RedactArgPos), errors.MySQLErrorCode(int(code)), errors.RFCCodeText(rfcCode))
  156. return err
  157. }
  158. // NewStd calls New using the standard message for the error code
  159. // Attention:
  160. // this method is not goroutine-safe and
  161. // usually be used in global variable initializer
  162. func (ec ErrClass) NewStd(code ErrCode) *Error {
  163. return ec.NewStdErr(code, mysql.MySQLErrName[uint16(code)])
  164. }
  165. // Synthesize synthesizes an *Error in the air
  166. // it didn't register error into ErrClassToMySQLCodes
  167. // so it's goroutine-safe
  168. // and often be used to create Error came from other systems like TiKV.
  169. func (ec ErrClass) Synthesize(code ErrCode, message string) *Error {
  170. return errors.Normalize(message, errors.MySQLErrorCode(int(code)), errors.RFCCodeText(fmt.Sprintf("%s:%d", errClass2Desc[ec], code)))
  171. }
  172. // ToSQLError convert Error to mysql.SQLError.
  173. func ToSQLError(e *Error) *mysql.SQLError {
  174. code := getMySQLErrorCode(e)
  175. return mysql.NewErrf(code, "%s", nil, e.GetMsg())
  176. }
  177. var defaultMySQLErrorCode uint16
  178. func getMySQLErrorCode(e *Error) uint16 {
  179. rfcCode := e.RFCCode()
  180. var class ErrClass
  181. if index := strings.Index(string(rfcCode), ":"); index > 0 {
  182. if ec, has := rfcCode2errClass.Get(string(rfcCode)[:index]); has {
  183. class = ec
  184. } else {
  185. log.Warn("Unknown error class", zap.String("class", string(rfcCode)[:index]))
  186. return defaultMySQLErrorCode
  187. }
  188. }
  189. codeMap, ok := ErrClassToMySQLCodes[class]
  190. if !ok {
  191. log.Warn("Unknown error class", zap.Int("class", int(class)))
  192. return defaultMySQLErrorCode
  193. }
  194. _, ok = codeMap[ErrCode(e.Code())]
  195. if !ok {
  196. log.Debug("Unknown error code", zap.Int("class", int(class)), zap.Int("code", int(e.Code())))
  197. return defaultMySQLErrorCode
  198. }
  199. return uint16(e.Code())
  200. }
  201. var (
  202. // ErrClassToMySQLCodes is the map of ErrClass to code-set.
  203. ErrClassToMySQLCodes = make(map[ErrClass]map[ErrCode]struct{})
  204. ErrCritical = ClassGlobal.NewStdErr(CodeExecResultIsEmpty, mysql.Message("critical error %v", nil))
  205. ErrResultUndetermined = ClassGlobal.NewStdErr(CodeResultUndetermined, mysql.Message("execution result undetermined", nil))
  206. )
  207. func init() {
  208. defaultMySQLErrorCode = mysql.ErrUnknown
  209. }
  210. // ErrorEqual returns a boolean indicating whether err1 is equal to err2.
  211. func ErrorEqual(err1, err2 error) bool {
  212. e1 := errors.Cause(err1)
  213. e2 := errors.Cause(err2)
  214. if e1 == e2 {
  215. return true
  216. }
  217. if e1 == nil || e2 == nil {
  218. return e1 == e2
  219. }
  220. te1, ok1 := e1.(*Error)
  221. te2, ok2 := e2.(*Error)
  222. if ok1 && ok2 {
  223. return te1.RFCCode() == te2.RFCCode()
  224. }
  225. return e1.Error() == e2.Error()
  226. }
  227. // ErrorNotEqual returns a boolean indicating whether err1 isn't equal to err2.
  228. func ErrorNotEqual(err1, err2 error) bool {
  229. return !ErrorEqual(err1, err2)
  230. }
  231. // MustNil cleans up and fatals if err is not nil.
  232. func MustNil(err error, closeFuns ...func()) {
  233. if err != nil {
  234. for _, f := range closeFuns {
  235. f()
  236. }
  237. log.Fatal("unexpected error", zap.Error(err), zap.Stack("stack"))
  238. }
  239. }
  240. // Call executes a function and checks the returned err.
  241. func Call(fn func() error) {
  242. err := fn()
  243. if err != nil {
  244. log.Error("function call errored", zap.Error(err), zap.Stack("stack"))
  245. }
  246. }
  247. // Log logs the error if it is not nil.
  248. func Log(err error) {
  249. if err != nil {
  250. log.Error("encountered error", zap.Error(err), zap.Stack("stack"))
  251. }
  252. }
  253. func GetErrClass(e *Error) ErrClass {
  254. rfcCode := e.RFCCode()
  255. if index := strings.Index(string(rfcCode), ":"); index > 0 {
  256. if class, has := rfcCode2errClass.Get(string(rfcCode)[:index]); has {
  257. return class
  258. }
  259. }
  260. return ErrClass(-1)
  261. }