github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/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  	"fmt"
    18  	"runtime"
    19  	"strconv"
    20  
    21  	"github.com/insionng/yougam/libraries/juju/errors"
    22  	"github.com/insionng/yougam/libraries/ngaut/log"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/mysql"
    24  )
    25  
    26  // Common base error instances.
    27  var (
    28  	CommitNotInTransaction   = ClassExecutor.New(CodeCommitNotInTransaction, "commit not in transaction")
    29  	RollbackNotInTransaction = ClassExecutor.New(CodeRollbackNotInTransaction, "rollback not in transaction")
    30  	ExecResultIsEmpty        = ClassExecutor.New(CodeExecResultIsEmpty, "exec result is empty")
    31  
    32  	MissConnectionID = ClassExpression.New(CodeMissConnectionID, "miss connection id information")
    33  )
    34  
    35  // ErrCode represents a specific error type in a error class.
    36  // Same error code can be used in different error classes.
    37  type ErrCode int
    38  
    39  // Executor error codes.
    40  const (
    41  	CodeCommitNotInTransaction   ErrCode = 1
    42  	CodeRollbackNotInTransaction         = 2
    43  	CodeExecResultIsEmpty                = 3
    44  )
    45  
    46  // Expression error codes.
    47  const (
    48  	CodeMissConnectionID ErrCode = iota + 1
    49  )
    50  
    51  // ErrClass represents a class of errors.
    52  type ErrClass int
    53  
    54  // Error classes.
    55  const (
    56  	ClassAutoid ErrClass = iota + 1
    57  	ClassDDL
    58  	ClassDomain
    59  	ClassEvaluator
    60  	ClassExecutor
    61  	ClassExpression
    62  	ClassInspectkv
    63  	ClassKV
    64  	ClassMeta
    65  	ClassOptimizer
    66  	ClassOptimizerPlan
    67  	ClassParser
    68  	ClassPerfSchema
    69  	ClassPrivilege
    70  	ClassSchema
    71  	ClassServer
    72  	ClassStructure
    73  	ClassVariable
    74  	ClassXEval
    75  	// Add more as needed.
    76  )
    77  
    78  // String implements fmt.Stringer interface.
    79  func (ec ErrClass) String() string {
    80  	switch ec {
    81  	case ClassAutoid:
    82  		return "autoid"
    83  	case ClassDDL:
    84  		return "ddl"
    85  	case ClassDomain:
    86  		return "domain"
    87  	case ClassExecutor:
    88  		return "executor"
    89  	case ClassExpression:
    90  		return "expression"
    91  	case ClassInspectkv:
    92  		return "inspectkv"
    93  	case ClassMeta:
    94  		return "meta"
    95  	case ClassKV:
    96  		return "kv"
    97  	case ClassOptimizer:
    98  		return "optimizer"
    99  	case ClassParser:
   100  		return "parser"
   101  	case ClassPerfSchema:
   102  		return "perfschema"
   103  	case ClassPrivilege:
   104  		return "privilege"
   105  	case ClassSchema:
   106  		return "schema"
   107  	case ClassServer:
   108  		return "server"
   109  	case ClassStructure:
   110  		return "structure"
   111  	case ClassVariable:
   112  		return "variable"
   113  	}
   114  	return strconv.Itoa(int(ec))
   115  }
   116  
   117  // EqualClass returns true if err is *Error with the same class.
   118  func (ec ErrClass) EqualClass(err error) bool {
   119  	e := errors.Cause(err)
   120  	if e == nil {
   121  		return false
   122  	}
   123  	if te, ok := e.(*Error); ok {
   124  		return te.class == ec
   125  	}
   126  	return false
   127  }
   128  
   129  // NotEqualClass returns true if err is not *Error with the same class.
   130  func (ec ErrClass) NotEqualClass(err error) bool {
   131  	return !ec.EqualClass(err)
   132  }
   133  
   134  // New creates an *Error with an error code and an error message.
   135  // Usually used to create base *Error.
   136  func (ec ErrClass) New(code ErrCode, message string) *Error {
   137  	return &Error{
   138  		class:   ec,
   139  		code:    code,
   140  		message: message,
   141  	}
   142  }
   143  
   144  // Error implements error interface and adds integer Class and Code, so
   145  // errors with different message can be compared.
   146  type Error struct {
   147  	class   ErrClass
   148  	code    ErrCode
   149  	message string
   150  	file    string
   151  	line    int
   152  }
   153  
   154  // Class returns ErrClass
   155  func (e *Error) Class() ErrClass {
   156  	return e.class
   157  }
   158  
   159  // Code returns ErrCode
   160  func (e *Error) Code() ErrCode {
   161  	return e.code
   162  }
   163  
   164  // Location returns the location where the error is created,
   165  // implements juju/errors locationer interface.
   166  func (e *Error) Location() (file string, line int) {
   167  	return e.file, e.line
   168  }
   169  
   170  // Error implements error interface.
   171  func (e *Error) Error() string {
   172  	return fmt.Sprintf("[%s:%d]%s", e.class, e.code, e.message)
   173  }
   174  
   175  // Gen generates a new *Error with the same class and code, and a new formatted message.
   176  func (e *Error) Gen(format string, args ...interface{}) *Error {
   177  	err := *e
   178  	err.message = fmt.Sprintf(format, args...)
   179  	_, err.file, err.line, _ = runtime.Caller(1)
   180  	return &err
   181  }
   182  
   183  // Equal checks if err is equal to e.
   184  func (e *Error) Equal(err error) bool {
   185  	originErr := errors.Cause(err)
   186  	if originErr == nil {
   187  		return false
   188  	}
   189  	inErr, ok := originErr.(*Error)
   190  	return ok && e.class == inErr.class && e.code == inErr.code
   191  }
   192  
   193  // NotEqual checks if err is not equal to e.
   194  func (e *Error) NotEqual(err error) bool {
   195  	return !e.Equal(err)
   196  }
   197  
   198  // ToSQLError convert Error to mysql.SQLError.
   199  func (e *Error) ToSQLError() *mysql.SQLError {
   200  	code := e.getMySQLErrorCode()
   201  	return mysql.NewErrf(code, e.message)
   202  }
   203  
   204  var defaultMySQLErrorCode uint16
   205  
   206  func (e *Error) getMySQLErrorCode() uint16 {
   207  	codeMap, ok := ErrClassToMySQLCodes[e.class]
   208  	if !ok {
   209  		log.Warnf("Unknown error class: %v", e.class)
   210  		return defaultMySQLErrorCode
   211  	}
   212  	code, ok := codeMap[e.code]
   213  	if !ok {
   214  		log.Warnf("Unknown error class: %v code: %v", e.class, e.code)
   215  		return defaultMySQLErrorCode
   216  	}
   217  	return code
   218  }
   219  
   220  var (
   221  	// ErrCode to mysql error code map.
   222  	parserMySQLErrCodes     = map[ErrCode]uint16{}
   223  	executorMySQLErrCodes   = map[ErrCode]uint16{}
   224  	serverMySQLErrCodes     = map[ErrCode]uint16{}
   225  	expressionMySQLErrCodes = map[ErrCode]uint16{}
   226  
   227  	// ErrClassToMySQLCodes is the map of ErrClass to code-map.
   228  	ErrClassToMySQLCodes map[ErrClass](map[ErrCode]uint16)
   229  )
   230  
   231  func init() {
   232  	ErrClassToMySQLCodes = make(map[ErrClass](map[ErrCode]uint16))
   233  	ErrClassToMySQLCodes[ClassExecutor] = executorMySQLErrCodes
   234  	ErrClassToMySQLCodes[ClassExpression] = expressionMySQLErrCodes
   235  	ErrClassToMySQLCodes[ClassParser] = parserMySQLErrCodes
   236  	ErrClassToMySQLCodes[ClassServer] = serverMySQLErrCodes
   237  	defaultMySQLErrorCode = mysql.ErrUnknown
   238  }
   239  
   240  // ErrorEqual returns a boolean indicating whether err1 is equal to err2.
   241  func ErrorEqual(err1, err2 error) bool {
   242  	e1 := errors.Cause(err1)
   243  	e2 := errors.Cause(err2)
   244  
   245  	if e1 == e2 {
   246  		return true
   247  	}
   248  
   249  	if e1 == nil || e2 == nil {
   250  		return e1 == e2
   251  	}
   252  
   253  	te1, ok1 := e1.(*Error)
   254  	te2, ok2 := e2.(*Error)
   255  	if ok1 && ok2 {
   256  		return te1.class == te2.class && te1.code == te2.code
   257  	}
   258  
   259  	return e1.Error() == e2.Error()
   260  }
   261  
   262  // ErrorNotEqual returns a boolean indicating whether err1 isn't equal to err2.
   263  func ErrorNotEqual(err1, err2 error) bool {
   264  	return !ErrorEqual(err1, err2)
   265  }