forked from forgejo/forgejo
Integrate public as bindata optionally (#293)
* Dropped unused codekit config * Integrated dynamic and static bindata for public * Ignore public bindata * Add a general generate make task * Integrated flexible public assets into web command * Updated vendoring, added all missiong govendor deps * Made the linter happy with the bindata and dynamic code * Moved public bindata definition to modules directory * Ignoring the new bindata path now * Updated to the new public modules import path * Updated public bindata command and drop the new prefix
This commit is contained in:
parent
4680c349dd
commit
b6a95a8cb3
691 changed files with 305318 additions and 1272 deletions
68
vendor/github.com/pingcap/tidb/util/auth.go
generated
vendored
Normal file
68
vendor/github.com/pingcap/tidb/util/auth.go
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2015 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 util
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
// CalcPassword is the algorithm convert hashed password to auth string.
|
||||
// See: https://dev.mysql.com/doc/internals/en/secure-password-authentication.html
|
||||
// SHA1( password ) XOR SHA1( "20-bytes random data from server" <concat> SHA1( SHA1( password ) ) )
|
||||
func CalcPassword(scramble, sha1pwd []byte) []byte {
|
||||
if len(sha1pwd) == 0 {
|
||||
return nil
|
||||
}
|
||||
// scrambleHash = SHA1(scramble + SHA1(sha1pwd))
|
||||
// inner Hash
|
||||
hash := Sha1Hash(sha1pwd)
|
||||
// outer Hash
|
||||
crypt := sha1.New()
|
||||
crypt.Write(scramble)
|
||||
crypt.Write(hash)
|
||||
scramble = crypt.Sum(nil)
|
||||
// token = scrambleHash XOR stage1Hash
|
||||
for i := range scramble {
|
||||
scramble[i] ^= sha1pwd[i]
|
||||
}
|
||||
return scramble
|
||||
}
|
||||
|
||||
// Sha1Hash is an util function to calculate sha1 hash.
|
||||
func Sha1Hash(bs []byte) []byte {
|
||||
crypt := sha1.New()
|
||||
crypt.Write(bs)
|
||||
return crypt.Sum(nil)
|
||||
}
|
||||
|
||||
// EncodePassword converts plaintext password to hashed hex string.
|
||||
func EncodePassword(pwd string) string {
|
||||
if len(pwd) == 0 {
|
||||
return ""
|
||||
}
|
||||
hash := Sha1Hash([]byte(pwd))
|
||||
return hex.EncodeToString(hash)
|
||||
}
|
||||
|
||||
// DecodePassword converts hex string password to byte array.
|
||||
func DecodePassword(pwd string) ([]byte, error) {
|
||||
x, err := hex.DecodeString(pwd)
|
||||
if err != nil {
|
||||
return nil, errors.Trace(err)
|
||||
}
|
||||
return x, nil
|
||||
}
|
6
vendor/github.com/pingcap/tidb/util/bytes/bytes.go
generated
vendored
Normal file
6
vendor/github.com/pingcap/tidb/util/bytes/bytes.go
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
package bytes
|
||||
|
||||
// CloneBytes returns a deep copy of slice b.
|
||||
func CloneBytes(b []byte) []byte {
|
||||
return append([]byte(nil), b...)
|
||||
}
|
369
vendor/github.com/pingcap/tidb/util/charset/charset.go
generated
vendored
Normal file
369
vendor/github.com/pingcap/tidb/util/charset/charset.go
generated
vendored
Normal file
|
@ -0,0 +1,369 @@
|
|||
// Copyright 2015 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 charset
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
// Charset is a charset.
|
||||
// Now we only support MySQL.
|
||||
type Charset struct {
|
||||
Name string
|
||||
DefaultCollation *Collation
|
||||
Collations map[string]*Collation
|
||||
Desc string
|
||||
Maxlen int
|
||||
}
|
||||
|
||||
// Collation is a collation.
|
||||
// Now we only support MySQL.
|
||||
type Collation struct {
|
||||
ID int
|
||||
CharsetName string
|
||||
Name string
|
||||
IsDefault bool
|
||||
}
|
||||
|
||||
var charsets = make(map[string]*Charset)
|
||||
|
||||
// All the supported charsets should be in the following table.
|
||||
var charsetInfos = []*Charset{
|
||||
{"utf8", nil, make(map[string]*Collation), "UTF-8 Unicode", 3},
|
||||
{"latin1", nil, make(map[string]*Collation), "cp1252 West European", 1},
|
||||
{"utf8mb4", nil, make(map[string]*Collation), "UTF-8 Unicode", 4},
|
||||
{"ascii", nil, make(map[string]*Collation), "US ASCII", 1},
|
||||
}
|
||||
|
||||
func init() {
|
||||
for _, c := range charsetInfos {
|
||||
charsets[c.Name] = c
|
||||
}
|
||||
for _, c := range collations {
|
||||
charset, ok := charsets[c.CharsetName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
charset.Collations[c.Name] = c
|
||||
if c.IsDefault {
|
||||
charset.DefaultCollation = c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Desc is a charset description.
|
||||
type Desc struct {
|
||||
Name string
|
||||
Desc string
|
||||
DefaultCollation string
|
||||
Maxlen int
|
||||
}
|
||||
|
||||
// GetAllCharsets gets all charset descriptions in the local charsets.
|
||||
func GetAllCharsets() []*Desc {
|
||||
descs := make([]*Desc, 0, len(charsets))
|
||||
// The charsetInfos is an array, so the iterate order will be stable.
|
||||
for _, ci := range charsetInfos {
|
||||
c, ok := charsets[ci.Name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
desc := &Desc{
|
||||
Name: c.Name,
|
||||
DefaultCollation: c.DefaultCollation.Name,
|
||||
Desc: c.Desc,
|
||||
Maxlen: c.Maxlen,
|
||||
}
|
||||
descs = append(descs, desc)
|
||||
}
|
||||
return descs
|
||||
}
|
||||
|
||||
// ValidCharsetAndCollation checks the charset and the collation validity
|
||||
// and retuns a boolean.
|
||||
func ValidCharsetAndCollation(cs string, co string) bool {
|
||||
// We will use utf8 as a default charset.
|
||||
if cs == "" {
|
||||
cs = "utf8"
|
||||
}
|
||||
|
||||
c, ok := charsets[cs]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if co == "" {
|
||||
return true
|
||||
}
|
||||
_, ok = c.Collations[co]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// GetDefaultCollation returns the default collation for charset
|
||||
func GetDefaultCollation(charset string) (string, error) {
|
||||
c, ok := charsets[charset]
|
||||
if !ok {
|
||||
return "", errors.Errorf("Unkown charset %s", charset)
|
||||
}
|
||||
return c.DefaultCollation.Name, nil
|
||||
}
|
||||
|
||||
// GetCharsetInfo returns charset and collation for cs as name.
|
||||
func GetCharsetInfo(cs string) (string, string, error) {
|
||||
c, ok := charsets[strings.ToLower(cs)]
|
||||
if !ok {
|
||||
return "", "", errors.Errorf("Unknown charset %s", cs)
|
||||
}
|
||||
return c.Name, c.DefaultCollation.Name, nil
|
||||
}
|
||||
|
||||
// GetCollations returns a list for all collations.
|
||||
func GetCollations() []*Collation {
|
||||
return collations
|
||||
}
|
||||
|
||||
const (
|
||||
// CharsetBin is used for marking binary charset.
|
||||
CharsetBin = "binary"
|
||||
// CollationBin is the default collation for CharsetBin.
|
||||
CollationBin = "binary"
|
||||
)
|
||||
|
||||
var collations = []*Collation{
|
||||
{1, "big5", "big5_chinese_ci", true},
|
||||
{2, "latin2", "latin2_czech_cs", false},
|
||||
{3, "dec8", "dec8_swedish_ci", true},
|
||||
{4, "cp850", "cp850_general_ci", true},
|
||||
{5, "latin1", "latin1_german1_ci", false},
|
||||
{6, "hp8", "hp8_english_ci", true},
|
||||
{7, "koi8r", "koi8r_general_ci", true},
|
||||
{8, "latin1", "latin1_swedish_ci", true},
|
||||
{9, "latin2", "latin2_general_ci", true},
|
||||
{10, "swe7", "swe7_swedish_ci", true},
|
||||
{11, "ascii", "ascii_general_ci", true},
|
||||
{12, "ujis", "ujis_japanese_ci", true},
|
||||
{13, "sjis", "sjis_japanese_ci", true},
|
||||
{14, "cp1251", "cp1251_bulgarian_ci", false},
|
||||
{15, "latin1", "latin1_danish_ci", false},
|
||||
{16, "hebrew", "hebrew_general_ci", true},
|
||||
{18, "tis620", "tis620_thai_ci", true},
|
||||
{19, "euckr", "euckr_korean_ci", true},
|
||||
{20, "latin7", "latin7_estonian_cs", false},
|
||||
{21, "latin2", "latin2_hungarian_ci", false},
|
||||
{22, "koi8u", "koi8u_general_ci", true},
|
||||
{23, "cp1251", "cp1251_ukrainian_ci", false},
|
||||
{24, "gb2312", "gb2312_chinese_ci", true},
|
||||
{25, "greek", "greek_general_ci", true},
|
||||
{26, "cp1250", "cp1250_general_ci", true},
|
||||
{27, "latin2", "latin2_croatian_ci", false},
|
||||
{28, "gbk", "gbk_chinese_ci", true},
|
||||
{29, "cp1257", "cp1257_lithuanian_ci", false},
|
||||
{30, "latin5", "latin5_turkish_ci", true},
|
||||
{31, "latin1", "latin1_german2_ci", false},
|
||||
{32, "armscii8", "armscii8_general_ci", true},
|
||||
{33, "utf8", "utf8_general_ci", true},
|
||||
{34, "cp1250", "cp1250_czech_cs", false},
|
||||
{35, "ucs2", "ucs2_general_ci", true},
|
||||
{36, "cp866", "cp866_general_ci", true},
|
||||
{37, "keybcs2", "keybcs2_general_ci", true},
|
||||
{38, "macce", "macce_general_ci", true},
|
||||
{39, "macroman", "macroman_general_ci", true},
|
||||
{40, "cp852", "cp852_general_ci", true},
|
||||
{41, "latin7", "latin7_general_ci", true},
|
||||
{42, "latin7", "latin7_general_cs", false},
|
||||
{43, "macce", "macce_bin", false},
|
||||
{44, "cp1250", "cp1250_croatian_ci", false},
|
||||
{45, "utf8mb4", "utf8mb4_general_ci", true},
|
||||
{46, "utf8mb4", "utf8mb4_bin", false},
|
||||
{47, "latin1", "latin1_bin", false},
|
||||
{48, "latin1", "latin1_general_ci", false},
|
||||
{49, "latin1", "latin1_general_cs", false},
|
||||
{50, "cp1251", "cp1251_bin", false},
|
||||
{51, "cp1251", "cp1251_general_ci", true},
|
||||
{52, "cp1251", "cp1251_general_cs", false},
|
||||
{53, "macroman", "macroman_bin", false},
|
||||
{54, "utf16", "utf16_general_ci", true},
|
||||
{55, "utf16", "utf16_bin", false},
|
||||
{56, "utf16le", "utf16le_general_ci", true},
|
||||
{57, "cp1256", "cp1256_general_ci", true},
|
||||
{58, "cp1257", "cp1257_bin", false},
|
||||
{59, "cp1257", "cp1257_general_ci", true},
|
||||
{60, "utf32", "utf32_general_ci", true},
|
||||
{61, "utf32", "utf32_bin", false},
|
||||
{62, "utf16le", "utf16le_bin", false},
|
||||
{63, "binary", "binary", true},
|
||||
{64, "armscii8", "armscii8_bin", false},
|
||||
{65, "ascii", "ascii_bin", false},
|
||||
{66, "cp1250", "cp1250_bin", false},
|
||||
{67, "cp1256", "cp1256_bin", false},
|
||||
{68, "cp866", "cp866_bin", false},
|
||||
{69, "dec8", "dec8_bin", false},
|
||||
{70, "greek", "greek_bin", false},
|
||||
{71, "hebrew", "hebrew_bin", false},
|
||||
{72, "hp8", "hp8_bin", false},
|
||||
{73, "keybcs2", "keybcs2_bin", false},
|
||||
{74, "koi8r", "koi8r_bin", false},
|
||||
{75, "koi8u", "koi8u_bin", false},
|
||||
{77, "latin2", "latin2_bin", false},
|
||||
{78, "latin5", "latin5_bin", false},
|
||||
{79, "latin7", "latin7_bin", false},
|
||||
{80, "cp850", "cp850_bin", false},
|
||||
{81, "cp852", "cp852_bin", false},
|
||||
{82, "swe7", "swe7_bin", false},
|
||||
{83, "utf8", "utf8_bin", false},
|
||||
{84, "big5", "big5_bin", false},
|
||||
{85, "euckr", "euckr_bin", false},
|
||||
{86, "gb2312", "gb2312_bin", false},
|
||||
{87, "gbk", "gbk_bin", false},
|
||||
{88, "sjis", "sjis_bin", false},
|
||||
{89, "tis620", "tis620_bin", false},
|
||||
{90, "ucs2", "ucs2_bin", false},
|
||||
{91, "ujis", "ujis_bin", false},
|
||||
{92, "geostd8", "geostd8_general_ci", true},
|
||||
{93, "geostd8", "geostd8_bin", false},
|
||||
{94, "latin1", "latin1_spanish_ci", false},
|
||||
{95, "cp932", "cp932_japanese_ci", true},
|
||||
{96, "cp932", "cp932_bin", false},
|
||||
{97, "eucjpms", "eucjpms_japanese_ci", true},
|
||||
{98, "eucjpms", "eucjpms_bin", false},
|
||||
{99, "cp1250", "cp1250_polish_ci", false},
|
||||
{101, "utf16", "utf16_unicode_ci", false},
|
||||
{102, "utf16", "utf16_icelandic_ci", false},
|
||||
{103, "utf16", "utf16_latvian_ci", false},
|
||||
{104, "utf16", "utf16_romanian_ci", false},
|
||||
{105, "utf16", "utf16_slovenian_ci", false},
|
||||
{106, "utf16", "utf16_polish_ci", false},
|
||||
{107, "utf16", "utf16_estonian_ci", false},
|
||||
{108, "utf16", "utf16_spanish_ci", false},
|
||||
{109, "utf16", "utf16_swedish_ci", false},
|
||||
{110, "utf16", "utf16_turkish_ci", false},
|
||||
{111, "utf16", "utf16_czech_ci", false},
|
||||
{112, "utf16", "utf16_danish_ci", false},
|
||||
{113, "utf16", "utf16_lithuanian_ci", false},
|
||||
{114, "utf16", "utf16_slovak_ci", false},
|
||||
{115, "utf16", "utf16_spanish2_ci", false},
|
||||
{116, "utf16", "utf16_roman_ci", false},
|
||||
{117, "utf16", "utf16_persian_ci", false},
|
||||
{118, "utf16", "utf16_esperanto_ci", false},
|
||||
{119, "utf16", "utf16_hungarian_ci", false},
|
||||
{120, "utf16", "utf16_sinhala_ci", false},
|
||||
{121, "utf16", "utf16_german2_ci", false},
|
||||
{122, "utf16", "utf16_croatian_ci", false},
|
||||
{123, "utf16", "utf16_unicode_520_ci", false},
|
||||
{124, "utf16", "utf16_vietnamese_ci", false},
|
||||
{128, "ucs2", "ucs2_unicode_ci", false},
|
||||
{129, "ucs2", "ucs2_icelandic_ci", false},
|
||||
{130, "ucs2", "ucs2_latvian_ci", false},
|
||||
{131, "ucs2", "ucs2_romanian_ci", false},
|
||||
{132, "ucs2", "ucs2_slovenian_ci", false},
|
||||
{133, "ucs2", "ucs2_polish_ci", false},
|
||||
{134, "ucs2", "ucs2_estonian_ci", false},
|
||||
{135, "ucs2", "ucs2_spanish_ci", false},
|
||||
{136, "ucs2", "ucs2_swedish_ci", false},
|
||||
{137, "ucs2", "ucs2_turkish_ci", false},
|
||||
{138, "ucs2", "ucs2_czech_ci", false},
|
||||
{139, "ucs2", "ucs2_danish_ci", false},
|
||||
{140, "ucs2", "ucs2_lithuanian_ci", false},
|
||||
{141, "ucs2", "ucs2_slovak_ci", false},
|
||||
{142, "ucs2", "ucs2_spanish2_ci", false},
|
||||
{143, "ucs2", "ucs2_roman_ci", false},
|
||||
{144, "ucs2", "ucs2_persian_ci", false},
|
||||
{145, "ucs2", "ucs2_esperanto_ci", false},
|
||||
{146, "ucs2", "ucs2_hungarian_ci", false},
|
||||
{147, "ucs2", "ucs2_sinhala_ci", false},
|
||||
{148, "ucs2", "ucs2_german2_ci", false},
|
||||
{149, "ucs2", "ucs2_croatian_ci", false},
|
||||
{150, "ucs2", "ucs2_unicode_520_ci", false},
|
||||
{151, "ucs2", "ucs2_vietnamese_ci", false},
|
||||
{159, "ucs2", "ucs2_general_mysql500_ci", false},
|
||||
{160, "utf32", "utf32_unicode_ci", false},
|
||||
{161, "utf32", "utf32_icelandic_ci", false},
|
||||
{162, "utf32", "utf32_latvian_ci", false},
|
||||
{163, "utf32", "utf32_romanian_ci", false},
|
||||
{164, "utf32", "utf32_slovenian_ci", false},
|
||||
{165, "utf32", "utf32_polish_ci", false},
|
||||
{166, "utf32", "utf32_estonian_ci", false},
|
||||
{167, "utf32", "utf32_spanish_ci", false},
|
||||
{168, "utf32", "utf32_swedish_ci", false},
|
||||
{169, "utf32", "utf32_turkish_ci", false},
|
||||
{170, "utf32", "utf32_czech_ci", false},
|
||||
{171, "utf32", "utf32_danish_ci", false},
|
||||
{172, "utf32", "utf32_lithuanian_ci", false},
|
||||
{173, "utf32", "utf32_slovak_ci", false},
|
||||
{174, "utf32", "utf32_spanish2_ci", false},
|
||||
{175, "utf32", "utf32_roman_ci", false},
|
||||
{176, "utf32", "utf32_persian_ci", false},
|
||||
{177, "utf32", "utf32_esperanto_ci", false},
|
||||
{178, "utf32", "utf32_hungarian_ci", false},
|
||||
{179, "utf32", "utf32_sinhala_ci", false},
|
||||
{180, "utf32", "utf32_german2_ci", false},
|
||||
{181, "utf32", "utf32_croatian_ci", false},
|
||||
{182, "utf32", "utf32_unicode_520_ci", false},
|
||||
{183, "utf32", "utf32_vietnamese_ci", false},
|
||||
{192, "utf8", "utf8_unicode_ci", false},
|
||||
{193, "utf8", "utf8_icelandic_ci", false},
|
||||
{194, "utf8", "utf8_latvian_ci", false},
|
||||
{195, "utf8", "utf8_romanian_ci", false},
|
||||
{196, "utf8", "utf8_slovenian_ci", false},
|
||||
{197, "utf8", "utf8_polish_ci", false},
|
||||
{198, "utf8", "utf8_estonian_ci", false},
|
||||
{199, "utf8", "utf8_spanish_ci", false},
|
||||
{200, "utf8", "utf8_swedish_ci", false},
|
||||
{201, "utf8", "utf8_turkish_ci", false},
|
||||
{202, "utf8", "utf8_czech_ci", false},
|
||||
{203, "utf8", "utf8_danish_ci", false},
|
||||
{204, "utf8", "utf8_lithuanian_ci", false},
|
||||
{205, "utf8", "utf8_slovak_ci", false},
|
||||
{206, "utf8", "utf8_spanish2_ci", false},
|
||||
{207, "utf8", "utf8_roman_ci", false},
|
||||
{208, "utf8", "utf8_persian_ci", false},
|
||||
{209, "utf8", "utf8_esperanto_ci", false},
|
||||
{210, "utf8", "utf8_hungarian_ci", false},
|
||||
{211, "utf8", "utf8_sinhala_ci", false},
|
||||
{212, "utf8", "utf8_german2_ci", false},
|
||||
{213, "utf8", "utf8_croatian_ci", false},
|
||||
{214, "utf8", "utf8_unicode_520_ci", false},
|
||||
{215, "utf8", "utf8_vietnamese_ci", false},
|
||||
{223, "utf8", "utf8_general_mysql500_ci", false},
|
||||
{224, "utf8mb4", "utf8mb4_unicode_ci", false},
|
||||
{225, "utf8mb4", "utf8mb4_icelandic_ci", false},
|
||||
{226, "utf8mb4", "utf8mb4_latvian_ci", false},
|
||||
{227, "utf8mb4", "utf8mb4_romanian_ci", false},
|
||||
{228, "utf8mb4", "utf8mb4_slovenian_ci", false},
|
||||
{229, "utf8mb4", "utf8mb4_polish_ci", false},
|
||||
{230, "utf8mb4", "utf8mb4_estonian_ci", false},
|
||||
{231, "utf8mb4", "utf8mb4_spanish_ci", false},
|
||||
{232, "utf8mb4", "utf8mb4_swedish_ci", false},
|
||||
{233, "utf8mb4", "utf8mb4_turkish_ci", false},
|
||||
{234, "utf8mb4", "utf8mb4_czech_ci", false},
|
||||
{235, "utf8mb4", "utf8mb4_danish_ci", false},
|
||||
{236, "utf8mb4", "utf8mb4_lithuanian_ci", false},
|
||||
{237, "utf8mb4", "utf8mb4_slovak_ci", false},
|
||||
{238, "utf8mb4", "utf8mb4_spanish2_ci", false},
|
||||
{239, "utf8mb4", "utf8mb4_roman_ci", false},
|
||||
{240, "utf8mb4", "utf8mb4_persian_ci", false},
|
||||
{241, "utf8mb4", "utf8mb4_esperanto_ci", false},
|
||||
{242, "utf8mb4", "utf8mb4_hungarian_ci", false},
|
||||
{243, "utf8mb4", "utf8mb4_sinhala_ci", false},
|
||||
{244, "utf8mb4", "utf8mb4_german2_ci", false},
|
||||
{245, "utf8mb4", "utf8mb4_croatian_ci", false},
|
||||
{246, "utf8mb4", "utf8mb4_unicode_520_ci", false},
|
||||
{247, "utf8mb4", "utf8mb4_vietnamese_ci", false},
|
||||
}
|
258
vendor/github.com/pingcap/tidb/util/charset/encoding_table.go
generated
vendored
Normal file
258
vendor/github.com/pingcap/tidb/util/charset/encoding_table.go
generated
vendored
Normal file
|
@ -0,0 +1,258 @@
|
|||
// Copyright 2015 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 charset
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/charmap"
|
||||
"golang.org/x/text/encoding/japanese"
|
||||
"golang.org/x/text/encoding/korean"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/encoding/traditionalchinese"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
)
|
||||
|
||||
// Lookup returns the encoding with the specified label, and its canonical
|
||||
// name. It returns nil and the empty string if label is not one of the
|
||||
// standard encodings for HTML. Matching is case-insensitive and ignores
|
||||
// leading and trailing whitespace.
|
||||
func Lookup(label string) (e encoding.Encoding, name string) {
|
||||
label = strings.ToLower(strings.Trim(label, "\t\n\r\f "))
|
||||
enc := encodings[label]
|
||||
return enc.e, enc.name
|
||||
}
|
||||
|
||||
var encodings = map[string]struct {
|
||||
e encoding.Encoding
|
||||
name string
|
||||
}{
|
||||
"unicode-1-1-utf-8": {encoding.Nop, "utf-8"},
|
||||
"utf-8": {encoding.Nop, "utf-8"},
|
||||
"utf8": {encoding.Nop, "utf-8"},
|
||||
"866": {charmap.CodePage866, "ibm866"},
|
||||
"cp866": {charmap.CodePage866, "ibm866"},
|
||||
"csibm866": {charmap.CodePage866, "ibm866"},
|
||||
"ibm866": {charmap.CodePage866, "ibm866"},
|
||||
"csisolatin2": {charmap.ISO8859_2, "iso-8859-2"},
|
||||
"iso-8859-2": {charmap.ISO8859_2, "iso-8859-2"},
|
||||
"iso-ir-101": {charmap.ISO8859_2, "iso-8859-2"},
|
||||
"iso8859-2": {charmap.ISO8859_2, "iso-8859-2"},
|
||||
"iso88592": {charmap.ISO8859_2, "iso-8859-2"},
|
||||
"iso_8859-2": {charmap.ISO8859_2, "iso-8859-2"},
|
||||
"iso_8859-2:1987": {charmap.ISO8859_2, "iso-8859-2"},
|
||||
"l2": {charmap.ISO8859_2, "iso-8859-2"},
|
||||
"latin2": {charmap.ISO8859_2, "iso-8859-2"},
|
||||
"csisolatin3": {charmap.ISO8859_3, "iso-8859-3"},
|
||||
"iso-8859-3": {charmap.ISO8859_3, "iso-8859-3"},
|
||||
"iso-ir-109": {charmap.ISO8859_3, "iso-8859-3"},
|
||||
"iso8859-3": {charmap.ISO8859_3, "iso-8859-3"},
|
||||
"iso88593": {charmap.ISO8859_3, "iso-8859-3"},
|
||||
"iso_8859-3": {charmap.ISO8859_3, "iso-8859-3"},
|
||||
"iso_8859-3:1988": {charmap.ISO8859_3, "iso-8859-3"},
|
||||
"l3": {charmap.ISO8859_3, "iso-8859-3"},
|
||||
"latin3": {charmap.ISO8859_3, "iso-8859-3"},
|
||||
"csisolatin4": {charmap.ISO8859_4, "iso-8859-4"},
|
||||
"iso-8859-4": {charmap.ISO8859_4, "iso-8859-4"},
|
||||
"iso-ir-110": {charmap.ISO8859_4, "iso-8859-4"},
|
||||
"iso8859-4": {charmap.ISO8859_4, "iso-8859-4"},
|
||||
"iso88594": {charmap.ISO8859_4, "iso-8859-4"},
|
||||
"iso_8859-4": {charmap.ISO8859_4, "iso-8859-4"},
|
||||
"iso_8859-4:1988": {charmap.ISO8859_4, "iso-8859-4"},
|
||||
"l4": {charmap.ISO8859_4, "iso-8859-4"},
|
||||
"latin4": {charmap.ISO8859_4, "iso-8859-4"},
|
||||
"csisolatincyrillic": {charmap.ISO8859_5, "iso-8859-5"},
|
||||
"cyrillic": {charmap.ISO8859_5, "iso-8859-5"},
|
||||
"iso-8859-5": {charmap.ISO8859_5, "iso-8859-5"},
|
||||
"iso-ir-144": {charmap.ISO8859_5, "iso-8859-5"},
|
||||
"iso8859-5": {charmap.ISO8859_5, "iso-8859-5"},
|
||||
"iso88595": {charmap.ISO8859_5, "iso-8859-5"},
|
||||
"iso_8859-5": {charmap.ISO8859_5, "iso-8859-5"},
|
||||
"iso_8859-5:1988": {charmap.ISO8859_5, "iso-8859-5"},
|
||||
"arabic": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"asmo-708": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"csiso88596e": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"csiso88596i": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"csisolatinarabic": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"ecma-114": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"iso-8859-6": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"iso-8859-6-e": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"iso-8859-6-i": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"iso-ir-127": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"iso8859-6": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"iso88596": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"iso_8859-6": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"iso_8859-6:1987": {charmap.ISO8859_6, "iso-8859-6"},
|
||||
"csisolatingreek": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"ecma-118": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"elot_928": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"greek": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"greek8": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"iso-8859-7": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"iso-ir-126": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"iso8859-7": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"iso88597": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"iso_8859-7": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"iso_8859-7:1987": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"sun_eu_greek": {charmap.ISO8859_7, "iso-8859-7"},
|
||||
"csiso88598e": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"csisolatinhebrew": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"hebrew": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"iso-8859-8": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"iso-8859-8-e": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"iso-ir-138": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"iso8859-8": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"iso88598": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"iso_8859-8": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"iso_8859-8:1988": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"visual": {charmap.ISO8859_8, "iso-8859-8"},
|
||||
"csiso88598i": {charmap.ISO8859_8, "iso-8859-8-i"},
|
||||
"iso-8859-8-i": {charmap.ISO8859_8, "iso-8859-8-i"},
|
||||
"logical": {charmap.ISO8859_8, "iso-8859-8-i"},
|
||||
"csisolatin6": {charmap.ISO8859_10, "iso-8859-10"},
|
||||
"iso-8859-10": {charmap.ISO8859_10, "iso-8859-10"},
|
||||
"iso-ir-157": {charmap.ISO8859_10, "iso-8859-10"},
|
||||
"iso8859-10": {charmap.ISO8859_10, "iso-8859-10"},
|
||||
"iso885910": {charmap.ISO8859_10, "iso-8859-10"},
|
||||
"l6": {charmap.ISO8859_10, "iso-8859-10"},
|
||||
"latin6": {charmap.ISO8859_10, "iso-8859-10"},
|
||||
"iso-8859-13": {charmap.ISO8859_13, "iso-8859-13"},
|
||||
"iso8859-13": {charmap.ISO8859_13, "iso-8859-13"},
|
||||
"iso885913": {charmap.ISO8859_13, "iso-8859-13"},
|
||||
"iso-8859-14": {charmap.ISO8859_14, "iso-8859-14"},
|
||||
"iso8859-14": {charmap.ISO8859_14, "iso-8859-14"},
|
||||
"iso885914": {charmap.ISO8859_14, "iso-8859-14"},
|
||||
"csisolatin9": {charmap.ISO8859_15, "iso-8859-15"},
|
||||
"iso-8859-15": {charmap.ISO8859_15, "iso-8859-15"},
|
||||
"iso8859-15": {charmap.ISO8859_15, "iso-8859-15"},
|
||||
"iso885915": {charmap.ISO8859_15, "iso-8859-15"},
|
||||
"iso_8859-15": {charmap.ISO8859_15, "iso-8859-15"},
|
||||
"l9": {charmap.ISO8859_15, "iso-8859-15"},
|
||||
"iso-8859-16": {charmap.ISO8859_16, "iso-8859-16"},
|
||||
"cskoi8r": {charmap.KOI8R, "koi8-r"},
|
||||
"koi": {charmap.KOI8R, "koi8-r"},
|
||||
"koi8": {charmap.KOI8R, "koi8-r"},
|
||||
"koi8-r": {charmap.KOI8R, "koi8-r"},
|
||||
"koi8_r": {charmap.KOI8R, "koi8-r"},
|
||||
"koi8-u": {charmap.KOI8U, "koi8-u"},
|
||||
"csmacintosh": {charmap.Macintosh, "macintosh"},
|
||||
"mac": {charmap.Macintosh, "macintosh"},
|
||||
"macintosh": {charmap.Macintosh, "macintosh"},
|
||||
"x-mac-roman": {charmap.Macintosh, "macintosh"},
|
||||
"dos-874": {charmap.Windows874, "windows-874"},
|
||||
"iso-8859-11": {charmap.Windows874, "windows-874"},
|
||||
"iso8859-11": {charmap.Windows874, "windows-874"},
|
||||
"iso885911": {charmap.Windows874, "windows-874"},
|
||||
"tis-620": {charmap.Windows874, "windows-874"},
|
||||
"windows-874": {charmap.Windows874, "windows-874"},
|
||||
"cp1250": {charmap.Windows1250, "windows-1250"},
|
||||
"windows-1250": {charmap.Windows1250, "windows-1250"},
|
||||
"x-cp1250": {charmap.Windows1250, "windows-1250"},
|
||||
"cp1251": {charmap.Windows1251, "windows-1251"},
|
||||
"windows-1251": {charmap.Windows1251, "windows-1251"},
|
||||
"x-cp1251": {charmap.Windows1251, "windows-1251"},
|
||||
"ansi_x3.4-1968": {charmap.Windows1252, "windows-1252"},
|
||||
"ascii": {charmap.Windows1252, "windows-1252"},
|
||||
"cp1252": {charmap.Windows1252, "windows-1252"},
|
||||
"cp819": {charmap.Windows1252, "windows-1252"},
|
||||
"csisolatin1": {charmap.Windows1252, "windows-1252"},
|
||||
"ibm819": {charmap.Windows1252, "windows-1252"},
|
||||
"iso-8859-1": {charmap.Windows1252, "windows-1252"},
|
||||
"iso-ir-100": {charmap.Windows1252, "windows-1252"},
|
||||
"iso8859-1": {charmap.Windows1252, "windows-1252"},
|
||||
"iso88591": {charmap.Windows1252, "windows-1252"},
|
||||
"iso_8859-1": {charmap.Windows1252, "windows-1252"},
|
||||
"iso_8859-1:1987": {charmap.Windows1252, "windows-1252"},
|
||||
"l1": {charmap.Windows1252, "windows-1252"},
|
||||
"latin1": {charmap.Windows1252, "windows-1252"},
|
||||
"us-ascii": {charmap.Windows1252, "windows-1252"},
|
||||
"windows-1252": {charmap.Windows1252, "windows-1252"},
|
||||
"x-cp1252": {charmap.Windows1252, "windows-1252"},
|
||||
"cp1253": {charmap.Windows1253, "windows-1253"},
|
||||
"windows-1253": {charmap.Windows1253, "windows-1253"},
|
||||
"x-cp1253": {charmap.Windows1253, "windows-1253"},
|
||||
"cp1254": {charmap.Windows1254, "windows-1254"},
|
||||
"csisolatin5": {charmap.Windows1254, "windows-1254"},
|
||||
"iso-8859-9": {charmap.Windows1254, "windows-1254"},
|
||||
"iso-ir-148": {charmap.Windows1254, "windows-1254"},
|
||||
"iso8859-9": {charmap.Windows1254, "windows-1254"},
|
||||
"iso88599": {charmap.Windows1254, "windows-1254"},
|
||||
"iso_8859-9": {charmap.Windows1254, "windows-1254"},
|
||||
"iso_8859-9:1989": {charmap.Windows1254, "windows-1254"},
|
||||
"l5": {charmap.Windows1254, "windows-1254"},
|
||||
"latin5": {charmap.Windows1254, "windows-1254"},
|
||||
"windows-1254": {charmap.Windows1254, "windows-1254"},
|
||||
"x-cp1254": {charmap.Windows1254, "windows-1254"},
|
||||
"cp1255": {charmap.Windows1255, "windows-1255"},
|
||||
"windows-1255": {charmap.Windows1255, "windows-1255"},
|
||||
"x-cp1255": {charmap.Windows1255, "windows-1255"},
|
||||
"cp1256": {charmap.Windows1256, "windows-1256"},
|
||||
"windows-1256": {charmap.Windows1256, "windows-1256"},
|
||||
"x-cp1256": {charmap.Windows1256, "windows-1256"},
|
||||
"cp1257": {charmap.Windows1257, "windows-1257"},
|
||||
"windows-1257": {charmap.Windows1257, "windows-1257"},
|
||||
"x-cp1257": {charmap.Windows1257, "windows-1257"},
|
||||
"cp1258": {charmap.Windows1258, "windows-1258"},
|
||||
"windows-1258": {charmap.Windows1258, "windows-1258"},
|
||||
"x-cp1258": {charmap.Windows1258, "windows-1258"},
|
||||
"x-mac-cyrillic": {charmap.MacintoshCyrillic, "x-mac-cyrillic"},
|
||||
"x-mac-ukrainian": {charmap.MacintoshCyrillic, "x-mac-cyrillic"},
|
||||
"chinese": {simplifiedchinese.GBK, "gbk"},
|
||||
"csgb2312": {simplifiedchinese.GBK, "gbk"},
|
||||
"csiso58gb231280": {simplifiedchinese.GBK, "gbk"},
|
||||
"gb2312": {simplifiedchinese.GBK, "gbk"},
|
||||
"gb_2312": {simplifiedchinese.GBK, "gbk"},
|
||||
"gb_2312-80": {simplifiedchinese.GBK, "gbk"},
|
||||
"gbk": {simplifiedchinese.GBK, "gbk"},
|
||||
"iso-ir-58": {simplifiedchinese.GBK, "gbk"},
|
||||
"x-gbk": {simplifiedchinese.GBK, "gbk"},
|
||||
"gb18030": {simplifiedchinese.GB18030, "gb18030"},
|
||||
"hz-gb-2312": {simplifiedchinese.HZGB2312, "hz-gb-2312"},
|
||||
"big5": {traditionalchinese.Big5, "big5"},
|
||||
"big5-hkscs": {traditionalchinese.Big5, "big5"},
|
||||
"cn-big5": {traditionalchinese.Big5, "big5"},
|
||||
"csbig5": {traditionalchinese.Big5, "big5"},
|
||||
"x-x-big5": {traditionalchinese.Big5, "big5"},
|
||||
"cseucpkdfmtjapanese": {japanese.EUCJP, "euc-jp"},
|
||||
"euc-jp": {japanese.EUCJP, "euc-jp"},
|
||||
"x-euc-jp": {japanese.EUCJP, "euc-jp"},
|
||||
"csiso2022jp": {japanese.ISO2022JP, "iso-2022-jp"},
|
||||
"iso-2022-jp": {japanese.ISO2022JP, "iso-2022-jp"},
|
||||
"csshiftjis": {japanese.ShiftJIS, "shift_jis"},
|
||||
"ms_kanji": {japanese.ShiftJIS, "shift_jis"},
|
||||
"shift-jis": {japanese.ShiftJIS, "shift_jis"},
|
||||
"shift_jis": {japanese.ShiftJIS, "shift_jis"},
|
||||
"sjis": {japanese.ShiftJIS, "shift_jis"},
|
||||
"windows-31j": {japanese.ShiftJIS, "shift_jis"},
|
||||
"x-sjis": {japanese.ShiftJIS, "shift_jis"},
|
||||
"cseuckr": {korean.EUCKR, "euc-kr"},
|
||||
"csksc56011987": {korean.EUCKR, "euc-kr"},
|
||||
"euc-kr": {korean.EUCKR, "euc-kr"},
|
||||
"iso-ir-149": {korean.EUCKR, "euc-kr"},
|
||||
"korean": {korean.EUCKR, "euc-kr"},
|
||||
"ks_c_5601-1987": {korean.EUCKR, "euc-kr"},
|
||||
"ks_c_5601-1989": {korean.EUCKR, "euc-kr"},
|
||||
"ksc5601": {korean.EUCKR, "euc-kr"},
|
||||
"ksc_5601": {korean.EUCKR, "euc-kr"},
|
||||
"windows-949": {korean.EUCKR, "euc-kr"},
|
||||
"csiso2022kr": {encoding.Replacement, "replacement"},
|
||||
"iso-2022-kr": {encoding.Replacement, "replacement"},
|
||||
"iso-2022-cn": {encoding.Replacement, "replacement"},
|
||||
"iso-2022-cn-ext": {encoding.Replacement, "replacement"},
|
||||
"utf-16be": {unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM), "utf-16be"},
|
||||
"utf-16": {unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM), "utf-16le"},
|
||||
"utf-16le": {unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM), "utf-16le"},
|
||||
"x-user-defined": {charmap.XUserDefined, "x-user-defined"},
|
||||
}
|
197
vendor/github.com/pingcap/tidb/util/codec/bytes.go
generated
vendored
Normal file
197
vendor/github.com/pingcap/tidb/util/codec/bytes.go
generated
vendored
Normal file
|
@ -0,0 +1,197 @@
|
|||
// Copyright 2015 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 codec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
encGroupSize = 8
|
||||
encMarker = byte(0xFF)
|
||||
encPad = byte(0x0)
|
||||
)
|
||||
|
||||
var (
|
||||
pads = make([]byte, encGroupSize)
|
||||
encPads = []byte{encPad}
|
||||
)
|
||||
|
||||
// EncodeBytes guarantees the encoded value is in ascending order for comparison,
|
||||
// encoding with the following rule:
|
||||
// [group1][marker1]...[groupN][markerN]
|
||||
// group is 8 bytes slice which is padding with 0.
|
||||
// marker is `0xFF - padding 0 count`
|
||||
// For example:
|
||||
// [] -> [0, 0, 0, 0, 0, 0, 0, 0, 247]
|
||||
// [1, 2, 3] -> [1, 2, 3, 0, 0, 0, 0, 0, 250]
|
||||
// [1, 2, 3, 0] -> [1, 2, 3, 0, 0, 0, 0, 0, 251]
|
||||
// [1, 2, 3, 4, 5, 6, 7, 8] -> [1, 2, 3, 4, 5, 6, 7, 8, 255, 0, 0, 0, 0, 0, 0, 0, 0, 247]
|
||||
// Refer: https://github.com/facebook/mysql-5.6/wiki/MyRocks-record-format#memcomparable-format
|
||||
func EncodeBytes(b []byte, data []byte) []byte {
|
||||
// Allocate more space to avoid unnecessary slice growing.
|
||||
// Assume that the byte slice size is about `(len(data) / encGroupSize + 1) * (encGroupSize + 1)` bytes,
|
||||
// that is `(len(data) / 8 + 1) * 9` in our implement.
|
||||
dLen := len(data)
|
||||
reallocSize := (dLen/encGroupSize + 1) * (encGroupSize + 1)
|
||||
result := reallocBytes(b, reallocSize)
|
||||
for idx := 0; idx <= dLen; idx += encGroupSize {
|
||||
remain := dLen - idx
|
||||
padCount := 0
|
||||
if remain >= encGroupSize {
|
||||
result = append(result, data[idx:idx+encGroupSize]...)
|
||||
} else {
|
||||
padCount = encGroupSize - remain
|
||||
result = append(result, data[idx:]...)
|
||||
result = append(result, pads[:padCount]...)
|
||||
}
|
||||
|
||||
marker := encMarker - byte(padCount)
|
||||
result = append(result, marker)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func decodeBytes(b []byte, reverse bool) ([]byte, []byte, error) {
|
||||
data := make([]byte, 0, len(b))
|
||||
for {
|
||||
if len(b) < encGroupSize+1 {
|
||||
return nil, nil, errors.New("insufficient bytes to decode value")
|
||||
}
|
||||
|
||||
groupBytes := b[:encGroupSize+1]
|
||||
if reverse {
|
||||
reverseBytes(groupBytes)
|
||||
}
|
||||
|
||||
group := groupBytes[:encGroupSize]
|
||||
marker := groupBytes[encGroupSize]
|
||||
|
||||
// Check validity of marker.
|
||||
padCount := encMarker - marker
|
||||
realGroupSize := encGroupSize - padCount
|
||||
if padCount > encGroupSize {
|
||||
return nil, nil, errors.Errorf("invalid marker byte, group bytes %q", groupBytes)
|
||||
}
|
||||
|
||||
data = append(data, group[:realGroupSize]...)
|
||||
b = b[encGroupSize+1:]
|
||||
|
||||
if marker != encMarker {
|
||||
// Check validity of padding bytes.
|
||||
if bytes.Count(group[realGroupSize:], encPads) != int(padCount) {
|
||||
return nil, nil, errors.Errorf("invalid padding byte, group bytes %q", groupBytes)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return b, data, nil
|
||||
}
|
||||
|
||||
// DecodeBytes decodes bytes which is encoded by EncodeBytes before,
|
||||
// returns the leftover bytes and decoded value if no error.
|
||||
func DecodeBytes(b []byte) ([]byte, []byte, error) {
|
||||
return decodeBytes(b, false)
|
||||
}
|
||||
|
||||
// EncodeBytesDesc first encodes bytes using EncodeBytes, then bitwise reverses
|
||||
// encoded value to guarantee the encoded value is in descending order for comparison.
|
||||
func EncodeBytesDesc(b []byte, data []byte) []byte {
|
||||
n := len(b)
|
||||
b = EncodeBytes(b, data)
|
||||
reverseBytes(b[n:])
|
||||
return b
|
||||
}
|
||||
|
||||
// DecodeBytesDesc decodes bytes which is encoded by EncodeBytesDesc before,
|
||||
// returns the leftover bytes and decoded value if no error.
|
||||
func DecodeBytesDesc(b []byte) ([]byte, []byte, error) {
|
||||
return decodeBytes(b, true)
|
||||
}
|
||||
|
||||
// EncodeCompactBytes joins bytes with its length into a byte slice. It is more
|
||||
// efficient in both space and time compare to EncodeBytes. Note that the encoded
|
||||
// result is not memcomparable.
|
||||
func EncodeCompactBytes(b []byte, data []byte) []byte {
|
||||
b = reallocBytes(b, binary.MaxVarintLen64+len(data))
|
||||
b = EncodeVarint(b, int64(len(data)))
|
||||
return append(b, data...)
|
||||
}
|
||||
|
||||
// DecodeCompactBytes decodes bytes which is encoded by EncodeCompactBytes before.
|
||||
func DecodeCompactBytes(b []byte) ([]byte, []byte, error) {
|
||||
b, n, err := DecodeVarint(b)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Trace(err)
|
||||
}
|
||||
if int64(len(b)) < n {
|
||||
return nil, nil, errors.Errorf("insufficient bytes to decode value, expected length: %v", n)
|
||||
}
|
||||
return b[n:], b[:n], nil
|
||||
}
|
||||
|
||||
// See https://golang.org/src/crypto/cipher/xor.go
|
||||
const wordSize = int(unsafe.Sizeof(uintptr(0)))
|
||||
const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64"
|
||||
|
||||
func fastReverseBytes(b []byte) {
|
||||
n := len(b)
|
||||
w := n / wordSize
|
||||
if w > 0 {
|
||||
bw := *(*[]uintptr)(unsafe.Pointer(&b))
|
||||
for i := 0; i < w; i++ {
|
||||
bw[i] = ^bw[i]
|
||||
}
|
||||
}
|
||||
|
||||
for i := w * wordSize; i < n; i++ {
|
||||
b[i] = ^b[i]
|
||||
}
|
||||
}
|
||||
|
||||
func safeReverseBytes(b []byte) {
|
||||
for i := range b {
|
||||
b[i] = ^b[i]
|
||||
}
|
||||
}
|
||||
|
||||
func reverseBytes(b []byte) {
|
||||
if supportsUnaligned {
|
||||
fastReverseBytes(b)
|
||||
return
|
||||
}
|
||||
|
||||
safeReverseBytes(b)
|
||||
}
|
||||
|
||||
// like realloc.
|
||||
func reallocBytes(b []byte, n int) []byte {
|
||||
newSize := len(b) + n
|
||||
if cap(b) < newSize {
|
||||
bs := make([]byte, len(b), newSize)
|
||||
copy(bs, b)
|
||||
return bs
|
||||
}
|
||||
|
||||
// slice b has capability to store n bytes
|
||||
return b
|
||||
}
|
165
vendor/github.com/pingcap/tidb/util/codec/codec.go
generated
vendored
Normal file
165
vendor/github.com/pingcap/tidb/util/codec/codec.go
generated
vendored
Normal file
|
@ -0,0 +1,165 @@
|
|||
// Copyright 2015 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 codec
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/pingcap/tidb/mysql"
|
||||
"github.com/pingcap/tidb/util/types"
|
||||
)
|
||||
|
||||
const (
|
||||
nilFlag byte = iota
|
||||
bytesFlag
|
||||
compactBytesFlag
|
||||
intFlag
|
||||
uintFlag
|
||||
floatFlag
|
||||
decimalFlag
|
||||
durationFlag
|
||||
)
|
||||
|
||||
func encode(b []byte, vals []types.Datum, comparable bool) ([]byte, error) {
|
||||
for _, val := range vals {
|
||||
switch val.Kind() {
|
||||
case types.KindInt64:
|
||||
b = append(b, intFlag)
|
||||
b = EncodeInt(b, val.GetInt64())
|
||||
case types.KindUint64:
|
||||
b = append(b, uintFlag)
|
||||
b = EncodeUint(b, val.GetUint64())
|
||||
case types.KindFloat32, types.KindFloat64:
|
||||
b = append(b, floatFlag)
|
||||
b = EncodeFloat(b, val.GetFloat64())
|
||||
case types.KindString, types.KindBytes:
|
||||
b = encodeBytes(b, val.GetBytes(), comparable)
|
||||
case types.KindMysqlTime:
|
||||
b = encodeBytes(b, []byte(val.GetMysqlTime().String()), comparable)
|
||||
case types.KindMysqlDuration:
|
||||
// duration may have negative value, so we cannot use String to encode directly.
|
||||
b = append(b, durationFlag)
|
||||
b = EncodeInt(b, int64(val.GetMysqlDuration().Duration))
|
||||
case types.KindMysqlDecimal:
|
||||
b = append(b, decimalFlag)
|
||||
b = EncodeDecimal(b, val.GetMysqlDecimal())
|
||||
case types.KindMysqlHex:
|
||||
b = append(b, intFlag)
|
||||
b = EncodeInt(b, int64(val.GetMysqlHex().ToNumber()))
|
||||
case types.KindMysqlBit:
|
||||
b = append(b, uintFlag)
|
||||
b = EncodeUint(b, uint64(val.GetMysqlBit().ToNumber()))
|
||||
case types.KindMysqlEnum:
|
||||
b = append(b, uintFlag)
|
||||
b = EncodeUint(b, uint64(val.GetMysqlEnum().ToNumber()))
|
||||
case types.KindMysqlSet:
|
||||
b = append(b, uintFlag)
|
||||
b = EncodeUint(b, uint64(val.GetMysqlSet().ToNumber()))
|
||||
case types.KindNull:
|
||||
b = append(b, nilFlag)
|
||||
default:
|
||||
return nil, errors.Errorf("unsupport encode type %d", val.Kind())
|
||||
}
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func encodeBytes(b []byte, v []byte, comparable bool) []byte {
|
||||
if comparable {
|
||||
b = append(b, bytesFlag)
|
||||
b = EncodeBytes(b, v)
|
||||
} else {
|
||||
b = append(b, compactBytesFlag)
|
||||
b = EncodeCompactBytes(b, v)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// EncodeKey appends the encoded values to byte slice b, returns the appended
|
||||
// slice. It guarantees the encoded value is in ascending order for comparison.
|
||||
func EncodeKey(b []byte, v ...types.Datum) ([]byte, error) {
|
||||
return encode(b, v, true)
|
||||
}
|
||||
|
||||
// EncodeValue appends the encoded values to byte slice b, returning the appended
|
||||
// slice. It does not guarantee the order for comparison.
|
||||
func EncodeValue(b []byte, v ...types.Datum) ([]byte, error) {
|
||||
return encode(b, v, false)
|
||||
}
|
||||
|
||||
// Decode decodes values from a byte slice generated with EncodeKey or EncodeValue
|
||||
// before.
|
||||
func Decode(b []byte) ([]types.Datum, error) {
|
||||
if len(b) < 1 {
|
||||
return nil, errors.New("invalid encoded key")
|
||||
}
|
||||
|
||||
var (
|
||||
flag byte
|
||||
err error
|
||||
values = make([]types.Datum, 0, 1)
|
||||
)
|
||||
|
||||
for len(b) > 0 {
|
||||
flag = b[0]
|
||||
b = b[1:]
|
||||
var d types.Datum
|
||||
switch flag {
|
||||
case intFlag:
|
||||
var v int64
|
||||
b, v, err = DecodeInt(b)
|
||||
d.SetInt64(v)
|
||||
case uintFlag:
|
||||
var v uint64
|
||||
b, v, err = DecodeUint(b)
|
||||
d.SetUint64(v)
|
||||
case floatFlag:
|
||||
var v float64
|
||||
b, v, err = DecodeFloat(b)
|
||||
d.SetFloat64(v)
|
||||
case bytesFlag:
|
||||
var v []byte
|
||||
b, v, err = DecodeBytes(b)
|
||||
d.SetBytes(v)
|
||||
case compactBytesFlag:
|
||||
var v []byte
|
||||
b, v, err = DecodeCompactBytes(b)
|
||||
d.SetBytes(v)
|
||||
case decimalFlag:
|
||||
var v mysql.Decimal
|
||||
b, v, err = DecodeDecimal(b)
|
||||
d.SetValue(v)
|
||||
case durationFlag:
|
||||
var r int64
|
||||
b, r, err = DecodeInt(b)
|
||||
if err == nil {
|
||||
// use max fsp, let outer to do round manually.
|
||||
v := mysql.Duration{Duration: time.Duration(r), Fsp: mysql.MaxFsp}
|
||||
d.SetValue(v)
|
||||
}
|
||||
case nilFlag:
|
||||
default:
|
||||
return nil, errors.Errorf("invalid encoded key flag %v", flag)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Trace(err)
|
||||
}
|
||||
|
||||
values = append(values, d)
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
183
vendor/github.com/pingcap/tidb/util/codec/decimal.go
generated
vendored
Normal file
183
vendor/github.com/pingcap/tidb/util/codec/decimal.go
generated
vendored
Normal file
|
@ -0,0 +1,183 @@
|
|||
// Copyright 2015 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 codec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/pingcap/tidb/mysql"
|
||||
)
|
||||
|
||||
const (
|
||||
negativeSign int64 = 8
|
||||
zeroSign int64 = 16
|
||||
positiveSign int64 = 24
|
||||
)
|
||||
|
||||
func codecSign(value int64) int64 {
|
||||
if value < 0 {
|
||||
return negativeSign
|
||||
}
|
||||
|
||||
return positiveSign
|
||||
}
|
||||
|
||||
func encodeExp(expValue int64, expSign int64, valSign int64) int64 {
|
||||
if expSign == negativeSign {
|
||||
expValue = -expValue
|
||||
}
|
||||
|
||||
if expSign != valSign {
|
||||
expValue = ^expValue
|
||||
}
|
||||
|
||||
return expValue
|
||||
}
|
||||
|
||||
func decodeExp(expValue int64, expSign int64, valSign int64) int64 {
|
||||
if expSign != valSign {
|
||||
expValue = ^expValue
|
||||
}
|
||||
|
||||
if expSign == negativeSign {
|
||||
expValue = -expValue
|
||||
}
|
||||
|
||||
return expValue
|
||||
}
|
||||
|
||||
func codecValue(value []byte, valSign int64) {
|
||||
if valSign == negativeSign {
|
||||
reverseBytes(value)
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeDecimal encodes a decimal d into a byte slice which can be sorted lexicographically later.
|
||||
// EncodeDecimal guarantees that the encoded value is in ascending order for comparison.
|
||||
// Decimal encoding:
|
||||
// Byte -> value sign
|
||||
// Byte -> exp sign
|
||||
// EncodeInt -> exp value
|
||||
// EncodeBytes -> abs value bytes
|
||||
func EncodeDecimal(b []byte, d mysql.Decimal) []byte {
|
||||
if d.Equals(mysql.ZeroDecimal) {
|
||||
return append(b, byte(zeroSign))
|
||||
}
|
||||
|
||||
v := d.BigIntValue()
|
||||
valSign := codecSign(int64(v.Sign()))
|
||||
|
||||
absVal := new(big.Int)
|
||||
absVal.Abs(v)
|
||||
|
||||
value := []byte(absVal.String())
|
||||
|
||||
// Trim right side "0", like "12.34000" -> "12.34" or "0.1234000" -> "0.1234".
|
||||
if d.Exponent() != 0 {
|
||||
value = bytes.TrimRight(value, "0")
|
||||
}
|
||||
|
||||
// Get exp and value, format is "value":"exp".
|
||||
// like "12.34" -> "0.1234":"2".
|
||||
// like "-0.01234" -> "-0.1234":"-1".
|
||||
exp := int64(0)
|
||||
div := big.NewInt(10)
|
||||
for ; ; exp++ {
|
||||
if absVal.Sign() == 0 {
|
||||
break
|
||||
}
|
||||
absVal = absVal.Div(absVal, div)
|
||||
}
|
||||
|
||||
expVal := exp + int64(d.Exponent())
|
||||
expSign := codecSign(expVal)
|
||||
|
||||
// For negtive exp, do bit reverse for exp.
|
||||
// For negtive decimal, do bit reverse for exp and value.
|
||||
expVal = encodeExp(expVal, expSign, valSign)
|
||||
codecValue(value, valSign)
|
||||
|
||||
b = append(b, byte(valSign))
|
||||
b = append(b, byte(expSign))
|
||||
b = EncodeInt(b, expVal)
|
||||
b = EncodeBytes(b, value)
|
||||
return b
|
||||
}
|
||||
|
||||
// DecodeDecimal decodes bytes to decimal.
|
||||
// DecodeFloat decodes a float from a byte slice
|
||||
// Decimal decoding:
|
||||
// Byte -> value sign
|
||||
// Byte -> exp sign
|
||||
// DecodeInt -> exp value
|
||||
// DecodeBytes -> abs value bytes
|
||||
func DecodeDecimal(b []byte) ([]byte, mysql.Decimal, error) {
|
||||
var (
|
||||
r = b
|
||||
d mysql.Decimal
|
||||
err error
|
||||
)
|
||||
|
||||
// Decode value sign.
|
||||
valSign := int64(r[0])
|
||||
r = r[1:]
|
||||
if valSign == zeroSign {
|
||||
d, err = mysql.ParseDecimal("0")
|
||||
return r, d, errors.Trace(err)
|
||||
}
|
||||
|
||||
// Decode exp sign.
|
||||
expSign := int64(r[0])
|
||||
r = r[1:]
|
||||
|
||||
// Decode exp value.
|
||||
expVal := int64(0)
|
||||
r, expVal, err = DecodeInt(r)
|
||||
if err != nil {
|
||||
return r, d, errors.Trace(err)
|
||||
}
|
||||
expVal = decodeExp(expVal, expSign, valSign)
|
||||
|
||||
// Decode abs value bytes.
|
||||
value := []byte{}
|
||||
r, value, err = DecodeBytes(r)
|
||||
if err != nil {
|
||||
return r, d, errors.Trace(err)
|
||||
}
|
||||
codecValue(value, valSign)
|
||||
|
||||
// Generate decimal string value.
|
||||
var decimalStr []byte
|
||||
if valSign == negativeSign {
|
||||
decimalStr = append(decimalStr, '-')
|
||||
}
|
||||
|
||||
if expVal <= 0 {
|
||||
// Like decimal "0.1234" or "0.01234".
|
||||
decimalStr = append(decimalStr, '0')
|
||||
decimalStr = append(decimalStr, '.')
|
||||
decimalStr = append(decimalStr, bytes.Repeat([]byte{'0'}, -int(expVal))...)
|
||||
decimalStr = append(decimalStr, value...)
|
||||
} else {
|
||||
// Like decimal "12.34".
|
||||
decimalStr = append(decimalStr, value[:expVal]...)
|
||||
decimalStr = append(decimalStr, '.')
|
||||
decimalStr = append(decimalStr, value[expVal:]...)
|
||||
}
|
||||
|
||||
d, err = mysql.ParseDecimal(string(decimalStr))
|
||||
return r, d, errors.Trace(err)
|
||||
}
|
65
vendor/github.com/pingcap/tidb/util/codec/float.go
generated
vendored
Normal file
65
vendor/github.com/pingcap/tidb/util/codec/float.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2015 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 codec
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
func encodeFloatToCmpUint64(f float64) uint64 {
|
||||
u := math.Float64bits(f)
|
||||
if f >= 0 {
|
||||
u |= signMask
|
||||
} else {
|
||||
u = ^u
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func decodeCmpUintToFloat(u uint64) float64 {
|
||||
if u&signMask > 0 {
|
||||
u &= ^signMask
|
||||
} else {
|
||||
u = ^u
|
||||
}
|
||||
return math.Float64frombits(u)
|
||||
}
|
||||
|
||||
// EncodeFloat encodes a float v into a byte slice which can be sorted lexicographically later.
|
||||
// EncodeFloat guarantees that the encoded value is in ascending order for comparison.
|
||||
func EncodeFloat(b []byte, v float64) []byte {
|
||||
u := encodeFloatToCmpUint64(v)
|
||||
return EncodeUint(b, u)
|
||||
}
|
||||
|
||||
// DecodeFloat decodes a float from a byte slice generated with EncodeFloat before.
|
||||
func DecodeFloat(b []byte) ([]byte, float64, error) {
|
||||
b, u, err := DecodeUint(b)
|
||||
return b, decodeCmpUintToFloat(u), errors.Trace(err)
|
||||
}
|
||||
|
||||
// EncodeFloatDesc encodes a float v into a byte slice which can be sorted lexicographically later.
|
||||
// EncodeFloatDesc guarantees that the encoded value is in descending order for comparison.
|
||||
func EncodeFloatDesc(b []byte, v float64) []byte {
|
||||
u := encodeFloatToCmpUint64(v)
|
||||
return EncodeUintDesc(b, u)
|
||||
}
|
||||
|
||||
// DecodeFloatDesc decodes a float from a byte slice generated with EncodeFloatDesc before.
|
||||
func DecodeFloatDesc(b []byte) ([]byte, float64, error) {
|
||||
b, u, err := DecodeUintDesc(b)
|
||||
return b, decodeCmpUintToFloat(u), errors.Trace(err)
|
||||
}
|
170
vendor/github.com/pingcap/tidb/util/codec/number.go
generated
vendored
Normal file
170
vendor/github.com/pingcap/tidb/util/codec/number.go
generated
vendored
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2015 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 codec
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
const signMask uint64 = 0x8000000000000000
|
||||
|
||||
func encodeIntToCmpUint(v int64) uint64 {
|
||||
u := uint64(v)
|
||||
if u&signMask > 0 {
|
||||
u &= ^signMask
|
||||
} else {
|
||||
u |= signMask
|
||||
}
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
func decodeCmpUintToInt(u uint64) int64 {
|
||||
if u&signMask > 0 {
|
||||
u &= ^signMask
|
||||
} else {
|
||||
u |= signMask
|
||||
}
|
||||
|
||||
return int64(u)
|
||||
}
|
||||
|
||||
// EncodeInt appends the encoded value to slice b and returns the appended slice.
|
||||
// EncodeInt guarantees that the encoded value is in ascending order for comparison.
|
||||
func EncodeInt(b []byte, v int64) []byte {
|
||||
var data [8]byte
|
||||
u := encodeIntToCmpUint(v)
|
||||
binary.BigEndian.PutUint64(data[:], u)
|
||||
return append(b, data[:]...)
|
||||
}
|
||||
|
||||
// EncodeIntDesc appends the encoded value to slice b and returns the appended slice.
|
||||
// EncodeIntDesc guarantees that the encoded value is in descending order for comparison.
|
||||
func EncodeIntDesc(b []byte, v int64) []byte {
|
||||
var data [8]byte
|
||||
u := encodeIntToCmpUint(v)
|
||||
binary.BigEndian.PutUint64(data[:], ^u)
|
||||
return append(b, data[:]...)
|
||||
}
|
||||
|
||||
// DecodeInt decodes value encoded by EncodeInt before.
|
||||
// It returns the leftover un-decoded slice, decoded value if no error.
|
||||
func DecodeInt(b []byte) ([]byte, int64, error) {
|
||||
if len(b) < 8 {
|
||||
return nil, 0, errors.New("insufficient bytes to decode value")
|
||||
}
|
||||
|
||||
u := binary.BigEndian.Uint64(b[:8])
|
||||
v := decodeCmpUintToInt(u)
|
||||
b = b[8:]
|
||||
return b, v, nil
|
||||
}
|
||||
|
||||
// DecodeIntDesc decodes value encoded by EncodeInt before.
|
||||
// It returns the leftover un-decoded slice, decoded value if no error.
|
||||
func DecodeIntDesc(b []byte) ([]byte, int64, error) {
|
||||
if len(b) < 8 {
|
||||
return nil, 0, errors.New("insufficient bytes to decode value")
|
||||
}
|
||||
|
||||
u := binary.BigEndian.Uint64(b[:8])
|
||||
v := decodeCmpUintToInt(^u)
|
||||
b = b[8:]
|
||||
return b, v, nil
|
||||
}
|
||||
|
||||
// EncodeUint appends the encoded value to slice b and returns the appended slice.
|
||||
// EncodeUint guarantees that the encoded value is in ascending order for comparison.
|
||||
func EncodeUint(b []byte, v uint64) []byte {
|
||||
var data [8]byte
|
||||
binary.BigEndian.PutUint64(data[:], v)
|
||||
return append(b, data[:]...)
|
||||
}
|
||||
|
||||
// EncodeUintDesc appends the encoded value to slice b and returns the appended slice.
|
||||
// EncodeUintDesc guarantees that the encoded value is in descending order for comparison.
|
||||
func EncodeUintDesc(b []byte, v uint64) []byte {
|
||||
var data [8]byte
|
||||
binary.BigEndian.PutUint64(data[:], ^v)
|
||||
return append(b, data[:]...)
|
||||
}
|
||||
|
||||
// DecodeUint decodes value encoded by EncodeUint before.
|
||||
// It returns the leftover un-decoded slice, decoded value if no error.
|
||||
func DecodeUint(b []byte) ([]byte, uint64, error) {
|
||||
if len(b) < 8 {
|
||||
return nil, 0, errors.New("insufficient bytes to decode value")
|
||||
}
|
||||
|
||||
v := binary.BigEndian.Uint64(b[:8])
|
||||
b = b[8:]
|
||||
return b, v, nil
|
||||
}
|
||||
|
||||
// DecodeUintDesc decodes value encoded by EncodeInt before.
|
||||
// It returns the leftover un-decoded slice, decoded value if no error.
|
||||
func DecodeUintDesc(b []byte) ([]byte, uint64, error) {
|
||||
if len(b) < 8 {
|
||||
return nil, 0, errors.New("insufficient bytes to decode value")
|
||||
}
|
||||
|
||||
data := b[:8]
|
||||
v := binary.BigEndian.Uint64(data)
|
||||
b = b[8:]
|
||||
return b, ^v, nil
|
||||
}
|
||||
|
||||
// EncodeVarint appends the encoded value to slice b and returns the appended slice.
|
||||
// Note that the encoded result is not memcomparable.
|
||||
func EncodeVarint(b []byte, v int64) []byte {
|
||||
var data [binary.MaxVarintLen64]byte
|
||||
n := binary.PutVarint(data[:], v)
|
||||
return append(b, data[:n]...)
|
||||
}
|
||||
|
||||
// DecodeVarint decodes value encoded by EncodeVarint before.
|
||||
// It returns the leftover un-decoded slice, decoded value if no error.
|
||||
func DecodeVarint(b []byte) ([]byte, int64, error) {
|
||||
v, n := binary.Varint(b)
|
||||
if n > 0 {
|
||||
return b[n:], v, nil
|
||||
}
|
||||
if n < 0 {
|
||||
return nil, 0, errors.New("value larger than 64 bits")
|
||||
}
|
||||
return nil, 0, errors.New("insufficient bytes to decode value")
|
||||
}
|
||||
|
||||
// EncodeUvarint appends the encoded value to slice b and returns the appended slice.
|
||||
// Note that the encoded result is not memcomparable.
|
||||
func EncodeUvarint(b []byte, v uint64) []byte {
|
||||
var data [binary.MaxVarintLen64]byte
|
||||
n := binary.PutUvarint(data[:], v)
|
||||
return append(b, data[:n]...)
|
||||
}
|
||||
|
||||
// DecodeUvarint decodes value encoded by EncodeUvarint before.
|
||||
// It returns the leftover un-decoded slice, decoded value if no error.
|
||||
func DecodeUvarint(b []byte) ([]byte, uint64, error) {
|
||||
v, n := binary.Uvarint(b)
|
||||
if n > 0 {
|
||||
return b[n:], v, nil
|
||||
}
|
||||
if n < 0 {
|
||||
return nil, 0, errors.New("value larger than 64 bits")
|
||||
}
|
||||
return nil, 0, errors.New("insufficient bytes to decode value")
|
||||
}
|
47
vendor/github.com/pingcap/tidb/util/distinct/distinct.go
generated
vendored
Normal file
47
vendor/github.com/pingcap/tidb/util/distinct/distinct.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2015 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 distinct
|
||||
|
||||
import (
|
||||
"github.com/juju/errors"
|
||||
"github.com/pingcap/tidb/util/codec"
|
||||
"github.com/pingcap/tidb/util/types"
|
||||
)
|
||||
|
||||
// CreateDistinctChecker creates a new distinct checker.
|
||||
func CreateDistinctChecker() *Checker {
|
||||
return &Checker{
|
||||
existingKeys: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// Checker stores existing keys and checks if given data is distinct.
|
||||
type Checker struct {
|
||||
existingKeys map[string]bool
|
||||
}
|
||||
|
||||
// Check checks if values is distinct.
|
||||
func (d *Checker) Check(values []interface{}) (bool, error) {
|
||||
bs, err := codec.EncodeValue([]byte{}, types.MakeDatums(values...)...)
|
||||
if err != nil {
|
||||
return false, errors.Trace(err)
|
||||
}
|
||||
key := string(bs)
|
||||
_, ok := d.existingKeys[key]
|
||||
if ok {
|
||||
return false, nil
|
||||
}
|
||||
d.existingKeys[key] = true
|
||||
return true, nil
|
||||
}
|
43
vendor/github.com/pingcap/tidb/util/hack/hack.go
generated
vendored
Normal file
43
vendor/github.com/pingcap/tidb/util/hack/hack.go
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2015 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 hack
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// String converts slice to string without copy.
|
||||
// Use at your own risk.
|
||||
func String(b []byte) (s string) {
|
||||
if len(b) == 0 {
|
||||
return ""
|
||||
}
|
||||
pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
pstring := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
pstring.Data = pbytes.Data
|
||||
pstring.Len = pbytes.Len
|
||||
return
|
||||
}
|
||||
|
||||
// Slice converts string to slice without copy.
|
||||
// Use at your own risk.
|
||||
func Slice(s string) (b []byte) {
|
||||
pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
pstring := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
pbytes.Data = pstring.Data
|
||||
pbytes.Len = pstring.Len
|
||||
pbytes.Cap = pstring.Len
|
||||
return
|
||||
}
|
97
vendor/github.com/pingcap/tidb/util/prefix_helper.go
generated
vendored
Normal file
97
vendor/github.com/pingcap/tidb/util/prefix_helper.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Copyright 2014 The ql Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSES/QL-LICENSE file.
|
||||
|
||||
// Copyright 2015 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 util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/pingcap/tidb/kv"
|
||||
)
|
||||
|
||||
// ScanMetaWithPrefix scans metadata with the prefix.
|
||||
func ScanMetaWithPrefix(retriever kv.Retriever, prefix kv.Key, filter func(kv.Key, []byte) bool) error {
|
||||
iter, err := retriever.Seek(prefix)
|
||||
if err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
defer iter.Close()
|
||||
|
||||
for {
|
||||
if err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
|
||||
if iter.Valid() && iter.Key().HasPrefix(prefix) {
|
||||
if !filter(iter.Key(), iter.Value()) {
|
||||
break
|
||||
}
|
||||
err = iter.Next()
|
||||
if err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelKeyWithPrefix deletes keys with prefix.
|
||||
func DelKeyWithPrefix(rm kv.RetrieverMutator, prefix kv.Key) error {
|
||||
var keys []kv.Key
|
||||
iter, err := rm.Seek(prefix)
|
||||
if err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
|
||||
defer iter.Close()
|
||||
for {
|
||||
if err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
|
||||
if iter.Valid() && iter.Key().HasPrefix(prefix) {
|
||||
keys = append(keys, iter.Key().Clone())
|
||||
err = iter.Next()
|
||||
if err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
err := rm.Delete(key)
|
||||
if err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RowKeyPrefixFilter returns a function which checks whether currentKey has decoded rowKeyPrefix as prefix.
|
||||
func RowKeyPrefixFilter(rowKeyPrefix kv.Key) kv.FnKeyCmp {
|
||||
return func(currentKey kv.Key) bool {
|
||||
// Next until key without prefix of this record.
|
||||
return !bytes.HasPrefix(currentKey, rowKeyPrefix)
|
||||
}
|
||||
}
|
81
vendor/github.com/pingcap/tidb/util/segmentmap/segmentmap.go
generated
vendored
Normal file
81
vendor/github.com/pingcap/tidb/util/segmentmap/segmentmap.go
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2015 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 segmentmap
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
// SegmentMap is used for handle a big map slice by slice.
|
||||
// It's not thread safe.
|
||||
type SegmentMap struct {
|
||||
size int64
|
||||
maps []map[string]interface{}
|
||||
|
||||
crcTable *crc32.Table
|
||||
}
|
||||
|
||||
// NewSegmentMap create a new SegmentMap.
|
||||
func NewSegmentMap(size int64) (*SegmentMap, error) {
|
||||
if size <= 0 {
|
||||
return nil, errors.Errorf("Invalid size: %d", size)
|
||||
}
|
||||
|
||||
sm := &SegmentMap{
|
||||
maps: make([]map[string]interface{}, size),
|
||||
size: size,
|
||||
}
|
||||
for i := int64(0); i < size; i++ {
|
||||
sm.maps[i] = make(map[string]interface{})
|
||||
}
|
||||
|
||||
sm.crcTable = crc32.MakeTable(crc32.Castagnoli)
|
||||
return sm, nil
|
||||
}
|
||||
|
||||
// Get is the same as map[k].
|
||||
func (sm *SegmentMap) Get(key []byte) (interface{}, bool) {
|
||||
idx := int64(crc32.Checksum(key, sm.crcTable)) % sm.size
|
||||
val, ok := sm.maps[idx][string(key)]
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// GetSegment gets the map specific by index.
|
||||
func (sm *SegmentMap) GetSegment(index int64) (map[string]interface{}, error) {
|
||||
if index >= sm.size || index < 0 {
|
||||
return nil, errors.Errorf("index out of bound: %d", index)
|
||||
}
|
||||
|
||||
return sm.maps[index], nil
|
||||
}
|
||||
|
||||
// Set if key not exists, returns whether already exists.
|
||||
func (sm *SegmentMap) Set(key []byte, value interface{}, force bool) bool {
|
||||
idx := int64(crc32.Checksum(key, sm.crcTable)) % sm.size
|
||||
k := string(key)
|
||||
_, exist := sm.maps[idx][k]
|
||||
if exist && !force {
|
||||
return exist
|
||||
}
|
||||
|
||||
sm.maps[idx][k] = value
|
||||
return exist
|
||||
}
|
||||
|
||||
// SegmentCount returns how many inner segments.
|
||||
func (sm *SegmentMap) SegmentCount() int64 {
|
||||
return sm.size
|
||||
}
|
36
vendor/github.com/pingcap/tidb/util/sqlexec/restricted_sql_executor.go
generated
vendored
Normal file
36
vendor/github.com/pingcap/tidb/util/sqlexec/restricted_sql_executor.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2015 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 sqlexec
|
||||
|
||||
import (
|
||||
"github.com/pingcap/tidb/ast"
|
||||
"github.com/pingcap/tidb/context"
|
||||
)
|
||||
|
||||
// RestrictedSQLExecutor is an interface provides executing restricted sql statement.
|
||||
// Why we need this interface?
|
||||
// When we execute some management statements, we need to operate system tables.
|
||||
// For example when executing create user statement, we need to check if the user already
|
||||
// exists in the mysql.User table and insert a new row if not exists. In this case, we need
|
||||
// a convenience way to manipulate system tables. The most simple way is executing sql statement.
|
||||
// In order to execute sql statement in stmts package, we add this interface to solve dependence problem.
|
||||
// And in the same time, we do not want this interface becomes a general way to run sql statement.
|
||||
// We hope this could be used with some restrictions such as only allowing system tables as target,
|
||||
// do not allowing recursion call.
|
||||
// For more infomation please refer to the comments in session.ExecRestrictedSQL().
|
||||
// This is implemented in session.go.
|
||||
type RestrictedSQLExecutor interface {
|
||||
// ExecRestrictedSQL run sql statement in ctx with some restriction.
|
||||
ExecRestrictedSQL(ctx context.Context, sql string) (ast.RecordSet, error)
|
||||
}
|
53
vendor/github.com/pingcap/tidb/util/stringutil/string_util.go
generated
vendored
Normal file
53
vendor/github.com/pingcap/tidb/util/stringutil/string_util.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2015 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 stringutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// See: https://dev.mysql.com/doc/refman/5.7/en/string-literals.html#character-escape-sequences
|
||||
const validEscapeChars = `0'"bntrz\\%_`
|
||||
|
||||
// RemoveUselessBackslash removes backslashs which could be ignored in the string literal.
|
||||
// See: https://dev.mysql.com/doc/refman/5.7/en/string-literals.html
|
||||
// " Each of these sequences begins with a backslash (“\”), known as the escape character.
|
||||
// MySQL recognizes the escape sequences shown in Table 9.1, “Special Character Escape Sequences”.
|
||||
// For all other escape sequences, backslash is ignored. That is, the escaped character is
|
||||
// interpreted as if it was not escaped. For example, “\x” is just “x”. These sequences are case sensitive.
|
||||
// For example, “\b” is interpreted as a backspace, but “\B” is interpreted as “B”."
|
||||
func RemoveUselessBackslash(s string) string {
|
||||
var (
|
||||
buf bytes.Buffer
|
||||
i = 0
|
||||
)
|
||||
for i < len(s)-1 {
|
||||
if s[i] != '\\' {
|
||||
buf.WriteByte(s[i])
|
||||
i++
|
||||
continue
|
||||
}
|
||||
next := s[i+1]
|
||||
if strings.IndexByte(validEscapeChars, next) != -1 {
|
||||
buf.WriteByte(s[i])
|
||||
}
|
||||
buf.WriteByte(next)
|
||||
i += 2
|
||||
}
|
||||
if i == len(s)-1 {
|
||||
buf.WriteByte(s[i])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
72
vendor/github.com/pingcap/tidb/util/types/compare.go
generated
vendored
Normal file
72
vendor/github.com/pingcap/tidb/util/types/compare.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2014 The ql Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSES/QL-LICENSE file.
|
||||
|
||||
// Copyright 2015 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 types
|
||||
|
||||
// CompareInt64 returns an integer comparing the int64 x to y.
|
||||
func CompareInt64(x, y int64) int {
|
||||
if x < y {
|
||||
return -1
|
||||
} else if x == y {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// CompareUint64 returns an integer comparing the uint64 x to y.
|
||||
func CompareUint64(x, y uint64) int {
|
||||
if x < y {
|
||||
return -1
|
||||
} else if x == y {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// CompareFloat64 returns an integer comparing the float64 x to y.
|
||||
func CompareFloat64(x, y float64) int {
|
||||
if x < y {
|
||||
return -1
|
||||
} else if x == y {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// CompareString returns an integer comparing the string x to y.
|
||||
func CompareString(x, y string) int {
|
||||
if x < y {
|
||||
return -1
|
||||
} else if x == y {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// Compare returns an integer comparing the interface a with b.
|
||||
// a > b -> 1
|
||||
// a = b -> 0
|
||||
// a < b -> -1
|
||||
func Compare(a, b interface{}) (int, error) {
|
||||
aDatum := NewDatum(a)
|
||||
bDatum := NewDatum(b)
|
||||
return aDatum.CompareDatum(bDatum)
|
||||
}
|
437
vendor/github.com/pingcap/tidb/util/types/convert.go
generated
vendored
Normal file
437
vendor/github.com/pingcap/tidb/util/types/convert.go
generated
vendored
Normal file
|
@ -0,0 +1,437 @@
|
|||
// Copyright 2014 The ql Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSES/QL-LICENSE file.
|
||||
|
||||
// Copyright 2015 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 types
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/pingcap/tidb/mysql"
|
||||
)
|
||||
|
||||
// InvConv returns a failed convertion error.
|
||||
func invConv(val interface{}, tp byte) (interface{}, error) {
|
||||
return nil, errors.Errorf("cannot convert %v (type %T) to type %s", val, val, TypeStr(tp))
|
||||
}
|
||||
|
||||
func truncateStr(str string, flen int) string {
|
||||
if flen != UnspecifiedLength && len(str) > flen {
|
||||
str = str[:flen]
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
var unsignedUpperBound = map[byte]uint64{
|
||||
mysql.TypeTiny: math.MaxUint8,
|
||||
mysql.TypeShort: math.MaxUint16,
|
||||
mysql.TypeInt24: mysql.MaxUint24,
|
||||
mysql.TypeLong: math.MaxUint32,
|
||||
mysql.TypeLonglong: math.MaxUint64,
|
||||
mysql.TypeBit: math.MaxUint64,
|
||||
mysql.TypeEnum: math.MaxUint64,
|
||||
mysql.TypeSet: math.MaxUint64,
|
||||
}
|
||||
|
||||
var signedUpperBound = map[byte]int64{
|
||||
mysql.TypeTiny: math.MaxInt8,
|
||||
mysql.TypeShort: math.MaxInt16,
|
||||
mysql.TypeInt24: mysql.MaxInt24,
|
||||
mysql.TypeLong: math.MaxInt32,
|
||||
mysql.TypeLonglong: math.MaxInt64,
|
||||
}
|
||||
|
||||
var signedLowerBound = map[byte]int64{
|
||||
mysql.TypeTiny: math.MinInt8,
|
||||
mysql.TypeShort: math.MinInt16,
|
||||
mysql.TypeInt24: mysql.MinInt24,
|
||||
mysql.TypeLong: math.MinInt32,
|
||||
mysql.TypeLonglong: math.MinInt64,
|
||||
}
|
||||
|
||||
func convertFloatToInt(val float64, lowerBound int64, upperBound int64, tp byte) (int64, error) {
|
||||
val = RoundFloat(val)
|
||||
if val < float64(lowerBound) {
|
||||
return lowerBound, overflow(val, tp)
|
||||
}
|
||||
|
||||
if val > float64(upperBound) {
|
||||
return upperBound, overflow(val, tp)
|
||||
}
|
||||
|
||||
return int64(val), nil
|
||||
}
|
||||
|
||||
func convertIntToInt(val int64, lowerBound int64, upperBound int64, tp byte) (int64, error) {
|
||||
if val < lowerBound {
|
||||
return lowerBound, overflow(val, tp)
|
||||
}
|
||||
|
||||
if val > upperBound {
|
||||
return upperBound, overflow(val, tp)
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func convertUintToInt(val uint64, upperBound int64, tp byte) (int64, error) {
|
||||
if val > uint64(upperBound) {
|
||||
return upperBound, overflow(val, tp)
|
||||
}
|
||||
|
||||
return int64(val), nil
|
||||
}
|
||||
|
||||
func convertToInt(val interface{}, target *FieldType) (int64, error) {
|
||||
tp := target.Tp
|
||||
lowerBound := signedLowerBound[tp]
|
||||
upperBound := signedUpperBound[tp]
|
||||
|
||||
switch v := val.(type) {
|
||||
case bool:
|
||||
if v {
|
||||
return 1, nil
|
||||
}
|
||||
return 0, nil
|
||||
case uint64:
|
||||
return convertUintToInt(v, upperBound, tp)
|
||||
case int:
|
||||
return convertIntToInt(int64(v), lowerBound, upperBound, tp)
|
||||
case int64:
|
||||
return convertIntToInt(int64(v), lowerBound, upperBound, tp)
|
||||
case float32:
|
||||
return convertFloatToInt(float64(v), lowerBound, upperBound, tp)
|
||||
case float64:
|
||||
return convertFloatToInt(float64(v), lowerBound, upperBound, tp)
|
||||
case string:
|
||||
fval, err := StrToFloat(v)
|
||||
if err != nil {
|
||||
return 0, errors.Trace(err)
|
||||
}
|
||||
return convertFloatToInt(fval, lowerBound, upperBound, tp)
|
||||
case []byte:
|
||||
fval, err := StrToFloat(string(v))
|
||||
if err != nil {
|
||||
return 0, errors.Trace(err)
|
||||
}
|
||||
return convertFloatToInt(fval, lowerBound, upperBound, tp)
|
||||
case mysql.Time:
|
||||
// 2011-11-10 11:11:11.999999 -> 20111110111112
|
||||
ival := v.ToNumber().Round(0).IntPart()
|
||||
return convertIntToInt(ival, lowerBound, upperBound, tp)
|
||||
case mysql.Duration:
|
||||
// 11:11:11.999999 -> 111112
|
||||
ival := v.ToNumber().Round(0).IntPart()
|
||||
return convertIntToInt(ival, lowerBound, upperBound, tp)
|
||||
case mysql.Decimal:
|
||||
fval, _ := v.Float64()
|
||||
return convertFloatToInt(fval, lowerBound, upperBound, tp)
|
||||
case mysql.Hex:
|
||||
return convertFloatToInt(v.ToNumber(), lowerBound, upperBound, tp)
|
||||
case mysql.Bit:
|
||||
return convertFloatToInt(v.ToNumber(), lowerBound, upperBound, tp)
|
||||
case mysql.Enum:
|
||||
return convertFloatToInt(v.ToNumber(), lowerBound, upperBound, tp)
|
||||
case mysql.Set:
|
||||
return convertFloatToInt(v.ToNumber(), lowerBound, upperBound, tp)
|
||||
}
|
||||
return 0, typeError(val, target)
|
||||
}
|
||||
|
||||
func convertIntToUint(val int64, upperBound uint64, tp byte) (uint64, error) {
|
||||
if val < 0 {
|
||||
return 0, overflow(val, tp)
|
||||
}
|
||||
|
||||
if uint64(val) > upperBound {
|
||||
return upperBound, overflow(val, tp)
|
||||
}
|
||||
|
||||
return uint64(val), nil
|
||||
}
|
||||
|
||||
func convertUintToUint(val uint64, upperBound uint64, tp byte) (uint64, error) {
|
||||
if val > upperBound {
|
||||
return upperBound, overflow(val, tp)
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func convertFloatToUint(val float64, upperBound uint64, tp byte) (uint64, error) {
|
||||
val = RoundFloat(val)
|
||||
if val < 0 {
|
||||
return uint64(int64(val)), overflow(val, tp)
|
||||
}
|
||||
|
||||
if val > float64(upperBound) {
|
||||
return upperBound, overflow(val, tp)
|
||||
}
|
||||
|
||||
return uint64(val), nil
|
||||
}
|
||||
|
||||
// typeError returns error for invalid value type.
|
||||
func typeError(v interface{}, target *FieldType) error {
|
||||
return errors.Errorf("cannot use %v (type %T) in assignment to, or comparison with, column type %s)",
|
||||
v, v, target.String())
|
||||
}
|
||||
|
||||
func isCastType(tp byte) bool {
|
||||
switch tp {
|
||||
case mysql.TypeString, mysql.TypeDuration, mysql.TypeDatetime,
|
||||
mysql.TypeDate, mysql.TypeLonglong, mysql.TypeNewDecimal:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Cast casts val to certain types and does not return error.
|
||||
func Cast(val interface{}, target *FieldType) (interface{}, error) {
|
||||
if !isCastType(target.Tp) {
|
||||
return nil, errors.Errorf("unknown cast type - %v", target)
|
||||
}
|
||||
|
||||
return Convert(val, target)
|
||||
}
|
||||
|
||||
// Convert converts the val with type tp.
|
||||
func Convert(val interface{}, target *FieldType) (v interface{}, err error) {
|
||||
d := NewDatum(val)
|
||||
ret, err := d.ConvertTo(target)
|
||||
if err != nil {
|
||||
return ret.GetValue(), errors.Trace(err)
|
||||
}
|
||||
return ret.GetValue(), nil
|
||||
}
|
||||
|
||||
// StrToInt converts a string to an integer in best effort.
|
||||
// TODO: handle overflow and add unittest.
|
||||
func StrToInt(str string) (int64, error) {
|
||||
str = strings.TrimSpace(str)
|
||||
if len(str) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
negative := false
|
||||
i := 0
|
||||
if str[i] == '-' {
|
||||
negative = true
|
||||
i++
|
||||
} else if str[i] == '+' {
|
||||
i++
|
||||
}
|
||||
r := int64(0)
|
||||
for ; i < len(str); i++ {
|
||||
if !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
r = r*10 + int64(str[i]-'0')
|
||||
}
|
||||
if negative {
|
||||
r = -r
|
||||
}
|
||||
// TODO: if i < len(str), we should return an error.
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// StrToFloat converts a string to a float64 in best effort.
|
||||
func StrToFloat(str string) (float64, error) {
|
||||
str = strings.TrimSpace(str)
|
||||
if len(str) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// MySQL uses a very loose conversation, e.g, 123.abc -> 123
|
||||
// We should do a trade off whether supporting this feature or using a strict mode.
|
||||
// Now we use a strict mode.
|
||||
return strconv.ParseFloat(str, 64)
|
||||
}
|
||||
|
||||
// ToInt64 converts an interface to an int64.
|
||||
func ToInt64(value interface{}) (int64, error) {
|
||||
return convertToInt(value, NewFieldType(mysql.TypeLonglong))
|
||||
}
|
||||
|
||||
// ToFloat64 converts an interface to a float64.
|
||||
func ToFloat64(value interface{}) (float64, error) {
|
||||
switch v := value.(type) {
|
||||
case bool:
|
||||
if v {
|
||||
return 1, nil
|
||||
}
|
||||
return 0, nil
|
||||
case int:
|
||||
return float64(v), nil
|
||||
case int64:
|
||||
return float64(v), nil
|
||||
case uint64:
|
||||
return float64(v), nil
|
||||
case float32:
|
||||
return float64(v), nil
|
||||
case float64:
|
||||
return float64(v), nil
|
||||
case string:
|
||||
return StrToFloat(v)
|
||||
case []byte:
|
||||
return StrToFloat(string(v))
|
||||
case mysql.Time:
|
||||
f, _ := v.ToNumber().Float64()
|
||||
return f, nil
|
||||
case mysql.Duration:
|
||||
f, _ := v.ToNumber().Float64()
|
||||
return f, nil
|
||||
case mysql.Decimal:
|
||||
vv, _ := v.Float64()
|
||||
return vv, nil
|
||||
case mysql.Hex:
|
||||
return v.ToNumber(), nil
|
||||
case mysql.Bit:
|
||||
return v.ToNumber(), nil
|
||||
case mysql.Enum:
|
||||
return v.ToNumber(), nil
|
||||
case mysql.Set:
|
||||
return v.ToNumber(), nil
|
||||
default:
|
||||
return 0, errors.Errorf("cannot convert %v(type %T) to float64", value, value)
|
||||
}
|
||||
}
|
||||
|
||||
// ToDecimal converts an interface to a Decimal.
|
||||
func ToDecimal(value interface{}) (mysql.Decimal, error) {
|
||||
switch v := value.(type) {
|
||||
case bool:
|
||||
if v {
|
||||
return mysql.ConvertToDecimal(1)
|
||||
}
|
||||
return mysql.ConvertToDecimal(0)
|
||||
case []byte:
|
||||
return mysql.ConvertToDecimal(string(v))
|
||||
case mysql.Time:
|
||||
return v.ToNumber(), nil
|
||||
case mysql.Duration:
|
||||
return v.ToNumber(), nil
|
||||
default:
|
||||
return mysql.ConvertToDecimal(value)
|
||||
}
|
||||
}
|
||||
|
||||
// ToString converts an interface to a string.
|
||||
func ToString(value interface{}) (string, error) {
|
||||
switch v := value.(type) {
|
||||
case bool:
|
||||
if v {
|
||||
return "1", nil
|
||||
}
|
||||
return "0", nil
|
||||
case int:
|
||||
return strconv.FormatInt(int64(v), 10), nil
|
||||
case int64:
|
||||
return strconv.FormatInt(int64(v), 10), nil
|
||||
case uint64:
|
||||
return strconv.FormatUint(uint64(v), 10), nil
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(v), 'f', -1, 32), nil
|
||||
case float64:
|
||||
return strconv.FormatFloat(float64(v), 'f', -1, 64), nil
|
||||
case string:
|
||||
return v, nil
|
||||
case []byte:
|
||||
return string(v), nil
|
||||
case mysql.Time:
|
||||
return v.String(), nil
|
||||
case mysql.Duration:
|
||||
return v.String(), nil
|
||||
case mysql.Decimal:
|
||||
return v.String(), nil
|
||||
case mysql.Hex:
|
||||
return v.ToString(), nil
|
||||
case mysql.Bit:
|
||||
return v.ToString(), nil
|
||||
case mysql.Enum:
|
||||
return v.String(), nil
|
||||
case mysql.Set:
|
||||
return v.String(), nil
|
||||
default:
|
||||
return "", errors.Errorf("cannot convert %v(type %T) to string", value, value)
|
||||
}
|
||||
}
|
||||
|
||||
// ToBool converts an interface to a bool.
|
||||
// We will use 1 for true, and 0 for false.
|
||||
func ToBool(value interface{}) (int64, error) {
|
||||
isZero := false
|
||||
switch v := value.(type) {
|
||||
case bool:
|
||||
isZero = (v == false)
|
||||
case int:
|
||||
isZero = (v == 0)
|
||||
case int64:
|
||||
isZero = (v == 0)
|
||||
case uint64:
|
||||
isZero = (v == 0)
|
||||
case float32:
|
||||
isZero = (v == 0)
|
||||
case float64:
|
||||
isZero = (v == 0)
|
||||
case string:
|
||||
if len(v) == 0 {
|
||||
isZero = true
|
||||
} else {
|
||||
n, err := StrToInt(v)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
isZero = (n == 0)
|
||||
}
|
||||
case []byte:
|
||||
if len(v) == 0 {
|
||||
isZero = true
|
||||
} else {
|
||||
n, err := StrToInt(string(v))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
isZero = (n == 0)
|
||||
}
|
||||
case mysql.Time:
|
||||
isZero = v.IsZero()
|
||||
case mysql.Duration:
|
||||
isZero = (v.Duration == 0)
|
||||
case mysql.Decimal:
|
||||
vv, _ := v.Float64()
|
||||
isZero = (vv == 0)
|
||||
case mysql.Hex:
|
||||
isZero = (v.ToNumber() == 0)
|
||||
case mysql.Bit:
|
||||
isZero = (v.ToNumber() == 0)
|
||||
case mysql.Enum:
|
||||
isZero = (v.ToNumber() == 0)
|
||||
case mysql.Set:
|
||||
isZero = (v.ToNumber() == 0)
|
||||
default:
|
||||
return 0, errors.Errorf("cannot convert %v(type %T) to bool", value, value)
|
||||
}
|
||||
|
||||
if isZero {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return 1, nil
|
||||
}
|
1249
vendor/github.com/pingcap/tidb/util/types/datum.go
generated
vendored
Normal file
1249
vendor/github.com/pingcap/tidb/util/types/datum.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
310
vendor/github.com/pingcap/tidb/util/types/etc.go
generated
vendored
Normal file
310
vendor/github.com/pingcap/tidb/util/types/etc.go
generated
vendored
Normal file
|
@ -0,0 +1,310 @@
|
|||
// Copyright 2014 The ql Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSES/QL-LICENSE file.
|
||||
|
||||
// Copyright 2015 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 types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/pingcap/tidb/mysql"
|
||||
"github.com/pingcap/tidb/parser/opcode"
|
||||
"github.com/pingcap/tidb/terror"
|
||||
"github.com/pingcap/tidb/util/charset"
|
||||
)
|
||||
|
||||
// IsTypeBlob returns a boolean indicating whether the tp is a blob type.
|
||||
func IsTypeBlob(tp byte) bool {
|
||||
switch tp {
|
||||
case mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsTypeChar returns a boolean indicating
|
||||
// whether the tp is the char type like a string type or a varchar type.
|
||||
func IsTypeChar(tp byte) bool {
|
||||
switch tp {
|
||||
case mysql.TypeString, mysql.TypeVarchar:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var type2Str = map[byte]string{
|
||||
mysql.TypeBit: "bit",
|
||||
mysql.TypeBlob: "text",
|
||||
mysql.TypeDate: "date",
|
||||
mysql.TypeDatetime: "datetime",
|
||||
mysql.TypeDecimal: "decimal",
|
||||
mysql.TypeNewDecimal: "decimal",
|
||||
mysql.TypeDouble: "double",
|
||||
mysql.TypeEnum: "enum",
|
||||
mysql.TypeFloat: "float",
|
||||
mysql.TypeGeometry: "geometry",
|
||||
mysql.TypeInt24: "mediumint",
|
||||
mysql.TypeLong: "int",
|
||||
mysql.TypeLonglong: "bigint",
|
||||
mysql.TypeLongBlob: "longtext",
|
||||
mysql.TypeMediumBlob: "mediumtext",
|
||||
mysql.TypeNull: "null",
|
||||
mysql.TypeSet: "set",
|
||||
mysql.TypeShort: "smallint",
|
||||
mysql.TypeString: "char",
|
||||
mysql.TypeDuration: "time",
|
||||
mysql.TypeTimestamp: "timestamp",
|
||||
mysql.TypeTiny: "tinyint",
|
||||
mysql.TypeTinyBlob: "tinytext",
|
||||
mysql.TypeVarchar: "varchar",
|
||||
mysql.TypeVarString: "var_string",
|
||||
mysql.TypeYear: "year",
|
||||
}
|
||||
|
||||
// TypeStr converts tp to a string.
|
||||
func TypeStr(tp byte) (r string) {
|
||||
return type2Str[tp]
|
||||
}
|
||||
|
||||
// TypeToStr converts a field to a string.
|
||||
// It is used for converting Text to Blob,
|
||||
// or converting Char to Binary.
|
||||
// Args:
|
||||
// tp: type enum
|
||||
// cs: charset
|
||||
func TypeToStr(tp byte, cs string) (r string) {
|
||||
ts := type2Str[tp]
|
||||
if cs != charset.CharsetBin {
|
||||
return ts
|
||||
}
|
||||
if IsTypeBlob(tp) {
|
||||
ts = strings.Replace(ts, "text", "blob", 1)
|
||||
} else if IsTypeChar(tp) {
|
||||
ts = strings.Replace(ts, "char", "binary", 1)
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
// EOFAsNil filtrates errors,
|
||||
// If err is equal to io.EOF returns nil.
|
||||
func EOFAsNil(err error) error {
|
||||
if terror.ErrorEqual(err, io.EOF) {
|
||||
return nil
|
||||
}
|
||||
return errors.Trace(err)
|
||||
}
|
||||
|
||||
// InvOp2 returns an invalid operation error.
|
||||
func InvOp2(x, y interface{}, o opcode.Op) (interface{}, error) {
|
||||
return nil, errors.Errorf("Invalid operation: %v %v %v (mismatched types %T and %T)", x, o, y, x, y)
|
||||
}
|
||||
|
||||
// UndOp returns an undefined error.
|
||||
func UndOp(x interface{}, o opcode.Op) (interface{}, error) {
|
||||
return nil, errors.Errorf("Invalid operation: %v%v (operator %v not defined on %T)", o, x, o, x)
|
||||
}
|
||||
|
||||
// Overflow returns an overflowed error.
|
||||
func overflow(v interface{}, tp byte) error {
|
||||
return errors.Errorf("constant %v overflows %s", v, TypeStr(tp))
|
||||
}
|
||||
|
||||
// TODO: collate should return errors from Compare.
|
||||
func collate(x, y []interface{}) (r int) {
|
||||
nx, ny := len(x), len(y)
|
||||
|
||||
switch {
|
||||
case nx == 0 && ny != 0:
|
||||
return -1
|
||||
case nx == 0 && ny == 0:
|
||||
return 0
|
||||
case nx != 0 && ny == 0:
|
||||
return 1
|
||||
}
|
||||
|
||||
r = 1
|
||||
if nx > ny {
|
||||
x, y, r = y, x, -r
|
||||
}
|
||||
|
||||
for i, xi := range x {
|
||||
// TODO: we may remove collate later, so here just panic error.
|
||||
c, err := Compare(xi, y[i])
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("should never happend %v", err))
|
||||
}
|
||||
|
||||
if c != 0 {
|
||||
return c * r
|
||||
}
|
||||
}
|
||||
|
||||
if nx == ny {
|
||||
return 0
|
||||
}
|
||||
|
||||
return -r
|
||||
}
|
||||
|
||||
// Collators maps a boolean value to a collated function.
|
||||
var Collators = map[bool]func(a, b []interface{}) int{false: collateDesc, true: collate}
|
||||
|
||||
func collateDesc(a, b []interface{}) int {
|
||||
return -collate(a, b)
|
||||
}
|
||||
|
||||
// IsOrderedType returns a boolean
|
||||
// whether the type of y can be used by order by.
|
||||
func IsOrderedType(v interface{}) (r bool) {
|
||||
switch v.(type) {
|
||||
case int, int8, int16, int32, int64,
|
||||
uint, uint8, uint16, uint32, uint64,
|
||||
float32, float64, string, []byte,
|
||||
mysql.Decimal, mysql.Time, mysql.Duration,
|
||||
mysql.Hex, mysql.Bit, mysql.Enum, mysql.Set:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone copies an interface to another interface.
|
||||
// It does a deep copy.
|
||||
func Clone(from interface{}) (interface{}, error) {
|
||||
if from == nil {
|
||||
return nil, nil
|
||||
}
|
||||
switch x := from.(type) {
|
||||
case uint8, uint16, uint32, uint64, float32, float64,
|
||||
int16, int8, bool, string, int, int64, int32,
|
||||
mysql.Time, mysql.Duration, mysql.Decimal,
|
||||
mysql.Hex, mysql.Bit, mysql.Enum, mysql.Set:
|
||||
return x, nil
|
||||
case []byte:
|
||||
target := make([]byte, len(from.([]byte)))
|
||||
copy(target, from.([]byte))
|
||||
return target, nil
|
||||
case []interface{}:
|
||||
var r []interface{}
|
||||
for _, v := range from.([]interface{}) {
|
||||
vv, err := Clone(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r = append(r, vv)
|
||||
}
|
||||
return r, nil
|
||||
default:
|
||||
return nil, errors.Errorf("Clone invalid type %T", from)
|
||||
}
|
||||
}
|
||||
|
||||
func convergeType(a interface{}, hasDecimal, hasFloat *bool) (x interface{}) {
|
||||
x = a
|
||||
switch v := a.(type) {
|
||||
case bool:
|
||||
// treat bool as 1 and 0
|
||||
if v {
|
||||
x = int64(1)
|
||||
} else {
|
||||
x = int64(0)
|
||||
}
|
||||
case int:
|
||||
x = int64(v)
|
||||
case int8:
|
||||
x = int64(v)
|
||||
case int16:
|
||||
x = int64(v)
|
||||
case int32:
|
||||
x = int64(v)
|
||||
case int64:
|
||||
x = int64(v)
|
||||
case uint:
|
||||
x = uint64(v)
|
||||
case uint8:
|
||||
x = uint64(v)
|
||||
case uint16:
|
||||
x = uint64(v)
|
||||
case uint32:
|
||||
x = uint64(v)
|
||||
case uint64:
|
||||
x = uint64(v)
|
||||
case float32:
|
||||
x = float64(v)
|
||||
*hasFloat = true
|
||||
case float64:
|
||||
x = float64(v)
|
||||
*hasFloat = true
|
||||
case mysql.Decimal:
|
||||
x = v
|
||||
*hasDecimal = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Coerce changes type.
|
||||
// If a or b is Decimal, changes the both to Decimal.
|
||||
// Else if a or b is Float, changes the both to Float.
|
||||
func Coerce(a, b interface{}) (x, y interface{}) {
|
||||
var hasDecimal bool
|
||||
var hasFloat bool
|
||||
x = convergeType(a, &hasDecimal, &hasFloat)
|
||||
y = convergeType(b, &hasDecimal, &hasFloat)
|
||||
if hasDecimal {
|
||||
d, err := mysql.ConvertToDecimal(x)
|
||||
if err == nil {
|
||||
x = d
|
||||
}
|
||||
d, err = mysql.ConvertToDecimal(y)
|
||||
if err == nil {
|
||||
y = d
|
||||
}
|
||||
} else if hasFloat {
|
||||
switch v := x.(type) {
|
||||
case int64:
|
||||
x = float64(v)
|
||||
case uint64:
|
||||
x = float64(v)
|
||||
case mysql.Hex:
|
||||
x = v.ToNumber()
|
||||
case mysql.Bit:
|
||||
x = v.ToNumber()
|
||||
case mysql.Enum:
|
||||
x = v.ToNumber()
|
||||
case mysql.Set:
|
||||
x = v.ToNumber()
|
||||
}
|
||||
switch v := y.(type) {
|
||||
case int64:
|
||||
y = float64(v)
|
||||
case uint64:
|
||||
y = float64(v)
|
||||
case mysql.Hex:
|
||||
y = v.ToNumber()
|
||||
case mysql.Bit:
|
||||
y = v.ToNumber()
|
||||
case mysql.Enum:
|
||||
y = v.ToNumber()
|
||||
case mysql.Set:
|
||||
y = v.ToNumber()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
1045
vendor/github.com/pingcap/tidb/util/types/field_type.go
generated
vendored
Normal file
1045
vendor/github.com/pingcap/tidb/util/types/field_type.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
111
vendor/github.com/pingcap/tidb/util/types/helper.go
generated
vendored
Normal file
111
vendor/github.com/pingcap/tidb/util/types/helper.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
// Copyright 2015 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 types
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/pingcap/tidb/mysql"
|
||||
)
|
||||
|
||||
// RoundFloat rounds float val to the nearest integer value with float64 format, like GNU rint function.
|
||||
// RoundFloat uses default rounding mode, see http://www.gnu.org/software/libc/manual/html_node/Rounding.html
|
||||
// so we will choose the even number if the result is midway between two representable value.
|
||||
// e.g, 1.5 -> 2, 2.5 -> 2.
|
||||
func RoundFloat(f float64) float64 {
|
||||
if math.Remainder(f, 1.0) < 0 {
|
||||
return math.Ceil(f)
|
||||
}
|
||||
return math.Floor(f)
|
||||
}
|
||||
|
||||
func getMaxFloat(flen int, decimal int) float64 {
|
||||
intPartLen := flen - decimal
|
||||
f := math.Pow10(intPartLen)
|
||||
f -= math.Pow10(-decimal)
|
||||
return f
|
||||
}
|
||||
|
||||
func truncateFloat(f float64, decimal int) float64 {
|
||||
pow := math.Pow10(decimal)
|
||||
t := (f - math.Floor(f)) * pow
|
||||
|
||||
round := RoundFloat(t)
|
||||
|
||||
f = math.Floor(f) + round/pow
|
||||
return f
|
||||
}
|
||||
|
||||
// TruncateFloat tries to truncate f.
|
||||
// If the result exceeds the max/min float that flen/decimal allowed, returns the max/min float allowed.
|
||||
func TruncateFloat(f float64, flen int, decimal int) (float64, error) {
|
||||
if math.IsNaN(f) {
|
||||
// nan returns 0
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
maxF := getMaxFloat(flen, decimal)
|
||||
|
||||
if !math.IsInf(f, 0) {
|
||||
f = truncateFloat(f, decimal)
|
||||
}
|
||||
|
||||
if f > maxF {
|
||||
f = maxF
|
||||
} else if f < -maxF {
|
||||
f = -maxF
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// CalculateSum adds v to sum.
|
||||
func CalculateSum(sum interface{}, v interface{}) (interface{}, error) {
|
||||
// for avg and sum calculation
|
||||
// avg and sum use decimal for integer and decimal type, use float for others
|
||||
// see https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html
|
||||
var (
|
||||
data interface{}
|
||||
err error
|
||||
)
|
||||
|
||||
switch y := v.(type) {
|
||||
case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
data, err = mysql.ConvertToDecimal(v)
|
||||
case mysql.Decimal:
|
||||
data = y
|
||||
case nil:
|
||||
data = nil
|
||||
default:
|
||||
data, err = ToFloat64(v)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Trace(err)
|
||||
}
|
||||
if data == nil {
|
||||
return sum, nil
|
||||
}
|
||||
switch x := sum.(type) {
|
||||
case nil:
|
||||
return data, nil
|
||||
case float64:
|
||||
return x + data.(float64), nil
|
||||
case mysql.Decimal:
|
||||
return x.Add(data.(mysql.Decimal)), nil
|
||||
default:
|
||||
return nil, errors.Errorf("invalid value %v(%T) for aggregate", x, x)
|
||||
}
|
||||
}
|
191
vendor/github.com/pingcap/tidb/util/types/overflow.go
generated
vendored
Normal file
191
vendor/github.com/pingcap/tidb/util/types/overflow.go
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
// Copyright 2015 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 types
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
// ErrArithOverflow is the error for arthimetic operation overflow.
|
||||
var ErrArithOverflow = errors.New("operation overflow")
|
||||
|
||||
// AddUint64 adds uint64 a and b if no overflow, else returns error.
|
||||
func AddUint64(a uint64, b uint64) (uint64, error) {
|
||||
if math.MaxUint64-a < b {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a + b, nil
|
||||
}
|
||||
|
||||
// AddInt64 adds int64 a and b if no overflow, otherwise returns error.
|
||||
func AddInt64(a int64, b int64) (int64, error) {
|
||||
if (a > 0 && b > 0 && math.MaxInt64-a < b) ||
|
||||
(a < 0 && b < 0 && math.MinInt64-a > b) {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return a + b, nil
|
||||
}
|
||||
|
||||
// AddInteger adds uint64 a and int64 b and returns uint64 if no overflow error.
|
||||
func AddInteger(a uint64, b int64) (uint64, error) {
|
||||
if b >= 0 {
|
||||
return AddUint64(a, uint64(b))
|
||||
}
|
||||
|
||||
if uint64(-b) > a {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a - uint64(-b), nil
|
||||
}
|
||||
|
||||
// SubUint64 substracts uint64 a with b and returns uint64 if no overflow error.
|
||||
func SubUint64(a uint64, b uint64) (uint64, error) {
|
||||
if a < b {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a - b, nil
|
||||
}
|
||||
|
||||
// SubInt64 substracts int64 a with b and returns int64 if no overflow error.
|
||||
func SubInt64(a int64, b int64) (int64, error) {
|
||||
if (a > 0 && b < 0 && math.MaxInt64-a < -b) ||
|
||||
(a < 0 && b > 0 && math.MinInt64-a > -b) ||
|
||||
(a == 0 && b == math.MinInt64) {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a - b, nil
|
||||
}
|
||||
|
||||
// SubUintWithInt substracts uint64 a with int64 b and returns uint64 if no overflow error.
|
||||
func SubUintWithInt(a uint64, b int64) (uint64, error) {
|
||||
if b < 0 {
|
||||
return AddUint64(a, uint64(-b))
|
||||
}
|
||||
return SubUint64(a, uint64(b))
|
||||
}
|
||||
|
||||
// SubIntWithUint substracts int64 a with uint64 b and returns uint64 if no overflow error.
|
||||
func SubIntWithUint(a int64, b uint64) (uint64, error) {
|
||||
if a < 0 || uint64(a) < b {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return uint64(a) - b, nil
|
||||
}
|
||||
|
||||
// MulUint64 multiplies uint64 a and b and returns uint64 if no overflow error.
|
||||
func MulUint64(a uint64, b uint64) (uint64, error) {
|
||||
if b > 0 && a > math.MaxUint64/b {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a * b, nil
|
||||
}
|
||||
|
||||
// MulInt64 multiplies int64 a and b and returns int64 if no overflow error.
|
||||
func MulInt64(a int64, b int64) (int64, error) {
|
||||
if a == 0 || b == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var (
|
||||
res uint64
|
||||
err error
|
||||
negative = false
|
||||
)
|
||||
|
||||
if a > 0 && b > 0 {
|
||||
res, err = MulUint64(uint64(a), uint64(b))
|
||||
} else if a < 0 && b < 0 {
|
||||
res, err = MulUint64(uint64(-a), uint64(-b))
|
||||
} else if a < 0 && b > 0 {
|
||||
negative = true
|
||||
res, err = MulUint64(uint64(-a), uint64(b))
|
||||
} else {
|
||||
negative = true
|
||||
res, err = MulUint64(uint64(a), uint64(-b))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return 0, errors.Trace(err)
|
||||
}
|
||||
|
||||
if negative {
|
||||
// negative result
|
||||
if res > math.MaxInt64+1 {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return -int64(res), nil
|
||||
}
|
||||
|
||||
// positive result
|
||||
if res > math.MaxInt64 {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return int64(res), nil
|
||||
}
|
||||
|
||||
// MulInteger multiplies uint64 a and int64 b, and returns uint64 if no overflow error.
|
||||
func MulInteger(a uint64, b int64) (uint64, error) {
|
||||
if a == 0 || b == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if b < 0 {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return MulUint64(a, uint64(b))
|
||||
}
|
||||
|
||||
// DivInt64 divides int64 a with b, returns int64 if no overflow error.
|
||||
// It just checks overflow, if b is zero, a "divide by zero" panic throws.
|
||||
func DivInt64(a int64, b int64) (int64, error) {
|
||||
if a == math.MinInt64 && b == -1 {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return a / b, nil
|
||||
}
|
||||
|
||||
// DivUintWithInt divides uint64 a with int64 b, returns uint64 if no overflow error.
|
||||
// It just checks overflow, if b is zero, a "divide by zero" panic throws.
|
||||
func DivUintWithInt(a uint64, b int64) (uint64, error) {
|
||||
if b < 0 {
|
||||
if a != 0 && uint64(-b) <= a {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return a / uint64(b), nil
|
||||
}
|
||||
|
||||
// DivIntWithUint divides int64 a with uint64 b, returns uint64 if no overflow error.
|
||||
// It just checks overflow, if b is zero, a "divide by zero" panic throws.
|
||||
func DivIntWithUint(a int64, b uint64) (uint64, error) {
|
||||
if a < 0 {
|
||||
if uint64(-a) >= b {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return uint64(a) / b, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue