forked from forgejo/forgejo
Update to github.com/lafriks/xormstore@v1.3.0 (#8317)
This commit is contained in:
parent
3a7e3dbfb4
commit
149758c912
31 changed files with 1682 additions and 1088 deletions
252
vendor/github.com/denisenkom/go-mssqldb/internal/decimal/decimal.go
generated
vendored
Normal file
252
vendor/github.com/denisenkom/go-mssqldb/internal/decimal/decimal.go
generated
vendored
Normal file
|
@ -0,0 +1,252 @@
|
|||
package decimal
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Decimal represents decimal type in the Microsoft Open Specifications: http://msdn.microsoft.com/en-us/library/ee780893.aspx
|
||||
type Decimal struct {
|
||||
integer [4]uint32 // Little-endian
|
||||
positive bool
|
||||
prec uint8
|
||||
scale uint8
|
||||
}
|
||||
|
||||
var (
|
||||
scaletblflt64 [39]float64
|
||||
int10 big.Int
|
||||
int1e5 big.Int
|
||||
)
|
||||
|
||||
func init() {
|
||||
var acc float64 = 1
|
||||
for i := 0; i <= 38; i++ {
|
||||
scaletblflt64[i] = acc
|
||||
acc *= 10
|
||||
}
|
||||
|
||||
int10.SetInt64(10)
|
||||
int1e5.SetInt64(1e5)
|
||||
}
|
||||
|
||||
const autoScale = 100
|
||||
|
||||
// SetInteger sets the ind'th element in the integer array
|
||||
func (d *Decimal) SetInteger(integer uint32, ind uint8) {
|
||||
d.integer[ind] = integer
|
||||
}
|
||||
|
||||
// SetPositive sets the positive member
|
||||
func (d *Decimal) SetPositive(positive bool) {
|
||||
d.positive = positive
|
||||
}
|
||||
|
||||
// SetPrec sets the prec member
|
||||
func (d *Decimal) SetPrec(prec uint8) {
|
||||
d.prec = prec
|
||||
}
|
||||
|
||||
// SetScale sets the scale member
|
||||
func (d *Decimal) SetScale(scale uint8) {
|
||||
d.scale = scale
|
||||
}
|
||||
|
||||
// IsPositive returns true if the Decimal is positive
|
||||
func (d *Decimal) IsPositive() bool {
|
||||
return d.positive
|
||||
}
|
||||
|
||||
// ToFloat64 converts decimal to a float64
|
||||
func (d Decimal) ToFloat64() float64 {
|
||||
val := float64(0)
|
||||
for i := 3; i >= 0; i-- {
|
||||
val *= 0x100000000
|
||||
val += float64(d.integer[i])
|
||||
}
|
||||
if !d.positive {
|
||||
val = -val
|
||||
}
|
||||
if d.scale != 0 {
|
||||
val /= scaletblflt64[d.scale]
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// BigInt converts decimal to a bigint
|
||||
func (d Decimal) BigInt() big.Int {
|
||||
bytes := make([]byte, 16)
|
||||
binary.BigEndian.PutUint32(bytes[0:4], d.integer[3])
|
||||
binary.BigEndian.PutUint32(bytes[4:8], d.integer[2])
|
||||
binary.BigEndian.PutUint32(bytes[8:12], d.integer[1])
|
||||
binary.BigEndian.PutUint32(bytes[12:16], d.integer[0])
|
||||
var x big.Int
|
||||
x.SetBytes(bytes)
|
||||
if !d.positive {
|
||||
x.Neg(&x)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Bytes converts decimal to a scaled byte slice
|
||||
func (d Decimal) Bytes() []byte {
|
||||
x := d.BigInt()
|
||||
return ScaleBytes(x.String(), d.scale)
|
||||
}
|
||||
|
||||
// UnscaledBytes converts decimal to a unscaled byte slice
|
||||
func (d Decimal) UnscaledBytes() []byte {
|
||||
x := d.BigInt()
|
||||
return x.Bytes()
|
||||
}
|
||||
|
||||
// String converts decimal to a string
|
||||
func (d Decimal) String() string {
|
||||
return string(d.Bytes())
|
||||
}
|
||||
|
||||
// Float64ToDecimal converts float64 to decimal
|
||||
func Float64ToDecimal(f float64) (Decimal, error) {
|
||||
return Float64ToDecimalScale(f, autoScale)
|
||||
}
|
||||
|
||||
// Float64ToDecimalScale converts float64 to decimal; user can specify the scale
|
||||
func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) {
|
||||
var dec Decimal
|
||||
if math.IsNaN(f) {
|
||||
return dec, errors.New("NaN")
|
||||
}
|
||||
if math.IsInf(f, 0) {
|
||||
return dec, errors.New("Infinity can't be converted to decimal")
|
||||
}
|
||||
dec.positive = f >= 0
|
||||
if !dec.positive {
|
||||
f = math.Abs(f)
|
||||
}
|
||||
if f > 3.402823669209385e+38 {
|
||||
return dec, errors.New("Float value is out of range")
|
||||
}
|
||||
dec.prec = 20
|
||||
var integer float64
|
||||
for dec.scale = 0; dec.scale <= scale; dec.scale++ {
|
||||
integer = f * scaletblflt64[dec.scale]
|
||||
_, frac := math.Modf(integer)
|
||||
if frac == 0 && scale == autoScale {
|
||||
break
|
||||
}
|
||||
}
|
||||
for i := 0; i < 4; i++ {
|
||||
mod := math.Mod(integer, 0x100000000)
|
||||
integer -= mod
|
||||
integer /= 0x100000000
|
||||
dec.integer[i] = uint32(mod)
|
||||
if mod-math.Trunc(mod) >= 0.5 {
|
||||
dec.integer[i] = uint32(mod) + 1
|
||||
}
|
||||
}
|
||||
return dec, nil
|
||||
}
|
||||
|
||||
// Int64ToDecimalScale converts float64 to decimal; user can specify the scale
|
||||
func Int64ToDecimalScale(v int64, scale uint8) Decimal {
|
||||
positive := v >= 0
|
||||
if !positive {
|
||||
if v == math.MinInt64 {
|
||||
// Special case - can't negate
|
||||
return Decimal{
|
||||
integer: [4]uint32{0, 0x80000000, 0, 0},
|
||||
positive: false,
|
||||
prec: 20,
|
||||
scale: 0,
|
||||
}
|
||||
}
|
||||
v = -v
|
||||
}
|
||||
return Decimal{
|
||||
integer: [4]uint32{uint32(v), uint32(v >> 32), 0, 0},
|
||||
positive: positive,
|
||||
prec: 20,
|
||||
scale: scale,
|
||||
}
|
||||
}
|
||||
|
||||
// StringToDecimalScale converts string to decimal
|
||||
func StringToDecimalScale(v string, outScale uint8) (Decimal, error) {
|
||||
var r big.Int
|
||||
var unscaled string
|
||||
var inScale int
|
||||
|
||||
point := strings.LastIndexByte(v, '.')
|
||||
if point == -1 {
|
||||
inScale = 0
|
||||
unscaled = v
|
||||
} else {
|
||||
inScale = len(v) - point - 1
|
||||
unscaled = v[:point] + v[point+1:]
|
||||
}
|
||||
if inScale > math.MaxUint8 {
|
||||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: scale too large", v)
|
||||
}
|
||||
|
||||
_, ok := r.SetString(unscaled, 10)
|
||||
if !ok {
|
||||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number", v)
|
||||
}
|
||||
|
||||
if inScale > int(outScale) {
|
||||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: scale %d is larger than the scale %d of the target column", v, inScale, outScale)
|
||||
}
|
||||
for inScale < int(outScale) {
|
||||
if int(outScale)-inScale >= 5 {
|
||||
r.Mul(&r, &int1e5)
|
||||
inScale += 5
|
||||
} else {
|
||||
r.Mul(&r, &int10)
|
||||
inScale++
|
||||
}
|
||||
}
|
||||
|
||||
bytes := r.Bytes()
|
||||
if len(bytes) > 16 {
|
||||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: precision too large", v)
|
||||
}
|
||||
var out [4]uint32
|
||||
for i, b := range bytes {
|
||||
pos := len(bytes) - i - 1
|
||||
out[pos/4] += uint32(b) << uint(pos%4*8)
|
||||
}
|
||||
return Decimal{
|
||||
integer: out,
|
||||
positive: r.Sign() >= 0,
|
||||
prec: 20,
|
||||
scale: uint8(inScale),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ScaleBytes converts a stringified decimal to a scaled byte slice
|
||||
func ScaleBytes(s string, scale uint8) []byte {
|
||||
z := make([]byte, 0, len(s)+1)
|
||||
if s[0] == '-' || s[0] == '+' {
|
||||
z = append(z, byte(s[0]))
|
||||
s = s[1:]
|
||||
}
|
||||
pos := len(s) - int(scale)
|
||||
if pos <= 0 {
|
||||
z = append(z, byte('0'))
|
||||
} else if pos > 0 {
|
||||
z = append(z, []byte(s[:pos])...)
|
||||
}
|
||||
if scale > 0 {
|
||||
z = append(z, byte('.'))
|
||||
for pos < 0 {
|
||||
z = append(z, byte('0'))
|
||||
pos++
|
||||
}
|
||||
z = append(z, []byte(s[pos:])...)
|
||||
}
|
||||
return z
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue