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