github.com/XiaoMi/Gaea@v1.2.5/parser/tidb-types/overflow.go (about) 1 // Copyright 2015 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package types 15 16 import ( 17 "fmt" 18 "math" 19 20 "github.com/pingcap/errors" 21 ) 22 23 // AddUint64 adds uint64 a and b if no overflow, else returns error. 24 func AddUint64(a uint64, b uint64) (uint64, error) { 25 if math.MaxUint64-a < b { 26 return 0, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b)) 27 } 28 return a + b, nil 29 } 30 31 // AddInt64 adds int64 a and b if no overflow, otherwise returns error. 32 func AddInt64(a int64, b int64) (int64, error) { 33 if (a > 0 && b > 0 && math.MaxInt64-a < b) || 34 (a < 0 && b < 0 && math.MinInt64-a > b) { 35 return 0, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b)) 36 } 37 38 return a + b, nil 39 } 40 41 // AddInteger adds uint64 a and int64 b and returns uint64 if no overflow error. 42 func AddInteger(a uint64, b int64) (uint64, error) { 43 if b >= 0 { 44 return AddUint64(a, uint64(b)) 45 } 46 47 if uint64(-b) > a { 48 return 0, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b)) 49 } 50 return a - uint64(-b), nil 51 } 52 53 // SubUint64 subtracts uint64 a with b and returns uint64 if no overflow error. 54 func SubUint64(a uint64, b uint64) (uint64, error) { 55 if a < b { 56 return 0, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b)) 57 } 58 return a - b, nil 59 } 60 61 // SubInt64 subtracts int64 a with b and returns int64 if no overflow error. 62 func SubInt64(a int64, b int64) (int64, error) { 63 if (a > 0 && b < 0 && math.MaxInt64-a < -b) || 64 (a < 0 && b > 0 && math.MinInt64-a > -b) || 65 (a == 0 && b == math.MinInt64) { 66 return 0, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b)) 67 } 68 return a - b, nil 69 } 70 71 // SubUintWithInt subtracts uint64 a with int64 b and returns uint64 if no overflow error. 72 func SubUintWithInt(a uint64, b int64) (uint64, error) { 73 if b < 0 { 74 return AddUint64(a, uint64(-b)) 75 } 76 return SubUint64(a, uint64(b)) 77 } 78 79 // SubIntWithUint subtracts int64 a with uint64 b and returns uint64 if no overflow error. 80 func SubIntWithUint(a int64, b uint64) (uint64, error) { 81 if a < 0 || uint64(a) < b { 82 return 0, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b)) 83 } 84 return uint64(a) - b, nil 85 } 86 87 // MulUint64 multiplies uint64 a and b and returns uint64 if no overflow error. 88 func MulUint64(a uint64, b uint64) (uint64, error) { 89 if b > 0 && a > math.MaxUint64/b { 90 return 0, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b)) 91 } 92 return a * b, nil 93 } 94 95 // MulInt64 multiplies int64 a and b and returns int64 if no overflow error. 96 func MulInt64(a int64, b int64) (int64, error) { 97 if a == 0 || b == 0 { 98 return 0, nil 99 } 100 101 var ( 102 res uint64 103 err error 104 negative = false 105 ) 106 107 if a > 0 && b > 0 { 108 res, err = MulUint64(uint64(a), uint64(b)) 109 } else if a < 0 && b < 0 { 110 res, err = MulUint64(uint64(-a), uint64(-b)) 111 } else if a < 0 && b > 0 { 112 negative = true 113 res, err = MulUint64(uint64(-a), uint64(b)) 114 } else { 115 negative = true 116 res, err = MulUint64(uint64(a), uint64(-b)) 117 } 118 119 if err != nil { 120 return 0, errors.Trace(err) 121 } 122 123 if negative { 124 // negative result 125 if res > math.MaxInt64+1 { 126 return 0, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b)) 127 } 128 129 return -int64(res), nil 130 } 131 132 // positive result 133 if res > math.MaxInt64 { 134 return 0, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b)) 135 } 136 137 return int64(res), nil 138 } 139 140 // MulInteger multiplies uint64 a and int64 b, and returns uint64 if no overflow error. 141 func MulInteger(a uint64, b int64) (uint64, error) { 142 if a == 0 || b == 0 { 143 return 0, nil 144 } 145 146 if b < 0 { 147 return 0, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b)) 148 } 149 150 return MulUint64(a, uint64(b)) 151 } 152 153 // DivInt64 divides int64 a with b, returns int64 if no overflow error. 154 // It just checks overflow, if b is zero, a "divide by zero" panic throws. 155 func DivInt64(a int64, b int64) (int64, error) { 156 if a == math.MinInt64 && b == -1 { 157 return 0, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b)) 158 } 159 160 return a / b, nil 161 } 162 163 // DivUintWithInt divides uint64 a with int64 b, returns uint64 if no overflow error. 164 // It just checks overflow, if b is zero, a "divide by zero" panic throws. 165 func DivUintWithInt(a uint64, b int64) (uint64, error) { 166 if b < 0 { 167 if a != 0 && uint64(-b) <= a { 168 return 0, ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%d, %d)", a, b)) 169 } 170 171 return 0, nil 172 } 173 174 return a / uint64(b), nil 175 } 176 177 // DivIntWithUint divides int64 a with uint64 b, returns uint64 if no overflow error. 178 // It just checks overflow, if b is zero, a "divide by zero" panic throws. 179 func DivIntWithUint(a int64, b uint64) (uint64, error) { 180 if a < 0 { 181 if uint64(-a) >= b { 182 return 0, ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%d, %d)", a, b)) 183 } 184 185 return 0, nil 186 } 187 188 return uint64(a) / b, nil 189 }