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  }