github.com/XiaoMi/Gaea@v1.2.5/parser/terror/terror.go (about) 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 14 package terror 15 16 import ( 17 "encoding/json" 18 "fmt" 19 "strconv" 20 21 "github.com/pingcap/errors" 22 23 "github.com/XiaoMi/Gaea/log" 24 "github.com/XiaoMi/Gaea/mysql" 25 ) 26 27 // Global error instances. 28 var ( 29 ErrCritical = ClassGlobal.New(CodeExecResultIsEmpty, "critical error %v") 30 ErrResultUndetermined = ClassGlobal.New(CodeResultUndetermined, "execution result undetermined") 31 ) 32 33 // ErrCode represents a specific error type in a error class. 34 // Same error code can be used in different error classes. 35 type ErrCode int 36 37 const ( 38 // Executor error codes. 39 40 // CodeUnknown is for errors of unknown reason. 41 CodeUnknown ErrCode = -1 42 // CodeExecResultIsEmpty indicates execution result is empty. 43 CodeExecResultIsEmpty ErrCode = 3 44 45 // Expression error codes. 46 47 // CodeMissConnectionID indicates connection id is missing. 48 CodeMissConnectionID ErrCode = 1 49 50 // Special error codes. 51 52 // CodeResultUndetermined indicates the sql execution result is undetermined. 53 CodeResultUndetermined ErrCode = 2 54 ) 55 56 // ErrClass represents a class of errors. 57 type ErrClass int 58 59 // Error classes. 60 const ( 61 ClassAutoid ErrClass = iota + 1 62 ClassDDL 63 ClassDomain 64 ClassEvaluator 65 ClassExecutor 66 ClassExpression 67 ClassAdmin 68 ClassKV 69 ClassMeta 70 ClassOptimizer 71 ClassParser 72 ClassPerfSchema 73 ClassPrivilege 74 ClassSchema 75 ClassServer 76 ClassStructure 77 ClassVariable 78 ClassXEval 79 ClassTable 80 ClassTypes 81 ClassGlobal 82 ClassMockTikv 83 ClassJSON 84 ClassTiKV 85 ClassSession 86 ClassPlugin 87 // Add more as needed. 88 ) 89 90 var errClz2Str = map[ErrClass]string{ 91 ClassAutoid: "autoid", 92 ClassDDL: "ddl", 93 ClassDomain: "domain", 94 ClassExecutor: "executor", 95 ClassExpression: "expression", 96 ClassAdmin: "admin", 97 ClassMeta: "meta", 98 ClassKV: "kv", 99 ClassOptimizer: "planner", 100 ClassParser: "parser", 101 ClassPerfSchema: "perfschema", 102 ClassPrivilege: "privilege", 103 ClassSchema: "schema", 104 ClassServer: "server", 105 ClassStructure: "structure", 106 ClassVariable: "variable", 107 ClassTable: "table", 108 ClassTypes: "types", 109 ClassGlobal: "global", 110 ClassMockTikv: "mocktikv", 111 ClassJSON: "json", 112 ClassTiKV: "tikv", 113 ClassSession: "session", 114 ClassPlugin: "plugin", 115 } 116 117 // String implements fmt.Stringer interface. 118 func (ec ErrClass) String() string { 119 if s, exists := errClz2Str[ec]; exists { 120 return s 121 } 122 return strconv.Itoa(int(ec)) 123 } 124 125 // EqualClass returns true if err is *Error with the same class. 126 func (ec ErrClass) EqualClass(err error) bool { 127 e := errors.Cause(err) 128 if e == nil { 129 return false 130 } 131 if te, ok := e.(*Error); ok { 132 return te.class == ec 133 } 134 return false 135 } 136 137 // NotEqualClass returns true if err is not *Error with the same class. 138 func (ec ErrClass) NotEqualClass(err error) bool { 139 return !ec.EqualClass(err) 140 } 141 142 // New creates an *Error with an error code and an error message. 143 // Usually used to create base *Error. 144 func (ec ErrClass) New(code ErrCode, message string) *Error { 145 return &Error{ 146 class: ec, 147 code: code, 148 message: message, 149 } 150 } 151 152 // Error implements error interface and adds integer Class and Code, so 153 // errors with different message can be compared. 154 type Error struct { 155 class ErrClass 156 code ErrCode 157 message string 158 args []interface{} 159 file string 160 line int 161 } 162 163 // Class returns ErrClass 164 func (e *Error) Class() ErrClass { 165 return e.class 166 } 167 168 // Code returns ErrCode 169 func (e *Error) Code() ErrCode { 170 return e.code 171 } 172 173 // MarshalJSON implements json.Marshaler interface. 174 func (e *Error) MarshalJSON() ([]byte, error) { 175 return json.Marshal(&struct { 176 Class ErrClass `json:"class"` 177 Code ErrCode `json:"code"` 178 Msg string `json:"message"` 179 }{ 180 Class: e.class, 181 Code: e.code, 182 Msg: e.getMsg(), 183 }) 184 } 185 186 // UnmarshalJSON implements json.Unmarshaler interface. 187 func (e *Error) UnmarshalJSON(data []byte) error { 188 err := &struct { 189 Class ErrClass `json:"class"` 190 Code ErrCode `json:"code"` 191 Msg string `json:"message"` 192 }{} 193 194 if err := json.Unmarshal(data, &err); err != nil { 195 return errors.Trace(err) 196 } 197 198 e.class = err.Class 199 e.code = err.Code 200 e.message = err.Msg 201 return nil 202 } 203 204 // Location returns the location where the error is created, 205 // implements juju/errors locationer interface. 206 func (e *Error) Location() (file string, line int) { 207 return e.file, e.line 208 } 209 210 // Error implements error interface. 211 func (e *Error) Error() string { 212 return fmt.Sprintf("[%s:%d]%s", e.class, e.code, e.getMsg()) 213 } 214 215 func (e *Error) getMsg() string { 216 if len(e.args) > 0 { 217 return fmt.Sprintf(e.message, e.args...) 218 } 219 return e.message 220 } 221 222 // GenWithStack generates a new *Error with the same class and code, and a new formatted message. 223 func (e *Error) GenWithStack(format string, args ...interface{}) error { 224 err := *e 225 err.message = format 226 err.args = args 227 return errors.AddStack(&err) 228 } 229 230 // GenWithStackByArgs generates a new *Error with the same class and code, and new arguments. 231 func (e *Error) GenWithStackByArgs(args ...interface{}) error { 232 err := *e 233 err.args = args 234 return errors.AddStack(&err) 235 } 236 237 // FastGen generates a new *Error with the same class and code, and a new formatted message. 238 // This will not call runtime.Caller to get file and line. 239 func (e *Error) FastGen(format string, args ...interface{}) error { 240 err := *e 241 err.message = format 242 err.args = args 243 return &err 244 } 245 246 // Equal checks if err is equal to e. 247 func (e *Error) Equal(err error) bool { 248 originErr := errors.Cause(err) 249 if originErr == nil { 250 return false 251 } 252 253 if error(e) == originErr { 254 return true 255 } 256 inErr, ok := originErr.(*Error) 257 return ok && e.class == inErr.class && e.code == inErr.code 258 } 259 260 // NotEqual checks if err is not equal to e. 261 func (e *Error) NotEqual(err error) bool { 262 return !e.Equal(err) 263 } 264 265 // ToSQLError convert Error to mysql.SQLError. 266 func (e *Error) ToSQLError() *mysql.SQLError { 267 code := e.getMySQLErrorCode() 268 return mysql.NewErrf(code, "%s", e.getMsg()) 269 } 270 271 var defaultMySQLErrorCode uint16 272 273 func (e *Error) getMySQLErrorCode() uint16 { 274 codeMap, ok := ErrClassToMySQLCodes[e.class] 275 if !ok { 276 log.Warn("Unknown error class: %v", e.class) 277 return defaultMySQLErrorCode 278 } 279 code, ok := codeMap[e.code] 280 if !ok { 281 log.Warn("Unknown error class: %v code: %v", e.class, e.code) 282 return defaultMySQLErrorCode 283 } 284 return code 285 } 286 287 var ( 288 // ErrClassToMySQLCodes is the map of ErrClass to code-map. 289 ErrClassToMySQLCodes map[ErrClass]map[ErrCode]uint16 290 ) 291 292 func init() { 293 ErrClassToMySQLCodes = make(map[ErrClass]map[ErrCode]uint16) 294 defaultMySQLErrorCode = mysql.ErrUnknown 295 } 296 297 // ErrorEqual returns a boolean indicating whether err1 is equal to err2. 298 func ErrorEqual(err1, err2 error) bool { 299 e1 := errors.Cause(err1) 300 e2 := errors.Cause(err2) 301 302 if e1 == e2 { 303 return true 304 } 305 306 if e1 == nil || e2 == nil { 307 return e1 == e2 308 } 309 310 te1, ok1 := e1.(*Error) 311 te2, ok2 := e2.(*Error) 312 if ok1 && ok2 { 313 return te1.class == te2.class && te1.code == te2.code 314 } 315 316 return e1.Error() == e2.Error() 317 } 318 319 // ErrorNotEqual returns a boolean indicating whether err1 isn't equal to err2. 320 func ErrorNotEqual(err1, err2 error) bool { 321 return !ErrorEqual(err1, err2) 322 } 323 324 // MustNil cleans up and fatals if err is not nil. 325 func MustNil(err error, closeFuns ...func()) { 326 if err != nil { 327 for _, f := range closeFuns { 328 f() 329 } 330 log.Fatal(errors.ErrorStack(err)) 331 } 332 } 333 334 // Call executes a function and checks the returned err. 335 func Call(fn func() error) { 336 err := fn() 337 if err != nil { 338 log.Warn(errors.ErrorStack(err)) 339 } 340 } 341 342 // Log logs the error if it is not nil. 343 func Log(err error) { 344 if err != nil { 345 log.Warn(errors.ErrorStack(err)) 346 } 347 }