github.com/xiyichan/dm8@v0.0.0-20211213021639-be727be3e136/q.go (about) 1 /* 2 * Copyright (c) 2000-2018, 达梦数据库有限公司. 3 * All rights reserved. 4 */ 5 package dm 6 7 import ( 8 "math/big" 9 "reflect" 10 "strconv" 11 "strings" 12 ) 13 14 const ( 15 XDEC_MAX_PREC int = 38 16 XDEC_SIZE = 21 17 18 FLAG_ZERO int = 0x80 19 FLAG_POSITIVE int = 0xC1 20 FLAG_NEGTIVE int = 0x3E 21 EXP_MAX int = 0xFF - 1 - FLAG_POSITIVE 22 EXP_MIN int = FLAG_NEGTIVE + 1 - 0x7F 23 24 NUM_POSITIVE int = 1 25 NUM_NEGTIVE int = 101 26 ) 27 28 type DmDecimal struct { 29 sign int 30 weight int 31 prec int 32 scale int 33 digits string 34 } 35 36 func NewDecimalFromInt64(x int64) (*DmDecimal, error) { 37 return NewDecimalFromBigInt(big.NewInt(x)) 38 } 39 func (d DmDecimal) ToInt64() int64 { 40 return d.ToBigInt().Int64() 41 } 42 func NewDecimalFromFloat64(x float64) (*DmDecimal, error) { 43 return NewDecimalFromBigFloat(big.NewFloat(x)) 44 } 45 func (d DmDecimal) ToFloat64() float64 { 46 f, _ := d.ToBigFloat().Float64() 47 return f 48 } 49 func NewDecimalFromBigInt(bigInt *big.Int) (*DmDecimal, error) { 50 return newDecimal(bigInt, len(bigInt.String()), 0) 51 } 52 func (d DmDecimal) ToBigInt() *big.Int { 53 if d.isZero() { 54 return big.NewInt(0) 55 } 56 var digits = d.digits 57 if d.sign < 0 { 58 digits = "-" + digits 59 } 60 i1, ok := new(big.Int).SetString(digits, 10) 61 if !ok { 62 return nil 63 } 64 if d.weight > 0 { 65 i2, ok := new(big.Int).SetString("1"+strings.Repeat("0", d.weight), 10) 66 if !ok { 67 return nil 68 } 69 i1.Mul(i1, i2) 70 } else if d.weight < 0 { 71 i2, ok := new(big.Int).SetString("1"+strings.Repeat("0", -d.weight), 10) 72 if !ok { 73 return nil 74 } 75 i1.Quo(i1, i2) 76 } 77 return i1 78 } 79 func NewDecimalFromBigFloat(bigFloat *big.Float) (*DmDecimal, error) { 80 return newDecimal(bigFloat, int(bigFloat.Prec()), int(bigFloat.Prec())) 81 } 82 func (d DmDecimal) ToBigFloat() *big.Float { 83 if d.isZero() { 84 return big.NewFloat(0.0) 85 } 86 var digits = d.digits 87 if d.sign < 0 { 88 digits = "-" + digits 89 } 90 f1, ok := new(big.Float).SetString(digits) 91 if !ok { 92 return nil 93 } 94 if d.weight > 0 { 95 f2, ok := new(big.Float).SetString("1" + strings.Repeat("0", d.weight)) 96 if !ok { 97 return nil 98 } 99 f1.Mul(f1, f2) 100 } else if d.weight < 0 { 101 f2, ok := new(big.Float).SetString("1" + strings.Repeat("0", -d.weight)) 102 if !ok { 103 return nil 104 } 105 f1.Quo(f1, f2) 106 } 107 return f1 108 } 109 110 func NewDecimalFromString(s string) (*DmDecimal, error) { 111 num, ok := new(big.Float).SetString(strings.TrimSpace(s)) 112 if !ok { 113 return nil, ECGO_DATA_CONVERTION_ERROR.throw() 114 } 115 return NewDecimalFromBigFloat(num) 116 } 117 118 func (d DmDecimal) String() string { 119 return d.ToBigFloat().Text('f', 10) 120 } 121 122 func (d DmDecimal) Sign() int { 123 return d.sign 124 } 125 126 func (dest *DmDecimal) Scan(src interface{}) error { 127 if dest == nil { 128 return ECGO_STORE_IN_NIL_POINTER.throw() 129 } 130 switch src := src.(type) { 131 case nil: 132 *dest = *new(DmDecimal) 133 return nil 134 case int, int8, int16, int32, int64: 135 d, err := NewDecimalFromInt64(reflect.ValueOf(src).Int()) 136 if err != nil { 137 return err 138 } 139 *dest = *d 140 return nil 141 case uint, uint8, uint16, uint32, uint64: 142 d, err := NewDecimalFromBigInt(new(big.Int).SetUint64(reflect.ValueOf(src).Uint())) 143 if err != nil { 144 return err 145 } 146 *dest = *d 147 return nil 148 case string: 149 d, err := NewDecimalFromString(src) 150 if err != nil { 151 return err 152 } 153 *dest = *d 154 return nil 155 case *DmDecimal: 156 *dest = *src 157 return nil 158 default: 159 return UNSUPPORTED_SCAN 160 } 161 } 162 163 func newDecimal(dec interface{}, prec int, scale int) (*DmDecimal, error) { 164 d := &DmDecimal{ 165 prec: prec, 166 scale: scale, 167 } 168 switch de := dec.(type) { 169 case *big.Int: 170 d.sign = de.Sign() 171 172 if d.isZero() { 173 return d, nil 174 } 175 str := de.String() 176 177 if d.sign < 0 { 178 str = str[1:] 179 } 180 181 if err := checkPrec(len(str), prec); err != nil { 182 return d, err 183 } 184 i := 0 185 istart := len(str) - 1 186 187 for i = istart; i > 0; i-- { 188 if str[i] != '0' { 189 break 190 } 191 } 192 str = str[:i+1] 193 d.weight += istart - i 194 195 if isOdd(d.weight) { 196 str += "0" 197 d.weight -= 1 198 } 199 if isOdd(len(str)) { 200 str = "0" + str 201 } 202 d.digits = str 203 case *big.Float: 204 d.sign = de.Sign() 205 206 if d.isZero() { 207 return d, nil 208 } 209 str := de.Text('f', -1) 210 211 if d.sign < 0 { 212 str = str[1:] 213 } 214 215 pointIndex := strings.IndexByte(str, '.') 216 i, istart, length := 0, 0, len(str) 217 218 if pointIndex != -1 { 219 if str[0] == '0' { 220 221 istart = 2 222 for i = istart; i < length; i++ { 223 if str[i] != '0' { 224 break 225 } 226 } 227 str = str[i:] 228 d.weight -= i - istart + len(str) 229 } else { 230 str = str[:pointIndex] + str[pointIndex+1:] 231 d.weight -= length - pointIndex - 1 232 } 233 } 234 235 length = len(str) 236 istart = length - 1 237 for i = istart; i > 0; i-- { 238 if str[i] != '0' { 239 break 240 } 241 } 242 str = str[:i+1] + str[length:] 243 d.weight += istart - i 244 245 if isOdd(d.weight) { 246 str += "0" 247 d.weight -= 1 248 } 249 if isOdd(len(str)) { 250 str = "0" + str 251 } 252 d.digits = str 253 case []byte: 254 return decodeDecimal(de, prec, scale) 255 } 256 return d, nil 257 } 258 259 func (d DmDecimal) encodeDecimal() ([]byte, error) { 260 if d.isZero() { 261 return []byte{byte(FLAG_ZERO)}, nil 262 } 263 exp := (d.weight+len(d.digits))/2 - 1 264 if exp > EXP_MAX || exp < EXP_MIN { 265 return nil, ECGO_DATA_TOO_LONG.throw() 266 } 267 validLen := len(d.digits)/2 + 1 268 269 if d.sign < 0 && validLen >= XDEC_SIZE { 270 validLen = XDEC_SIZE - 1 271 } else if validLen > XDEC_SIZE { 272 validLen = XDEC_SIZE 273 } 274 retLen := validLen 275 if d.sign < 0 { 276 retLen = validLen + 1 277 } 278 retBytes := make([]byte, retLen) 279 if d.sign > 0 { 280 retBytes[0] = byte(exp + FLAG_POSITIVE) 281 } else { 282 retBytes[0] = byte(FLAG_NEGTIVE - exp) 283 } 284 285 ibytes := 1 286 for ichar := 0; ibytes < validLen; { 287 digit1, err := strconv.Atoi(string(d.digits[ichar])) 288 if err != nil { 289 return nil, err 290 } 291 ichar++ 292 digit2, err := strconv.Atoi(string(d.digits[ichar])) 293 ichar++ 294 if err != nil { 295 return nil, err 296 } 297 298 digit := digit1*10 + digit2 299 if d.sign > 0 { 300 retBytes[ibytes] = byte(digit + NUM_POSITIVE) 301 } else { 302 retBytes[ibytes] = byte(NUM_NEGTIVE - digit) 303 } 304 ibytes++ 305 } 306 if d.sign < 0 && ibytes < retLen { 307 retBytes[ibytes] = 0x66 308 ibytes++ 309 } 310 if ibytes < retLen { 311 retBytes[ibytes] = 0x00 312 } 313 return retBytes, nil 314 } 315 316 func decodeDecimal(values []byte, prec int, scale int) (*DmDecimal, error) { 317 var decimal = &DmDecimal{ 318 prec: prec, 319 scale: scale, 320 sign: 0, 321 weight: 0, 322 } 323 if values == nil || len(values) == 0 || len(values) > XDEC_SIZE { 324 return nil, ECGO_FATAL_ERROR.throw() 325 } 326 if values[0] == byte(FLAG_ZERO) || len(values) == 1 { 327 return decimal, nil 328 } 329 if values[0]&byte(FLAG_ZERO) != 0 { 330 decimal.sign = 1 331 } else { 332 decimal.sign = -1 333 } 334 335 var flag = int(Dm_build_599.Dm_build_719(values, 0)) 336 var exp int 337 if decimal.sign > 0 { 338 exp = flag - FLAG_POSITIVE 339 } else { 340 exp = FLAG_NEGTIVE - flag 341 } 342 var digit = 0 343 var sf = "" 344 for ival := 1; ival < len(values); ival++ { 345 if decimal.sign > 0 { 346 digit = int(values[ival]) - NUM_POSITIVE 347 } else { 348 digit = NUM_NEGTIVE - int(values[ival]) 349 } 350 if digit < 0 || digit > 99 { 351 break 352 } 353 if digit < 10 { 354 sf += "0" 355 } 356 sf += strconv.Itoa(digit) 357 } 358 decimal.digits = sf 359 decimal.weight = exp*2 - (len(decimal.digits) - 2) 360 361 return decimal, nil 362 } 363 364 func (d DmDecimal) isZero() bool { 365 return d.sign == 0 366 } 367 368 func checkPrec(len int, prec int) error { 369 if prec > 0 && len > prec || len > XDEC_MAX_PREC { 370 return ECGO_DATA_TOO_LONG.throw() 371 } 372 return nil 373 } 374 375 func isOdd(val int) bool { 376 return val%2 != 0 377 }