mysql.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. // Package native is a thread unsafe engine for MyMySQL.
  2. package native
  3. import (
  4. "bufio"
  5. "fmt"
  6. "io"
  7. "net"
  8. "reflect"
  9. "strings"
  10. "time"
  11. "github.com/ziutek/mymysql/mysql"
  12. )
  13. type serverInfo struct {
  14. prot_ver byte
  15. serv_ver []byte
  16. thr_id uint32
  17. scramble [20]byte
  18. caps uint16
  19. lang byte
  20. }
  21. // MySQL connection handler
  22. type Conn struct {
  23. proto string // Network protocol
  24. laddr string // Local address
  25. raddr string // Remote (server) address
  26. user string // MySQL username
  27. passwd string // MySQL password
  28. dbname string // Database name
  29. net_conn net.Conn // MySQL connection
  30. rd *bufio.Reader
  31. wr *bufio.Writer
  32. info serverInfo // MySQL server information
  33. seq byte // MySQL sequence number
  34. unreaded_reply bool
  35. init_cmds []string // MySQL commands/queries executed after connect
  36. stmt_map map[uint32]*Stmt // For reprepare during reconnect
  37. // Current status of MySQL server connection
  38. status mysql.ConnStatus
  39. // Maximum packet size that client can accept from server.
  40. // Default 16*1024*1024-1. You may change it before connect.
  41. max_pkt_size int
  42. // Timeout for connect
  43. timeout time.Duration
  44. dialer mysql.Dialer
  45. // Return only types accepted by godrv
  46. narrowTypeSet bool
  47. // Store full information about fields in result
  48. fullFieldInfo bool
  49. // Debug logging. You may change it at any time.
  50. Debug bool
  51. }
  52. // Create new MySQL handler. The first three arguments are passed to net.Bind
  53. // for create connection. user and passwd are for authentication. Optional db
  54. // is database name (you may not specify it and use Use() method later).
  55. func New(proto, laddr, raddr, user, passwd string, db ...string) mysql.Conn {
  56. my := Conn{
  57. proto: proto,
  58. laddr: laddr,
  59. raddr: raddr,
  60. user: user,
  61. passwd: passwd,
  62. stmt_map: make(map[uint32]*Stmt),
  63. max_pkt_size: 16*1024*1024 - 1,
  64. timeout: 2 * time.Minute,
  65. fullFieldInfo: true,
  66. }
  67. if len(db) == 1 {
  68. my.dbname = db[0]
  69. } else if len(db) > 1 {
  70. panic("mymy.New: too many arguments")
  71. }
  72. return &my
  73. }
  74. func (my *Conn) Credentials() (user, passwd string) {
  75. return my.user, my.passwd
  76. }
  77. func (my *Conn) NarrowTypeSet(narrow bool) {
  78. my.narrowTypeSet = narrow
  79. }
  80. func (my *Conn) FullFieldInfo(full bool) {
  81. my.fullFieldInfo = full
  82. }
  83. // Creates new (not connected) connection using configuration from current
  84. // connection.
  85. func (my *Conn) Clone() mysql.Conn {
  86. var c *Conn
  87. if my.dbname == "" {
  88. c = New(my.proto, my.laddr, my.raddr, my.user, my.passwd).(*Conn)
  89. } else {
  90. c = New(my.proto, my.laddr, my.raddr, my.user, my.passwd, my.dbname).(*Conn)
  91. }
  92. c.max_pkt_size = my.max_pkt_size
  93. c.timeout = my.timeout
  94. c.Debug = my.Debug
  95. return c
  96. }
  97. // If new_size > 0 sets maximum packet size. Returns old size.
  98. func (my *Conn) SetMaxPktSize(new_size int) int {
  99. old_size := my.max_pkt_size
  100. if new_size > 0 {
  101. my.max_pkt_size = new_size
  102. }
  103. return old_size
  104. }
  105. // SetTimeout sets timeout for Connect and Reconnect
  106. func (my *Conn) SetTimeout(timeout time.Duration) {
  107. my.timeout = timeout
  108. }
  109. // NetConn return internall net.Conn
  110. func (my *Conn) NetConn() net.Conn {
  111. return my.net_conn
  112. }
  113. type timeoutError struct{}
  114. func (e *timeoutError) Error() string { return "i/o timeout" }
  115. func (e *timeoutError) Timeout() bool { return true }
  116. func (e *timeoutError) Temporary() bool { return true }
  117. type stringAddr struct {
  118. net, addr string
  119. }
  120. func (a stringAddr) Network() string { return a.net }
  121. func (a stringAddr) String() string { return a.addr }
  122. var DefaultDialer mysql.Dialer = func(proto, laddr, raddr string,
  123. timeout time.Duration) (net.Conn, error) {
  124. if proto == "" {
  125. proto = "unix"
  126. if strings.IndexRune(raddr, ':') != -1 {
  127. proto = "tcp"
  128. }
  129. }
  130. // Make a connection
  131. d := &net.Dialer{Timeout: timeout}
  132. if laddr != "" {
  133. var err error
  134. switch proto {
  135. case "tcp", "tcp4", "tcp6":
  136. d.LocalAddr, err = net.ResolveTCPAddr(proto, laddr)
  137. case "unix":
  138. d.LocalAddr, err = net.ResolveTCPAddr(proto, laddr)
  139. default:
  140. err = net.UnknownNetworkError(proto)
  141. }
  142. if err != nil {
  143. return nil, err
  144. }
  145. }
  146. return d.Dial(proto, raddr)
  147. }
  148. func (my *Conn) SetDialer(d mysql.Dialer) {
  149. my.dialer = d
  150. }
  151. func (my *Conn) connect() (err error) {
  152. defer catchError(&err)
  153. my.net_conn = nil
  154. if my.dialer != nil {
  155. my.net_conn, err = my.dialer(my.proto, my.laddr, my.raddr, my.timeout)
  156. if err != nil {
  157. my.net_conn = nil
  158. return
  159. }
  160. }
  161. if my.net_conn == nil {
  162. my.net_conn, err = DefaultDialer(my.proto, my.laddr, my.raddr, my.timeout)
  163. if err != nil {
  164. my.net_conn = nil
  165. return
  166. }
  167. }
  168. my.rd = bufio.NewReader(my.net_conn)
  169. my.wr = bufio.NewWriter(my.net_conn)
  170. // Initialisation
  171. my.init()
  172. my.auth()
  173. res := my.getResult(nil, nil)
  174. if res == nil {
  175. // Try old password
  176. my.oldPasswd()
  177. res = my.getResult(nil, nil)
  178. if res == nil {
  179. return mysql.ErrAuthentication
  180. }
  181. }
  182. // Execute all registered commands
  183. for _, cmd := range my.init_cmds {
  184. // Send command
  185. my.sendCmdStr(_COM_QUERY, cmd)
  186. // Get command response
  187. res := my.getResponse()
  188. // Read and discard all result rows
  189. row := res.MakeRow()
  190. for res != nil {
  191. // Only read rows if they exist
  192. if !res.StatusOnly() {
  193. //read each row in this set
  194. for {
  195. err = res.getRow(row)
  196. if err == io.EOF {
  197. break
  198. } else if err != nil {
  199. return
  200. }
  201. }
  202. }
  203. // Move to the next result
  204. if res, err = res.nextResult(); err != nil {
  205. return
  206. }
  207. }
  208. }
  209. return
  210. }
  211. // Establishes a connection with MySQL server version 4.1 or later.
  212. func (my *Conn) Connect() (err error) {
  213. if my.net_conn != nil {
  214. return mysql.ErrAlredyConn
  215. }
  216. return my.connect()
  217. }
  218. // Check if connection is established
  219. func (my *Conn) IsConnected() bool {
  220. return my.net_conn != nil
  221. }
  222. func (my *Conn) closeConn() (err error) {
  223. defer catchError(&err)
  224. // Always close and invalidate connection, even if
  225. // COM_QUIT returns an error
  226. defer func() {
  227. err = my.net_conn.Close()
  228. my.net_conn = nil // Mark that we disconnect
  229. }()
  230. // Close the connection
  231. my.sendCmd(_COM_QUIT)
  232. return
  233. }
  234. // Close connection to the server
  235. func (my *Conn) Close() (err error) {
  236. if my.net_conn == nil {
  237. return mysql.ErrNotConn
  238. }
  239. if my.unreaded_reply {
  240. return mysql.ErrUnreadedReply
  241. }
  242. return my.closeConn()
  243. }
  244. // Close and reopen connection.
  245. // Ignore unreaded rows, reprepare all prepared statements.
  246. func (my *Conn) Reconnect() (err error) {
  247. if my.net_conn != nil {
  248. // Close connection, ignore all errors
  249. my.closeConn()
  250. }
  251. // Reopen the connection.
  252. if err = my.connect(); err != nil {
  253. return
  254. }
  255. // Reprepare all prepared statements
  256. var (
  257. new_stmt *Stmt
  258. new_map = make(map[uint32]*Stmt)
  259. )
  260. for _, stmt := range my.stmt_map {
  261. new_stmt, err = my.prepare(stmt.sql)
  262. if err != nil {
  263. return
  264. }
  265. // Assume that fields set in new_stmt by prepare() are indentical to
  266. // corresponding fields in stmt. Why can they be different?
  267. stmt.id = new_stmt.id
  268. stmt.rebind = true
  269. new_map[stmt.id] = stmt
  270. }
  271. // Replace the stmt_map
  272. my.stmt_map = new_map
  273. return
  274. }
  275. // Change database
  276. func (my *Conn) Use(dbname string) (err error) {
  277. defer catchError(&err)
  278. if my.net_conn == nil {
  279. return mysql.ErrNotConn
  280. }
  281. if my.unreaded_reply {
  282. return mysql.ErrUnreadedReply
  283. }
  284. // Send command
  285. my.sendCmdStr(_COM_INIT_DB, dbname)
  286. // Get server response
  287. my.getResult(nil, nil)
  288. // Save new database name if no errors
  289. my.dbname = dbname
  290. return
  291. }
  292. func (my *Conn) getResponse() (res *Result) {
  293. res = my.getResult(nil, nil)
  294. if res == nil {
  295. panic(mysql.ErrBadResult)
  296. }
  297. my.unreaded_reply = !res.StatusOnly()
  298. return
  299. }
  300. // Start new query.
  301. //
  302. // If you specify the parameters, the SQL string will be a result of
  303. // fmt.Sprintf(sql, params...).
  304. // You must get all result rows (if they exists) before next query.
  305. func (my *Conn) Start(sql string, params ...interface{}) (res mysql.Result, err error) {
  306. defer catchError(&err)
  307. if my.net_conn == nil {
  308. return nil, mysql.ErrNotConn
  309. }
  310. if my.unreaded_reply {
  311. return nil, mysql.ErrUnreadedReply
  312. }
  313. if len(params) != 0 {
  314. sql = fmt.Sprintf(sql, params...)
  315. }
  316. // Send query
  317. my.sendCmdStr(_COM_QUERY, sql)
  318. // Get command response
  319. res = my.getResponse()
  320. return
  321. }
  322. func (res *Result) getRow(row mysql.Row) (err error) {
  323. defer catchError(&err)
  324. if res.my.getResult(res, row) != nil {
  325. return io.EOF
  326. }
  327. return nil
  328. }
  329. // Returns true if more results exixts. You don't have to call it before
  330. // NextResult method (NextResult returns nil if there is no more results).
  331. func (res *Result) MoreResults() bool {
  332. return res.status&mysql.SERVER_MORE_RESULTS_EXISTS != 0
  333. }
  334. // Get the data row from server. This method reads one row of result set
  335. // directly from network connection (without rows buffering on client side).
  336. // Returns io.EOF if there is no more rows in current result set.
  337. func (res *Result) ScanRow(row mysql.Row) error {
  338. if row == nil {
  339. return mysql.ErrRowLength
  340. }
  341. if res.eor_returned {
  342. return mysql.ErrReadAfterEOR
  343. }
  344. if res.StatusOnly() {
  345. // There is no fields in result (OK result)
  346. res.eor_returned = true
  347. return io.EOF
  348. }
  349. err := res.getRow(row)
  350. if err == io.EOF {
  351. res.eor_returned = true
  352. if !res.MoreResults() {
  353. res.my.unreaded_reply = false
  354. }
  355. }
  356. return err
  357. }
  358. // Like ScanRow but allocates memory for every row.
  359. // Returns nil row insted of io.EOF error.
  360. func (res *Result) GetRow() (mysql.Row, error) {
  361. return mysql.GetRow(res)
  362. }
  363. func (res *Result) nextResult() (next *Result, err error) {
  364. defer catchError(&err)
  365. if res.MoreResults() {
  366. next = res.my.getResponse()
  367. }
  368. return
  369. }
  370. // This function is used when last query was the multi result query or
  371. // procedure call. Returns the next result or nil if no more resuts exists.
  372. //
  373. // Statements within the procedure may produce unknown number of result sets.
  374. // The final result from the procedure is a status result that includes no
  375. // result set (Result.StatusOnly() == true) .
  376. func (res *Result) NextResult() (mysql.Result, error) {
  377. if !res.MoreResults() {
  378. return nil, nil
  379. }
  380. res, err := res.nextResult()
  381. return res, err
  382. }
  383. // Send MySQL PING to the server.
  384. func (my *Conn) Ping() (err error) {
  385. defer catchError(&err)
  386. if my.net_conn == nil {
  387. return mysql.ErrNotConn
  388. }
  389. if my.unreaded_reply {
  390. return mysql.ErrUnreadedReply
  391. }
  392. // Send command
  393. my.sendCmd(_COM_PING)
  394. // Get server response
  395. my.getResult(nil, nil)
  396. return
  397. }
  398. func (my *Conn) prepare(sql string) (stmt *Stmt, err error) {
  399. defer catchError(&err)
  400. // Send command
  401. my.sendCmdStr(_COM_STMT_PREPARE, sql)
  402. // Get server response
  403. stmt, ok := my.getPrepareResult(nil).(*Stmt)
  404. if !ok {
  405. return nil, mysql.ErrBadResult
  406. }
  407. if len(stmt.params) > 0 {
  408. // Get param fields
  409. my.getPrepareResult(stmt)
  410. }
  411. if len(stmt.fields) > 0 {
  412. // Get column fields
  413. my.getPrepareResult(stmt)
  414. }
  415. return
  416. }
  417. // Prepare server side statement. Return statement handler.
  418. func (my *Conn) Prepare(sql string) (mysql.Stmt, error) {
  419. if my.net_conn == nil {
  420. return nil, mysql.ErrNotConn
  421. }
  422. if my.unreaded_reply {
  423. return nil, mysql.ErrUnreadedReply
  424. }
  425. stmt, err := my.prepare(sql)
  426. if err != nil {
  427. return nil, err
  428. }
  429. // Connect statement with database handler
  430. my.stmt_map[stmt.id] = stmt
  431. // Save SQL for reconnect
  432. stmt.sql = sql
  433. return stmt, nil
  434. }
  435. // Bind input data for the parameter markers in the SQL statement that was
  436. // passed to Prepare.
  437. //
  438. // params may be a parameter list (slice), a struct or a pointer to the struct.
  439. // A struct field can by value or pointer to value. A parameter (slice element)
  440. // can be value, pointer to value or pointer to pointer to value.
  441. // Values may be of the folowind types: intXX, uintXX, floatXX, bool, []byte,
  442. // Blob, string, Time, Date, Time, Timestamp, Raw.
  443. func (stmt *Stmt) Bind(params ...interface{}) {
  444. stmt.rebind = true
  445. if len(params) == 1 {
  446. // Check for struct binding
  447. pval := reflect.ValueOf(params[0])
  448. kind := pval.Kind()
  449. if kind == reflect.Ptr {
  450. // Dereference pointer
  451. pval = pval.Elem()
  452. kind = pval.Kind()
  453. }
  454. typ := pval.Type()
  455. if kind == reflect.Struct &&
  456. typ != timeType &&
  457. typ != dateType &&
  458. typ != timestampType &&
  459. typ != rawType {
  460. // We have a struct to bind
  461. if pval.NumField() != stmt.param_count {
  462. panic(mysql.ErrBindCount)
  463. }
  464. if !pval.CanAddr() {
  465. // Make an addressable structure
  466. v := reflect.New(pval.Type()).Elem()
  467. v.Set(pval)
  468. pval = v
  469. }
  470. for ii := 0; ii < stmt.param_count; ii++ {
  471. stmt.params[ii] = bindValue(pval.Field(ii))
  472. }
  473. stmt.binded = true
  474. return
  475. }
  476. }
  477. // There isn't struct to bind
  478. if len(params) != stmt.param_count {
  479. panic(mysql.ErrBindCount)
  480. }
  481. for ii, par := range params {
  482. pval := reflect.ValueOf(par)
  483. if pval.IsValid() {
  484. if pval.Kind() == reflect.Ptr {
  485. // Dereference pointer - this value i addressable
  486. pval = pval.Elem()
  487. } else {
  488. // Make an addressable value
  489. v := reflect.New(pval.Type()).Elem()
  490. v.Set(pval)
  491. pval = v
  492. }
  493. }
  494. stmt.params[ii] = bindValue(pval)
  495. }
  496. stmt.binded = true
  497. }
  498. // Execute prepared statement. If statement requires parameters you may bind
  499. // them first or specify directly. After this command you may use GetRow to
  500. // retrieve data.
  501. func (stmt *Stmt) Run(params ...interface{}) (res mysql.Result, err error) {
  502. defer catchError(&err)
  503. if stmt.my.net_conn == nil {
  504. return nil, mysql.ErrNotConn
  505. }
  506. if stmt.my.unreaded_reply {
  507. return nil, mysql.ErrUnreadedReply
  508. }
  509. // Bind parameters if any
  510. if len(params) != 0 {
  511. stmt.Bind(params...)
  512. } else if stmt.param_count != 0 && !stmt.binded {
  513. panic(mysql.ErrBindCount)
  514. }
  515. // Send EXEC command with binded parameters
  516. stmt.sendCmdExec()
  517. // Get response
  518. r := stmt.my.getResponse()
  519. r.binary = true
  520. res = r
  521. return
  522. }
  523. // Destroy statement on server side. Client side handler is invalid after this
  524. // command.
  525. func (stmt *Stmt) Delete() (err error) {
  526. defer catchError(&err)
  527. if stmt.my.net_conn == nil {
  528. return mysql.ErrNotConn
  529. }
  530. if stmt.my.unreaded_reply {
  531. return mysql.ErrUnreadedReply
  532. }
  533. // Allways delete statement on client side, even if
  534. // the command return an error.
  535. defer func() {
  536. // Delete statement from stmt_map
  537. delete(stmt.my.stmt_map, stmt.id)
  538. // Invalidate handler
  539. *stmt = Stmt{}
  540. }()
  541. // Send command
  542. stmt.my.sendCmdU32(_COM_STMT_CLOSE, stmt.id)
  543. return
  544. }
  545. // Resets a prepared statement on server: data sent to the server, unbuffered
  546. // result sets and current errors.
  547. func (stmt *Stmt) Reset() (err error) {
  548. defer catchError(&err)
  549. if stmt.my.net_conn == nil {
  550. return mysql.ErrNotConn
  551. }
  552. if stmt.my.unreaded_reply {
  553. return mysql.ErrUnreadedReply
  554. }
  555. // Next exec must send type information. We set rebind flag regardless of
  556. // whether the command succeeds or not.
  557. stmt.rebind = true
  558. // Send command
  559. stmt.my.sendCmdU32(_COM_STMT_RESET, stmt.id)
  560. // Get result
  561. stmt.my.getResult(nil, nil)
  562. return
  563. }
  564. // Send long data to MySQL server in chunks.
  565. // You can call this method after Bind and before Exec. It can be called
  566. // multiple times for one parameter to send TEXT or BLOB data in chunks.
  567. //
  568. // pnum - Parameter number to associate the data with.
  569. //
  570. // data - Data source string, []byte or io.Reader.
  571. //
  572. // pkt_size - It must be must be greater than 6 and less or equal to MySQL
  573. // max_allowed_packet variable. You can obtain value of this variable
  574. // using such query: SHOW variables WHERE Variable_name = 'max_allowed_packet'
  575. // If data source is io.Reader then (pkt_size - 6) is size of a buffer that
  576. // will be allocated for reading.
  577. //
  578. // If you have data source of type string or []byte in one piece you may
  579. // properly set pkt_size and call this method once. If you have data in
  580. // multiple pieces you can call this method multiple times. If data source is
  581. // io.Reader you should properly set pkt_size. Data will be readed from
  582. // io.Reader and send in pieces to the server until EOF.
  583. func (stmt *Stmt) SendLongData(pnum int, data interface{}, pkt_size int) (err error) {
  584. defer catchError(&err)
  585. if stmt.my.net_conn == nil {
  586. return mysql.ErrNotConn
  587. }
  588. if stmt.my.unreaded_reply {
  589. return mysql.ErrUnreadedReply
  590. }
  591. if pnum < 0 || pnum >= stmt.param_count {
  592. return mysql.ErrWrongParamNum
  593. }
  594. if pkt_size -= 6; pkt_size < 0 {
  595. return mysql.ErrSmallPktSize
  596. }
  597. switch dd := data.(type) {
  598. case io.Reader:
  599. buf := make([]byte, pkt_size)
  600. for {
  601. nn, ee := dd.Read(buf)
  602. if nn != 0 {
  603. stmt.my.sendLongData(stmt.id, uint16(pnum), buf[0:nn])
  604. }
  605. if ee == io.EOF {
  606. return
  607. }
  608. if ee != nil {
  609. return ee
  610. }
  611. }
  612. case []byte:
  613. for len(dd) > pkt_size {
  614. stmt.my.sendLongData(stmt.id, uint16(pnum), dd[0:pkt_size])
  615. dd = dd[pkt_size:]
  616. }
  617. stmt.my.sendLongData(stmt.id, uint16(pnum), dd)
  618. return
  619. case string:
  620. for len(dd) > pkt_size {
  621. stmt.my.sendLongData(
  622. stmt.id,
  623. uint16(pnum),
  624. []byte(dd[0:pkt_size]),
  625. )
  626. dd = dd[pkt_size:]
  627. }
  628. stmt.my.sendLongData(stmt.id, uint16(pnum), []byte(dd))
  629. return
  630. }
  631. return mysql.ErrUnkDataType
  632. }
  633. // Returns the thread ID of the current connection.
  634. func (my *Conn) ThreadId() uint32 {
  635. return my.info.thr_id
  636. }
  637. // Register MySQL command/query to be executed immediately after connecting to
  638. // the server. You may register multiple commands. They will be executed in
  639. // the order of registration. Yhis method is mainly useful for reconnect.
  640. func (my *Conn) Register(sql string) {
  641. my.init_cmds = append(my.init_cmds, sql)
  642. }
  643. // See mysql.Query
  644. func (my *Conn) Query(sql string, params ...interface{}) ([]mysql.Row, mysql.Result, error) {
  645. return mysql.Query(my, sql, params...)
  646. }
  647. // See mysql.QueryFirst
  648. func (my *Conn) QueryFirst(sql string, params ...interface{}) (mysql.Row, mysql.Result, error) {
  649. return mysql.QueryFirst(my, sql, params...)
  650. }
  651. // See mysql.QueryLast
  652. func (my *Conn) QueryLast(sql string, params ...interface{}) (mysql.Row, mysql.Result, error) {
  653. return mysql.QueryLast(my, sql, params...)
  654. }
  655. // See mysql.Exec
  656. func (stmt *Stmt) Exec(params ...interface{}) ([]mysql.Row, mysql.Result, error) {
  657. return mysql.Exec(stmt, params...)
  658. }
  659. // See mysql.ExecFirst
  660. func (stmt *Stmt) ExecFirst(params ...interface{}) (mysql.Row, mysql.Result, error) {
  661. return mysql.ExecFirst(stmt, params...)
  662. }
  663. // See mysql.ExecLast
  664. func (stmt *Stmt) ExecLast(params ...interface{}) (mysql.Row, mysql.Result, error) {
  665. return mysql.ExecLast(stmt, params...)
  666. }
  667. // See mysql.End
  668. func (res *Result) End() error {
  669. return mysql.End(res)
  670. }
  671. // See mysql.GetFirstRow
  672. func (res *Result) GetFirstRow() (mysql.Row, error) {
  673. return mysql.GetFirstRow(res)
  674. }
  675. // See mysql.GetLastRow
  676. func (res *Result) GetLastRow() (mysql.Row, error) {
  677. return mysql.GetLastRow(res)
  678. }
  679. // See mysql.GetRows
  680. func (res *Result) GetRows() ([]mysql.Row, error) {
  681. return mysql.GetRows(res)
  682. }
  683. // Escapes special characters in the txt, so it is safe to place returned string
  684. // to Query method.
  685. func (my *Conn) Escape(txt string) string {
  686. return mysql.Escape(my, txt)
  687. }
  688. func (my *Conn) Status() mysql.ConnStatus {
  689. return my.status
  690. }
  691. type Transaction struct {
  692. *Conn
  693. }
  694. // Starts a new transaction
  695. func (my *Conn) Begin() (mysql.Transaction, error) {
  696. _, err := my.Start("START TRANSACTION")
  697. return &Transaction{my}, err
  698. }
  699. // Commit a transaction
  700. func (tr Transaction) Commit() error {
  701. _, err := tr.Start("COMMIT")
  702. tr.Conn = nil // Invalidate this transaction
  703. return err
  704. }
  705. // Rollback a transaction
  706. func (tr Transaction) Rollback() error {
  707. _, err := tr.Start("ROLLBACK")
  708. tr.Conn = nil // Invalidate this transaction
  709. return err
  710. }
  711. func (tr Transaction) IsValid() bool {
  712. return tr.Conn != nil
  713. }
  714. // Binds statement to the context of transaction. For native engine this is
  715. // identity function.
  716. func (tr Transaction) Do(st mysql.Stmt) mysql.Stmt {
  717. if s, ok := st.(*Stmt); !ok || s.my != tr.Conn {
  718. panic("Transaction and statement doesn't belong to the same connection")
  719. }
  720. return st
  721. }
  722. func init() {
  723. mysql.New = New
  724. }