本站源代码
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

958 lignes
23KB

  1. package mssql
  2. import (
  3. "context"
  4. "database/sql"
  5. "database/sql/driver"
  6. "encoding/binary"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "math"
  11. "net"
  12. "reflect"
  13. "strings"
  14. "time"
  15. "unicode"
  16. "github.com/denisenkom/go-mssqldb/internal/querytext"
  17. )
  18. // ReturnStatus may be used to return the return value from a proc.
  19. //
  20. // var rs mssql.ReturnStatus
  21. // _, err := db.Exec("theproc", &rs)
  22. // log.Printf("return status = %d", rs)
  23. type ReturnStatus int32
  24. var driverInstance = &Driver{processQueryText: true}
  25. var driverInstanceNoProcess = &Driver{processQueryText: false}
  26. func init() {
  27. sql.Register("mssql", driverInstance)
  28. sql.Register("sqlserver", driverInstanceNoProcess)
  29. createDialer = func(p *connectParams) Dialer {
  30. return netDialer{&net.Dialer{KeepAlive: p.keepAlive}}
  31. }
  32. }
  33. var createDialer func(p *connectParams) Dialer
  34. type netDialer struct {
  35. nd *net.Dialer
  36. }
  37. func (d netDialer) DialContext(ctx context.Context, network string, addr string) (net.Conn, error) {
  38. return d.nd.DialContext(ctx, network, addr)
  39. }
  40. type Driver struct {
  41. log optionalLogger
  42. processQueryText bool
  43. }
  44. // OpenConnector opens a new connector. Useful to dial with a context.
  45. func (d *Driver) OpenConnector(dsn string) (*Connector, error) {
  46. params, err := parseConnectParams(dsn)
  47. if err != nil {
  48. return nil, err
  49. }
  50. return &Connector{
  51. params: params,
  52. driver: d,
  53. }, nil
  54. }
  55. func (d *Driver) Open(dsn string) (driver.Conn, error) {
  56. return d.open(context.Background(), dsn)
  57. }
  58. func SetLogger(logger Logger) {
  59. driverInstance.SetLogger(logger)
  60. driverInstanceNoProcess.SetLogger(logger)
  61. }
  62. func (d *Driver) SetLogger(logger Logger) {
  63. d.log = optionalLogger{logger}
  64. }
  65. // NewConnector creates a new connector from a DSN.
  66. // The returned connector may be used with sql.OpenDB.
  67. func NewConnector(dsn string) (*Connector, error) {
  68. params, err := parseConnectParams(dsn)
  69. if err != nil {
  70. return nil, err
  71. }
  72. c := &Connector{
  73. params: params,
  74. driver: driverInstanceNoProcess,
  75. }
  76. return c, nil
  77. }
  78. // Connector holds the parsed DSN and is ready to make a new connection
  79. // at any time.
  80. //
  81. // In the future, settings that cannot be passed through a string DSN
  82. // may be set directly on the connector.
  83. type Connector struct {
  84. params connectParams
  85. driver *Driver
  86. // SessionInitSQL is executed after marking a given session to be reset.
  87. // When not present, the next query will still reset the session to the
  88. // database defaults.
  89. //
  90. // When present the connection will immediately mark the session to
  91. // be reset, then execute the SessionInitSQL text to setup the session
  92. // that may be different from the base database defaults.
  93. //
  94. // For Example, the application relies on the following defaults
  95. // but is not allowed to set them at the database system level.
  96. //
  97. // SET XACT_ABORT ON;
  98. // SET TEXTSIZE -1;
  99. // SET ANSI_NULLS ON;
  100. // SET LOCK_TIMEOUT 10000;
  101. //
  102. // SessionInitSQL should not attempt to manually call sp_reset_connection.
  103. // This will happen at the TDS layer.
  104. //
  105. // SessionInitSQL is optional. The session will be reset even if
  106. // SessionInitSQL is empty.
  107. SessionInitSQL string
  108. // Dialer sets a custom dialer for all network operations.
  109. // If Dialer is not set, normal net dialers are used.
  110. Dialer Dialer
  111. }
  112. type Dialer interface {
  113. DialContext(ctx context.Context, network string, addr string) (net.Conn, error)
  114. }
  115. func (c *Connector) getDialer(p *connectParams) Dialer {
  116. if c != nil && c.Dialer != nil {
  117. return c.Dialer
  118. }
  119. return createDialer(p)
  120. }
  121. type Conn struct {
  122. connector *Connector
  123. sess *tdsSession
  124. transactionCtx context.Context
  125. resetSession bool
  126. processQueryText bool
  127. connectionGood bool
  128. outs map[string]interface{}
  129. returnStatus *ReturnStatus
  130. }
  131. func (c *Conn) setReturnStatus(s ReturnStatus) {
  132. if c.returnStatus == nil {
  133. return
  134. }
  135. *c.returnStatus = s
  136. }
  137. func (c *Conn) checkBadConn(err error) error {
  138. // this is a hack to address Issue #275
  139. // we set connectionGood flag to false if
  140. // error indicates that connection is not usable
  141. // but we return actual error instead of ErrBadConn
  142. // this will cause connection to stay in a pool
  143. // but next request to this connection will return ErrBadConn
  144. // it might be possible to revise this hack after
  145. // https://github.com/golang/go/issues/20807
  146. // is implemented
  147. switch err {
  148. case nil:
  149. return nil
  150. case io.EOF:
  151. c.connectionGood = false
  152. return driver.ErrBadConn
  153. case driver.ErrBadConn:
  154. // It is an internal programming error if driver.ErrBadConn
  155. // is ever passed to this function. driver.ErrBadConn should
  156. // only ever be returned in response to a *mssql.Conn.connectionGood == false
  157. // check in the external facing API.
  158. panic("driver.ErrBadConn in checkBadConn. This should not happen.")
  159. }
  160. switch err.(type) {
  161. case net.Error:
  162. c.connectionGood = false
  163. return err
  164. case StreamError:
  165. c.connectionGood = false
  166. return err
  167. default:
  168. return err
  169. }
  170. }
  171. func (c *Conn) clearOuts() {
  172. c.outs = nil
  173. }
  174. func (c *Conn) simpleProcessResp(ctx context.Context) error {
  175. tokchan := make(chan tokenStruct, 5)
  176. go processResponse(ctx, c.sess, tokchan, c.outs)
  177. c.clearOuts()
  178. for tok := range tokchan {
  179. switch token := tok.(type) {
  180. case doneStruct:
  181. if token.isError() {
  182. return c.checkBadConn(token.getError())
  183. }
  184. case error:
  185. return c.checkBadConn(token)
  186. }
  187. }
  188. return nil
  189. }
  190. func (c *Conn) Commit() error {
  191. if !c.connectionGood {
  192. return driver.ErrBadConn
  193. }
  194. if err := c.sendCommitRequest(); err != nil {
  195. return c.checkBadConn(err)
  196. }
  197. return c.simpleProcessResp(c.transactionCtx)
  198. }
  199. func (c *Conn) sendCommitRequest() error {
  200. headers := []headerStruct{
  201. {hdrtype: dataStmHdrTransDescr,
  202. data: transDescrHdr{c.sess.tranid, 1}.pack()},
  203. }
  204. reset := c.resetSession
  205. c.resetSession = false
  206. if err := sendCommitXact(c.sess.buf, headers, "", 0, 0, "", reset); err != nil {
  207. if c.sess.logFlags&logErrors != 0 {
  208. c.sess.log.Printf("Failed to send CommitXact with %v", err)
  209. }
  210. c.connectionGood = false
  211. return fmt.Errorf("Faild to send CommitXact: %v", err)
  212. }
  213. return nil
  214. }
  215. func (c *Conn) Rollback() error {
  216. if !c.connectionGood {
  217. return driver.ErrBadConn
  218. }
  219. if err := c.sendRollbackRequest(); err != nil {
  220. return c.checkBadConn(err)
  221. }
  222. return c.simpleProcessResp(c.transactionCtx)
  223. }
  224. func (c *Conn) sendRollbackRequest() error {
  225. headers := []headerStruct{
  226. {hdrtype: dataStmHdrTransDescr,
  227. data: transDescrHdr{c.sess.tranid, 1}.pack()},
  228. }
  229. reset := c.resetSession
  230. c.resetSession = false
  231. if err := sendRollbackXact(c.sess.buf, headers, "", 0, 0, "", reset); err != nil {
  232. if c.sess.logFlags&logErrors != 0 {
  233. c.sess.log.Printf("Failed to send RollbackXact with %v", err)
  234. }
  235. c.connectionGood = false
  236. return fmt.Errorf("Failed to send RollbackXact: %v", err)
  237. }
  238. return nil
  239. }
  240. func (c *Conn) Begin() (driver.Tx, error) {
  241. return c.begin(context.Background(), isolationUseCurrent)
  242. }
  243. func (c *Conn) begin(ctx context.Context, tdsIsolation isoLevel) (tx driver.Tx, err error) {
  244. if !c.connectionGood {
  245. return nil, driver.ErrBadConn
  246. }
  247. err = c.sendBeginRequest(ctx, tdsIsolation)
  248. if err != nil {
  249. return nil, c.checkBadConn(err)
  250. }
  251. tx, err = c.processBeginResponse(ctx)
  252. if err != nil {
  253. return nil, c.checkBadConn(err)
  254. }
  255. return
  256. }
  257. func (c *Conn) sendBeginRequest(ctx context.Context, tdsIsolation isoLevel) error {
  258. c.transactionCtx = ctx
  259. headers := []headerStruct{
  260. {hdrtype: dataStmHdrTransDescr,
  261. data: transDescrHdr{0, 1}.pack()},
  262. }
  263. reset := c.resetSession
  264. c.resetSession = false
  265. if err := sendBeginXact(c.sess.buf, headers, tdsIsolation, "", reset); err != nil {
  266. if c.sess.logFlags&logErrors != 0 {
  267. c.sess.log.Printf("Failed to send BeginXact with %v", err)
  268. }
  269. c.connectionGood = false
  270. return fmt.Errorf("Failed to send BeginXact: %v", err)
  271. }
  272. return nil
  273. }
  274. func (c *Conn) processBeginResponse(ctx context.Context) (driver.Tx, error) {
  275. if err := c.simpleProcessResp(ctx); err != nil {
  276. return nil, err
  277. }
  278. // successful BEGINXACT request will return sess.tranid
  279. // for started transaction
  280. return c, nil
  281. }
  282. func (d *Driver) open(ctx context.Context, dsn string) (*Conn, error) {
  283. params, err := parseConnectParams(dsn)
  284. if err != nil {
  285. return nil, err
  286. }
  287. return d.connect(ctx, nil, params)
  288. }
  289. // connect to the server, using the provided context for dialing only.
  290. func (d *Driver) connect(ctx context.Context, c *Connector, params connectParams) (*Conn, error) {
  291. sess, err := connect(ctx, c, d.log, params)
  292. if err != nil {
  293. // main server failed, try fail-over partner
  294. if params.failOverPartner == "" {
  295. return nil, err
  296. }
  297. params.host = params.failOverPartner
  298. if params.failOverPort != 0 {
  299. params.port = params.failOverPort
  300. }
  301. sess, err = connect(ctx, c, d.log, params)
  302. if err != nil {
  303. // fail-over partner also failed, now fail
  304. return nil, err
  305. }
  306. }
  307. conn := &Conn{
  308. connector: c,
  309. sess: sess,
  310. transactionCtx: context.Background(),
  311. processQueryText: d.processQueryText,
  312. connectionGood: true,
  313. }
  314. return conn, nil
  315. }
  316. func (c *Conn) Close() error {
  317. return c.sess.buf.transport.Close()
  318. }
  319. type Stmt struct {
  320. c *Conn
  321. query string
  322. paramCount int
  323. notifSub *queryNotifSub
  324. }
  325. type queryNotifSub struct {
  326. msgText string
  327. options string
  328. timeout uint32
  329. }
  330. func (c *Conn) Prepare(query string) (driver.Stmt, error) {
  331. if !c.connectionGood {
  332. return nil, driver.ErrBadConn
  333. }
  334. if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") {
  335. return c.prepareCopyIn(context.Background(), query)
  336. }
  337. return c.prepareContext(context.Background(), query)
  338. }
  339. func (c *Conn) prepareContext(ctx context.Context, query string) (*Stmt, error) {
  340. paramCount := -1
  341. if c.processQueryText {
  342. query, paramCount = querytext.ParseParams(query)
  343. }
  344. return &Stmt{c, query, paramCount, nil}, nil
  345. }
  346. func (s *Stmt) Close() error {
  347. return nil
  348. }
  349. func (s *Stmt) SetQueryNotification(id, options string, timeout time.Duration) {
  350. to := uint32(timeout / time.Second)
  351. if to < 1 {
  352. to = 1
  353. }
  354. s.notifSub = &queryNotifSub{id, options, to}
  355. }
  356. func (s *Stmt) NumInput() int {
  357. return s.paramCount
  358. }
  359. func (s *Stmt) sendQuery(args []namedValue) (err error) {
  360. headers := []headerStruct{
  361. {hdrtype: dataStmHdrTransDescr,
  362. data: transDescrHdr{s.c.sess.tranid, 1}.pack()},
  363. }
  364. if s.notifSub != nil {
  365. headers = append(headers,
  366. headerStruct{
  367. hdrtype: dataStmHdrQueryNotif,
  368. data: queryNotifHdr{
  369. s.notifSub.msgText,
  370. s.notifSub.options,
  371. s.notifSub.timeout,
  372. }.pack(),
  373. })
  374. }
  375. conn := s.c
  376. // no need to check number of parameters here, it is checked by database/sql
  377. if conn.sess.logFlags&logSQL != 0 {
  378. conn.sess.log.Println(s.query)
  379. }
  380. if conn.sess.logFlags&logParams != 0 && len(args) > 0 {
  381. for i := 0; i < len(args); i++ {
  382. if len(args[i].Name) > 0 {
  383. s.c.sess.log.Printf("\t@%s\t%v\n", args[i].Name, args[i].Value)
  384. } else {
  385. s.c.sess.log.Printf("\t@p%d\t%v\n", i+1, args[i].Value)
  386. }
  387. }
  388. }
  389. reset := conn.resetSession
  390. conn.resetSession = false
  391. if len(args) == 0 {
  392. if err = sendSqlBatch72(conn.sess.buf, s.query, headers, reset); err != nil {
  393. if conn.sess.logFlags&logErrors != 0 {
  394. conn.sess.log.Printf("Failed to send SqlBatch with %v", err)
  395. }
  396. conn.connectionGood = false
  397. return fmt.Errorf("failed to send SQL Batch: %v", err)
  398. }
  399. } else {
  400. proc := sp_ExecuteSql
  401. var params []param
  402. if isProc(s.query) {
  403. proc.name = s.query
  404. params, _, err = s.makeRPCParams(args, true)
  405. if err != nil {
  406. return
  407. }
  408. } else {
  409. var decls []string
  410. params, decls, err = s.makeRPCParams(args, false)
  411. if err != nil {
  412. return
  413. }
  414. params[0] = makeStrParam(s.query)
  415. params[1] = makeStrParam(strings.Join(decls, ","))
  416. }
  417. if err = sendRpc(conn.sess.buf, headers, proc, 0, params, reset); err != nil {
  418. if conn.sess.logFlags&logErrors != 0 {
  419. conn.sess.log.Printf("Failed to send Rpc with %v", err)
  420. }
  421. conn.connectionGood = false
  422. return fmt.Errorf("Failed to send RPC: %v", err)
  423. }
  424. }
  425. return
  426. }
  427. // isProc takes the query text in s and determines if it is a stored proc name
  428. // or SQL text.
  429. func isProc(s string) bool {
  430. if len(s) == 0 {
  431. return false
  432. }
  433. const (
  434. outside = iota
  435. text
  436. escaped
  437. )
  438. st := outside
  439. var rn1, rPrev rune
  440. for _, r := range s {
  441. rPrev = rn1
  442. rn1 = r
  443. switch r {
  444. // No newlines or string sequences.
  445. case '\n', '\r', '\'', ';':
  446. return false
  447. }
  448. switch st {
  449. case outside:
  450. switch {
  451. case unicode.IsSpace(r):
  452. return false
  453. case r == '[':
  454. st = escaped
  455. continue
  456. case r == ']' && rPrev == ']':
  457. st = escaped
  458. continue
  459. case unicode.IsLetter(r):
  460. st = text
  461. }
  462. case text:
  463. switch {
  464. case r == '.':
  465. st = outside
  466. continue
  467. case unicode.IsSpace(r):
  468. return false
  469. }
  470. case escaped:
  471. switch {
  472. case r == ']':
  473. st = outside
  474. continue
  475. }
  476. }
  477. }
  478. return true
  479. }
  480. func (s *Stmt) makeRPCParams(args []namedValue, isProc bool) ([]param, []string, error) {
  481. var err error
  482. var offset int
  483. if !isProc {
  484. offset = 2
  485. }
  486. params := make([]param, len(args)+offset)
  487. decls := make([]string, len(args))
  488. for i, val := range args {
  489. params[i+offset], err = s.makeParam(val.Value)
  490. if err != nil {
  491. return nil, nil, err
  492. }
  493. var name string
  494. if len(val.Name) > 0 {
  495. name = "@" + val.Name
  496. } else if !isProc {
  497. name = fmt.Sprintf("@p%d", val.Ordinal)
  498. }
  499. params[i+offset].Name = name
  500. decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+offset].ti))
  501. }
  502. return params, decls, nil
  503. }
  504. type namedValue struct {
  505. Name string
  506. Ordinal int
  507. Value driver.Value
  508. }
  509. func convertOldArgs(args []driver.Value) []namedValue {
  510. list := make([]namedValue, len(args))
  511. for i, v := range args {
  512. list[i] = namedValue{
  513. Ordinal: i + 1,
  514. Value: v,
  515. }
  516. }
  517. return list
  518. }
  519. func (s *Stmt) Query(args []driver.Value) (driver.Rows, error) {
  520. return s.queryContext(context.Background(), convertOldArgs(args))
  521. }
  522. func (s *Stmt) queryContext(ctx context.Context, args []namedValue) (rows driver.Rows, err error) {
  523. if !s.c.connectionGood {
  524. return nil, driver.ErrBadConn
  525. }
  526. if err = s.sendQuery(args); err != nil {
  527. return nil, s.c.checkBadConn(err)
  528. }
  529. return s.processQueryResponse(ctx)
  530. }
  531. func (s *Stmt) processQueryResponse(ctx context.Context) (res driver.Rows, err error) {
  532. tokchan := make(chan tokenStruct, 5)
  533. ctx, cancel := context.WithCancel(ctx)
  534. go processResponse(ctx, s.c.sess, tokchan, s.c.outs)
  535. s.c.clearOuts()
  536. // process metadata
  537. var cols []columnStruct
  538. loop:
  539. for tok := range tokchan {
  540. switch token := tok.(type) {
  541. // By ignoring DONE token we effectively
  542. // skip empty result-sets.
  543. // This improves results in queries like that:
  544. // set nocount on; select 1
  545. // see TestIgnoreEmptyResults test
  546. //case doneStruct:
  547. //break loop
  548. case []columnStruct:
  549. cols = token
  550. break loop
  551. case doneStruct:
  552. if token.isError() {
  553. return nil, s.c.checkBadConn(token.getError())
  554. }
  555. case ReturnStatus:
  556. s.c.setReturnStatus(token)
  557. case error:
  558. return nil, s.c.checkBadConn(token)
  559. }
  560. }
  561. res = &Rows{stmt: s, tokchan: tokchan, cols: cols, cancel: cancel}
  562. return
  563. }
  564. func (s *Stmt) Exec(args []driver.Value) (driver.Result, error) {
  565. return s.exec(context.Background(), convertOldArgs(args))
  566. }
  567. func (s *Stmt) exec(ctx context.Context, args []namedValue) (res driver.Result, err error) {
  568. if !s.c.connectionGood {
  569. return nil, driver.ErrBadConn
  570. }
  571. if err = s.sendQuery(args); err != nil {
  572. return nil, s.c.checkBadConn(err)
  573. }
  574. if res, err = s.processExec(ctx); err != nil {
  575. return nil, s.c.checkBadConn(err)
  576. }
  577. return
  578. }
  579. func (s *Stmt) processExec(ctx context.Context) (res driver.Result, err error) {
  580. tokchan := make(chan tokenStruct, 5)
  581. go processResponse(ctx, s.c.sess, tokchan, s.c.outs)
  582. s.c.clearOuts()
  583. var rowCount int64
  584. for token := range tokchan {
  585. switch token := token.(type) {
  586. case doneInProcStruct:
  587. if token.Status&doneCount != 0 {
  588. rowCount += int64(token.RowCount)
  589. }
  590. case doneStruct:
  591. if token.Status&doneCount != 0 {
  592. rowCount += int64(token.RowCount)
  593. }
  594. if token.isError() {
  595. return nil, token.getError()
  596. }
  597. case ReturnStatus:
  598. s.c.setReturnStatus(token)
  599. case error:
  600. return nil, token
  601. }
  602. }
  603. return &Result{s.c, rowCount}, nil
  604. }
  605. type Rows struct {
  606. stmt *Stmt
  607. cols []columnStruct
  608. tokchan chan tokenStruct
  609. nextCols []columnStruct
  610. cancel func()
  611. }
  612. func (rc *Rows) Close() error {
  613. rc.cancel()
  614. for _ = range rc.tokchan {
  615. }
  616. rc.tokchan = nil
  617. return nil
  618. }
  619. func (rc *Rows) Columns() (res []string) {
  620. res = make([]string, len(rc.cols))
  621. for i, col := range rc.cols {
  622. res[i] = col.ColName
  623. }
  624. return
  625. }
  626. func (rc *Rows) Next(dest []driver.Value) error {
  627. if !rc.stmt.c.connectionGood {
  628. return driver.ErrBadConn
  629. }
  630. if rc.nextCols != nil {
  631. return io.EOF
  632. }
  633. for tok := range rc.tokchan {
  634. switch tokdata := tok.(type) {
  635. case []columnStruct:
  636. rc.nextCols = tokdata
  637. return io.EOF
  638. case []interface{}:
  639. for i := range dest {
  640. dest[i] = tokdata[i]
  641. }
  642. return nil
  643. case doneStruct:
  644. if tokdata.isError() {
  645. return rc.stmt.c.checkBadConn(tokdata.getError())
  646. }
  647. case ReturnStatus:
  648. rc.stmt.c.setReturnStatus(tokdata)
  649. case error:
  650. return rc.stmt.c.checkBadConn(tokdata)
  651. }
  652. }
  653. return io.EOF
  654. }
  655. func (rc *Rows) HasNextResultSet() bool {
  656. return rc.nextCols != nil
  657. }
  658. func (rc *Rows) NextResultSet() error {
  659. rc.cols = rc.nextCols
  660. rc.nextCols = nil
  661. if rc.cols == nil {
  662. return io.EOF
  663. }
  664. return nil
  665. }
  666. // It should return
  667. // the value type that can be used to scan types into. For example, the database
  668. // column type "bigint" this should return "reflect.TypeOf(int64(0))".
  669. func (r *Rows) ColumnTypeScanType(index int) reflect.Type {
  670. return makeGoLangScanType(r.cols[index].ti)
  671. }
  672. // RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the
  673. // database system type name without the length. Type names should be uppercase.
  674. // Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT",
  675. // "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML",
  676. // "TIMESTAMP".
  677. func (r *Rows) ColumnTypeDatabaseTypeName(index int) string {
  678. return makeGoLangTypeName(r.cols[index].ti)
  679. }
  680. // RowsColumnTypeLength may be implemented by Rows. It should return the length
  681. // of the column type if the column is a variable length type. If the column is
  682. // not a variable length type ok should return false.
  683. // If length is not limited other than system limits, it should return math.MaxInt64.
  684. // The following are examples of returned values for various types:
  685. // TEXT (math.MaxInt64, true)
  686. // varchar(10) (10, true)
  687. // nvarchar(10) (10, true)
  688. // decimal (0, false)
  689. // int (0, false)
  690. // bytea(30) (30, true)
  691. func (r *Rows) ColumnTypeLength(index int) (int64, bool) {
  692. return makeGoLangTypeLength(r.cols[index].ti)
  693. }
  694. // It should return
  695. // the precision and scale for decimal types. If not applicable, ok should be false.
  696. // The following are examples of returned values for various types:
  697. // decimal(38, 4) (38, 4, true)
  698. // int (0, 0, false)
  699. // decimal (math.MaxInt64, math.MaxInt64, true)
  700. func (r *Rows) ColumnTypePrecisionScale(index int) (int64, int64, bool) {
  701. return makeGoLangTypePrecisionScale(r.cols[index].ti)
  702. }
  703. // The nullable value should
  704. // be true if it is known the column may be null, or false if the column is known
  705. // to be not nullable.
  706. // If the column nullability is unknown, ok should be false.
  707. func (r *Rows) ColumnTypeNullable(index int) (nullable, ok bool) {
  708. nullable = r.cols[index].Flags&colFlagNullable != 0
  709. ok = true
  710. return
  711. }
  712. func makeStrParam(val string) (res param) {
  713. res.ti.TypeId = typeNVarChar
  714. res.buffer = str2ucs2(val)
  715. res.ti.Size = len(res.buffer)
  716. return
  717. }
  718. func (s *Stmt) makeParam(val driver.Value) (res param, err error) {
  719. if val == nil {
  720. res.ti.TypeId = typeNull
  721. res.buffer = nil
  722. res.ti.Size = 0
  723. return
  724. }
  725. switch val := val.(type) {
  726. case int64:
  727. res.ti.TypeId = typeIntN
  728. res.buffer = make([]byte, 8)
  729. res.ti.Size = 8
  730. binary.LittleEndian.PutUint64(res.buffer, uint64(val))
  731. case sql.NullInt64:
  732. // only null values should be getting here
  733. res.ti.TypeId = typeIntN
  734. res.ti.Size = 8
  735. res.buffer = []byte{}
  736. case float64:
  737. res.ti.TypeId = typeFltN
  738. res.ti.Size = 8
  739. res.buffer = make([]byte, 8)
  740. binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(val))
  741. case sql.NullFloat64:
  742. // only null values should be getting here
  743. res.ti.TypeId = typeFltN
  744. res.ti.Size = 8
  745. res.buffer = []byte{}
  746. case []byte:
  747. res.ti.TypeId = typeBigVarBin
  748. res.ti.Size = len(val)
  749. res.buffer = val
  750. case string:
  751. res = makeStrParam(val)
  752. case sql.NullString:
  753. // only null values should be getting here
  754. res.ti.TypeId = typeNVarChar
  755. res.buffer = nil
  756. res.ti.Size = 8000
  757. case bool:
  758. res.ti.TypeId = typeBitN
  759. res.ti.Size = 1
  760. res.buffer = make([]byte, 1)
  761. if val {
  762. res.buffer[0] = 1
  763. }
  764. case sql.NullBool:
  765. // only null values should be getting here
  766. res.ti.TypeId = typeBitN
  767. res.ti.Size = 1
  768. res.buffer = []byte{}
  769. case time.Time:
  770. if s.c.sess.loginAck.TDSVersion >= verTDS73 {
  771. res.ti.TypeId = typeDateTimeOffsetN
  772. res.ti.Scale = 7
  773. res.buffer = encodeDateTimeOffset(val, int(res.ti.Scale))
  774. res.ti.Size = len(res.buffer)
  775. } else {
  776. res.ti.TypeId = typeDateTimeN
  777. res.buffer = encodeDateTime(val)
  778. res.ti.Size = len(res.buffer)
  779. }
  780. default:
  781. return s.makeParamExtra(val)
  782. }
  783. return
  784. }
  785. type Result struct {
  786. c *Conn
  787. rowsAffected int64
  788. }
  789. func (r *Result) RowsAffected() (int64, error) {
  790. return r.rowsAffected, nil
  791. }
  792. var _ driver.Pinger = &Conn{}
  793. // Ping is used to check if the remote server is available and satisfies the Pinger interface.
  794. func (c *Conn) Ping(ctx context.Context) error {
  795. if !c.connectionGood {
  796. return driver.ErrBadConn
  797. }
  798. stmt := &Stmt{c, `select 1;`, 0, nil}
  799. _, err := stmt.ExecContext(ctx, nil)
  800. return err
  801. }
  802. var _ driver.ConnBeginTx = &Conn{}
  803. // BeginTx satisfies ConnBeginTx.
  804. func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
  805. if !c.connectionGood {
  806. return nil, driver.ErrBadConn
  807. }
  808. if opts.ReadOnly {
  809. return nil, errors.New("Read-only transactions are not supported")
  810. }
  811. var tdsIsolation isoLevel
  812. switch sql.IsolationLevel(opts.Isolation) {
  813. case sql.LevelDefault:
  814. tdsIsolation = isolationUseCurrent
  815. case sql.LevelReadUncommitted:
  816. tdsIsolation = isolationReadUncommited
  817. case sql.LevelReadCommitted:
  818. tdsIsolation = isolationReadCommited
  819. case sql.LevelWriteCommitted:
  820. return nil, errors.New("LevelWriteCommitted isolation level is not supported")
  821. case sql.LevelRepeatableRead:
  822. tdsIsolation = isolationRepeatableRead
  823. case sql.LevelSnapshot:
  824. tdsIsolation = isolationSnapshot
  825. case sql.LevelSerializable:
  826. tdsIsolation = isolationSerializable
  827. case sql.LevelLinearizable:
  828. return nil, errors.New("LevelLinearizable isolation level is not supported")
  829. default:
  830. return nil, errors.New("Isolation level is not supported or unknown")
  831. }
  832. return c.begin(ctx, tdsIsolation)
  833. }
  834. func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
  835. if !c.connectionGood {
  836. return nil, driver.ErrBadConn
  837. }
  838. if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") {
  839. return c.prepareCopyIn(ctx, query)
  840. }
  841. return c.prepareContext(ctx, query)
  842. }
  843. func (s *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
  844. if !s.c.connectionGood {
  845. return nil, driver.ErrBadConn
  846. }
  847. list := make([]namedValue, len(args))
  848. for i, nv := range args {
  849. list[i] = namedValue(nv)
  850. }
  851. return s.queryContext(ctx, list)
  852. }
  853. func (s *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
  854. if !s.c.connectionGood {
  855. return nil, driver.ErrBadConn
  856. }
  857. list := make([]namedValue, len(args))
  858. for i, nv := range args {
  859. list[i] = namedValue(nv)
  860. }
  861. return s.exec(ctx, list)
  862. }
上海开阖软件有限公司 沪ICP备12045867号-1