diff --git a/compatible_shim.go b/compatible_shim.go new file mode 100644 index 00000000..ba446e08 --- /dev/null +++ b/compatible_shim.go @@ -0,0 +1,99 @@ +// Copyright 2020 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package errors + +import ( + "encoding/json" + "strconv" + "strings" +) + +// class2RFCCode is used for compatible with old version of TiDB. When +// marshal Error to json, old version of TiDB contain a 'class' field +// which is represented for error class. In order to parse and convert +// json to errors.Error, using this map to convert error class to RFC +// error code text. here is reference: +// https://github.com/pingcap/parser/blob/release-3.0/terror/terror.go#L58 +var class2RFCCode = map[int]string{ + 1: "autoid", + 2: "ddl", + 3: "domain", + 4: "evaluator", + 5: "executor", + 6: "expression", + 7: "admin", + 8: "kv", + 9: "meta", + 10: "planner", + 11: "parser", + 12: "perfschema", + 13: "privilege", + 14: "schema", + 15: "server", + 16: "struct", + 17: "variable", + 18: "xeval", + 19: "table", + 20: "types", + 21: "global", + 22: "mocktikv", + 23: "json", + 24: "tikv", + 25: "session", + 26: "plugin", + 27: "util", +} +var rfcCode2class map[string]int + +func init() { + rfcCode2class = make(map[string]int) + for k, v := range class2RFCCode { + rfcCode2class[v] = k + } +} + + +// MarshalJSON implements json.Marshaler interface. +// aware that this function cannot save a 'registered' status, +// since we cannot access the registry when unmarshaling, +// and the original global registry would be removed here. +// This function is reserved for compatibility. +func (e *Error) MarshalJSON() ([]byte, error) { + ec := strings.Split(string(e.codeText), ":")[0] + return json.Marshal(&jsonError{ + Class: rfcCode2class[ec], + Code: int(e.code), + Msg: e.GetMsg(), + RFCCode: string(e.codeText), + }) +} + +// UnmarshalJSON implements json.Unmarshaler interface. +// aware that this function cannot create a 'registered' error, +// since we cannot access the registry in this context, +// and the original global registry is removed. +// This function is reserved for compatibility. +func (e *Error) UnmarshalJSON(data []byte) error { + tErr := &jsonError{} + if err := json.Unmarshal(data, &tErr); err != nil { + return Trace(err) + } + e.codeText = ErrCodeText(tErr.RFCCode) + if tErr.RFCCode == "" && tErr.Class > 0 { + e.codeText = ErrCodeText(class2RFCCode[tErr.Class] + ":" + strconv.Itoa(tErr.Code)) + } + e.code = ErrCode(tErr.Code) + e.message = tErr.Msg + return nil +} diff --git a/terror_error.go b/normalize.go similarity index 69% rename from terror_error.go rename to normalize.go index a0b0ee74..5712fe72 100644 --- a/terror_error.go +++ b/normalize.go @@ -14,11 +14,9 @@ package errors import ( - "encoding/json" "fmt" "runtime" "strconv" - "strings" "go.uber.org/atomic" ) @@ -36,59 +34,9 @@ type ErrCodeText string type ErrorID string type RFCErrorCode string -// class2RFCCode is used for compatible with old version of TiDB. When -// marshal Error to json, old version of TiDB contain a 'class' field -// which is represented for error class. In order to parser and convert -// json to errors.Error, using this map to convert error class to RFC -// error code text. here is reference: -// https://github.com/pingcap/parser/blob/release-3.0/terror/terror.go#L58 -var class2RFCCode = map[int]string{ - 1: "autoid", - 2: "ddl", - 3: "domain", - 4: "evaluator", - 5: "executor", - 6: "expression", - 7: "admin", - 8: "kv", - 9: "meta", - 10: "planner", - 11: "parser", - 12: "perfschema", - 13: "privilege", - 14: "schema", - 15: "server", - 16: "struct", - 17: "variable", - 18: "xeval", - 19: "table", - 20: "types", - 21: "global", - 22: "mocktikv", - 23: "json", - 24: "tikv", - 25: "session", - 26: "plugin", - 27: "util", -} -var rfcCode2class map[string]int - -func init() { - rfcCode2class = make(map[string]int) - for k, v := range class2RFCCode { - rfcCode2class[v] = k - } -} - // Error is the 'prototype' of a type of errors. // Use DefineError to make a *Error: -// var ErrUnavailable = ClassRegion.DefineError(). -// TextualCode("Unavailable"). -// Description("A certain Raft Group is not available, such as the number of replicas is not enough.\n" + -// "This error usually occurs when the TiKV server is busy or the TiKV node is down."). -// Workaround("Check the status, monitoring data and log of the TiKV server."). -// MessageTemplate("Region %d is unavailable"). -// Build() +// var ErrUnavailable = errors.Normalize("Region %d is unavailable", errors.RFCCodeText("Unavailable")) // // "throw" it at runtime: // func Somewhat() error { @@ -111,14 +59,6 @@ type Error struct { // message is a template of the description of this error. // printf-style formatting is enabled. message string - // The workaround field: how to work around this error. - // It's used to teach the users how to solve the error if occurring in the real environment. - workaround string - // description is the expanded detail of why this error occurred. - // This could be written by developer at a static env, - // and the more detail this field explaining the better, - // even some guess of the cause could be included. - description string // redactArgsPos defines the positions of arguments in message that need to be redacted. // And it is controlled by the global var RedactLogEnabled. // For example, an original error is `Duplicate entry 'PRIMARY' for key 'key'`, @@ -303,40 +243,6 @@ type jsonError struct { RFCCode string `json:"rfccode"` } -// MarshalJSON implements json.Marshaler interface. -// aware that this function cannot save a 'registered' status, -// since we cannot access the registry when unmarshaling, -// and the original global registry would be removed here. -// This function is reserved for compatibility. -func (e *Error) MarshalJSON() ([]byte, error) { - ec := strings.Split(string(e.codeText), ":")[0] - return json.Marshal(&jsonError{ - Class: rfcCode2class[ec], - Code: int(e.code), - Msg: e.GetMsg(), - RFCCode: string(e.codeText), - }) -} - -// UnmarshalJSON implements json.Unmarshaler interface. -// aware that this function cannot create a 'registered' error, -// since we cannot access the registry in this context, -// and the original global registry is removed. -// This function is reserved for compatibility. -func (e *Error) UnmarshalJSON(data []byte) error { - tErr := &jsonError{} - if err := json.Unmarshal(data, &tErr); err != nil { - return Trace(err) - } - e.codeText = ErrCodeText(tErr.RFCCode) - if tErr.RFCCode == "" && tErr.Class > 0 { - e.codeText = ErrCodeText(class2RFCCode[tErr.Class] + ":" + strconv.Itoa(tErr.Code)) - } - e.code = ErrCode(tErr.Code) - e.message = tErr.Msg - return nil -} - func (e *Error) Wrap(err error) *Error { if err != nil { newErr := *e @@ -375,20 +281,6 @@ func (e *Error) GenWithStackByCause(args ...interface{}) error { type NormalizeOption func(*Error) -// Description returns a NormalizeOption to set description. -func Description(desc string) NormalizeOption { - return func(e *Error) { - e.description = desc - } -} - -// Workaround returns a NormalizeOption to set workaround. -func Workaround(wr string) NormalizeOption { - return func(e *Error) { - e.workaround = wr - } -} - func RedactArgs(pos []int) NormalizeOption { return func(e *Error) { e.redactArgsPos = pos diff --git a/terror_test/terror_test.go b/terror_test/terror_test.go index 1b88b000..7967412f 100644 --- a/terror_test/terror_test.go +++ b/terror_test/terror_test.go @@ -135,7 +135,7 @@ func (s *testTErrorSuite) TestRFCCode(c *C) { c2err2 := errors.Normalize("nothing", errors.RFCCodeText("TestErr2:Err2")) c.Assert(c1err1.RFCCode(), Equals, errors.RFCErrorCode("TestErr1:Err1")) c.Assert(c2err2.RFCCode(), Equals, errors.RFCErrorCode("TestErr2:Err2")) - berr := errors.Normalize("nothing", errors.RFCCodeText("Blank:B1"), errors.Workaround(`Do nothing`)) + berr := errors.Normalize("nothing", errors.RFCCodeText("Blank:B1")) c.Assert(berr.RFCCode(), Equals, errors.RFCErrorCode("Blank:B1")) }