Files
tidb/br/pkg/utils/key.go
2021-08-06 00:17:12 +08:00

92 lines
2.0 KiB
Go

// Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
package utils
import (
"bytes"
"encoding/hex"
"fmt"
"io"
"strings"
"github.com/pingcap/errors"
berrors "github.com/pingcap/tidb/br/pkg/errors"
)
// ParseKey parse key by given format.
func ParseKey(format, key string) ([]byte, error) {
switch format {
case "raw":
return []byte(key), nil
case "escaped":
return unescapedKey(key)
case "hex":
key, err := hex.DecodeString(key)
if err != nil {
return nil, errors.Trace(err)
}
return key, nil
}
return nil, errors.Annotate(berrors.ErrInvalidArgument, "unknown format")
}
// Ref PD: https://github.com/pingcap/pd/blob/master/tools/pd-ctl/pdctl/command/region_command.go#L334
func unescapedKey(text string) ([]byte, error) {
var buf []byte
r := bytes.NewBuffer([]byte(text))
for {
c, err := r.ReadByte()
if err != nil {
if errors.Cause(err) != io.EOF { // nolint:errorlint
return nil, errors.Trace(err)
}
break
}
if c != '\\' {
buf = append(buf, c)
continue
}
n := r.Next(1)
if len(n) == 0 {
return nil, io.EOF
}
// See: https://golang.org/ref/spec#Rune_literals
if idx := strings.IndexByte(`abfnrtv\'"`, n[0]); idx != -1 {
buf = append(buf, []byte("\a\b\f\n\r\t\v\\'\"")[idx])
continue
}
switch n[0] {
case 'x':
fmt.Sscanf(string(r.Next(2)), "%02x", &c)
buf = append(buf, c)
default:
n = append(n, r.Next(2)...)
_, err := fmt.Sscanf(string(n), "%03o", &c)
if err != nil {
return nil, errors.Trace(err)
}
buf = append(buf, c)
}
}
return buf, nil
}
// CompareEndKey compared two keys that BOTH represent the EXCLUSIVE ending of some range. An empty end key is the very
// end, so an empty key is greater than any other keys.
// Please note that this function is not applicable if any one argument is not an EXCLUSIVE ending of a range.
func CompareEndKey(a, b []byte) int {
if len(a) == 0 {
if len(b) == 0 {
return 0
}
return 1
}
if len(b) == 0 {
return -1
}
return bytes.Compare(a, b)
}