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  }