tidb overflow 代码
文件路径:/types/overflow.go
/ 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,
/ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/ See the License for the specific language governing permissions and
/ limitations under the License.
package types
import (
"fmt"
"math"
"time"
"github.com/pingcap/errors"
)
/ 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, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b))
}
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, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b))
}
return a + b, nil
}
/ AddDuration adds time.Duration a and b if no overflow, otherwise returns error.
func AddDuration(a time.Duration, b time.Duration) (time.Duration, error) {
if (a > 0 && b > 0 && math.MaxInt64-a < b) ||
(a < 0 && b < 0 && math.MinInt64-a > b) {
return 0, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", int64(a), int64(b)))
}
return a + b, nil
}
/ SubDuration subtracts time.Duration a with b and returns time.Duration if no overflow error.
func SubDuration(a time.Duration, b time.Duration) (time.Duration, 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, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b))
}
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, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b))
}
return a - uint64(-b), nil
}
/ SubUint64 subtracts uint64 a with b and returns uint64 if no overflow error.
func SubUint64(a uint64, b uint64) (uint64, error) {
if a < b {
return 0, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b))
}
return a - b, nil
}
/ SubInt64 subtracts 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, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b))
}
return a - b, nil
}
/ SubUintWithInt subtracts 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 subtracts 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, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b))
}
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, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b))
}
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, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b))
}
return -int64(res), nil
}
/ positive result
if res > math.MaxInt64 {
return 0, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b))
}
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, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b))
}
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, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b))
}
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, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b))
}
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, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b))
}
return 0, nil
}
return uint64(a) / b, nil
}