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  }