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  }