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 }