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