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

     1  /*
     2   * Copyright (c) 2000-2018, 达梦数据库有限公司.
     3   * All rights reserved.
     4   */
     5  package dm
     6  
     7  import (
     8  	"container/list"
     9  	"context"
    10  	"database/sql"
    11  	"database/sql/driver"
    12  	"fmt"
    13  	"gitee.com/curryzheng/dm/util"
    14  	"io"
    15  	"math/big"
    16  	"reflect"
    17  	"strconv"
    18  	"strings"
    19  	"time"
    20  )
    21  
    22  const (
    23  	BIND_IN byte = 0x01
    24  
    25  	BIND_OUT byte = 0x10
    26  )
    27  
    28  var rp = newRsPool()
    29  
    30  type DmStatement struct {
    31  	filterable
    32  
    33  	dmConn    *DmConnection
    34  	rsMap     map[int16]*innerRows
    35  	inUse     bool
    36  	innerUsed bool
    37  
    38  	innerExec bool
    39  
    40  	id int32
    41  
    42  	cursorName string
    43  
    44  	readBaseColName bool
    45  
    46  	execInfo *execRetInfo
    47  
    48  	resultSetType int
    49  
    50  	resultSetConcurrency int
    51  
    52  	resultSetHoldability int
    53  
    54  	nativeSql string
    55  
    56  	maxFieldSize int
    57  
    58  	maxRows int64
    59  
    60  	escapeProcessing bool
    61  
    62  	queryTimeout int32
    63  
    64  	fetchDirection int
    65  
    66  	fetchSize int
    67  
    68  	cursorUpdateRow int64
    69  
    70  	closeOnCompletion bool
    71  
    72  	isBatch bool
    73  
    74  	closed bool
    75  
    76  	columns []column
    77  
    78  	params []parameter
    79  
    80  	paramCount int32
    81  
    82  	curRowBindIndicator []byte
    83  
    84  	preExec bool
    85  }
    86  
    87  type stmtPoolInfo struct {
    88  	id int32
    89  
    90  	cursorName string
    91  
    92  	readBaseColName bool
    93  }
    94  
    95  type rsPoolKey struct {
    96  	dbGuid        string
    97  	currentSchema string
    98  	sql           string
    99  	paramCount    int
   100  }
   101  
   102  func newRsPoolKey(stmt *DmStatement, sql string) rsPoolKey {
   103  	rpk := new(rsPoolKey)
   104  	rpk.dbGuid = stmt.dmConn.Guid
   105  	rpk.currentSchema = stmt.dmConn.Schema
   106  	rpk.paramCount = int(stmt.paramCount)
   107  
   108  	rpk.sql = sql
   109  	return *rpk
   110  }
   111  
   112  func (key rsPoolKey) equals(destKey rsPoolKey) bool {
   113  	return key.dbGuid == destKey.dbGuid &&
   114  		key.currentSchema == destKey.currentSchema &&
   115  		key.sql == destKey.sql &&
   116  		key.paramCount == destKey.paramCount
   117  
   118  }
   119  
   120  type rsPoolValue struct {
   121  	m_lastChkTime int
   122  	m_TbIds       []int32
   123  	m_TbTss       []int64
   124  	execInfo      *execRetInfo
   125  }
   126  
   127  func newRsPoolValue(execInfo *execRetInfo) rsPoolValue {
   128  	rpv := new(rsPoolValue)
   129  	rpv.execInfo = execInfo
   130  	rpv.m_lastChkTime = time.Now().Nanosecond()
   131  	copy(rpv.m_TbIds, execInfo.tbIds)
   132  	copy(rpv.m_TbTss, execInfo.tbTss)
   133  	return *rpv
   134  }
   135  
   136  func (rpv rsPoolValue) refreshed(conn *DmConnection) (bool, error) {
   137  
   138  	if conn.dmConnector.rsRefreshFreq == 0 {
   139  		return false, nil
   140  	}
   141  
   142  	if rpv.m_lastChkTime+conn.dmConnector.rsRefreshFreq*int(time.Second) > time.Now().Nanosecond() {
   143  		return false, nil
   144  	}
   145  
   146  	tss, err := conn.Access.Dm_build_840(interface{}(rpv.m_TbIds).([]uint32))
   147  	if err != nil {
   148  		return false, err
   149  	}
   150  	rpv.m_lastChkTime = time.Now().Nanosecond()
   151  
   152  	var tbCount int
   153  	if tss != nil {
   154  		tbCount = len(tss)
   155  	}
   156  
   157  	if tbCount != len(rpv.m_TbTss) {
   158  		return true, nil
   159  	}
   160  
   161  	for i := 0; i < tbCount; i++ {
   162  		if rpv.m_TbTss[i] != tss[i] {
   163  			return true, nil
   164  		}
   165  
   166  	}
   167  	return false, nil
   168  }
   169  
   170  func (rpv rsPoolValue) getResultSet(stmt *DmStatement) *innerRows {
   171  	destDatas := rpv.execInfo.rsDatas
   172  	var totalRows int
   173  	if rpv.execInfo.rsDatas != nil {
   174  		totalRows = len(rpv.execInfo.rsDatas)
   175  	}
   176  
   177  	if stmt.maxRows > 0 && stmt.maxRows < int64(totalRows) {
   178  		destDatas = make([][][]byte, stmt.maxRows)
   179  		copy(destDatas[:len(destDatas)], rpv.execInfo.rsDatas[:len(destDatas)])
   180  	}
   181  
   182  	rs := newLocalInnerRows(stmt, stmt.columns, destDatas)
   183  	rs.id = 1
   184  	return rs
   185  }
   186  
   187  func (rpv rsPoolValue) getDataLen() int {
   188  	return rpv.execInfo.rsSizeof
   189  }
   190  
   191  type rsPool struct {
   192  	rsMap        map[rsPoolKey]rsPoolValue
   193  	rsList       *list.List
   194  	totalDataLen int
   195  }
   196  
   197  func newRsPool() *rsPool {
   198  	rp := new(rsPool)
   199  	rp.rsMap = make(map[rsPoolKey]rsPoolValue, 100)
   200  	rp.rsList = list.New()
   201  	return rp
   202  }
   203  
   204  func (rp *rsPool) removeInList(key rsPoolKey) {
   205  	for e := rp.rsList.Front(); e != nil && e.Value.(rsPoolKey).equals(key); e = e.Next() {
   206  		rp.rsList.Remove(e)
   207  	}
   208  }
   209  
   210  func (rp *rsPool) put(stmt *DmStatement, sql string, execInfo *execRetInfo) {
   211  	var dataLen int
   212  	if execInfo != nil {
   213  		dataLen = execInfo.rsSizeof
   214  	}
   215  
   216  	cacheSize := stmt.dmConn.dmConnector.rsCacheSize * 1024 * 1024
   217  
   218  	for rp.totalDataLen+dataLen > cacheSize {
   219  		if rp.totalDataLen == 0 {
   220  			return
   221  		}
   222  
   223  		lk := rp.rsList.Back().Value.(rsPoolKey)
   224  		rp.totalDataLen -= rp.rsMap[lk].getDataLen()
   225  		rp.rsList.Remove(rp.rsList.Back())
   226  		delete(rp.rsMap, rp.rsList.Back().Value.(rsPoolKey))
   227  	}
   228  
   229  	key := newRsPoolKey(stmt, sql)
   230  	value := newRsPoolValue(execInfo)
   231  
   232  	if _, ok := rp.rsMap[key]; !ok {
   233  		rp.rsList.PushFront(key)
   234  	} else {
   235  		rp.removeInList(key)
   236  		rp.rsList.PushFront(key)
   237  	}
   238  
   239  	rp.rsMap[key] = value
   240  	rp.totalDataLen += dataLen
   241  }
   242  
   243  func (rp *rsPool) get(stmt *DmStatement, sql string) (*rsPoolValue, error) {
   244  	key := newRsPoolKey(stmt, sql)
   245  
   246  	v, ok := rp.rsMap[key]
   247  	if ok {
   248  		b, err := v.refreshed(stmt.dmConn)
   249  		if err != nil {
   250  			return nil, err
   251  		}
   252  
   253  		if b {
   254  			rp.removeInList(key)
   255  			delete(rp.rsMap, key)
   256  			return nil, nil
   257  		}
   258  
   259  		rp.removeInList(key)
   260  		rp.rsList.PushFront(key)
   261  		return &v, nil
   262  	} else {
   263  		return nil, nil
   264  	}
   265  }
   266  
   267  func (s *DmStatement) Close() error {
   268  	if s.closed {
   269  		return nil
   270  	}
   271  	if len(s.filterChain.filters) == 0 {
   272  		return s.close()
   273  	}
   274  	return s.filterChain.reset().DmStatementClose(s)
   275  }
   276  
   277  func (s *DmStatement) NumInput() int {
   278  	if err := s.checkClosed(); err != nil {
   279  		return 0
   280  	}
   281  	if len(s.filterChain.filters) == 0 {
   282  		return s.numInput()
   283  	}
   284  	return s.filterChain.reset().DmStatementNumInput(s)
   285  }
   286  
   287  func (s *DmStatement) Exec(args []driver.Value) (driver.Result, error) {
   288  	if err := s.checkClosed(); err != nil {
   289  		return nil, err
   290  	}
   291  	if len(s.filterChain.filters) == 0 {
   292  		return s.exec(args)
   293  	}
   294  	return s.filterChain.reset().DmStatementExec(s, args)
   295  }
   296  
   297  func (s *DmStatement) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
   298  	if err := s.checkClosed(); err != nil {
   299  		return nil, err
   300  	}
   301  	if len(s.filterChain.filters) == 0 {
   302  		return s.execContext(ctx, args)
   303  	}
   304  	return s.filterChain.reset().DmStatementExecContext(s, ctx, args)
   305  }
   306  
   307  func (s *DmStatement) Query(args []driver.Value) (driver.Rows, error) {
   308  	if err := s.checkClosed(); err != nil {
   309  		return nil, err
   310  	}
   311  	if len(s.filterChain.filters) == 0 {
   312  		return s.query(args)
   313  	}
   314  	return s.filterChain.reset().DmStatementQuery(s, args)
   315  }
   316  
   317  func (s *DmStatement) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
   318  	if err := s.checkClosed(); err != nil {
   319  		return nil, err
   320  	}
   321  	if len(s.filterChain.filters) == 0 {
   322  		return s.queryContext(ctx, args)
   323  	}
   324  	return s.filterChain.reset().DmStatementQueryContext(s, ctx, args)
   325  }
   326  
   327  func (s *DmStatement) CheckNamedValue(nv *driver.NamedValue) error {
   328  	if len(s.filterChain.filters) == 0 {
   329  		return s.checkNamedValue(nv)
   330  	}
   331  	return s.filterChain.reset().DmStatementCheckNamedValue(s, nv)
   332  }
   333  
   334  func (st *DmStatement) prepare() error {
   335  	var err error
   336  	if st.dmConn.dmConnector.escapeProcess {
   337  		st.nativeSql, err = st.dmConn.escape(st.nativeSql, st.dmConn.dmConnector.keyWords)
   338  		if err != nil {
   339  			return err
   340  		}
   341  	}
   342  
   343  	st.execInfo, err = st.dmConn.Access.Dm_build_765(st, Dm_build_1043)
   344  	if err != nil {
   345  		return err
   346  	}
   347  	st.curRowBindIndicator = make([]byte, st.paramCount)
   348  	return nil
   349  }
   350  
   351  func (stmt *DmStatement) close() error {
   352  	if stmt.closed {
   353  		return nil
   354  	}
   355  	stmt.inUse = true
   356  	if stmt.dmConn.stmtPool != nil && len(stmt.dmConn.stmtPool) < stmt.dmConn.dmConnector.stmtPoolMaxSize {
   357  		stmt.pool()
   358  		return nil
   359  	} else {
   360  		return stmt.free()
   361  	}
   362  }
   363  
   364  func (stmt *DmStatement) numInput() int {
   365  	return int(stmt.paramCount)
   366  }
   367  
   368  func (stmt *DmStatement) checkNamedValue(nv *driver.NamedValue) error {
   369  	var err error
   370  	var cvt = converter{stmt.dmConn, false}
   371  	nv.Value, err = cvt.ConvertValue(nv.Value)
   372  	stmt.isBatch = cvt.isBatch
   373  	return err
   374  }
   375  
   376  func (stmt *DmStatement) exec(args []driver.Value) (*DmResult, error) {
   377  	var err error
   378  
   379  	stmt.inUse = true
   380  	if stmt.isBatch && len(args) > 0 {
   381  		var tmpArg []driver.Value
   382  		var arg driver.Value
   383  		for i := len(args) - 1; i >= 0; i-- {
   384  			if args[i] != nil {
   385  				arg = args[i]
   386  				break
   387  			}
   388  		}
   389  		for _, row := range arg.([][]interface{}) {
   390  			tmpArg = append(tmpArg, row)
   391  		}
   392  		err = stmt.executeBatch(tmpArg)
   393  	} else {
   394  		err = stmt.executeInner(args, Dm_build_1045)
   395  	}
   396  	if err != nil {
   397  		return nil, err
   398  	}
   399  	return newDmResult(stmt, stmt.execInfo), nil
   400  }
   401  
   402  func (stmt *DmStatement) execContext(ctx context.Context, args []driver.NamedValue) (*DmResult, error) {
   403  	stmt.inUse = true
   404  	dargs, err := namedValueToValue(stmt, args)
   405  	if err != nil {
   406  		return nil, err
   407  	}
   408  
   409  	if err := stmt.dmConn.watchCancel(ctx); err != nil {
   410  		return nil, err
   411  	}
   412  	defer stmt.dmConn.finish()
   413  
   414  	return stmt.exec(dargs)
   415  }
   416  
   417  func (stmt *DmStatement) query(args []driver.Value) (*DmRows, error) {
   418  	var err error
   419  	stmt.inUse = true
   420  	err = stmt.executeInner(args, Dm_build_1044)
   421  	if err != nil {
   422  		return nil, err
   423  	}
   424  
   425  	return newDmRows(newInnerRows(0, stmt, stmt.execInfo)), nil
   426  }
   427  
   428  func (stmt *DmStatement) queryContext(ctx context.Context, args []driver.NamedValue) (*DmRows, error) {
   429  	stmt.inUse = true
   430  	dargs, err := namedValueToValue(stmt, args)
   431  	if err != nil {
   432  		return nil, err
   433  	}
   434  
   435  	if err := stmt.dmConn.watchCancel(ctx); err != nil {
   436  		return nil, err
   437  	}
   438  
   439  	rows, err := stmt.query(dargs)
   440  	if err != nil {
   441  		stmt.dmConn.finish()
   442  		return nil, err
   443  	}
   444  	rows.finish = stmt.dmConn.finish
   445  	return rows, err
   446  }
   447  
   448  func NewDmStmt(conn *DmConnection, sql string) (*DmStatement, error) {
   449  	var s *DmStatement
   450  
   451  	if s == nil {
   452  		s = new(DmStatement)
   453  		s.resetFilterable(&conn.filterable)
   454  		s.objId = -1
   455  		s.idGenerator = dmStmtIDGenerator
   456  		s.dmConn = conn
   457  		s.maxRows = int64(conn.dmConnector.maxRows)
   458  		s.nativeSql = sql
   459  		s.rsMap = make(map[int16]*innerRows)
   460  		s.inUse = true
   461  		s.isBatch = conn.isBatch
   462  
   463  		if conn.stmtPool != nil && len(conn.stmtPool) > 0 {
   464  			len := len(conn.stmtPool)
   465  			spi := conn.stmtPool[0]
   466  			copy(conn.stmtPool, conn.stmtPool[1:])
   467  			conn.stmtPool = conn.stmtPool[:len-1]
   468  			s.id = spi.id
   469  			s.cursorName = spi.cursorName
   470  			s.readBaseColName = spi.readBaseColName
   471  		} else {
   472  			err := conn.Access.Dm_build_747(s)
   473  			if err != nil {
   474  				return nil, err
   475  			}
   476  		}
   477  
   478  	}
   479  
   480  	return s, nil
   481  
   482  }
   483  
   484  func (stmt *DmStatement) checkClosed() error {
   485  	if stmt.dmConn.closed.IsSet() {
   486  		return driver.ErrBadConn
   487  	} else if stmt.closed {
   488  		return ECGO_STATEMENT_HANDLE_CLOSED.throw()
   489  	}
   490  
   491  	return nil
   492  }
   493  
   494  func (stmt *DmStatement) pool() {
   495  	for _, rs := range stmt.rsMap {
   496  		rs.Close()
   497  	}
   498  
   499  	stmt.dmConn.stmtPool = append(stmt.dmConn.stmtPool, stmtPoolInfo{stmt.id, stmt.cursorName, stmt.readBaseColName})
   500  	delete(stmt.dmConn.stmtMap, stmt.id)
   501  	stmt.inUse = false
   502  	stmt.closed = true
   503  }
   504  
   505  func (stmt *DmStatement) free() error {
   506  	for _, rs := range stmt.rsMap {
   507  		rs.Close()
   508  	}
   509  
   510  	err := stmt.dmConn.Access.Dm_build_752(int32(stmt.id))
   511  	if err != nil {
   512  		return err
   513  	}
   514  	delete(stmt.dmConn.stmtMap, stmt.id)
   515  	stmt.inUse = false
   516  	stmt.closed = true
   517  	return nil
   518  }
   519  
   520  func encodeArgs(stmt *DmStatement, args []driver.Value) ([]interface{}, error) {
   521  	bytes := make([]interface{}, len(args), len(args))
   522  
   523  	var err error
   524  
   525  	for i, arg := range args {
   526  	nextSwitch:
   527  		if stmt.params[i].colType == CURSOR {
   528  			if stmt.params[i].cursorStmt == nil {
   529  				stmt.params[i].cursorStmt = &DmStatement{dmConn: stmt.dmConn}
   530  				stmt.params[i].cursorStmt.resetFilterable(&stmt.dmConn.filterable)
   531  				err = stmt.params[i].cursorStmt.dmConn.Access.Dm_build_747(stmt.params[i].cursorStmt)
   532  			}
   533  			stmt.curRowBindIndicator[i] |= BIND_OUT
   534  			continue
   535  		}
   536  		if arg == nil {
   537  			if resetColType(stmt, i, NULL) {
   538  				bytes[i] = ParamDataEnum_Null
   539  			}
   540  			continue
   541  		}
   542  
   543  		switch v := arg.(type) {
   544  		case bool:
   545  			if resetColType(stmt, i, TINYINT) {
   546  				bytes[i], err = G2DB.fromBool(v, stmt.params[i], stmt.dmConn)
   547  			}
   548  		case int8:
   549  			if resetColType(stmt, i, TINYINT) {
   550  				bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn)
   551  			}
   552  		case int16:
   553  			if resetColType(stmt, i, SMALLINT) {
   554  				bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn)
   555  			}
   556  		case int32:
   557  			if resetColType(stmt, i, INT) {
   558  				bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn)
   559  			}
   560  		case int64:
   561  			if resetColType(stmt, i, BIGINT) {
   562  				bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn)
   563  			}
   564  		case int:
   565  			if resetColType(stmt, i, BIGINT) {
   566  				bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn)
   567  			}
   568  		case uint8:
   569  			if resetColType(stmt, i, SMALLINT) {
   570  				bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn)
   571  			}
   572  		case uint16:
   573  			if resetColType(stmt, i, INT) {
   574  				bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn)
   575  			}
   576  		case uint32:
   577  			if resetColType(stmt, i, BIGINT) {
   578  				bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn)
   579  			}
   580  
   581  		case float32:
   582  			if resetColType(stmt, i, REAL) {
   583  				bytes[i], err = G2DB.fromFloat32(v, stmt.params[i], stmt.dmConn)
   584  			}
   585  		case float64:
   586  			if resetColType(stmt, i, DOUBLE) {
   587  				bytes[i], err = G2DB.fromFloat64(float64(v), stmt.params[i], stmt.dmConn)
   588  			}
   589  		case []byte:
   590  			if v == nil {
   591  				if resetColType(stmt, i, NULL) {
   592  					bytes[i] = ParamDataEnum_Null
   593  				}
   594  			} else if resetColType(stmt, i, VARBINARY) {
   595  				bytes[i], err = G2DB.fromBytes(v, stmt.params[i], stmt.dmConn)
   596  			}
   597  		case string:
   598  
   599  			if v == "" && emptyStringToNil(stmt.params[i].colType) {
   600  				arg = nil
   601  				goto nextSwitch
   602  			}
   603  			if resetColType(stmt, i, VARCHAR) {
   604  				bytes[i], err = G2DB.fromString(v, stmt.params[i], stmt.dmConn)
   605  			}
   606  		case time.Time:
   607  			if resetColType(stmt, i, DATETIME_TZ) {
   608  				bytes[i], err = G2DB.fromTime(v, stmt.params[i], stmt.dmConn)
   609  			}
   610  		case DmTimestamp:
   611  			if resetColType(stmt, i, DATETIME_TZ) {
   612  				bytes[i], err = G2DB.fromTime(v.ToTime(), stmt.params[i], stmt.dmConn)
   613  			}
   614  		case DmIntervalDT:
   615  			if resetColType(stmt, i, INTERVAL_DT) {
   616  				bytes[i], err = G2DB.fromDmIntervalDT(v, stmt.params[i], stmt.dmConn)
   617  			}
   618  		case DmIntervalYM:
   619  			if resetColType(stmt, i, INTERVAL_YM) {
   620  				bytes[i], err = G2DB.fromDmdbIntervalYM(v, stmt.params[i], stmt.dmConn)
   621  			}
   622  		case DmDecimal:
   623  			if resetColType(stmt, i, DECIMAL) {
   624  				bytes[i], err = G2DB.fromDecimal(v, stmt.params[i], stmt.dmConn)
   625  			}
   626  
   627  		case DmBlob:
   628  			if resetColType(stmt, i, BLOB) {
   629  				bytes[i], err = G2DB.fromBlob(DmBlob(v), stmt.params[i], stmt.dmConn)
   630  				if err != nil {
   631  					return nil, err
   632  				}
   633  			}
   634  		case DmClob:
   635  			if resetColType(stmt, i, CLOB) {
   636  				bytes[i], err = G2DB.fromClob(DmClob(v), stmt.params[i], stmt.dmConn)
   637  				if err != nil {
   638  					return nil, err
   639  				}
   640  			}
   641  		case DmArray:
   642  			if resetColType(stmt, i, ARRAY) {
   643  				da := &v
   644  				da, err = da.create(stmt.dmConn)
   645  				if err != nil {
   646  					return nil, err
   647  				}
   648  
   649  				bytes[i], err = G2DB.fromArray(da, stmt.params[i], stmt.dmConn)
   650  			}
   651  		case DmStruct:
   652  			if resetColType(stmt, i, RECORD) {
   653  				ds := &v
   654  				ds, err = ds.create(stmt.dmConn)
   655  				if err != nil {
   656  					return nil, err
   657  				}
   658  
   659  				bytes[i], err = G2DB.fromStruct(ds, stmt.params[i], stmt.dmConn)
   660  			}
   661  		case sql.Out:
   662  			var cvt = converter{stmt.dmConn, false}
   663  			if arg, err = cvt.ConvertValue(v.Dest); err != nil {
   664  				return nil, err
   665  			}
   666  			goto nextSwitch
   667  
   668  		case *DmTimestamp:
   669  			if resetColType(stmt, i, DATETIME_TZ) {
   670  				bytes[i], err = G2DB.fromTime(v.ToTime(), stmt.params[i], stmt.dmConn)
   671  			}
   672  		case *DmIntervalDT:
   673  			if resetColType(stmt, i, INTERVAL_DT) {
   674  				bytes[i], err = G2DB.fromDmIntervalDT(*v, stmt.params[i], stmt.dmConn)
   675  			}
   676  		case *DmIntervalYM:
   677  			if resetColType(stmt, i, INTERVAL_YM) {
   678  				bytes[i], err = G2DB.fromDmdbIntervalYM(*v, stmt.params[i], stmt.dmConn)
   679  			}
   680  		case *DmDecimal:
   681  			if resetColType(stmt, i, DECIMAL) {
   682  				bytes[i], err = G2DB.fromDecimal(*v, stmt.params[i], stmt.dmConn)
   683  			}
   684  		case *DmBlob:
   685  			if resetColType(stmt, i, BLOB) {
   686  				bytes[i], err = G2DB.fromBlob(DmBlob(*v), stmt.params[i], stmt.dmConn)
   687  			}
   688  		case *DmClob:
   689  			if resetColType(stmt, i, CLOB) {
   690  				bytes[i], err = G2DB.fromClob(DmClob(*v), stmt.params[i], stmt.dmConn)
   691  			}
   692  		case *DmArray:
   693  			if resetColType(stmt, i, ARRAY) {
   694  				v, err = v.create(stmt.dmConn)
   695  				if err != nil {
   696  					return nil, err
   697  				}
   698  
   699  				bytes[i], err = G2DB.fromArray(v, stmt.params[i], stmt.dmConn)
   700  			}
   701  		case *DmStruct:
   702  			if resetColType(stmt, i, RECORD) {
   703  				v, err = v.create(stmt.dmConn)
   704  				if err != nil {
   705  					return nil, err
   706  				}
   707  
   708  				bytes[i], err = G2DB.fromStruct(v, stmt.params[i], stmt.dmConn)
   709  			}
   710  		case *driver.Rows:
   711  			if stmt.params[i].colType == CURSOR && !resetColType(stmt, i, CURSOR) && stmt.params[i].cursorStmt == nil {
   712  				stmt.params[i].cursorStmt = &DmStatement{dmConn: stmt.dmConn}
   713  				stmt.params[i].cursorStmt.resetFilterable(&stmt.dmConn.filterable)
   714  				err = stmt.params[i].cursorStmt.dmConn.Access.Dm_build_747(stmt.params[i].cursorStmt)
   715  			}
   716  		case io.Reader:
   717  			bytes[i], err = G2DB.fromReader(io.Reader(v), stmt.params[i], stmt.dmConn)
   718  			if err != nil {
   719  				return nil, err
   720  			}
   721  		default:
   722  			err = ECGO_UNSUPPORTED_INPARAM_TYPE.throw()
   723  		}
   724  
   725  		if err != nil {
   726  			return nil, err
   727  		}
   728  
   729  	}
   730  
   731  	return bytes, nil
   732  }
   733  
   734  type converter struct {
   735  	conn    *DmConnection
   736  	isBatch bool
   737  }
   738  type decimalDecompose interface {
   739  	Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32)
   740  }
   741  
   742  func (c *converter) ConvertValue(v interface{}) (driver.Value, error) {
   743  	if driver.IsValue(v) {
   744  		return v, nil
   745  	}
   746  
   747  	switch vr := v.(type) {
   748  	case driver.Valuer:
   749  		sv, err := callValuerValue(vr)
   750  		if err != nil {
   751  			return nil, err
   752  		}
   753  
   754  		return sv, nil
   755  
   756  	case decimalDecompose, DmDecimal, *DmDecimal, DmTimestamp, *DmTimestamp, DmIntervalDT, *DmIntervalDT,
   757  		DmIntervalYM, *DmIntervalYM, driver.Rows, *driver.Rows, DmArray, *DmArray, DmStruct, *DmStruct, sql.Out:
   758  		return vr, nil
   759  	case big.Int:
   760  		return NewDecimalFromBigInt(&vr)
   761  	case big.Float:
   762  		return NewDecimalFromBigFloat(&vr)
   763  	case DmClob:
   764  
   765  		if vr.connection == nil {
   766  			vr.connection = c.conn
   767  		}
   768  		return vr, nil
   769  	case *DmClob:
   770  
   771  		if vr.connection == nil {
   772  			vr.connection = c.conn
   773  		}
   774  		return vr, nil
   775  	case DmBlob:
   776  
   777  		if vr.connection == nil {
   778  			vr.connection = c.conn
   779  		}
   780  		return vr, nil
   781  	case *DmBlob:
   782  
   783  		if vr.connection == nil {
   784  			vr.connection = c.conn
   785  		}
   786  		return vr, nil
   787  	case io.Reader:
   788  		return vr, nil
   789  	}
   790  
   791  	rv := reflect.ValueOf(v)
   792  	switch rv.Kind() {
   793  	case reflect.Ptr:
   794  		if rv.IsNil() {
   795  			return nil, nil
   796  		} else {
   797  			return c.ConvertValue(rv.Elem().Interface())
   798  		}
   799  	case reflect.Int:
   800  		return rv.Int(), nil
   801  	case reflect.Int8:
   802  		return int8(rv.Int()), nil
   803  	case reflect.Int16:
   804  		return int16(rv.Int()), nil
   805  	case reflect.Int32:
   806  		return int32(rv.Int()), nil
   807  	case reflect.Int64:
   808  		return int64(rv.Int()), nil
   809  	case reflect.Uint8:
   810  		return uint8(rv.Uint()), nil
   811  	case reflect.Uint16:
   812  		return uint16(rv.Uint()), nil
   813  	case reflect.Uint32:
   814  		return uint32(rv.Uint()), nil
   815  	case reflect.Uint64, reflect.Uint:
   816  		u64 := rv.Uint()
   817  		if u64 >= 1<<63 {
   818  			bigInt := &big.Int{}
   819  			bigInt.SetString(strconv.FormatUint(u64, 10), 10)
   820  			return NewDecimalFromBigInt(bigInt)
   821  		}
   822  		return int64(u64), nil
   823  	case reflect.Float32:
   824  		return float32(rv.Float()), nil
   825  	case reflect.Float64:
   826  		return float64(rv.Float()), nil
   827  	case reflect.Bool:
   828  		return rv.Bool(), nil
   829  	case reflect.Slice:
   830  		ek := rv.Type().Elem().Kind()
   831  		if ek == reflect.Uint8 {
   832  			return rv.Bytes(), nil
   833  		} else if ek == reflect.Slice {
   834  			c.isBatch = true
   835  			return v, nil
   836  		}
   837  		return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek)
   838  	case reflect.String:
   839  		return rv.String(), nil
   840  	}
   841  	return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
   842  }
   843  
   844  var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
   845  
   846  func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
   847  	if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
   848  		rv.IsNil() &&
   849  		rv.Type().Elem().Implements(valuerReflectType) {
   850  		return nil, nil
   851  	}
   852  	return vr.Value()
   853  }
   854  
   855  func namedValueToValue(stmt *DmStatement, named []driver.NamedValue) ([]driver.Value, error) {
   856  
   857  	dargs := make([]driver.Value, stmt.paramCount)
   858  	for i, _ := range dargs {
   859  		found := false
   860  		for _, nv := range named {
   861  			if nv.Name != "" && strings.ToUpper(nv.Name) == strings.ToUpper(stmt.params[i].name) {
   862  				dargs[i] = nv.Value
   863  				found = true
   864  				break
   865  			}
   866  		}
   867  
   868  		if !found && i < len(named) {
   869  			dargs[i] = named[i].Value
   870  		}
   871  
   872  	}
   873  	return dargs, nil
   874  }
   875  
   876  func (stmt *DmStatement) executeInner(args []driver.Value, executeType int16) (err error) {
   877  
   878  	var bytes []interface{}
   879  
   880  	if stmt.paramCount > 0 {
   881  		bytes, err = encodeArgs(stmt, args)
   882  		if err != nil {
   883  			return err
   884  		}
   885  	}
   886  	stmt.execInfo, err = stmt.dmConn.Access.Dm_build_797(stmt, bytes, false)
   887  	if err != nil {
   888  		return err
   889  	}
   890  	if stmt.execInfo.outParamDatas != nil {
   891  		for i, outParamData := range stmt.execInfo.outParamDatas {
   892  			if stmt.curRowBindIndicator[i]&BIND_OUT == BIND_OUT {
   893  				if arg, ok := args[i].(*driver.Rows); ok && stmt.params[i].colType == CURSOR && outParamData == nil {
   894  					var tmpExecInfo *execRetInfo
   895  					if tmpExecInfo, err = stmt.dmConn.Access.Dm_build_807(stmt.params[i].cursorStmt, 1); err != nil {
   896  						return err
   897  					}
   898  					if tmpExecInfo.hasResultSet {
   899  						*arg = newDmRows(newInnerRows(0, stmt.params[i].cursorStmt, tmpExecInfo))
   900  					} else {
   901  						*arg = nil
   902  					}
   903  					continue
   904  				}
   905  				if args[i] == nil {
   906  					if outParamData == nil {
   907  						continue
   908  					}
   909  
   910  					switch stmt.params[i].colType {
   911  					case BOOLEAN:
   912  						args[i], err = DB2G.toBool(outParamData, &stmt.params[i].column, stmt.dmConn)
   913  					case BIT:
   914  						if strings.ToLower(stmt.params[i].typeName) == "boolean" {
   915  							args[i], err = DB2G.toBool(outParamData, &stmt.params[i].column, stmt.dmConn)
   916  						}
   917  
   918  						args[i], err = DB2G.toInt8(outParamData, &stmt.params[i].column, stmt.dmConn)
   919  					case TINYINT:
   920  						args[i], err = DB2G.toInt8(outParamData, &stmt.params[i].column, stmt.dmConn)
   921  					case SMALLINT:
   922  						args[i], err = DB2G.toInt16(outParamData, &stmt.params[i].column, stmt.dmConn)
   923  					case INT:
   924  						args[i], err = DB2G.toInt32(outParamData, &stmt.params[i].column, stmt.dmConn)
   925  					case BIGINT:
   926  						args[i], err = DB2G.toInt64(outParamData, &stmt.params[i].column, stmt.dmConn)
   927  					case REAL:
   928  						args[i], err = DB2G.toFloat32(outParamData, &stmt.params[i].column, stmt.dmConn)
   929  					case DOUBLE:
   930  						args[i], err = DB2G.toFloat64(outParamData, &stmt.params[i].column, stmt.dmConn)
   931  					case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ:
   932  						args[i], err = DB2G.toTime(outParamData, &stmt.params[i].column, stmt.dmConn)
   933  					case INTERVAL_DT:
   934  						args[i] = newDmIntervalDTByBytes(outParamData)
   935  					case INTERVAL_YM:
   936  						args[i] = newDmIntervalYMByBytes(outParamData)
   937  					case DECIMAL:
   938  						args[i], err = DB2G.toDmDecimal(outParamData, &stmt.params[i].column, stmt.dmConn)
   939  					case BINARY, VARBINARY:
   940  						args[i] = util.StringUtil.BytesToHexString(outParamData, false)
   941  					case BLOB:
   942  						args[i] = DB2G.toDmBlob(outParamData, &stmt.params[i].column, stmt.dmConn)
   943  					case CHAR, VARCHAR2, VARCHAR:
   944  						args[i] = DB2G.toString(outParamData, &stmt.params[i].column, stmt.dmConn)
   945  					case CLOB:
   946  						args[i] = DB2G.toDmClob(outParamData, stmt.dmConn, &stmt.params[i].column)
   947  					default:
   948  						err = ECGO_UNSUPPORTED_OUTPARAM_TYPE.throw()
   949  					}
   950  				} else {
   951  				nextSwitch:
   952  					switch v := args[i].(type) {
   953  					case sql.Out:
   954  						args[i] = v.Dest
   955  						goto nextSwitch
   956  					case *string:
   957  						if outParamData == nil {
   958  							*v = ""
   959  						} else {
   960  							*v = DB2G.toString(outParamData, &stmt.params[i].column, stmt.dmConn)
   961  						}
   962  					case *sql.NullString:
   963  						if outParamData == nil {
   964  							v.String = ""
   965  							v.Valid = false
   966  						} else {
   967  							v.String = DB2G.toString(outParamData, &stmt.params[i].column, stmt.dmConn)
   968  							v.Valid = true
   969  						}
   970  					case *[]byte:
   971  						if outParamData == nil {
   972  							*v = nil
   973  						} else {
   974  							var val []byte
   975  							if val, err = DB2G.toBytes(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
   976  								return err
   977  							}
   978  							*v = val
   979  						}
   980  					case *bool:
   981  						if outParamData == nil {
   982  							*v = false
   983  						} else {
   984  							var val bool
   985  							if val, err = DB2G.toBool(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
   986  								return err
   987  							}
   988  							*v = val
   989  						}
   990  					case *sql.NullBool:
   991  						if outParamData == nil {
   992  							v.Bool = false
   993  							v.Valid = false
   994  						} else {
   995  							var val bool
   996  							if val, err = DB2G.toBool(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
   997  								return err
   998  							}
   999  							v.Bool = val
  1000  							v.Valid = true
  1001  						}
  1002  					case *int8:
  1003  						if outParamData == nil {
  1004  							*v = 0
  1005  						} else {
  1006  							var val int8
  1007  							if val, err = DB2G.toInt8(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1008  								return err
  1009  							}
  1010  							*v = val
  1011  						}
  1012  					case *int16:
  1013  						if outParamData == nil {
  1014  							*v = 0
  1015  						} else {
  1016  							var val int16
  1017  							if val, err = DB2G.toInt16(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1018  								return err
  1019  							}
  1020  							*v = val
  1021  						}
  1022  					case *int32:
  1023  						if outParamData == nil {
  1024  							*v = 0
  1025  						} else {
  1026  							var val int32
  1027  							if val, err = DB2G.toInt32(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1028  								return err
  1029  							}
  1030  							*v = val
  1031  						}
  1032  					case *sql.NullInt32:
  1033  						if outParamData == nil {
  1034  							v.Int32 = 0
  1035  							v.Valid = false
  1036  						} else {
  1037  							var val int32
  1038  							if val, err = DB2G.toInt32(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1039  								return err
  1040  							}
  1041  							v.Int32 = val
  1042  							v.Valid = true
  1043  						}
  1044  					case *int64:
  1045  						if outParamData == nil {
  1046  							*v = 0
  1047  						} else {
  1048  							var val int64
  1049  							if val, err = DB2G.toInt64(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1050  								return err
  1051  							}
  1052  							*v = val
  1053  						}
  1054  					case *sql.NullInt64:
  1055  						if outParamData == nil {
  1056  							v.Int64 = 0
  1057  							v.Valid = false
  1058  						} else {
  1059  							var val int64
  1060  							if val, err = DB2G.toInt64(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1061  								return err
  1062  							}
  1063  							v.Int64 = val
  1064  							v.Valid = true
  1065  						}
  1066  					case *uint8:
  1067  						if outParamData == nil {
  1068  							*v = 0
  1069  						} else {
  1070  							var val uint8
  1071  							if val, err = DB2G.toByte(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1072  								return err
  1073  							}
  1074  							*v = val
  1075  						}
  1076  					case *uint16:
  1077  						if outParamData == nil {
  1078  							*v = 0
  1079  						} else {
  1080  							var val uint16
  1081  							if val, err = DB2G.toUInt16(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1082  								return err
  1083  							}
  1084  							*v = val
  1085  						}
  1086  					case *uint32:
  1087  						if outParamData == nil {
  1088  							*v = 0
  1089  						} else {
  1090  							var val uint32
  1091  							if val, err = DB2G.toUInt32(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1092  								return err
  1093  							}
  1094  							*v = val
  1095  						}
  1096  					case *uint64:
  1097  						if outParamData == nil {
  1098  							*v = 0
  1099  						} else {
  1100  							var val uint64
  1101  							if val, err = DB2G.toUInt64(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1102  								return err
  1103  							}
  1104  							*v = val
  1105  						}
  1106  					case *int:
  1107  						if outParamData == nil {
  1108  							*v = 0
  1109  						} else {
  1110  							var val int
  1111  							if val, err = DB2G.toInt(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1112  								return err
  1113  							}
  1114  							*v = val
  1115  						}
  1116  					case *uint:
  1117  						if outParamData == nil {
  1118  							*v = 0
  1119  						} else {
  1120  							var val uint
  1121  							if val, err = DB2G.toUInt(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1122  								return err
  1123  							}
  1124  							*v = val
  1125  						}
  1126  					case *float32:
  1127  						if outParamData == nil {
  1128  							*v = 0.0
  1129  						} else {
  1130  							var val float32
  1131  							if val, err = DB2G.toFloat32(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1132  								return err
  1133  							}
  1134  							*v = val
  1135  						}
  1136  					case *float64:
  1137  						if outParamData == nil {
  1138  							*v = 0.0
  1139  						} else {
  1140  							var val float64
  1141  							if val, err = DB2G.toFloat64(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1142  								return err
  1143  							}
  1144  							*v = val
  1145  						}
  1146  					case *sql.NullFloat64:
  1147  						if outParamData == nil {
  1148  							v.Float64 = 0.0
  1149  							v.Valid = false
  1150  						} else {
  1151  							var val float64
  1152  							if val, err = DB2G.toFloat64(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1153  								return err
  1154  							}
  1155  							v.Float64 = val
  1156  							v.Valid = true
  1157  						}
  1158  					case *time.Time:
  1159  						if outParamData == nil {
  1160  							*v = time.Time{}
  1161  						} else {
  1162  							var val time.Time
  1163  							if val, err = DB2G.toTime(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1164  								return err
  1165  							}
  1166  							*v = val
  1167  						}
  1168  					case *sql.NullTime:
  1169  						if outParamData == nil {
  1170  							v.Time = time.Time{}
  1171  							v.Valid = false
  1172  						} else {
  1173  							var val time.Time
  1174  							if val, err = DB2G.toTime(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1175  								return err
  1176  							}
  1177  							v.Time = val
  1178  							v.Valid = true
  1179  						}
  1180  					case *DmTimestamp:
  1181  						if outParamData == nil {
  1182  							*v = DmTimestamp{}
  1183  						} else {
  1184  							*v = *newDmTimestampFromBytes(outParamData, stmt.params[i].column, stmt.dmConn)
  1185  						}
  1186  					case *DmIntervalDT:
  1187  						if outParamData == nil {
  1188  							*v = DmIntervalDT{}
  1189  						} else {
  1190  							*v = *newDmIntervalDTByBytes(outParamData)
  1191  						}
  1192  					case *DmIntervalYM:
  1193  						if outParamData == nil {
  1194  							*v = DmIntervalYM{}
  1195  						} else {
  1196  							*v = *newDmIntervalYMByBytes(outParamData)
  1197  						}
  1198  					case *DmDecimal:
  1199  						if outParamData == nil {
  1200  							*v = DmDecimal{}
  1201  						} else {
  1202  							var val *DmDecimal
  1203  							if val, err = DB2G.toDmDecimal(outParamData, &stmt.params[i].column, stmt.dmConn); err != nil {
  1204  								return err
  1205  							}
  1206  							*v = *val
  1207  						}
  1208  					case *DmBlob:
  1209  						if outParamData == nil {
  1210  							*v = DmBlob{}
  1211  						} else {
  1212  							*v = *DB2G.toDmBlob(outParamData, &stmt.params[i].column, stmt.dmConn)
  1213  						}
  1214  					case *DmClob:
  1215  						if outParamData == nil {
  1216  							*v = DmClob{}
  1217  						} else {
  1218  							*v = *DB2G.toDmClob(outParamData, stmt.dmConn, &stmt.params[i].column)
  1219  						}
  1220  					case *driver.Rows:
  1221  						if stmt.params[i].colType == CURSOR {
  1222  							var tmpExecInfo *execRetInfo
  1223  							tmpExecInfo, err = stmt.dmConn.Access.Dm_build_807(stmt.params[i].cursorStmt, 1)
  1224  							if err != nil {
  1225  								return err
  1226  							}
  1227  
  1228  							if tmpExecInfo.hasResultSet {
  1229  								*v = newDmRows(newInnerRows(0, stmt.params[i].cursorStmt, tmpExecInfo))
  1230  							} else {
  1231  								*v = nil
  1232  							}
  1233  						}
  1234  					case *DmArray:
  1235  						if outParamData == nil {
  1236  							*v = DmArray{}
  1237  						} else {
  1238  							var val *DmArray
  1239  							if val, err = TypeDataSV.bytesToArray(outParamData, nil, stmt.params[i].typeDescriptor); err != nil {
  1240  								return err
  1241  							}
  1242  							*v = *val
  1243  						}
  1244  					case *DmStruct:
  1245  						if outParamData == nil {
  1246  							*v = DmStruct{}
  1247  						} else {
  1248  							var val *DmStruct
  1249  							if val, err = TypeDataSV.bytesToRecord(outParamData, nil, stmt.params[i].typeDescriptor); err != nil {
  1250  								return err
  1251  							}
  1252  							*v = *val
  1253  						}
  1254  					default:
  1255  						err = ECGO_UNSUPPORTED_OUTPARAM_TYPE.throw()
  1256  					}
  1257  				}
  1258  			}
  1259  		}
  1260  	}
  1261  
  1262  	return err
  1263  }
  1264  
  1265  func (stmt *DmStatement) executeBatch(args []driver.Value) (err error) {
  1266  
  1267  	var bytes [][]interface{}
  1268  
  1269  	if stmt.execInfo.retSqlType == Dm_build_1058 || stmt.execInfo.retSqlType == Dm_build_1063 {
  1270  		return ECGO_INVALID_SQL_TYPE.throw()
  1271  	}
  1272  
  1273  	if stmt.paramCount > 0 && args != nil && len(args) > 0 {
  1274  
  1275  		if len(args) == 1 || stmt.dmConn.dmConnector.batchType == 2 ||
  1276  			(stmt.dmConn.dmConnector.batchNotOnCall && stmt.execInfo.retSqlType == Dm_build_1059) {
  1277  			return stmt.executeBatchByRow(args)
  1278  		} else {
  1279  			for _, arg := range args {
  1280  				var newArg []driver.Value
  1281  				for _, a := range arg.([]interface{}) {
  1282  					newArg = append(newArg, a)
  1283  				}
  1284  				tmpBytes, err := encodeArgs(stmt, newArg)
  1285  				if err != nil {
  1286  					return err
  1287  				}
  1288  				bytes = append(bytes, tmpBytes)
  1289  			}
  1290  			stmt.execInfo, err = stmt.dmConn.Access.Dm_build_786(stmt, bytes, stmt.preExec)
  1291  		}
  1292  	}
  1293  	return err
  1294  }
  1295  
  1296  func (stmt *DmStatement) executeBatchByRow(args []driver.Value) (err error) {
  1297  	count := len(args)
  1298  	stmt.execInfo = NewExceInfo()
  1299  	stmt.execInfo.updateCounts = make([]int64, count)
  1300  	var sqlErrBuilder strings.Builder
  1301  	for i := 0; i < count; i++ {
  1302  		tmpExecInfo, err := stmt.dmConn.Access.Dm_build_797(stmt, args[i].([]interface{}), stmt.preExec || i != 0)
  1303  		if err == nil {
  1304  			stmt.execInfo.union(tmpExecInfo, i, 1)
  1305  		} else {
  1306  			stmt.execInfo.updateCounts[i] = -1
  1307  			if stmt.dmConn.dmConnector.continueBatchOnError {
  1308  				sqlErrBuilder.WriteString("row[" + strconv.Itoa(i) + "]:" + err.Error() + util.LINE_SEPARATOR)
  1309  			} else {
  1310  				return ECGO_BATCH_ERROR.addDetailln(err.Error()).throw()
  1311  			}
  1312  		}
  1313  	}
  1314  	if sqlErrBuilder.Len() > 0 {
  1315  		return EC_BP_WITH_ERROR.addDetail(sqlErrBuilder.String()).throw()
  1316  	}
  1317  	return nil
  1318  }