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  }