gitee.com/chunanyong/dm@v1.8.12/m.go (about) 1 /* 2 * Copyright (c) 2000-2018, 达梦数据库有限公司. 3 * All rights reserved. 4 */ 5 package dm 6 7 import ( 8 "bytes" 9 "context" 10 "database/sql" 11 "database/sql/driver" 12 "fmt" 13 "sync" 14 "sync/atomic" 15 16 "gitee.com/chunanyong/dm/parser" 17 18 "gitee.com/chunanyong/dm/util" 19 "golang.org/x/text/encoding" 20 ) 21 22 type DmConnection struct { 23 filterable 24 mu sync.Mutex 25 26 dmConnector *DmConnector 27 Access *dm_build_1345 28 stmtMap map[int32]*DmStatement 29 30 lastExecInfo *execRetInfo 31 lexer *parser.Lexer 32 encode encoding.Encoding 33 encodeBuffer *bytes.Buffer 34 transformReaderDst []byte 35 transformReaderSrc []byte 36 37 serverEncoding string 38 GlobalServerSeries int 39 ServerVersion string 40 Malini2 bool 41 Execute2 bool 42 LobEmptyCompOrcl bool 43 IsoLevel int32 44 ReadOnly bool 45 NewLobFlag bool 46 sslEncrypt int 47 MaxRowSize int32 48 DDLAutoCommit bool 49 BackslashEscape bool 50 SvrStat int32 51 SvrMode int32 52 ConstParaOpt bool 53 DbTimezone int16 54 LifeTimeRemainder int16 55 InstanceName string 56 Schema string 57 LastLoginIP string 58 LastLoginTime string 59 FailedAttempts int32 60 LoginWarningID int32 61 GraceTimeRemainder int32 62 Guid string 63 DbName string 64 StandbyHost string 65 StandbyPort int32 66 StandbyCount int32 67 SessionID int64 68 OracleDateLanguage byte 69 FormatDate string 70 FormatTimestamp string 71 FormatTimestampTZ string 72 FormatTime string 73 FormatTimeTZ string 74 Local bool 75 MsgVersion int32 76 TrxStatus int32 77 dscControl bool 78 trxFinish bool 79 autoCommit bool 80 isBatch bool 81 82 watching bool 83 watcher chan<- context.Context 84 closech chan struct{} 85 finished chan<- struct{} 86 canceled atomicError 87 closed atomicBool 88 } 89 90 func (conn *DmConnection) setTrxFinish(status int32) { 91 switch status & Dm_build_132 { 92 case Dm_build_129, Dm_build_130, Dm_build_131: 93 conn.trxFinish = true 94 default: 95 conn.trxFinish = false 96 } 97 } 98 99 func (dmConn *DmConnection) init() { 100 101 dmConn.stmtMap = make(map[int32]*DmStatement) 102 dmConn.DbTimezone = 0 103 dmConn.GlobalServerSeries = 0 104 dmConn.MaxRowSize = 0 105 dmConn.LobEmptyCompOrcl = false 106 dmConn.ReadOnly = false 107 dmConn.DDLAutoCommit = false 108 dmConn.ConstParaOpt = false 109 dmConn.IsoLevel = -1 110 dmConn.Malini2 = true 111 dmConn.NewLobFlag = true 112 dmConn.Execute2 = true 113 dmConn.serverEncoding = ENCODING_GB18030 114 dmConn.TrxStatus = Dm_build_80 115 dmConn.setTrxFinish(dmConn.TrxStatus) 116 dmConn.OracleDateLanguage = byte(Locale) 117 dmConn.lastExecInfo = NewExceInfo() 118 dmConn.MsgVersion = Dm_build_13 119 120 dmConn.idGenerator = dmConnIDGenerator 121 } 122 123 func (dmConn *DmConnection) reset() { 124 dmConn.DbTimezone = 0 125 dmConn.GlobalServerSeries = 0 126 dmConn.MaxRowSize = 0 127 dmConn.LobEmptyCompOrcl = false 128 dmConn.ReadOnly = false 129 dmConn.DDLAutoCommit = false 130 dmConn.ConstParaOpt = false 131 dmConn.IsoLevel = -1 132 dmConn.Malini2 = true 133 dmConn.NewLobFlag = true 134 dmConn.Execute2 = true 135 dmConn.serverEncoding = ENCODING_GB18030 136 dmConn.TrxStatus = Dm_build_80 137 dmConn.setTrxFinish(dmConn.TrxStatus) 138 } 139 140 func (dc *DmConnection) checkClosed() error { 141 if dc.closed.IsSet() { 142 return driver.ErrBadConn 143 } 144 145 return nil 146 } 147 148 func (dc *DmConnection) executeInner(query string, execType int16) (interface{}, error) { 149 150 stmt, err := NewDmStmt(dc, query) 151 152 if err != nil { 153 return nil, err 154 } 155 156 if execType == Dm_build_97 { 157 defer stmt.close() 158 } 159 160 stmt.innerUsed = true 161 if stmt.dmConn.dmConnector.escapeProcess { 162 stmt.nativeSql, err = stmt.dmConn.escape(stmt.nativeSql, stmt.dmConn.dmConnector.keyWords) 163 if err != nil { 164 stmt.close() 165 return nil, err 166 } 167 } 168 169 var optParamList []OptParameter 170 171 if stmt.dmConn.ConstParaOpt { 172 optParamList = make([]OptParameter, 0) 173 stmt.nativeSql, optParamList, err = stmt.dmConn.execOpt(stmt.nativeSql, optParamList, stmt.dmConn.getServerEncoding()) 174 if err != nil { 175 stmt.close() 176 optParamList = nil 177 } 178 } 179 180 if execType == Dm_build_96 && dc.dmConnector.enRsCache { 181 rpv, err := rp.get(stmt, query) 182 if err != nil { 183 return nil, err 184 } 185 186 if rpv != nil { 187 stmt.execInfo = rpv.execInfo 188 dc.lastExecInfo = rpv.execInfo 189 return newDmRows(rpv.getResultSet(stmt)), nil 190 } 191 } 192 193 var info *execRetInfo 194 195 if optParamList != nil && len(optParamList) > 0 { 196 info, err = dc.Access.Dm_build_1425(stmt, optParamList) 197 if err != nil { 198 stmt.nativeSql = query 199 info, err = dc.Access.Dm_build_1431(stmt, execType) 200 } 201 } else { 202 info, err = dc.Access.Dm_build_1431(stmt, execType) 203 } 204 205 if err != nil { 206 stmt.close() 207 return nil, err 208 } 209 dc.lastExecInfo = info 210 211 if execType == Dm_build_96 && info.hasResultSet { 212 return newDmRows(newInnerRows(0, stmt, info)), nil 213 } else { 214 return newDmResult(stmt, info), nil 215 } 216 } 217 218 func g2dbIsoLevel(isoLevel int32) int32 { 219 switch isoLevel { 220 case 1: 221 return Dm_build_84 222 case 2: 223 return Dm_build_85 224 case 4: 225 return Dm_build_86 226 case 6: 227 return Dm_build_87 228 default: 229 return -1 230 } 231 } 232 233 func (dc *DmConnection) Begin() (driver.Tx, error) { 234 if len(dc.filterChain.filters) == 0 { 235 return dc.begin() 236 } else { 237 return dc.filterChain.reset().DmConnectionBegin(dc) 238 } 239 } 240 241 func (dc *DmConnection) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { 242 if len(dc.filterChain.filters) == 0 { 243 return dc.beginTx(ctx, opts) 244 } 245 return dc.filterChain.reset().DmConnectionBeginTx(dc, ctx, opts) 246 } 247 248 func (dc *DmConnection) Commit() error { 249 if len(dc.filterChain.filters) == 0 { 250 return dc.commit() 251 } else { 252 return dc.filterChain.reset().DmConnectionCommit(dc) 253 } 254 } 255 256 func (dc *DmConnection) Rollback() error { 257 if len(dc.filterChain.filters) == 0 { 258 return dc.rollback() 259 } else { 260 return dc.filterChain.reset().DmConnectionRollback(dc) 261 } 262 } 263 264 func (dc *DmConnection) Close() error { 265 if len(dc.filterChain.filters) == 0 { 266 return dc.close() 267 } else { 268 return dc.filterChain.reset().DmConnectionClose(dc) 269 } 270 } 271 272 func (dc *DmConnection) Ping(ctx context.Context) error { 273 if len(dc.filterChain.filters) == 0 { 274 return dc.ping(ctx) 275 } else { 276 return dc.filterChain.reset().DmConnectionPing(dc, ctx) 277 } 278 } 279 280 func (dc *DmConnection) Exec(query string, args []driver.Value) (driver.Result, error) { 281 if len(dc.filterChain.filters) == 0 { 282 return dc.exec(query, args) 283 } 284 return dc.filterChain.reset().DmConnectionExec(dc, query, args) 285 } 286 287 func (dc *DmConnection) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { 288 if len(dc.filterChain.filters) == 0 { 289 return dc.execContext(ctx, query, args) 290 } 291 return dc.filterChain.reset().DmConnectionExecContext(dc, ctx, query, args) 292 } 293 294 func (dc *DmConnection) Query(query string, args []driver.Value) (driver.Rows, error) { 295 if len(dc.filterChain.filters) == 0 { 296 return dc.query(query, args) 297 } 298 return dc.filterChain.reset().DmConnectionQuery(dc, query, args) 299 } 300 301 func (dc *DmConnection) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { 302 if len(dc.filterChain.filters) == 0 { 303 return dc.queryContext(ctx, query, args) 304 } 305 return dc.filterChain.reset().DmConnectionQueryContext(dc, ctx, query, args) 306 } 307 308 func (dc *DmConnection) Prepare(query string) (driver.Stmt, error) { 309 if len(dc.filterChain.filters) == 0 { 310 return dc.prepare(query) 311 } 312 return dc.filterChain.reset().DmConnectionPrepare(dc, query) 313 } 314 315 func (dc *DmConnection) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { 316 if len(dc.filterChain.filters) == 0 { 317 return dc.prepareContext(ctx, query) 318 } 319 return dc.filterChain.reset().DmConnectionPrepareContext(dc, ctx, query) 320 } 321 322 func (dc *DmConnection) ResetSession(ctx context.Context) error { 323 if len(dc.filterChain.filters) == 0 { 324 return dc.resetSession(ctx) 325 } 326 if err := dc.filterChain.reset().DmConnectionResetSession(dc, ctx); err != nil { 327 return driver.ErrBadConn 328 } else { 329 return nil 330 } 331 } 332 333 func (dc *DmConnection) CheckNamedValue(nv *driver.NamedValue) error { 334 if len(dc.filterChain.filters) == 0 { 335 return dc.checkNamedValue(nv) 336 } 337 return dc.filterChain.reset().DmConnectionCheckNamedValue(dc, nv) 338 } 339 340 func (dc *DmConnection) begin() (*DmConnection, error) { 341 return dc.beginTx(context.Background(), driver.TxOptions{driver.IsolationLevel(sql.LevelDefault), false}) 342 } 343 344 func (dc *DmConnection) beginTx(ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { 345 if err := dc.watchCancel(ctx); err != nil { 346 return nil, err 347 } 348 defer dc.finish() 349 350 err := dc.checkClosed() 351 if err != nil { 352 return nil, err 353 } 354 355 dc.autoCommit = false 356 357 if sql.IsolationLevel(opts.Isolation) == sql.LevelDefault { 358 opts.Isolation = driver.IsolationLevel(sql.LevelReadCommitted) 359 } 360 361 if dc.ReadOnly != opts.ReadOnly { 362 dc.ReadOnly = opts.ReadOnly 363 var readonly = 0 364 if opts.ReadOnly { 365 readonly = 1 366 } 367 dc.exec(fmt.Sprintf("SP_SET_SESSION_READONLY(%d)", readonly), nil) 368 } 369 370 if dc.IsoLevel != int32(opts.Isolation) { 371 switch sql.IsolationLevel(opts.Isolation) { 372 case sql.LevelDefault, sql.LevelReadUncommitted: 373 return dc, nil 374 case sql.LevelReadCommitted, sql.LevelSerializable: 375 dc.IsoLevel = int32(opts.Isolation) 376 case sql.LevelRepeatableRead: 377 if dc.CompatibleMysql() { 378 dc.IsoLevel = int32(sql.LevelReadCommitted) 379 } else { 380 return nil, ECGO_INVALID_TRAN_ISOLATION.throw() 381 } 382 default: 383 return nil, ECGO_INVALID_TRAN_ISOLATION.throw() 384 } 385 386 err = dc.Access.Dm_build_1485(dc) 387 if err != nil { 388 return nil, err 389 } 390 } 391 392 return dc, nil 393 } 394 395 func (dc *DmConnection) commit() error { 396 err := dc.checkClosed() 397 if err != nil { 398 return err 399 } 400 401 defer func() { 402 dc.autoCommit = dc.dmConnector.autoCommit 403 if dc.ReadOnly { 404 dc.exec("SP_SET_SESSION_READONLY(0)", nil) 405 } 406 }() 407 408 if !dc.autoCommit { 409 err = dc.Access.Commit() 410 if err != nil { 411 return err 412 } 413 dc.trxFinish = true 414 return nil 415 } else if !dc.dmConnector.alwayseAllowCommit { 416 return ECGO_COMMIT_IN_AUTOCOMMIT_MODE.throw() 417 } 418 419 return nil 420 } 421 422 func (dc *DmConnection) rollback() error { 423 err := dc.checkClosed() 424 if err != nil { 425 return err 426 } 427 428 defer func() { 429 dc.autoCommit = dc.dmConnector.autoCommit 430 if dc.ReadOnly { 431 dc.exec("SP_SET_SESSION_READONLY(0)", nil) 432 } 433 }() 434 435 if !dc.autoCommit { 436 err = dc.Access.Rollback() 437 if err != nil { 438 return err 439 } 440 dc.trxFinish = true 441 return nil 442 } else if !dc.dmConnector.alwayseAllowCommit { 443 return ECGO_ROLLBACK_IN_AUTOCOMMIT_MODE.throw() 444 } 445 446 return nil 447 } 448 449 func (dc *DmConnection) reconnect() error { 450 err := dc.Access.Close() 451 if err != nil { 452 return err 453 } 454 455 for _, stmt := range dc.stmtMap { 456 457 for id, rs := range stmt.rsMap { 458 rs.Close() 459 delete(stmt.rsMap, id) 460 } 461 } 462 463 var newConn *DmConnection 464 if dc.dmConnector.group != nil { 465 if newConn, err = dc.dmConnector.group.connect(dc.dmConnector); err != nil { 466 return err 467 } 468 } else { 469 newConn, err = dc.dmConnector.connect(context.Background()) 470 } 471 472 oldMap := dc.stmtMap 473 newConn.mu = dc.mu 474 newConn.filterable = dc.filterable 475 *dc = *newConn 476 477 for _, stmt := range oldMap { 478 if stmt.closed { 479 continue 480 } 481 err = dc.Access.Dm_build_1403(stmt) 482 if err != nil { 483 stmt.free() 484 continue 485 } 486 487 if stmt.prepared || stmt.paramCount > 0 { 488 if err = stmt.prepare(); err != nil { 489 continue 490 } 491 } 492 493 dc.stmtMap[stmt.id] = stmt 494 } 495 496 return nil 497 } 498 499 func (dc *DmConnection) cleanup() { 500 dc.close() 501 } 502 503 func (dc *DmConnection) close() error { 504 if !dc.closed.TrySet(true) { 505 return nil 506 } 507 508 util.AbsorbPanic(func() { 509 close(dc.closech) 510 }) 511 if dc.Access == nil { 512 return nil 513 } 514 515 dc.rollback() 516 517 for _, stmt := range dc.stmtMap { 518 stmt.free() 519 } 520 521 dc.Access.Close() 522 523 return nil 524 } 525 526 func (dc *DmConnection) ping(ctx context.Context) error { 527 if err := dc.watchCancel(ctx); err != nil { 528 return err 529 } 530 defer dc.finish() 531 532 rows, err := dc.query("select 1", nil) 533 if err != nil { 534 return err 535 } 536 return rows.close() 537 } 538 539 func (dc *DmConnection) exec(query string, args []driver.Value) (*DmResult, error) { 540 err := dc.checkClosed() 541 if err != nil { 542 return nil, err 543 } 544 545 if args != nil && len(args) > 0 { 546 stmt, err := dc.prepare(query) 547 defer stmt.close() 548 if err != nil { 549 return nil, err 550 } 551 dc.lastExecInfo = stmt.execInfo 552 553 return stmt.exec(args) 554 } else { 555 r1, err := dc.executeInner(query, Dm_build_97) 556 if err != nil { 557 return nil, err 558 } 559 560 if r2, ok := r1.(*DmResult); ok { 561 return r2, nil 562 } else { 563 return nil, ECGO_NOT_EXEC_SQL.throw() 564 } 565 } 566 } 567 568 func (dc *DmConnection) execContext(ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { 569 if err := dc.watchCancel(ctx); err != nil { 570 return nil, err 571 } 572 defer dc.finish() 573 574 err := dc.checkClosed() 575 if err != nil { 576 return nil, err 577 } 578 579 if args != nil && len(args) > 0 { 580 stmt, err := dc.prepare(query) 581 defer stmt.close() 582 if err != nil { 583 return nil, err 584 } 585 dc.lastExecInfo = stmt.execInfo 586 dargs, err := namedValueToValue(stmt, args) 587 if err != nil { 588 return nil, err 589 } 590 return stmt.exec(dargs) 591 } else { 592 r1, err := dc.executeInner(query, Dm_build_97) 593 if err != nil { 594 return nil, err 595 } 596 597 if r2, ok := r1.(*DmResult); ok { 598 return r2, nil 599 } else { 600 return nil, ECGO_NOT_EXEC_SQL.throw() 601 } 602 } 603 } 604 605 func (dc *DmConnection) query(query string, args []driver.Value) (*DmRows, error) { 606 607 err := dc.checkClosed() 608 if err != nil { 609 return nil, err 610 } 611 612 if args != nil && len(args) > 0 { 613 stmt, err := dc.prepare(query) 614 if err != nil { 615 stmt.close() 616 return nil, err 617 } 618 dc.lastExecInfo = stmt.execInfo 619 620 stmt.innerUsed = true 621 return stmt.query(args) 622 623 } else { 624 r1, err := dc.executeInner(query, Dm_build_96) 625 if err != nil { 626 return nil, err 627 } 628 629 if r2, ok := r1.(*DmRows); ok { 630 return r2, nil 631 } else { 632 return nil, ECGO_NOT_QUERY_SQL.throw() 633 } 634 } 635 } 636 637 func (dc *DmConnection) queryContext(ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { 638 if err := dc.watchCancel(ctx); err != nil { 639 return nil, err 640 } 641 defer dc.finish() 642 643 err := dc.checkClosed() 644 if err != nil { 645 return nil, err 646 } 647 648 if args != nil && len(args) > 0 { 649 stmt, err := dc.prepare(query) 650 if err != nil { 651 if stmt != nil { 652 stmt.close() 653 } 654 return nil, err 655 } 656 dc.lastExecInfo = stmt.execInfo 657 658 stmt.innerUsed = true 659 dargs, err := namedValueToValue(stmt, args) 660 if err != nil { 661 return nil, err 662 } 663 return stmt.query(dargs) 664 665 } else { 666 r1, err := dc.executeInner(query, Dm_build_96) 667 if err != nil { 668 return nil, err 669 } 670 671 if r2, ok := r1.(*DmRows); ok { 672 return r2, nil 673 } else { 674 return nil, ECGO_NOT_QUERY_SQL.throw() 675 } 676 } 677 678 } 679 680 func (dc *DmConnection) prepare(query string) (stmt *DmStatement, err error) { 681 if err = dc.checkClosed(); err != nil { 682 return 683 } 684 if stmt, err = NewDmStmt(dc, query); err != nil { 685 return 686 } 687 err = stmt.prepare() 688 return 689 } 690 691 func (dc *DmConnection) prepareContext(ctx context.Context, query string) (*DmStatement, error) { 692 if err := dc.watchCancel(ctx); err != nil { 693 return nil, err 694 } 695 defer dc.finish() 696 697 return dc.prepare(query) 698 } 699 700 func (dc *DmConnection) resetSession(ctx context.Context) error { 701 if err := dc.watchCancel(ctx); err != nil { 702 return err 703 } 704 defer dc.finish() 705 706 err := dc.checkClosed() 707 if err != nil { 708 return err 709 } 710 711 return nil 712 } 713 714 func (dc *DmConnection) checkNamedValue(nv *driver.NamedValue) error { 715 var err error 716 var cvt = converter{dc, false} 717 nv.Value, err = cvt.ConvertValue(nv.Value) 718 dc.isBatch = cvt.isBatch 719 return err 720 } 721 722 func (dc *DmConnection) driverQuery(query string) (*DmStatement, *DmRows, error) { 723 stmt, err := NewDmStmt(dc, query) 724 if err != nil { 725 return nil, nil, err 726 } 727 stmt.innerUsed = true 728 stmt.innerExec = true 729 info, err := dc.Access.Dm_build_1431(stmt, Dm_build_96) 730 if err != nil { 731 return nil, nil, err 732 } 733 dc.lastExecInfo = info 734 stmt.innerExec = false 735 return stmt, newDmRows(newInnerRows(0, stmt, info)), nil 736 } 737 738 func (dc *DmConnection) getIndexOnEPGroup() int32 { 739 if dc.dmConnector.group == nil || dc.dmConnector.group.epList == nil { 740 return -1 741 } 742 for i := 0; i < len(dc.dmConnector.group.epList); i++ { 743 ep := dc.dmConnector.group.epList[i] 744 if dc.dmConnector.host == ep.host && dc.dmConnector.port == ep.port { 745 return int32(i) 746 } 747 } 748 return -1 749 } 750 751 func (dc *DmConnection) getServerEncoding() string { 752 if dc.dmConnector.charCode != "" { 753 return dc.dmConnector.charCode 754 } 755 return dc.serverEncoding 756 } 757 758 func (dc *DmConnection) lobFetchAll() bool { 759 return dc.dmConnector.lobMode == 2 760 } 761 762 func (conn *DmConnection) CompatibleOracle() bool { 763 return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_ORACLE 764 } 765 766 func (conn *DmConnection) CompatibleMysql() bool { 767 return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_MYSQL 768 } 769 770 func (conn *DmConnection) cancel(err error) { 771 conn.canceled.Set(err) 772 conn.close() 773 774 } 775 776 func (conn *DmConnection) finish() { 777 if !conn.watching || conn.finished == nil { 778 return 779 } 780 select { 781 case conn.finished <- struct{}{}: 782 conn.watching = false 783 case <-conn.closech: 784 } 785 } 786 787 func (conn *DmConnection) startWatcher() { 788 watcher := make(chan context.Context, 1) 789 conn.watcher = watcher 790 finished := make(chan struct{}) 791 conn.finished = finished 792 go func() { 793 for { 794 var ctx context.Context 795 select { 796 case ctx = <-watcher: 797 case <-conn.closech: 798 return 799 } 800 801 select { 802 case <-ctx.Done(): 803 conn.cancel(ctx.Err()) 804 case <-finished: 805 case <-conn.closech: 806 return 807 } 808 } 809 }() 810 } 811 812 func (conn *DmConnection) watchCancel(ctx context.Context) error { 813 if conn.watching { 814 815 conn.cleanup() 816 return nil 817 } 818 819 if err := ctx.Err(); err != nil { 820 return err 821 } 822 823 if ctx.Done() == nil { 824 return nil 825 } 826 827 if conn.watcher == nil { 828 return nil 829 } 830 831 conn.watching = true 832 conn.watcher <- ctx 833 return nil 834 } 835 836 type noCopy struct{} 837 838 func (*noCopy) Lock() {} 839 840 type atomicBool struct { 841 _noCopy noCopy 842 value uint32 843 } 844 845 func (ab *atomicBool) IsSet() bool { 846 return atomic.LoadUint32(&ab.value) > 0 847 } 848 849 func (ab *atomicBool) Set(value bool) { 850 if value { 851 atomic.StoreUint32(&ab.value, 1) 852 } else { 853 atomic.StoreUint32(&ab.value, 0) 854 } 855 } 856 857 func (ab *atomicBool) TrySet(value bool) bool { 858 if value { 859 return atomic.SwapUint32(&ab.value, 1) == 0 860 } 861 return atomic.SwapUint32(&ab.value, 0) > 0 862 } 863 864 type atomicError struct { 865 _noCopy noCopy 866 value atomic.Value 867 } 868 869 func (ae *atomicError) Set(value error) { 870 ae.value.Store(value) 871 } 872 873 func (ae *atomicError) Value() error { 874 if v := ae.value.Load(); v != nil { 875 876 return v.(error) 877 } 878 return nil 879 }