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