gitee.com/curryzheng/dm@v0.0.1/zzo.go (about)

     1  /*
     2   * Copyright (c) 2000-2018, 达梦数据库有限公司.
     3   * All rights reserved.
     4   */
     5  package dm
     6  
     7  import (
     8  	"database/sql"
     9  	"database/sql/driver"
    10  	"math"
    11  	"reflect"
    12  	"strings"
    13  	"time"
    14  )
    15  
    16  const (
    17  	INT8_MAX int8 = math.MaxInt8
    18  
    19  	INT8_MIN int8 = math.MinInt8
    20  
    21  	BYTE_MAX byte = math.MaxUint8
    22  
    23  	BYTE_MIN byte = 0
    24  
    25  	INT16_MAX int16 = math.MaxInt16
    26  
    27  	INT16_MIN int16 = math.MinInt16
    28  
    29  	UINT16_MAX uint16 = math.MaxUint16
    30  
    31  	UINT16_MIN uint16 = 0
    32  
    33  	INT32_MAX int32 = math.MaxInt32
    34  
    35  	INT32_MIN int32 = math.MinInt32
    36  
    37  	UINT32_MAX uint32 = math.MaxUint32
    38  
    39  	UINT32_MIN uint32 = 0
    40  
    41  	INT64_MAX int64 = math.MaxInt64
    42  
    43  	INT64_MIN int64 = math.MinInt64
    44  
    45  	UINT64_MAX uint64 = math.MaxUint64
    46  
    47  	UINT64_MIN uint64 = 0
    48  
    49  	FLOAT32_MAX float32 = 3.4e+38
    50  
    51  	FLOAT32_MIN float32 = -3.4e+38
    52  
    53  	BYTE_SIZE = 1
    54  
    55  	USINT_SIZE = 2
    56  
    57  	ULINT_SIZE = 4
    58  
    59  	DDWORD_SIZE = 8
    60  
    61  	LINT64_SIZE = 8
    62  
    63  	CHAR = 0
    64  
    65  	VARCHAR2 = 1
    66  
    67  	VARCHAR = 2
    68  
    69  	BIT = 3
    70  
    71  	TINYINT = 5
    72  
    73  	SMALLINT = 6
    74  
    75  	INT = 7
    76  
    77  	BIGINT = 8
    78  
    79  	DECIMAL = 9
    80  
    81  	REAL = 10
    82  
    83  	DOUBLE = 11
    84  
    85  	BLOB = 12
    86  
    87  	BOOLEAN = 13
    88  
    89  	DATE = 14
    90  
    91  	TIME = 15
    92  
    93  	DATETIME = 16
    94  
    95  	BINARY = 17
    96  
    97  	VARBINARY = 18
    98  
    99  	CLOB = 19
   100  
   101  	INTERVAL_YM = 20
   102  
   103  	INTERVAL_DT = 21
   104  
   105  	TIME_TZ = 22
   106  
   107  	DATETIME_TZ = 23
   108  
   109  	NULL = 25
   110  
   111  	ANY = 31
   112  
   113  	STAR_ALL = 32
   114  
   115  	STAR = 33
   116  
   117  	RECORD = 40
   118  
   119  	TYPE = 41
   120  
   121  	TYPE_REF = 42
   122  
   123  	UNKNOWN = 54
   124  
   125  	ARRAY = 117
   126  
   127  	CLASS = 119
   128  
   129  	CURSOR = 120
   130  
   131  	PLTYPE_RECORD = 121
   132  
   133  	SARRAY = 122
   134  
   135  	CURSOR_ORACLE = -10
   136  
   137  	BIT_PREC = BYTE_SIZE
   138  
   139  	TINYINT_PREC = BYTE_SIZE
   140  
   141  	SMALLINT_PREC = USINT_SIZE
   142  
   143  	INT_PREC = ULINT_SIZE
   144  
   145  	BIGINT_PREC = LINT64_SIZE
   146  
   147  	REAL_PREC = 4
   148  
   149  	DOUBLE_PREC = 8
   150  
   151  	DATE_PREC = 3
   152  
   153  	TIME_PREC = 5
   154  
   155  	DATETIME_PREC = 8
   156  
   157  	INTERVAL_YM_PREC = 3 * ULINT_SIZE
   158  
   159  	INTERVAL_DT_PREC = 6 * ULINT_SIZE
   160  
   161  	TIME_TZ_PREC = 7
   162  
   163  	DATETIME_TZ_PREC = 10
   164  
   165  	VARCHAR_PREC = 8188
   166  
   167  	VARBINARY_PREC = 8188
   168  
   169  	BLOB_PREC int32 = INT32_MAX
   170  
   171  	CLOB_PREC int32 = INT32_MAX
   172  
   173  	NULL_PREC = 0
   174  
   175  	LOCAL_TIME_ZONE_SCALE_MASK = 0x00001000
   176  
   177  	BFILE_PREC = 512
   178  
   179  	BFILE_SCALE = 6
   180  
   181  	COMPLEX_SCALE = 5
   182  
   183  	CURRENCY_PREC = 19
   184  
   185  	CURRENCY_SCALE = 4
   186  
   187  	FLOAT_SCALE_MASK = 0x81
   188  )
   189  
   190  func resetColType(stmt *DmStatement, i int, colType int32) bool {
   191  
   192  	parameter := &stmt.params[i]
   193  
   194  	if parameter.ioType == IO_TYPE_OUT {
   195  		stmt.curRowBindIndicator[i] |= BIND_OUT
   196  		return false
   197  	} else if parameter.ioType == IO_TYPE_IN {
   198  		stmt.curRowBindIndicator[i] |= BIND_IN
   199  	} else {
   200  		stmt.curRowBindIndicator[i] |= BIND_IN
   201  		stmt.curRowBindIndicator[i] |= BIND_OUT
   202  	}
   203  
   204  	if parameter.typeFlag != TYPE_FLAG_EXACT {
   205  
   206  		parameter.colType = colType
   207  		parameter.scale = 0
   208  		switch colType {
   209  		case BOOLEAN, BIT:
   210  			parameter.prec = BIT_PREC
   211  		case TINYINT:
   212  			parameter.prec = TINYINT_PREC
   213  		case SMALLINT:
   214  			parameter.prec = SMALLINT_PREC
   215  		case INT:
   216  			parameter.prec = INT_PREC
   217  		case BIGINT:
   218  			parameter.prec = BIGINT_PREC
   219  		case CHAR, VARCHAR, VARCHAR2:
   220  			parameter.prec = VARCHAR_PREC
   221  		case CLOB:
   222  			parameter.prec = CLOB_PREC
   223  		case BINARY, VARBINARY:
   224  			parameter.prec = VARBINARY_PREC
   225  		case BLOB:
   226  			parameter.prec = BLOB_PREC
   227  		case DATE:
   228  			parameter.prec = DATE_PREC
   229  		case TIME:
   230  			parameter.prec = TIME_PREC
   231  			parameter.scale = 6
   232  		case TIME_TZ:
   233  			parameter.prec = TIME_TZ_PREC
   234  			parameter.scale = 6
   235  		case DATETIME:
   236  			parameter.prec = DATETIME_PREC
   237  			parameter.scale = 6
   238  		case DATETIME_TZ:
   239  			parameter.prec = DATETIME_TZ_PREC
   240  			parameter.scale = 6
   241  		case REAL, DOUBLE, DECIMAL, INTERVAL_YM, INTERVAL_DT, ARRAY, CLASS, PLTYPE_RECORD, SARRAY:
   242  			parameter.prec = 0
   243  		case UNKNOWN, NULL:
   244  			parameter.colType = VARCHAR
   245  			parameter.prec = VARCHAR_PREC
   246  		}
   247  	}
   248  
   249  	return true
   250  }
   251  
   252  func isBFile(colType int, prec int, scale int) bool {
   253  	return colType == VARCHAR && prec == BFILE_PREC && scale == BFILE_SCALE
   254  }
   255  
   256  func isComplexType(colType int, scale int) bool {
   257  	return (colType == BLOB && scale == COMPLEX_SCALE) || colType == ARRAY || colType == SARRAY || colType == CLASS || colType == PLTYPE_RECORD
   258  }
   259  
   260  func isLocalTimeZone(colType int, scale int) bool {
   261  	return colType == DATETIME && (scale&LOCAL_TIME_ZONE_SCALE_MASK) != 0
   262  }
   263  
   264  func getLocalTimeZoneScale(colType int, scale int) int {
   265  	return scale & (^LOCAL_TIME_ZONE_SCALE_MASK)
   266  }
   267  
   268  func isFloat(colType int, scale int) bool {
   269  	return colType == DECIMAL && scale == FLOAT_SCALE_MASK
   270  }
   271  
   272  func getFloatPrec(prec int) int {
   273  	return int(math.Round(float64(prec)*0.30103)) + 1
   274  }
   275  
   276  func getFloatScale(scale int) int {
   277  	return scale & (^FLOAT_SCALE_MASK)
   278  }
   279  
   280  var (
   281  	scanTypeFloat32    = reflect.TypeOf(float32(0))
   282  	scanTypeFloat64    = reflect.TypeOf(float64(0))
   283  	scanTypeBool       = reflect.TypeOf(false)
   284  	scanTypeInt8       = reflect.TypeOf(int8(0))
   285  	scanTypeInt16      = reflect.TypeOf(int16(0))
   286  	scanTypeInt32      = reflect.TypeOf(int32(0))
   287  	scanTypeInt64      = reflect.TypeOf(int64(0))
   288  	scanTypeNullBool   = reflect.TypeOf(sql.NullBool{})
   289  	scanTypeNullFloat  = reflect.TypeOf(sql.NullFloat64{})
   290  	scanTypeNullInt    = reflect.TypeOf(sql.NullInt64{})
   291  	scanTypeNullString = reflect.TypeOf(sql.NullString{})
   292  	scanTypeNullTime   = reflect.TypeOf(sql.NullTime{})
   293  	scanTypeRawBytes   = reflect.TypeOf(sql.RawBytes{})
   294  	scanTypeString     = reflect.TypeOf("")
   295  	scanTypeTime       = reflect.TypeOf(time.Now())
   296  	scanTypeUnknown    = reflect.TypeOf(new(interface{}))
   297  )
   298  
   299  func (column *column) ScanType() reflect.Type {
   300  
   301  	switch column.colType {
   302  	case BOOLEAN:
   303  		if column.nullable {
   304  			return scanTypeNullBool
   305  		}
   306  
   307  		return scanTypeBool
   308  
   309  	case BIT:
   310  		if strings.ToLower(column.typeName) == "boolean" {
   311  
   312  			if column.nullable {
   313  				return scanTypeNullBool
   314  			}
   315  
   316  			return scanTypeBool
   317  		} else {
   318  
   319  			if column.nullable {
   320  				return scanTypeNullInt
   321  			}
   322  			return scanTypeInt8
   323  		}
   324  
   325  	case TINYINT:
   326  		if column.nullable {
   327  			return scanTypeNullInt
   328  		}
   329  		return scanTypeInt8
   330  
   331  	case SMALLINT:
   332  		if column.nullable {
   333  			return scanTypeNullInt
   334  		}
   335  		return scanTypeInt16
   336  
   337  	case INT:
   338  		if column.nullable {
   339  			return scanTypeNullInt
   340  		}
   341  
   342  		return scanTypeInt32
   343  
   344  	case BIGINT:
   345  		if column.nullable {
   346  			return scanTypeNullInt
   347  		}
   348  		return scanTypeInt64
   349  
   350  	case REAL:
   351  		if column.nullable {
   352  			return scanTypeNullFloat
   353  		}
   354  
   355  		return scanTypeFloat32
   356  
   357  	case DOUBLE:
   358  
   359  		if strings.ToLower(column.typeName) == "float" {
   360  			if column.nullable {
   361  				return scanTypeNullFloat
   362  			}
   363  
   364  			return scanTypeFloat32
   365  		}
   366  
   367  		if column.nullable {
   368  			return scanTypeNullFloat
   369  		}
   370  
   371  		return scanTypeFloat64
   372  	case DATE, TIME, DATETIME:
   373  		if column.nullable {
   374  			return scanTypeNullTime
   375  		}
   376  
   377  		return scanTypeTime
   378  
   379  	case DECIMAL, BINARY, VARBINARY, BLOB:
   380  		return scanTypeRawBytes
   381  
   382  	case CHAR, VARCHAR2, VARCHAR, CLOB:
   383  		if column.nullable {
   384  			return scanTypeNullString
   385  		}
   386  		return scanTypeString
   387  	}
   388  
   389  	return scanTypeUnknown
   390  }
   391  
   392  func (column *column) Length() (length int64, ok bool) {
   393  
   394  	switch column.colType {
   395  	case BINARY:
   396  	case VARBINARY:
   397  	case BLOB:
   398  	case CHAR:
   399  	case VARCHAR2:
   400  	case VARCHAR:
   401  	case CLOB:
   402  		return int64(column.prec), true
   403  	}
   404  
   405  	return int64(0), false
   406  }
   407  
   408  func (column *column) PrecisionScale() (precision, scale int64, ok bool) {
   409  	switch column.colType {
   410  	case DECIMAL:
   411  		return int64(column.prec), int64(column.scale), true
   412  	}
   413  
   414  	return int64(0), int64(0), false
   415  }
   416  
   417  func (column *column) getColumnData(bytes []byte, conn *DmConnection) (driver.Value, error) {
   418  	if bytes == nil {
   419  		return nil, nil
   420  	}
   421  
   422  	switch column.colType {
   423  	case BOOLEAN:
   424  		return bytes[0] != 0, nil
   425  	case BIT:
   426  		if strings.ToLower(column.typeName) == "boolean" {
   427  			return bytes[0] != 0, nil
   428  		}
   429  
   430  		return int8(bytes[0]), nil
   431  	case TINYINT:
   432  		return int8(bytes[0]), nil
   433  	case SMALLINT:
   434  		return Dm_build_1.Dm_build_98(bytes, 0), nil
   435  	case INT:
   436  		return Dm_build_1.Dm_build_103(bytes, 0), nil
   437  	case BIGINT:
   438  		return Dm_build_1.Dm_build_108(bytes, 0), nil
   439  	case REAL:
   440  		return Dm_build_1.Dm_build_113(bytes, 0), nil
   441  	case DOUBLE:
   442  
   443  		return Dm_build_1.Dm_build_117(bytes, 0), nil
   444  	case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ:
   445  		return DB2G.toTime(bytes, column, conn)
   446  	case INTERVAL_DT:
   447  		return newDmIntervalDTByBytes(bytes).String(), nil
   448  	case INTERVAL_YM:
   449  		return newDmIntervalYMByBytes(bytes).String(), nil
   450  	case DECIMAL:
   451  		tmp, err := DB2G.toDmDecimal(bytes, column, conn)
   452  		if err != nil {
   453  			return nil, err
   454  		}
   455  		return tmp.String(), nil
   456  
   457  	case BINARY, VARBINARY:
   458  		return bytes, nil
   459  	case BLOB:
   460  		blob := DB2G.toDmBlob(bytes, column, conn)
   461  		if conn.CompatibleMysql() {
   462  			l, err := blob.GetLength()
   463  			if err != nil {
   464  				return nil, err
   465  			}
   466  			return blob.getBytes(1, int32(l))
   467  		}
   468  		return blob, nil
   469  	case CHAR, VARCHAR2, VARCHAR:
   470  		return Dm_build_1.Dm_build_158(bytes, 0, len(bytes), conn.getServerEncoding(), conn), nil
   471  	case CLOB:
   472  		clob := DB2G.toDmClob(bytes, conn, column)
   473  		if conn.CompatibleMysql() {
   474  			l, err := clob.GetLength()
   475  			if err != nil {
   476  				return nil, err
   477  			}
   478  			return clob.getSubString(1, int32(l))
   479  		}
   480  		return clob, nil
   481  	}
   482  
   483  	return string(bytes), nil
   484  }
   485  
   486  func emptyStringToNil(t int32) bool {
   487  	switch t {
   488  	case BOOLEAN, BIT, TINYINT, SMALLINT, INT, BIGINT, REAL, DOUBLE, DECIMAL,
   489  		DATE, TIME, DATETIME, INTERVAL_DT, INTERVAL_YM, TIME_TZ, DATETIME_TZ:
   490  		return true
   491  	default:
   492  		return false
   493  	}
   494  }