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