github.com/wanlay/gorm-dm8@v1.0.5/dmr/r.go (about) 1 /* 2 * Copyright (c) 2000-2018, 达梦数据库有限公司. 3 * All rights reserved. 4 */ 5 package dmr 6 7 import ( 8 "database/sql/driver" 9 "math" 10 "strconv" 11 "strings" 12 13 "github.com/wanlay/gorm-dm8/dmr/util" 14 ) 15 16 const ( 17 QUA_Y = 0 18 QUA_YM = 1 19 QUA_MO = 2 20 ) 21 22 type DmIntervalYM struct { 23 leadScale int 24 isLeadScaleSet bool 25 _type byte 26 years int 27 months int 28 scaleForSvr int 29 30 Valid bool 31 } 32 33 func newDmIntervalYM() *DmIntervalYM { 34 return &DmIntervalYM{ 35 Valid: true, 36 } 37 } 38 39 func NewDmIntervalYMByString(str string) (ym *DmIntervalYM, err error) { 40 defer func() { 41 if p := recover(); p != nil { 42 err = ECGO_INVALID_TIME_INTERVAL.throw() 43 } 44 }() 45 ym = newDmIntervalYM() 46 ym.isLeadScaleSet = false 47 if err = ym.parseIntervYMString(strings.TrimSpace(str)); err != nil { 48 return nil, err 49 } 50 return ym, nil 51 } 52 53 func newDmIntervalYMByBytes(bytes []byte) *DmIntervalYM { 54 ym := newDmIntervalYM() 55 56 ym.scaleForSvr = int(Dm_build_1220.Dm_build_1322(bytes, 8)) 57 ym.leadScale = (ym.scaleForSvr >> 4) & 0x0000000F 58 ym._type = bytes[9] 59 switch ym._type { 60 case QUA_Y: 61 ym.years = int(Dm_build_1220.Dm_build_1322(bytes, 0)) 62 case QUA_YM: 63 ym.years = int(Dm_build_1220.Dm_build_1322(bytes, 0)) 64 ym.months = int(Dm_build_1220.Dm_build_1322(bytes, 4)) 65 case QUA_MO: 66 ym.months = int(Dm_build_1220.Dm_build_1322(bytes, 4)) 67 } 68 return ym 69 } 70 71 func (ym *DmIntervalYM) GetYear() int { 72 return ym.years 73 } 74 75 func (ym *DmIntervalYM) GetMonth() int { 76 return ym.months 77 } 78 79 func (ym *DmIntervalYM) GetYMType() byte { 80 return ym._type 81 } 82 83 func (ym *DmIntervalYM) String() string { 84 if !ym.Valid { 85 return "" 86 } 87 str := "INTERVAL " 88 var year, month string 89 var l int 90 var destLen int 91 92 switch ym._type { 93 case QUA_Y: 94 year = strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10) 95 if ym.years < 0 { 96 str += "-" 97 } 98 99 if ym.leadScale > len(year) { 100 l = len(year) 101 destLen = ym.leadScale 102 103 for destLen > l { 104 year = "0" + year 105 destLen-- 106 } 107 } 108 109 str += "'" + year + "' YEAR(" + strconv.FormatInt(int64(ym.leadScale), 10) + ")" 110 case QUA_YM: 111 year = strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10) 112 month = strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10) 113 114 if ym.years < 0 || ym.months < 0 { 115 str += "-" 116 } 117 118 if ym.leadScale > len(year) { 119 l = len(year) 120 destLen = ym.leadScale 121 122 for destLen > l { 123 year = "0" + year 124 destLen-- 125 } 126 } 127 128 if len(month) < 2 { 129 month = "0" + month 130 } 131 132 str += "'" + year + "-" + month + "' YEAR(" + strconv.FormatInt(int64(ym.leadScale), 10) + ") TO MONTH" 133 case QUA_MO: 134 135 month = strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10) 136 if ym.months < 0 { 137 str += "-" 138 } 139 140 if ym.leadScale > len(month) { 141 l = len(month) 142 destLen = ym.leadScale 143 for destLen > l { 144 month = "0" + month 145 destLen-- 146 } 147 } 148 149 str += "'" + month + "' MONTH(" + strconv.FormatInt(int64(ym.leadScale), 10) + ")" 150 } 151 return str 152 } 153 154 func (dest *DmIntervalYM) Scan(src interface{}) error { 155 if dest == nil { 156 return ECGO_STORE_IN_NIL_POINTER.throw() 157 } 158 switch src := src.(type) { 159 case nil: 160 *dest = *new(DmIntervalYM) 161 162 (*dest).Valid = false 163 return nil 164 case *DmIntervalYM: 165 *dest = *src 166 return nil 167 case string: 168 ret, err := NewDmIntervalYMByString(src) 169 if err != nil { 170 return err 171 } 172 *dest = *ret 173 return nil 174 default: 175 return UNSUPPORTED_SCAN 176 } 177 } 178 179 func (ym DmIntervalYM) Value() (driver.Value, error) { 180 if !ym.Valid { 181 return nil, nil 182 } 183 return ym, nil 184 } 185 186 func (ym *DmIntervalYM) parseIntervYMString(str string) error { 187 str = strings.ToUpper(str) 188 ret := strings.Split(str, " ") 189 l := len(ret) 190 if l < 3 || !util.StringUtil.EqualsIgnoreCase(ret[0], "INTERVAL") || !(strings.HasPrefix(ret[2], "YEAR") || strings.HasPrefix(ret[2], "MONTH")) { 191 return ECGO_INVALID_TIME_INTERVAL.throw() 192 } 193 ym._type = QUA_YM 194 yearId := strings.Index(str, "YEAR") 195 monthId := strings.Index(str, "MONTH") 196 toId := strings.Index(str, "TO") 197 var err error 198 if toId == -1 { 199 if yearId != -1 && monthId == -1 { 200 ym._type = QUA_Y 201 ym.leadScale, err = ym.getLeadPrec(str, yearId) 202 if err != nil { 203 return err 204 } 205 } else if monthId != -1 && yearId == -1 { 206 ym._type = QUA_MO 207 ym.leadScale, err = ym.getLeadPrec(str, monthId) 208 if err != nil { 209 return err 210 } 211 } else { 212 return ECGO_INVALID_TIME_INTERVAL.throw() 213 } 214 } else { 215 if yearId == -1 || monthId == -1 { 216 return ECGO_INVALID_TIME_INTERVAL.throw() 217 } 218 ym._type = QUA_YM 219 ym.leadScale, err = ym.getLeadPrec(str, yearId) 220 if err != nil { 221 return err 222 } 223 } 224 225 ym.scaleForSvr = (int(ym._type) << 8) + (ym.leadScale << 4) 226 timeVals, err := ym.getTimeValue(ret[1], int(ym._type)) 227 if err != nil { 228 return err 229 } 230 ym.years = timeVals[0] 231 ym.months = timeVals[1] 232 return ym.checkScale(ym.leadScale) 233 } 234 235 func (ym *DmIntervalYM) getLeadPrec(str string, startIndex int) (int, error) { 236 if ym.isLeadScaleSet { 237 return ym.leadScale, nil 238 } 239 240 leftBtId := strings.Index(str[startIndex:], "(") 241 rightBtId := strings.Index(str[startIndex:], ")") 242 leadPrec := 0 243 244 if rightBtId == -1 && leftBtId == -1 { 245 leftBtId += startIndex 246 rightBtId += startIndex 247 l := strings.Index(str, "'") 248 var r int 249 var dataStr string 250 if l != -1 { 251 r = strings.Index(str[l+1:], "'") 252 if r != -1 { 253 r += l + 1 254 } 255 } else { 256 r = -1 257 } 258 259 if r != -1 { 260 dataStr = strings.TrimSpace(str[l+1 : r]) 261 } else { 262 dataStr = "" 263 } 264 265 if dataStr != "" { 266 sign := dataStr[0] 267 if sign == '+' || sign == '-' { 268 dataStr = strings.TrimSpace(dataStr[1:]) 269 } 270 end := strings.Index(dataStr, "-") 271 272 if end != -1 { 273 dataStr = dataStr[:end] 274 } 275 276 leadPrec = len(dataStr) 277 } else { 278 leadPrec = 2 279 } 280 } else if rightBtId != -1 && leftBtId != -1 && rightBtId > leftBtId+1 { 281 leftBtId += startIndex 282 rightBtId += startIndex 283 strPrec := strings.TrimSpace(str[leftBtId+1 : rightBtId]) 284 temp, err := strconv.ParseInt(strPrec, 10, 32) 285 if err != nil { 286 return 0, err 287 } 288 289 leadPrec = int(temp) 290 } else { 291 return 0, ECGO_INVALID_TIME_INTERVAL.throw() 292 } 293 294 return leadPrec, nil 295 } 296 297 func (ym *DmIntervalYM) checkScale(prec int) error { 298 switch ym._type { 299 case QUA_Y: 300 if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)) { 301 return ECGO_INVALID_TIME_INTERVAL.throw() 302 } 303 case QUA_YM: 304 if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)) { 305 return ECGO_INVALID_TIME_INTERVAL.throw() 306 } 307 308 if int64(math.Abs(float64(ym.months))) > 11 { 309 return ECGO_INVALID_TIME_INTERVAL.throw() 310 } 311 312 case QUA_MO: 313 if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10)) { 314 return ECGO_INVALID_TIME_INTERVAL.throw() 315 } 316 } 317 return nil 318 } 319 320 func (ym *DmIntervalYM) getTimeValue(subStr string, _type int) ([]int, error) { 321 hasQuate := false 322 if subStr[0] == '\'' && subStr[len(subStr)-1] == '\'' { 323 hasQuate = true 324 subStr = strings.TrimSpace(subStr[1 : len(subStr)-1]) 325 } 326 327 negative := false 328 if strings.Index(subStr, "-") == 0 { 329 negative = true 330 subStr = subStr[1:] 331 } else if strings.Index(subStr, "+") == 0 { 332 negative = false 333 subStr = subStr[1:] 334 } 335 336 if subStr[0] == '\'' && subStr[len(subStr)-1] == '\'' { 337 hasQuate = true 338 subStr = strings.TrimSpace(subStr[1 : len(subStr)-1]) 339 } 340 341 if !hasQuate { 342 return nil, ECGO_INVALID_TIME_INTERVAL.throw() 343 } 344 345 lastSignIndex := strings.LastIndex(subStr, "-") 346 347 list := make([]string, 2) 348 if lastSignIndex == -1 || lastSignIndex == 0 { 349 list[0] = subStr 350 list[1] = "" 351 } else { 352 list[0] = subStr[0:lastSignIndex] 353 list[1] = subStr[lastSignIndex+1:] 354 } 355 356 var yearVal, monthVal int64 357 var err error 358 if ym._type == QUA_YM { 359 yearVal, err = strconv.ParseInt(list[0], 10, 32) 360 if err != nil { 361 return nil, err 362 } 363 364 if util.StringUtil.EqualsIgnoreCase(list[1], "") { 365 monthVal = 0 366 } else { 367 monthVal, err = strconv.ParseInt(list[1], 10, 32) 368 if err != nil { 369 return nil, err 370 } 371 } 372 373 if negative { 374 yearVal *= -1 375 monthVal *= -1 376 } 377 378 if yearVal > int64(math.Pow10(ym.leadScale))-1 || yearVal < 1-int64(math.Pow10(ym.leadScale)) { 379 return nil, ECGO_INVALID_TIME_INTERVAL.throw() 380 } 381 } else if ym._type == QUA_Y { 382 yearVal, err = strconv.ParseInt(list[0], 10, 32) 383 if err != nil { 384 return nil, err 385 } 386 monthVal = 0 387 388 if negative { 389 yearVal *= -1 390 } 391 392 if yearVal > int64(math.Pow10(ym.leadScale))-1 || yearVal < 1-int64(math.Pow10(ym.leadScale)) { 393 return nil, ECGO_INVALID_TIME_INTERVAL.throw() 394 } 395 } else { 396 yearVal = 0 397 monthVal, err = strconv.ParseInt(list[0], 10, 32) 398 if err != nil { 399 return nil, err 400 } 401 if negative { 402 monthVal *= -1 403 } 404 405 if monthVal > int64(math.Pow10(ym.leadScale))-1 || monthVal < 1-int64(math.Pow10(ym.leadScale)) { 406 return nil, ECGO_INVALID_TIME_INTERVAL.throw() 407 } 408 } 409 410 ret := make([]int, 2) 411 ret[0] = int(yearVal) 412 ret[1] = int(monthVal) 413 414 return ret, nil 415 } 416 417 func (ym *DmIntervalYM) encode(scale int) ([]byte, error) { 418 if scale == 0 { 419 scale = ym.scaleForSvr 420 } 421 year, month := ym.years, ym.months 422 if err := ym.checkScale(ym.leadScale); err != nil { 423 return nil, err 424 } 425 if scale != ym.scaleForSvr { 426 convertYM, err := ym.convertTo(scale) 427 if err != nil { 428 return nil, err 429 } 430 year = convertYM.years 431 month = convertYM.months 432 } else { 433 if err := ym.checkScale(ym.leadScale); err != nil { 434 return nil, err 435 } 436 } 437 438 bytes := make([]byte, 12) 439 Dm_build_1220.Dm_build_1236(bytes, 0, int32(year)) 440 Dm_build_1220.Dm_build_1236(bytes, 4, int32(month)) 441 Dm_build_1220.Dm_build_1236(bytes, 8, int32(scale)) 442 return bytes, nil 443 } 444 445 func (ym *DmIntervalYM) convertTo(scale int) (*DmIntervalYM, error) { 446 destType := (scale & 0x0000FF00) >> 8 447 leadPrec := (scale >> 4) & 0x0000000F 448 totalMonths := ym.years*12 + ym.months 449 year := 0 450 month := 0 451 switch destType { 452 case QUA_Y: 453 year = totalMonths / 12 454 455 if totalMonths%12 >= 6 { 456 year++ 457 } else if totalMonths%12 <= -6 { 458 year-- 459 } 460 if leadPrec < len(strconv.Itoa(int(math.Abs(float64(year))))) { 461 return nil, ECGO_INVALID_TIME_INTERVAL.throw() 462 } 463 case QUA_YM: 464 year = totalMonths / 12 465 month = totalMonths % 12 466 if leadPrec < len(strconv.Itoa(int(math.Abs(float64(year))))) { 467 return nil, ECGO_INVALID_TIME_INTERVAL.throw() 468 } 469 case QUA_MO: 470 month = totalMonths 471 if leadPrec < len(strconv.Itoa(int(math.Abs(float64(month))))) { 472 return nil, ECGO_INVALID_TIME_INTERVAL.throw() 473 } 474 } 475 return &DmIntervalYM{ 476 _type: byte(destType), 477 years: year, 478 months: month, 479 scaleForSvr: scale, 480 leadScale: (scale >> 4) & 0x0000000F, 481 Valid: true, 482 }, nil 483 } 484 485 func (ym *DmIntervalYM) checkValid() error { 486 if !ym.Valid { 487 return ECGO_IS_NULL.throw() 488 } 489 return nil 490 }