github.com/mattn/go-adodb@v0.0.1/adodb.go (about)

     1  package adodb
     2  
     3  import (
     4  	"database/sql"
     5  	"database/sql/driver"
     6  	"errors"
     7  	"io"
     8  	"math"
     9  	//"math/big"
    10  	"reflect"
    11  	"time"
    12  	"unsafe"
    13  
    14  	"github.com/go-ole/go-ole"
    15  	"github.com/go-ole/go-ole/oleutil"
    16  	"golang.org/x/net/context"
    17  )
    18  
    19  type releaser interface {
    20  	Release() int32
    21  }
    22  
    23  func fullRelease(obj releaser) {
    24  	last := int32(-1)
    25  	for {
    26  		ref := obj.Release()
    27  		if ref == 0 || ref == last {
    28  			break
    29  		}
    30  		last = ref
    31  	}
    32  }
    33  
    34  func init() {
    35  	sql.Register("adodb", &AdodbDriver{})
    36  }
    37  
    38  type AdodbDriver struct {
    39  }
    40  
    41  type AdodbConn struct {
    42  	db *ole.IDispatch
    43  }
    44  
    45  type AdodbTx struct {
    46  	c *AdodbConn
    47  }
    48  
    49  func (tx *AdodbTx) Commit() error {
    50  	rv, err := oleutil.CallMethod(tx.c.db, "CommitTrans")
    51  	if err != nil {
    52  		return err
    53  	}
    54  	rv.Clear()
    55  	return nil
    56  }
    57  
    58  func (tx *AdodbTx) Rollback() error {
    59  	rv, err := oleutil.CallMethod(tx.c.db, "Rollback")
    60  	if err != nil {
    61  		return err
    62  	}
    63  	rv.Clear()
    64  	return nil
    65  }
    66  
    67  func (c *AdodbConn) exec(ctx context.Context, query string, args []namedValue) (driver.Result, error) {
    68  	s, err := c.Prepare(query)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	result, err := s.(*AdodbStmt).exec(ctx, args)
    73  	s.Close()
    74  	if err != nil && err != driver.ErrSkip {
    75  		return nil, err
    76  	}
    77  	return result, nil
    78  }
    79  
    80  /*
    81  func (c *AdodbConn) Query(query string, args []driver.Value) (driver.Rows, error) {
    82  	list := make([]namedValue, len(args))
    83  	for i, v := range args {
    84  		list[i] = namedValue{
    85  			Ordinal: i + 1,
    86  			Value:   v,
    87  		}
    88  	}
    89  	return c.query(context.Background(), query, list)
    90  }
    91  
    92  func (c *AdodbConn) query(ctx context.Context, query string, args []namedValue) (driver.Rows, error) {
    93  	s, err := c.Prepare(query)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  	rows, err := s.(*AdodbStmt).query(ctx, args)
    98  	if err != nil && err != driver.ErrSkip {
    99  		s.Close()
   100  		return nil, err
   101  	}
   102  	return rows, nil
   103  }
   104  */
   105  
   106  func (c *AdodbConn) Begin() (driver.Tx, error) {
   107  	return c.begin(context.Background())
   108  }
   109  
   110  func (c *AdodbConn) begin(ctx context.Context) (driver.Tx, error) {
   111  	rv, err := oleutil.CallMethod(c.db, "BeginTrans")
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	rv.Clear()
   116  	return &AdodbTx{c: c}, nil
   117  }
   118  
   119  func (d *AdodbDriver) Open(dsn string) (driver.Conn, error) {
   120  	ole.CoInitialize(0)
   121  
   122  	unknown, err := oleutil.CreateObject("ADODB.Connection")
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	db, err := unknown.QueryInterface(ole.IID_IDispatch)
   127  	unknown.Release()
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	rc, err := oleutil.CallMethod(db, "Open", dsn)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	rc.Clear()
   136  	return &AdodbConn{db: db}, nil
   137  }
   138  
   139  func (c *AdodbConn) Close() error {
   140  	rv, err := oleutil.CallMethod(c.db, "Close")
   141  	if err != nil {
   142  		return err
   143  	}
   144  	rv.Clear()
   145  	fullRelease(c.db)
   146  	c.db = nil
   147  	ole.CoUninitialize()
   148  	return nil
   149  }
   150  
   151  type AdodbStmt struct {
   152  	c  *AdodbConn
   153  	s  *ole.IDispatch
   154  	ps *ole.IDispatch
   155  	pc int
   156  }
   157  
   158  func (c *AdodbConn) Prepare(query string) (driver.Stmt, error) {
   159  	return c.prepare(context.Background(), query)
   160  }
   161  
   162  func (c *AdodbConn) prepare(ctx context.Context, query string) (driver.Stmt, error) {
   163  	unknown, err := oleutil.CreateObject("ADODB.Command")
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	s, err := unknown.QueryInterface(ole.IID_IDispatch)
   168  	unknown.Release()
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	rv, err := oleutil.PutProperty(s, "ActiveConnection", c.db)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	rv.Clear()
   177  	rv, err = oleutil.PutProperty(s, "CommandText", query)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	rv.Clear()
   182  	rv, err = oleutil.PutProperty(s, "CommandType", 1)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	rv.Clear()
   187  	rv, err = oleutil.PutProperty(s, "Prepared", true)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	rv.Clear()
   192  	val, err := oleutil.GetProperty(s, "Parameters")
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  	ps := val.ToIDispatch()
   197  	val.Clear()
   198  
   199  	rv, err = oleutil.CallMethod(ps, "Refresh")
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	rv.Clear()
   204  	return &AdodbStmt{c: c, s: s, ps: ps, pc: -1}, nil
   205  }
   206  
   207  func (s *AdodbStmt) Close() error {
   208  	fullRelease(s.ps)
   209  	s.ps = nil
   210  	fullRelease(s.s)
   211  	s.s = nil
   212  	s.c = nil
   213  	return nil
   214  }
   215  
   216  func (s *AdodbStmt) NumInput() int {
   217  	if s.pc != -1 {
   218  		return s.pc
   219  	}
   220  	rv, err := oleutil.GetProperty(s.ps, "Count")
   221  	if err != nil {
   222  		return -1
   223  	}
   224  	s.pc = int(rv.Val)
   225  	rv.Clear()
   226  	return s.pc
   227  }
   228  
   229  func (s *AdodbStmt) bind(args []namedValue) error {
   230  	for i, v := range args {
   231  		var err error
   232  		var val *ole.VARIANT
   233  		if v.Name != "" {
   234  			val, err = oleutil.CallMethod(s.ps, "Item", v.Name)
   235  		} else {
   236  			val, err = oleutil.CallMethod(s.ps, "Item", int32(i))
   237  		}
   238  		if err != nil {
   239  			return err
   240  		}
   241  		item := val.ToIDispatch()
   242  		val.Clear()
   243  		t, err := oleutil.GetProperty(item, "Type")
   244  		if err != nil {
   245  			item.Release()
   246  			return err
   247  		}
   248  		rv, err := oleutil.PutProperty(item, "Value", v.Value)
   249  		if err != nil {
   250  			t.Clear()
   251  			item.Release()
   252  			return err
   253  		}
   254  		rv.Clear()
   255  		t.Clear()
   256  		item.Release()
   257  	}
   258  	return nil
   259  }
   260  
   261  type namedValue struct {
   262  	Name    string
   263  	Ordinal int
   264  	Value   driver.Value
   265  }
   266  
   267  func (s *AdodbStmt) Query(args []driver.Value) (driver.Rows, error) {
   268  	list := make([]namedValue, len(args))
   269  	for i, v := range args {
   270  		list[i] = namedValue{
   271  			Ordinal: i + 1,
   272  			Value:   v,
   273  		}
   274  	}
   275  	return s.query(context.Background(), list)
   276  }
   277  
   278  func (s *AdodbStmt) query(ctx context.Context, args []namedValue) (driver.Rows, error) {
   279  	if err := s.bind(args); err != nil {
   280  		return nil, err
   281  	}
   282  	res, err := oleutil.CallMethod(s.s, "Execute")
   283  	if err != nil {
   284  		return nil, err
   285  	}
   286  	rc := res.ToIDispatch()
   287  	rc.AddRef()
   288  	res.Clear()
   289  	return &AdodbRows{s: s, rc: rc, nc: -1, cols: nil}, nil
   290  }
   291  
   292  func (s *AdodbStmt) Exec(args []driver.Value) (driver.Result, error) {
   293  	list := make([]namedValue, len(args))
   294  	for i, v := range args {
   295  		list[i] = namedValue{
   296  			Ordinal: i + 1,
   297  			Value:   v,
   298  		}
   299  	}
   300  	return s.exec(context.Background(), list)
   301  }
   302  
   303  type AdodbResult struct {
   304  	n int64
   305  }
   306  
   307  func (r *AdodbResult) LastInsertId() (int64, error) {
   308  	return 0, errors.New("LastInsertId not supported")
   309  }
   310  
   311  func (r *AdodbResult) RowsAffected() (int64, error) {
   312  	return r.n, nil
   313  }
   314  
   315  func (s *AdodbStmt) exec(ctx context.Context, args []namedValue) (driver.Result, error) {
   316  	if err := s.bind(args); err != nil {
   317  		return nil, err
   318  	}
   319  	var rowsAffected int64
   320  	rc, err := oleutil.CallMethod(s.s, "Execute", &rowsAffected)
   321  	if err != nil {
   322  		return nil, err
   323  	}
   324  	rc.Clear()
   325  
   326  	return &AdodbResult{n: rowsAffected}, nil
   327  }
   328  
   329  type AdodbRows struct {
   330  	s    *AdodbStmt
   331  	rc   *ole.IDispatch
   332  	nc   int
   333  	cols []string
   334  }
   335  
   336  func (rc *AdodbRows) Close() error {
   337  	rv, err := oleutil.CallMethod(rc.rc, "Close")
   338  	if err != nil {
   339  		return err
   340  	}
   341  	rv.Clear()
   342  	fullRelease(rc.rc)
   343  	rc.rc = nil
   344  	rc.s = nil
   345  	return nil
   346  }
   347  
   348  func (rc *AdodbRows) Columns() []string {
   349  	if rc.nc != len(rc.cols) {
   350  		unknown, err := oleutil.GetProperty(rc.rc, "Fields")
   351  		if err != nil {
   352  			return []string{}
   353  		}
   354  		fields := unknown.ToIDispatch()
   355  		unknown.Clear()
   356  		defer fields.Release()
   357  		rv, err := oleutil.GetProperty(fields, "Count")
   358  		if err != nil {
   359  			return []string{}
   360  		}
   361  		rc.nc = int(rv.Val)
   362  		rv.Clear()
   363  		rc.cols = make([]string, rc.nc)
   364  		for i := 0; i < rc.nc; i++ {
   365  			var varval ole.VARIANT
   366  			varval.VT = ole.VT_I4
   367  			varval.Val = int64(i)
   368  			val, err := oleutil.CallMethod(fields, "Item", &varval)
   369  			if err != nil {
   370  				return []string{}
   371  			}
   372  			item := val.ToIDispatch()
   373  			val.Clear()
   374  			name, err := oleutil.GetProperty(item, "Name")
   375  			if err != nil {
   376  				item.Release()
   377  				return []string{}
   378  			}
   379  			rc.cols[i] = name.ToString()
   380  			name.Clear()
   381  			item.Release()
   382  		}
   383  	}
   384  	return rc.cols
   385  }
   386  
   387  func (rc *AdodbRows) Next(dest []driver.Value) error {
   388  	eof, err := oleutil.GetProperty(rc.rc, "EOF")
   389  	if err != nil {
   390  		return io.EOF
   391  	}
   392  	if eof.Val != 0 {
   393  		eof.Clear()
   394  		return io.EOF
   395  	}
   396  	eof.Clear()
   397  
   398  	unknown, err := oleutil.GetProperty(rc.rc, "Fields")
   399  	if err != nil {
   400  		return err
   401  	}
   402  	fields := unknown.ToIDispatch()
   403  	unknown.Clear()
   404  	defer fields.Release()
   405  	for i := range dest {
   406  		var varval ole.VARIANT
   407  		varval.VT = ole.VT_I4
   408  		varval.Val = int64(i)
   409  		rv, err := oleutil.CallMethod(fields, "Item", &varval)
   410  		if err != nil {
   411  			return err
   412  		}
   413  		field := rv.ToIDispatch()
   414  		rv.Clear()
   415  		val, err := oleutil.GetProperty(field, "Value")
   416  		if err != nil {
   417  			field.Release()
   418  			return err
   419  		}
   420  		if val.VT == 1 { // VT_NULL
   421  			dest[i] = nil
   422  			val.Clear()
   423  			field.Release()
   424  			continue
   425  		}
   426  		typ, err := oleutil.GetProperty(field, "Type")
   427  		if err != nil {
   428  			val.Clear()
   429  			field.Release()
   430  			return err
   431  		}
   432  		sc, err := oleutil.GetProperty(field, "NumericScale")
   433  		if err != nil {
   434  			typ.Clear()
   435  			val.Clear()
   436  			field.Release()
   437  			return err
   438  		}
   439  		switch typ.Val {
   440  		case 0: // ADEMPTY
   441  			dest[i] = nil
   442  		case 2: // ADSMALLINT
   443  			dest[i] = int64(int16(val.Val))
   444  		case 3: // ADINTEGER
   445  			dest[i] = int64(int32(val.Val))
   446  		case 4: // ADSINGLE
   447  			dest[i] = float64(math.Float32frombits(uint32(val.Val)))
   448  		case 5: // ADDOUBLE
   449  			dest[i] = math.Float64frombits(uint64(val.Val))
   450  		case 6: // ADCURRENCY
   451  			dest[i] = float64(val.Val) / 10000
   452  		case 7: // ADDATE
   453  			// see http://blogs.msdn.com/b/ericlippert/archive/2003/09/16/eric-s-complete-guide-to-vt-date.aspx
   454  			d, t := math.Modf(math.Float64frombits(uint64(val.Val)))
   455  			t = math.Abs(t)
   456  			dest[i] = time.Date(1899, 12, 30+int(d), 0, 0, int(t*86400+0.5), 0, time.Local)
   457  		case 8: // ADBSTR
   458  			dest[i] = val.ToString()
   459  		case 9: // ADIDISPATCH
   460  			dest[i] = val.ToIDispatch()
   461  		case 10: // ADERROR
   462  			// TODO
   463  		case 11: // ADBOOLEAN
   464  			dest[i] = val.Val != 0
   465  		case 12: // ADVARIANT
   466  			dest[i] = val
   467  		case 13: // ADIUNKNOWN
   468  			dest[i] = val.ToIUnknown()
   469  		case 14: // ADDECIMAL
   470  			sub := math.Pow(10, float64(sc.Val))
   471  			dest[i] = float64(float64(val.Val) / sub)
   472  		case 16: // ADTINYINT
   473  			dest[i] = int8(val.Val)
   474  		case 17: // ADUNSIGNEDTINYINT
   475  			dest[i] = uint8(val.Val)
   476  		case 18: // ADUNSIGNEDSMALLINT
   477  			dest[i] = uint16(val.Val)
   478  		case 19: // ADUNSIGNEDINT
   479  			dest[i] = uint32(val.Val)
   480  		case 20: // ADBIGINT
   481  			//dest[i] = big.NewInt(val.Val)
   482  			dest[i] = int64(val.Val)
   483  		case 21: // ADUNSIGNEDBIGINT
   484  			dest[i] = uint64(val.Val)
   485  		case 72: // ADGUID
   486  			dest[i] = val.ToString()
   487  		case 128: // ADBINARY
   488  			sa := (*ole.SafeArray)(unsafe.Pointer(uintptr(val.Val)))
   489  			conv := &ole.SafeArrayConversion{sa}
   490  			elems, err := conv.TotalElements(0)
   491  			if err != nil {
   492  				return err
   493  			}
   494  			dest[i] = (*[1 << 30]byte)(unsafe.Pointer(uintptr(sa.Data)))[0:elems]
   495  		case 129: // ADCHAR
   496  			dest[i] = val.ToString() //uint8(val.Val)
   497  		case 130: // ADWCHAR
   498  			dest[i] = val.ToString() //uint16(val.Val)
   499  		case 131: // ADNUMERIC
   500  			sub := math.Pow(10, float64(sc.Val))
   501  			dest[i] = float64(float64(val.Val) / sub)
   502  		case 132: // ADUSERDEFINED
   503  			dest[i] = uintptr(val.Val)
   504  		case 133: // ADDBDATE
   505  			// see http://blogs.msdn.com/b/ericlippert/archive/2003/09/16/eric-s-complete-guide-to-vt-date.aspx
   506  			d := math.Float64frombits(uint64(val.Val))
   507  			dest[i] = time.Date(1899, 12, 30+int(d), 0, 0, 0, 0, time.Local)
   508  		case 134: // ADDBTIME
   509  			t := math.Float64frombits(uint64(val.Val))
   510  			dest[i] = time.Date(0, 1, 1, 0, 0, int(t*86400), 0, time.Local)
   511  		case 135: // ADDBTIMESTAMP
   512  			d, t := math.Modf(math.Float64frombits(uint64(val.Val)))
   513  			t = math.Abs(t)
   514  			dest[i] = time.Date(1899, 12, 30+int(d), 0, 0, int(t*86400+0.5), 0, time.Local)
   515  		case 136: // ADCHAPTER
   516  			dest[i] = val.ToString()
   517  		case 200: // ADVARCHAR
   518  			dest[i] = val.ToString()
   519  		case 201: // ADLONGVARCHAR
   520  			dest[i] = val.ToString()
   521  		case 202: // ADVARWCHAR
   522  			dest[i] = val.ToString()
   523  		case 203: // ADLONGVARWCHAR
   524  			dest[i] = val.ToString()
   525  		case 204: // ADVARBINARY
   526  			// TODO
   527  		case 205: // ADLONGVARBINARY
   528  			sa := (*ole.SafeArray)(unsafe.Pointer(uintptr(val.Val)))
   529  			conv := &ole.SafeArrayConversion{sa}
   530  			elems, err := conv.TotalElements(0)
   531  			if err != nil {
   532  				return err
   533  			}
   534  			dest[i] = (*[1 << 30]byte)(unsafe.Pointer(uintptr(sa.Data)))[0:elems]
   535  		}
   536  		if typ.Val != 12 {
   537  			val.Clear()
   538  		}
   539  		typ.Clear()
   540  		sc.Clear()
   541  		field.Release()
   542  	}
   543  	rv, err := oleutil.CallMethod(rc.rc, "MoveNext")
   544  	if err != nil {
   545  		return err
   546  	}
   547  	rv.Clear()
   548  	return nil
   549  }
   550  
   551  // ColumnTypeDatabaseTypeName implement RowsColumnTypeDatabaseTypeName.
   552  func (rc *AdodbRows) ColumnTypeDatabaseTypeName(i int) string {
   553  	if i >= rc.nc {
   554  		return ""
   555  	}
   556  	unknown, err := oleutil.GetProperty(rc.rc, "Fields")
   557  	if err != nil {
   558  		return ""
   559  	}
   560  	fields := unknown.ToIDispatch()
   561  	unknown.Clear()
   562  	defer fields.Release()
   563  
   564  	var varval ole.VARIANT
   565  	varval.VT = ole.VT_I4
   566  	varval.Val = int64(i)
   567  	val, err := oleutil.CallMethod(fields, "Item", &varval)
   568  	if err != nil {
   569  		return ""
   570  	}
   571  	item := val.ToIDispatch()
   572  	val.Clear()
   573  	typ, err := oleutil.GetProperty(item, "Type")
   574  	if err != nil {
   575  		item.Release()
   576  		return ""
   577  	}
   578  	typname := ""
   579  	switch typ.Val {
   580  	case 0:
   581  		typname = "ADEMPTY"
   582  	case 2:
   583  		typname = "ADSMALLINT"
   584  	case 3:
   585  		typname = "ADINTEGER"
   586  	case 4:
   587  		typname = "ADSINGLE"
   588  	case 5:
   589  		typname = "ADDOUBLE"
   590  	case 6:
   591  		typname = "ADCURRENCY"
   592  	case 7:
   593  		typname = "ADDATE"
   594  	case 8:
   595  		typname = "ADBSTR"
   596  	case 9:
   597  		typname = "ADIDISPATCH"
   598  	case 10:
   599  		typname = "ADERROR"
   600  	case 11:
   601  		typname = "ADBOOLEAN"
   602  	case 12:
   603  		typname = "ADVARIANT"
   604  	case 13:
   605  		typname = "ADIUNKNOWN"
   606  	case 14:
   607  		typname = "ADDECIMAL"
   608  	case 16:
   609  		typname = "ADTINYINT"
   610  	case 17:
   611  		typname = "ADUNSIGNEDTINYINT"
   612  	case 18:
   613  		typname = "ADUNSIGNEDSMALLINT"
   614  	case 19:
   615  		typname = "ADUNSIGNEDINT"
   616  	case 20:
   617  		typname = "ADBIGINT"
   618  	case 21:
   619  		typname = "ADUNSIGNEDBIGINT"
   620  	case 72:
   621  		typname = "ADGUID"
   622  	case 128:
   623  		typname = "ADBINARY"
   624  	case 129:
   625  		typname = "ADCHAR"
   626  	case 130:
   627  		typname = "ADWCHAR"
   628  	case 131:
   629  		typname = "ADNUMERIC"
   630  	case 132:
   631  		typname = "ADUSERDEFINED"
   632  	case 133:
   633  		typname = "ADDBDATE"
   634  	case 134:
   635  		typname = "ADDBTIME"
   636  	case 135:
   637  		typname = "ADDBTIMESTAMP"
   638  	case 136:
   639  		typname = "ADCHAPTER"
   640  	case 200:
   641  		typname = "ADVARCHAR"
   642  	case 201:
   643  		typname = "ADLONGVARCHAR"
   644  	case 202:
   645  		typname = "ADVARWCHAR"
   646  	case 203:
   647  		typname = "ADLONGVARWCHAR"
   648  	case 204:
   649  		typname = "ADVARBINARY"
   650  	case 205:
   651  		typname = "ADLONGVARBINARY"
   652  	}
   653  	typ.Clear()
   654  	item.Release()
   655  	return typname
   656  }
   657  
   658  func (rc *AdodbRows) ColumnTypeLength(i int) (length int64, ok bool) {
   659  	if i >= rc.nc {
   660  		return 0, false
   661  	}
   662  	unknown, err := oleutil.GetProperty(rc.rc, "Fields")
   663  	if err != nil {
   664  		return 0, false
   665  	}
   666  	fields := unknown.ToIDispatch()
   667  	unknown.Clear()
   668  	defer fields.Release()
   669  
   670  	var varval ole.VARIANT
   671  	varval.VT = ole.VT_I4
   672  	varval.Val = int64(i)
   673  	val, err := oleutil.CallMethod(fields, "Item", &varval)
   674  	if err != nil {
   675  		return 0, false
   676  	}
   677  	item := val.ToIDispatch()
   678  	val.Clear()
   679  	siz, err := oleutil.GetProperty(item, "DefinedSize")
   680  	if err != nil {
   681  		item.Release()
   682  		return 0, false
   683  	}
   684  	sizval := siz.Val
   685  	siz.Clear()
   686  	item.Release()
   687  	return int64(sizval), true
   688  }
   689  
   690  // ColumnTypeNullable implement RowsColumnTypeNullable.
   691  func (rc *AdodbRows) ColumnTypeNullable(i int) (nullable, ok bool) {
   692  	if i >= rc.nc {
   693  		return false, false
   694  	}
   695  	unknown, err := oleutil.GetProperty(rc.rc, "Fields")
   696  	if err != nil {
   697  		return false, false
   698  	}
   699  	fields := unknown.ToIDispatch()
   700  	unknown.Clear()
   701  	defer fields.Release()
   702  
   703  	var varval ole.VARIANT
   704  	varval.VT = ole.VT_I4
   705  	varval.Val = int64(i)
   706  	val, err := oleutil.CallMethod(fields, "Item", &varval)
   707  	if err != nil {
   708  		return false, false
   709  	}
   710  	item := val.ToIDispatch()
   711  	val.Clear()
   712  	att, err := oleutil.GetProperty(item, "Attributes")
   713  	if err != nil {
   714  		item.Release()
   715  		return false, false
   716  	}
   717  	attributes := att.Val
   718  	att.Clear()
   719  	item.Release()
   720  	return attributes&0x20 != 0, true
   721  }
   722  
   723  // ColumnTypeScanType implement RowsColumnTypeScanType.
   724  func (rc *AdodbRows) ColumnTypeScanType(i int) reflect.Type {
   725  	if i >= rc.nc {
   726  		return reflect.TypeOf(nil)
   727  	}
   728  	unknown, err := oleutil.GetProperty(rc.rc, "Fields")
   729  	if err != nil {
   730  		return reflect.TypeOf(nil)
   731  	}
   732  	fields := unknown.ToIDispatch()
   733  	unknown.Clear()
   734  	defer fields.Release()
   735  
   736  	var varval ole.VARIANT
   737  	varval.VT = ole.VT_I4
   738  	varval.Val = int64(i)
   739  	val, err := oleutil.CallMethod(fields, "Item", &varval)
   740  	if err != nil {
   741  		return reflect.TypeOf(nil)
   742  	}
   743  	item := val.ToIDispatch()
   744  	val.Clear()
   745  	typ, err := oleutil.GetProperty(item, "Type")
   746  	if err != nil {
   747  		item.Release()
   748  		return reflect.TypeOf(nil)
   749  	}
   750  	var rt reflect.Type
   751  	switch typ.Val {
   752  	case 0: // ADEMPTY
   753  		rt = reflect.TypeOf(nil)
   754  	case 2: // ADSMALLINT
   755  		rt = reflect.TypeOf(int16(0))
   756  	case 3: // ADINTEGER
   757  		rt = reflect.TypeOf(int32(0))
   758  	case 4: // ADSINGLE
   759  		rt = reflect.TypeOf(float32(0))
   760  	case 5: // ADDOUBLE
   761  		rt = reflect.TypeOf(float64(0))
   762  	case 6: // ADCURRENCY
   763  		rt = reflect.TypeOf(float64(0))
   764  	case 7: // ADDATE
   765  		rt = reflect.TypeOf(time.Time{})
   766  	case 8: // ADBSTR
   767  		rt = reflect.TypeOf("")
   768  	case 9: // ADIDISPATCH
   769  		rt = reflect.TypeOf((*ole.IDispatch)(nil))
   770  	case 10: // ADERROR
   771  		rt = reflect.TypeOf((error)(nil))
   772  	case 11: // ADBOOLEAN
   773  		rt = reflect.TypeOf(true)
   774  	case 12: // ADVARIANT
   775  		var va ole.VARIANT
   776  		rt = reflect.TypeOf(va)
   777  	case 13: // ADIUNKNOWN
   778  		rt = reflect.TypeOf((*ole.IUnknown)(nil))
   779  	case 14: // ADDECIMAL
   780  		rt = reflect.TypeOf(float64(0))
   781  	case 16: // ADTINYINT
   782  		rt = reflect.TypeOf(int8(0))
   783  	case 17: // ADUNSIGNEDTINYINT
   784  		rt = reflect.TypeOf(uint8(0))
   785  	case 18: // ADUNSIGNEDSMALLINT
   786  		rt = reflect.TypeOf(uint16(0))
   787  	case 19: // ADUNSIGNEDINT
   788  		rt = reflect.TypeOf(uint32(0))
   789  	case 20: // ADBIGINT
   790  		//rt = reflect.TypeOf((*big.Int)(nil))
   791  		rt = reflect.TypeOf((int64)(0))
   792  	case 21: // ADUNSIGNEDBIGINT
   793  		//rt = reflect.TypeOf(nil)
   794  		rt = reflect.TypeOf((uint64)(0))
   795  	case 72: // ADGUID
   796  		var gi ole.GUID
   797  		rt = reflect.TypeOf(gi)
   798  	case 128: // ADBINARY
   799  		rt = reflect.TypeOf((*ole.SafeArray)(nil))
   800  	case 129: // ADCHAR
   801  		rt = reflect.TypeOf(byte(0))
   802  	case 130: // ADWCHAR
   803  		rt = reflect.TypeOf(rune(0))
   804  	case 131: // ADNUMERIC
   805  		rt = reflect.TypeOf(float64(0))
   806  	case 132: // ADUSERDEFINED
   807  		rt = reflect.TypeOf(uintptr(0))
   808  	case 133: // ADDBDATE
   809  		rt = reflect.TypeOf(time.Time{})
   810  	case 134: // ADDBTIME
   811  		rt = reflect.TypeOf(time.Time{})
   812  	case 135: // ADDBTIMESTAMP
   813  		rt = reflect.TypeOf(time.Time{})
   814  	case 136: // ADCHAPTER
   815  		rt = reflect.TypeOf("")
   816  	case 200: // ADVARCHAR
   817  		rt = reflect.TypeOf("")
   818  	case 201: // ADLONGVARCHAR
   819  		rt = reflect.TypeOf("")
   820  	case 202: // ADVARWCHAR
   821  		rt = reflect.TypeOf("")
   822  	case 203: // ADLONGVARWCHAR
   823  		rt = reflect.TypeOf("")
   824  	case 204: // ADVARBINARY
   825  		rt = reflect.TypeOf([]byte{})
   826  	case 205: // ADLONGVARBINARY
   827  		rt = reflect.TypeOf((*ole.SafeArray)(nil))
   828  	}
   829  	typ.Clear()
   830  	item.Release()
   831  	return rt
   832  }
   833  
   834  func (rc *AdodbRows) ColumnTypePrecisionScale(i int) (precision, scale int64, ok bool) {
   835  	if i >= rc.nc {
   836  		return 0, 0, false
   837  	}
   838  	unknown, err := oleutil.GetProperty(rc.rc, "Fields")
   839  	if err != nil {
   840  		return 0, 0, false
   841  	}
   842  	fields := unknown.ToIDispatch()
   843  	unknown.Clear()
   844  	defer fields.Release()
   845  
   846  	var varval ole.VARIANT
   847  	varval.VT = ole.VT_I4
   848  	varval.Val = int64(i)
   849  	val, err := oleutil.CallMethod(fields, "Item", &varval)
   850  	if err != nil {
   851  		return 0, 0, false
   852  	}
   853  
   854  	item := val.ToIDispatch()
   855  	val.Clear()
   856  
   857  	typ, err := oleutil.GetProperty(item, "Type")
   858  	if err != nil {
   859  		item.Release()
   860  		return 0, 0, false
   861  	}
   862  	if typ.Val != 131 {
   863  		item.Release()
   864  		return 0, 0, true
   865  	}
   866  
   867  	prec, err := oleutil.GetProperty(item, "Precision")
   868  	if err != nil {
   869  		item.Release()
   870  		return 0, 0, false
   871  	}
   872  
   873  	scl, err := oleutil.GetProperty(item, "NumericScale")
   874  	if err != nil {
   875  		item.Release()
   876  		return 0, 0, false
   877  	}
   878  
   879  	precval := prec.Val
   880  	sclval := scl.Val
   881  	prec.Clear()
   882  	scl.Clear()
   883  	item.Release()
   884  	return int64(precval), int64(sclval), true
   885  }