You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mssql.go 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  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. // 2.2.5.3.1 Query Notifications Header
  351. // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/e168d373-a7b7-41aa-b6ca-25985466a7e0
  352. // Timeout in milliseconds in TDS protocol.
  353. to := uint32(timeout / time.Millisecond)
  354. if to < 1 {
  355. to = 1
  356. }
  357. s.notifSub = &queryNotifSub{id, options, to}
  358. }
  359. func (s *Stmt) NumInput() int {
  360. return s.paramCount
  361. }
  362. func (s *Stmt) sendQuery(args []namedValue) (err error) {
  363. headers := []headerStruct{
  364. {hdrtype: dataStmHdrTransDescr,
  365. data: transDescrHdr{s.c.sess.tranid, 1}.pack()},
  366. }
  367. if s.notifSub != nil {
  368. headers = append(headers,
  369. headerStruct{
  370. hdrtype: dataStmHdrQueryNotif,
  371. data: queryNotifHdr{
  372. s.notifSub.msgText,
  373. s.notifSub.options,
  374. s.notifSub.timeout,
  375. }.pack(),
  376. })
  377. }
  378. conn := s.c
  379. // no need to check number of parameters here, it is checked by database/sql
  380. if conn.sess.logFlags&logSQL != 0 {
  381. conn.sess.log.Println(s.query)
  382. }
  383. if conn.sess.logFlags&logParams != 0 && len(args) > 0 {
  384. for i := 0; i < len(args); i++ {
  385. if len(args[i].Name) > 0 {
  386. s.c.sess.log.Printf("\t@%s\t%v\n", args[i].Name, args[i].Value)
  387. } else {
  388. s.c.sess.log.Printf("\t@p%d\t%v\n", i+1, args[i].Value)
  389. }
  390. }
  391. }
  392. reset := conn.resetSession
  393. conn.resetSession = false
  394. if len(args) == 0 {
  395. if err = sendSqlBatch72(conn.sess.buf, s.query, headers, reset); err != nil {
  396. if conn.sess.logFlags&logErrors != 0 {
  397. conn.sess.log.Printf("Failed to send SqlBatch with %v", err)
  398. }
  399. conn.connectionGood = false
  400. return fmt.Errorf("failed to send SQL Batch: %v", err)
  401. }
  402. } else {
  403. proc := sp_ExecuteSql
  404. var params []param
  405. if isProc(s.query) {
  406. proc.name = s.query
  407. params, _, err = s.makeRPCParams(args, true)
  408. if err != nil {
  409. return
  410. }
  411. } else {
  412. var decls []string
  413. params, decls, err = s.makeRPCParams(args, false)
  414. if err != nil {
  415. return
  416. }
  417. params[0] = makeStrParam(s.query)
  418. params[1] = makeStrParam(strings.Join(decls, ","))
  419. }
  420. if err = sendRpc(conn.sess.buf, headers, proc, 0, params, reset); err != nil {
  421. if conn.sess.logFlags&logErrors != 0 {
  422. conn.sess.log.Printf("Failed to send Rpc with %v", err)
  423. }
  424. conn.connectionGood = false
  425. return fmt.Errorf("Failed to send RPC: %v", err)
  426. }
  427. }
  428. return
  429. }
  430. // isProc takes the query text in s and determines if it is a stored proc name
  431. // or SQL text.
  432. func isProc(s string) bool {
  433. if len(s) == 0 {
  434. return false
  435. }
  436. const (
  437. outside = iota
  438. text
  439. escaped
  440. )
  441. st := outside
  442. var rn1, rPrev rune
  443. for _, r := range s {
  444. rPrev = rn1
  445. rn1 = r
  446. switch r {
  447. // No newlines or string sequences.
  448. case '\n', '\r', '\'', ';':
  449. return false
  450. }
  451. switch st {
  452. case outside:
  453. switch {
  454. case unicode.IsSpace(r):
  455. return false
  456. case r == '[':
  457. st = escaped
  458. continue
  459. case r == ']' && rPrev == ']':
  460. st = escaped
  461. continue
  462. case unicode.IsLetter(r):
  463. st = text
  464. }
  465. case text:
  466. switch {
  467. case r == '.':
  468. st = outside
  469. continue
  470. case unicode.IsSpace(r):
  471. return false
  472. }
  473. case escaped:
  474. switch {
  475. case r == ']':
  476. st = outside
  477. continue
  478. }
  479. }
  480. }
  481. return true
  482. }
  483. func (s *Stmt) makeRPCParams(args []namedValue, isProc bool) ([]param, []string, error) {
  484. var err error
  485. var offset int
  486. if !isProc {
  487. offset = 2
  488. }
  489. params := make([]param, len(args)+offset)
  490. decls := make([]string, len(args))
  491. for i, val := range args {
  492. params[i+offset], err = s.makeParam(val.Value)
  493. if err != nil {
  494. return nil, nil, err
  495. }
  496. var name string
  497. if len(val.Name) > 0 {
  498. name = "@" + val.Name
  499. } else if !isProc {
  500. name = fmt.Sprintf("@p%d", val.Ordinal)
  501. }
  502. params[i+offset].Name = name
  503. decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+offset].ti))
  504. }
  505. return params, decls, nil
  506. }
  507. type namedValue struct {
  508. Name string
  509. Ordinal int
  510. Value driver.Value
  511. }
  512. func convertOldArgs(args []driver.Value) []namedValue {
  513. list := make([]namedValue, len(args))
  514. for i, v := range args {
  515. list[i] = namedValue{
  516. Ordinal: i + 1,
  517. Value: v,
  518. }
  519. }
  520. return list
  521. }
  522. func (s *Stmt) Query(args []driver.Value) (driver.Rows, error) {
  523. return s.queryContext(context.Background(), convertOldArgs(args))
  524. }
  525. func (s *Stmt) queryContext(ctx context.Context, args []namedValue) (rows driver.Rows, err error) {
  526. if !s.c.connectionGood {
  527. return nil, driver.ErrBadConn
  528. }
  529. if err = s.sendQuery(args); err != nil {
  530. return nil, s.c.checkBadConn(err)
  531. }
  532. return s.processQueryResponse(ctx)
  533. }
  534. func (s *Stmt) processQueryResponse(ctx context.Context) (res driver.Rows, err error) {
  535. tokchan := make(chan tokenStruct, 5)
  536. ctx, cancel := context.WithCancel(ctx)
  537. go processResponse(ctx, s.c.sess, tokchan, s.c.outs)
  538. s.c.clearOuts()
  539. // process metadata
  540. var cols []columnStruct
  541. loop:
  542. for tok := range tokchan {
  543. switch token := tok.(type) {
  544. // By ignoring DONE token we effectively
  545. // skip empty result-sets.
  546. // This improves results in queries like that:
  547. // set nocount on; select 1
  548. // see TestIgnoreEmptyResults test
  549. //case doneStruct:
  550. //break loop
  551. case []columnStruct:
  552. cols = token
  553. break loop
  554. case doneStruct:
  555. if token.isError() {
  556. cancel()
  557. return nil, s.c.checkBadConn(token.getError())
  558. }
  559. case ReturnStatus:
  560. s.c.setReturnStatus(token)
  561. case error:
  562. cancel()
  563. return nil, s.c.checkBadConn(token)
  564. }
  565. }
  566. res = &Rows{stmt: s, tokchan: tokchan, cols: cols, cancel: cancel}
  567. return
  568. }
  569. func (s *Stmt) Exec(args []driver.Value) (driver.Result, error) {
  570. return s.exec(context.Background(), convertOldArgs(args))
  571. }
  572. func (s *Stmt) exec(ctx context.Context, args []namedValue) (res driver.Result, err error) {
  573. if !s.c.connectionGood {
  574. return nil, driver.ErrBadConn
  575. }
  576. if err = s.sendQuery(args); err != nil {
  577. return nil, s.c.checkBadConn(err)
  578. }
  579. if res, err = s.processExec(ctx); err != nil {
  580. return nil, s.c.checkBadConn(err)
  581. }
  582. return
  583. }
  584. func (s *Stmt) processExec(ctx context.Context) (res driver.Result, err error) {
  585. tokchan := make(chan tokenStruct, 5)
  586. go processResponse(ctx, s.c.sess, tokchan, s.c.outs)
  587. s.c.clearOuts()
  588. var rowCount int64
  589. for token := range tokchan {
  590. switch token := token.(type) {
  591. case doneInProcStruct:
  592. if token.Status&doneCount != 0 {
  593. rowCount += int64(token.RowCount)
  594. }
  595. case doneStruct:
  596. if token.Status&doneCount != 0 {
  597. rowCount += int64(token.RowCount)
  598. }
  599. if token.isError() {
  600. return nil, token.getError()
  601. }
  602. case ReturnStatus:
  603. s.c.setReturnStatus(token)
  604. case error:
  605. return nil, token
  606. }
  607. }
  608. return &Result{s.c, rowCount}, nil
  609. }
  610. type Rows struct {
  611. stmt *Stmt
  612. cols []columnStruct
  613. tokchan chan tokenStruct
  614. nextCols []columnStruct
  615. cancel func()
  616. }
  617. func (rc *Rows) Close() error {
  618. rc.cancel()
  619. for _ = range rc.tokchan {
  620. }
  621. rc.tokchan = nil
  622. return nil
  623. }
  624. func (rc *Rows) Columns() (res []string) {
  625. res = make([]string, len(rc.cols))
  626. for i, col := range rc.cols {
  627. res[i] = col.ColName
  628. }
  629. return
  630. }
  631. func (rc *Rows) Next(dest []driver.Value) error {
  632. if !rc.stmt.c.connectionGood {
  633. return driver.ErrBadConn
  634. }
  635. if rc.nextCols != nil {
  636. return io.EOF
  637. }
  638. for tok := range rc.tokchan {
  639. switch tokdata := tok.(type) {
  640. case []columnStruct:
  641. rc.nextCols = tokdata
  642. return io.EOF
  643. case []interface{}:
  644. for i := range dest {
  645. dest[i] = tokdata[i]
  646. }
  647. return nil
  648. case doneStruct:
  649. if tokdata.isError() {
  650. return rc.stmt.c.checkBadConn(tokdata.getError())
  651. }
  652. case ReturnStatus:
  653. rc.stmt.c.setReturnStatus(tokdata)
  654. case error:
  655. return rc.stmt.c.checkBadConn(tokdata)
  656. }
  657. }
  658. return io.EOF
  659. }
  660. func (rc *Rows) HasNextResultSet() bool {
  661. return rc.nextCols != nil
  662. }
  663. func (rc *Rows) NextResultSet() error {
  664. rc.cols = rc.nextCols
  665. rc.nextCols = nil
  666. if rc.cols == nil {
  667. return io.EOF
  668. }
  669. return nil
  670. }
  671. // It should return
  672. // the value type that can be used to scan types into. For example, the database
  673. // column type "bigint" this should return "reflect.TypeOf(int64(0))".
  674. func (r *Rows) ColumnTypeScanType(index int) reflect.Type {
  675. return makeGoLangScanType(r.cols[index].ti)
  676. }
  677. // RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the
  678. // database system type name without the length. Type names should be uppercase.
  679. // Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT",
  680. // "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML",
  681. // "TIMESTAMP".
  682. func (r *Rows) ColumnTypeDatabaseTypeName(index int) string {
  683. return makeGoLangTypeName(r.cols[index].ti)
  684. }
  685. // RowsColumnTypeLength may be implemented by Rows. It should return the length
  686. // of the column type if the column is a variable length type. If the column is
  687. // not a variable length type ok should return false.
  688. // If length is not limited other than system limits, it should return math.MaxInt64.
  689. // The following are examples of returned values for various types:
  690. // TEXT (math.MaxInt64, true)
  691. // varchar(10) (10, true)
  692. // nvarchar(10) (10, true)
  693. // decimal (0, false)
  694. // int (0, false)
  695. // bytea(30) (30, true)
  696. func (r *Rows) ColumnTypeLength(index int) (int64, bool) {
  697. return makeGoLangTypeLength(r.cols[index].ti)
  698. }
  699. // It should return
  700. // the precision and scale for decimal types. If not applicable, ok should be false.
  701. // The following are examples of returned values for various types:
  702. // decimal(38, 4) (38, 4, true)
  703. // int (0, 0, false)
  704. // decimal (math.MaxInt64, math.MaxInt64, true)
  705. func (r *Rows) ColumnTypePrecisionScale(index int) (int64, int64, bool) {
  706. return makeGoLangTypePrecisionScale(r.cols[index].ti)
  707. }
  708. // The nullable value should
  709. // be true if it is known the column may be null, or false if the column is known
  710. // to be not nullable.
  711. // If the column nullability is unknown, ok should be false.
  712. func (r *Rows) ColumnTypeNullable(index int) (nullable, ok bool) {
  713. nullable = r.cols[index].Flags&colFlagNullable != 0
  714. ok = true
  715. return
  716. }
  717. func makeStrParam(val string) (res param) {
  718. res.ti.TypeId = typeNVarChar
  719. res.buffer = str2ucs2(val)
  720. res.ti.Size = len(res.buffer)
  721. return
  722. }
  723. func (s *Stmt) makeParam(val driver.Value) (res param, err error) {
  724. if val == nil {
  725. res.ti.TypeId = typeNull
  726. res.buffer = nil
  727. res.ti.Size = 0
  728. return
  729. }
  730. switch val := val.(type) {
  731. case int64:
  732. res.ti.TypeId = typeIntN
  733. res.buffer = make([]byte, 8)
  734. res.ti.Size = 8
  735. binary.LittleEndian.PutUint64(res.buffer, uint64(val))
  736. case sql.NullInt64:
  737. // only null values should be getting here
  738. res.ti.TypeId = typeIntN
  739. res.ti.Size = 8
  740. res.buffer = []byte{}
  741. case float64:
  742. res.ti.TypeId = typeFltN
  743. res.ti.Size = 8
  744. res.buffer = make([]byte, 8)
  745. binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(val))
  746. case sql.NullFloat64:
  747. // only null values should be getting here
  748. res.ti.TypeId = typeFltN
  749. res.ti.Size = 8
  750. res.buffer = []byte{}
  751. case []byte:
  752. res.ti.TypeId = typeBigVarBin
  753. res.ti.Size = len(val)
  754. res.buffer = val
  755. case string:
  756. res = makeStrParam(val)
  757. case sql.NullString:
  758. // only null values should be getting here
  759. res.ti.TypeId = typeNVarChar
  760. res.buffer = nil
  761. res.ti.Size = 8000
  762. case bool:
  763. res.ti.TypeId = typeBitN
  764. res.ti.Size = 1
  765. res.buffer = make([]byte, 1)
  766. if val {
  767. res.buffer[0] = 1
  768. }
  769. case sql.NullBool:
  770. // only null values should be getting here
  771. res.ti.TypeId = typeBitN
  772. res.ti.Size = 1
  773. res.buffer = []byte{}
  774. case time.Time:
  775. if s.c.sess.loginAck.TDSVersion >= verTDS73 {
  776. res.ti.TypeId = typeDateTimeOffsetN
  777. res.ti.Scale = 7
  778. res.buffer = encodeDateTimeOffset(val, int(res.ti.Scale))
  779. res.ti.Size = len(res.buffer)
  780. } else {
  781. res.ti.TypeId = typeDateTimeN
  782. res.buffer = encodeDateTime(val)
  783. res.ti.Size = len(res.buffer)
  784. }
  785. default:
  786. return s.makeParamExtra(val)
  787. }
  788. return
  789. }
  790. type Result struct {
  791. c *Conn
  792. rowsAffected int64
  793. }
  794. func (r *Result) RowsAffected() (int64, error) {
  795. return r.rowsAffected, nil
  796. }
  797. var _ driver.Pinger = &Conn{}
  798. // Ping is used to check if the remote server is available and satisfies the Pinger interface.
  799. func (c *Conn) Ping(ctx context.Context) error {
  800. if !c.connectionGood {
  801. return driver.ErrBadConn
  802. }
  803. stmt := &Stmt{c, `select 1;`, 0, nil}
  804. _, err := stmt.ExecContext(ctx, nil)
  805. return err
  806. }
  807. var _ driver.ConnBeginTx = &Conn{}
  808. // BeginTx satisfies ConnBeginTx.
  809. func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
  810. if !c.connectionGood {
  811. return nil, driver.ErrBadConn
  812. }
  813. if opts.ReadOnly {
  814. return nil, errors.New("Read-only transactions are not supported")
  815. }
  816. var tdsIsolation isoLevel
  817. switch sql.IsolationLevel(opts.Isolation) {
  818. case sql.LevelDefault:
  819. tdsIsolation = isolationUseCurrent
  820. case sql.LevelReadUncommitted:
  821. tdsIsolation = isolationReadUncommited
  822. case sql.LevelReadCommitted:
  823. tdsIsolation = isolationReadCommited
  824. case sql.LevelWriteCommitted:
  825. return nil, errors.New("LevelWriteCommitted isolation level is not supported")
  826. case sql.LevelRepeatableRead:
  827. tdsIsolation = isolationRepeatableRead
  828. case sql.LevelSnapshot:
  829. tdsIsolation = isolationSnapshot
  830. case sql.LevelSerializable:
  831. tdsIsolation = isolationSerializable
  832. case sql.LevelLinearizable:
  833. return nil, errors.New("LevelLinearizable isolation level is not supported")
  834. default:
  835. return nil, errors.New("Isolation level is not supported or unknown")
  836. }
  837. return c.begin(ctx, tdsIsolation)
  838. }
  839. func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
  840. if !c.connectionGood {
  841. return nil, driver.ErrBadConn
  842. }
  843. if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") {
  844. return c.prepareCopyIn(ctx, query)
  845. }
  846. return c.prepareContext(ctx, query)
  847. }
  848. func (s *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
  849. if !s.c.connectionGood {
  850. return nil, driver.ErrBadConn
  851. }
  852. list := make([]namedValue, len(args))
  853. for i, nv := range args {
  854. list[i] = namedValue(nv)
  855. }
  856. return s.queryContext(ctx, list)
  857. }
  858. func (s *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
  859. if !s.c.connectionGood {
  860. return nil, driver.ErrBadConn
  861. }
  862. list := make([]namedValue, len(args))
  863. for i, nv := range args {
  864. list[i] = namedValue(nv)
  865. }
  866. return s.exec(ctx, list)
  867. }