Giter VIP home page Giter VIP logo

mymysql's Introduction

Sorry for my poor English. If you can help with improving the English in this documentation, please contact me.

MyMySQL v1.5.4 (2015-01-08)

This package contains MySQL client API written entirely in Go. It is designed to work with the MySQL protocol version 4.1 or greater. It definitely works well with MySQL server version 5.0 and 5.1 (I use these versions of MySQL servers for my applications). Some people claim that mymysql works with older versions of MySQL protocol too.

Changelog

v1.5.4: Bugs fixed in native and godrv packages.

v1.5.3: Bugs fixed in new godrv code.

v1.5.1: Conn.NetConn method added.

v1.5: Needs Go 1.1 (time.ParseInLocation and net.Dialer) to compile.

v1.4: Stmt.ResetParams, Stmt.Map and Stmt.NumFields methods disappeared. New Stmt.Fields method. godrv implements driver.Queryer interface which improves performance when compiled with Go tip.

v1.3: Overall performance improved by factor 1.5 to 1.8. All Encode* functions now accept properly sized []byte slice as first argument.

v1.2: Faster execution of simple queries in mymysql/godrv. EscapeString method renamed to Escape.

v1.1: Client error codes moved from mymysql/native package to mymysql/mysql.

v1.0: Transactions added to autorc, new Transaction.IsValid method. I think this library is mature enough to release it as v1.0

v0.4.11: Add Reconnect, Register, SetMaxPktSize, Bind to autorc.

v0.4.10: New Clone method for create connection from other connection.

v0.4.9: New method for create connection from configuration in file: NewFromCF.

v0.4.8: New methods for obtain only first/last row from result set. Better implementation of discarding rows in End method.

v0.4.7: ScanRow and MakeRow methods added. ScanRow is more efficient than GetRow because it doesn't allocate memory for every row received from the server. godrv Value.Next method now uses the new ScanRow method.

v0.4.6: StatusOnly method added to mysql.Result.

v0.4.5: New autorc.Conn.PrepareOnce method.

v0.4.4:

  1. Row.Int, Row.Uint, Row.Int64, ... methods now panic in case of error.
  2. New Row.Float method.

v0.4.3:

  1. Fixed issue with panic when the server returns MYSQL_TYPE_NEWDECIMAL.
  2. Decimals are returned as float64 (previously they were returned as []byte).

v0.4.2:

  1. A lot of changes with MySQL time handling:
  • Datetime type replaced by time.Time.
  • Time type replaced by time.Duration.
  • Support for time.Time type added to godrv.
  1. row.Int64/row.Uint64 methods added.

  2. Rename BindParams to Bind.

v0.4.1:

BindParams supports Go bool type.

v0.4:

  1. Modular design:
  • MySQL wire protocol handling moved to mymysql/native
  • Thread safe wrapper of native engine in separate mymysql/thrsafe
  • mymysql/mysql package contains definitions of interfaces to engines and common (engine-independent) functions.
  • Automatic reconnect interface moved to mymysql/autorc.
  1. mysql.New and other functions returns mostly interface types. So all previously exported members were converted to methods (with except mysql.Row and mysql.Field - their definition didn't changed).

  2. Transactions added. If you use *mymysql/thrsafe" engine transactions are fully thread safe.

  3. Driver for exp/sql.

Installing

To install all subpackages of mymysql you need to get three of them:

$ go get github.com/ziutek/mymysql/thrsafe
$ go get github.com/ziutek/mymysql/autorc
$ go get github.com/ziutek/mymysql/godrv

or just run one command to get all subpackages:

$ go get -v github.com/ziutek/mymysql/...

go get automagically selects the proper version of mymysql for your Go release. After this command mymysql is ready to use.

Testing

For testing you will need to create the test database and a test user:

mysql> create database test;
mysql> grant all privileges on test.* to testuser@localhost;
mysql> set password for testuser@localhost = password("TestPasswd9");

Make sure that MySQL max_allowed_packet variable in my.cnf is equal or greater than 34M (In order to test long packets).

The default MySQL server address is 127.0.0.1:3306.

Next run tests:

$ cd $GOPATH/src/github.com/ziutek/mymysql
$ ./all.bash test

Examples

Example 1

package main

import (
	"os"
	"github.com/ziutek/mymysql/mysql"
	_ "github.com/ziutek/mymysql/native" // Native engine
	// _ "github.com/ziutek/mymysql/thrsafe" // Thread safe engine
)

func main() {
	db := mysql.New("tcp", "", "127.0.0.1:3306", user, pass, dbname)

	err := db.Connect()
	if err != nil {
		panic(err)
	}

	rows, res, err := db.Query("select * from X where id > %d", 20)
	if err != nil {
		panic(err)
	}

	for _, row := range rows {
		for _, col := range row {
			if col == nil {
				// col has NULL value
			} else {
				// Do something with text in col (type []byte)
			}
		}
		// You can get specific value from a row
		val1 := row[1].([]byte)

		// You can use it directly if conversion isn't needed
		os.Stdout.Write(val1)

		// You can get converted value
		number := row.Int(0)      // Zero value
		str    := row.Str(1)      // First value
		bignum := row.MustUint(2) // Second value

		// You may get values by column name
		first := res.Map("FirstColumn")
		second := res.Map("SecondColumn")
		val1, val2 := row.Int(first), row.Str(second)
	}
}

If you do not want to load the entire result into memory you may use Start and GetRow methods:

res, err := db.Start("select * from X")
checkError(err)

// Print fields names
for _, field := range res.Fields() {
	fmt.Print(field.Name, " ")
}
fmt.Println()

// Print all rows
for {
	row, err := res.GetRow()
		checkError(err)

		if row == nil {
			// No more rows
			break
		}

	// Print all cols
	for _, col := range row {
		if col == nil {
			fmt.Print("<NULL>")
		} else {
			os.Stdout.Write(col.([]byte))
		}
		fmt.Print(" ")
	}
	fmt.Println()
}

GetRow method allocates a new chunk of memory for every received row. If your query returns hundreds of rows you should opt for the ScanRow method to avoid unnecessary allocations:

// Print all rows
row := res.MakeRow()
for {
	err := res.ScanRow(row)
	if err == io.EOF {
		 // No more rows
		 break
	}
	checkError(err)

	// Print all cols
	// [...]
}

Example 2 - prepared statements

You can use Run or Exec method for prepared statements:

stmt, err := db.Prepare("insert into X values (?, ?)")
checkError(err)

type Data struct {
	Id  int
	Tax *float32 // nil means NULL
}

data = new(Data)

for {
	err := getData(data)
	if err == endOfData {
		 break       
	}
	checkError(err)

	_, err = stmt.Run(data.Id, data.Tax)
	checkError(err)
}

getData is the function which retrieves data from somewhere and set Id and Tax fields of the Data struct. In the case of Tax field getData may assign a pointer the retrieved variable or nil if NULL should be stored in database.

If you pass parameters to Run or Exec method, the data is rebound on every method call. This isn't efficient if the statement will be executed more than once. You can bind parameters and use Run or Exec method without parameters, to avoid these unnecessary rebinds. Warning! If you use Bind in multithreaded applications, you should ensure that no other thread will use Bind for the same statement, until you no longer need bound parameters.

The simplest way to bind parameters is:

stmt.Bind(data.Id, data.Tax)

but you can't use it in our example, because parameters bound this way can't be changed by getData function. You may modify bindings like this:

stmt.Bind(&data.Id, &data.Tax)

and now it should work properly. But in our example there is better solution:

stmt.Bind(data)

If Bind method has one parameter, and this parameter is a struct or a pointer to the struct, it treats all fields of this struct as parameters and binds them.

This is the improved code of the previous example:

data = new(Data)
stmt.Bind(data)

for {
	err := getData(data)
	if isEndOfData(error) {
		 break       
	}
	checkError(err)

	_, err = stmt.Run()
	checkError(err)
}

Example 3 - using SendLongData in conjunction with http.Get

_, err = db.Start("CREATE TABLE web (url VARCHAR(80), content LONGBLOB)")
checkError(err)

ins, err := db.Prepare("INSERT INTO web VALUES (?, ?)")
checkError(err)

var url string

ins.Bind(&url, []byte(nil)) // []byte(nil) for properly type binding

for  {
	// Read URL from stdin
	url = ""
	fmt.Scanln(&url)
	if len(url) == 0 {
		// Stop reading if URL is blank line
		break
	}

	// Make a connection
	resp, err := http.Get(url)
	checkError(err)

	// We can retrieve response directly into database because 
	// the resp.Body implements io.Reader. Use 8 kB buffer.
	err = ins.SendLongData(1, resp.Body, 8192)
	checkError(err)

	// Execute insert statement
	_, err = ins.Run()
	checkError(err)
}

Example 4 - multi statement / multi result

res, err := db.Start("select id from M; select name from M")
checkError(err)

// Get result from first select
for {
	row, err := res.GetRow()
	checkError(err)
	if row == nil {
		// End of first result
		break
	}

	// Do something with with the data
	functionThatUseId(row.Int(0))
}

// Get result from second select
res, err = res.NextResult()
checkError(err)
if res == nil {
	panic("Hmm, there is no result. Why?!")
}
for {
	row, err := res.GetRow()
	checkError(err)
	if row == nil {
		// End of second result
		break
	}

	// Do something with with the data
	functionThatUseName(row.Str(0))
}

Example 5 - transactions

import (
	"github.com/ziutek/mymysql/mysql"
	_ "github.com/ziutek/mymysql/thrsafe" // for thread safe transactions
)
// [...]

// Statement prepared before transaction begins
ins, err := db.Prepare("insert A values (?, ?)")
checkError(err)

// Begin a new transaction
tr, err := db.Begin()
checkError(err)

// Now db is locked, so any method that uses db and sends commands to
// MySQL server will be blocked until Commit or Rollback is called.

// Commands in transaction are thread safe to
go func() {
	_, err = tr.Start("insert A values (1, 'jeden')")
	checkError(err)
} ()
_, err = tr.Start("insert A values (2, 'dwa')")
checkError(err)

// You can't use statements prepared before transaction in the usual way,
// because the connection is locked by the Begin method. You must bind the statement
// to the transaction before using it.
_, err = tr.Do(ins).Run(3, "three")
checkError(err)

// For a greater number of calls
ti := tr.Do(ins)
_, err = ti.Run(4, "four")
checkError(err)
_, err = ti.Run(5, "five")
checkError(err)

// At the end you can Commit or Rollback. tr is invalidated and using it
// after Commit/Rollback will cause a panic.
tr.Commit()

Example 6 - autoreconn interface

import (
	"github.com/ziutek/mymysql/autorc"
	_ "github.com/ziutek/mymysql/thrsafe" // You may also use the native engine
)

// [...]

db := autorc.New("tcp", "", "127.0.0.1:3306", user, pass, dbname)

// Initilisation commands. They will be executed after each connect.
db.Register("set names utf8")

// There is no need to explicitly connect to the MySQL server
rows, res, err := db.Query("SELECT * FROM R")
checkError(err)

// Now we are connected.

// It does not matter if connection will be interrupted during sleep, eg
// due to server reboot or network down.
time.Sleep(9e9)

// If we can reconnect in no more than db.MaxRetries attempts this
// statement will be prepared.
sel, err := db.Prepare("SELECT name FROM R where id > ?")
checkError(err)

// We can destroy our connection server side
_, _, err = db.Query("kill %d", db.Raw.ThreadId())
checkError(err)

// But it doesn't matter
sel.Bind(2)
rows, res, err = sel.Exec()
checkError(err)

Example 7 - use database/sql with mymysql driver

import (
    "database/sql"
    _"github.com/ziutek/mymysql/godrv"
)

// [...]

// Open new connection. The URI need to have the following syntax:
//
//   [PROTOCOL_SPECIFIC*]DBNAME/USER/PASSWD
//
// where protocol specific part may be empty (this means connection to
// local server using default protocol). Currently possible forms:
//   DBNAME/USER/PASSWD
//   unix:SOCKPATH*DBNAME/USER/PASSWD
//   unix:SOCKPATH,OPTIONS*DBNAME/USER/PASSWD
//   tcp:ADDR*DBNAME/USER/PASSWD
//   tcp:ADDR,OPTIONS*DBNAME/USER/PASSWD
//
// OPTIONS can contain comma separated list of options in form:
//   opt1=VAL1,opt2=VAL2,boolopt3,boolopt4
// Currently implemented options:
//   laddr   - local address/port (eg. 1.2.3.4:0)
//   timeout - connect timeout in format accepted by time.ParseDuration

// Register initialisation commands
// (workaround, see http://codereview.appspot.com/5706047)
godrv.Register("SET NAMES latin2") // Overrides default utf8
godrv.Register("CREATE TABLE IF NOT EXISTS my_table ( ... )")

// Create a connection handler
db, err := sql.Open("mymysql", "test/testuser/TestPasswd9")
checkErr(err)

// For other information about database/sql see its documentation.

ins, err := db.Prepare("INSERT my_table SET txt=?")
checkErr(err)

res, err := ins.Exec("some text")
checkErr(err)

id, err := res.LastInsertId()
checkErr(err)

checkErr(ins.Close(ins))

rows, err := db.Query("SELECT * FROM go")
checkErr(err)

for rows.Next() {
	var id int
	var txt string
	checkErr(rows.Scan(&id, &txt))
	// Do something with id and txt
}

checkErr(db.Close())

Example 8 - use stored procedures

import (
	"github.com/ziutek/mymysql/mysql"
	_ "github.com/ziutek/mymysql/thrsafe" // or native
)

// [...]

res, err := my.Start("CALL MyProcedure(1, 2, 3)")
checkErr(err)

// Procedure can return more than one result set so we have to read all
// results up to the result that doesn't include result set (status only
// result).
for !res.StatusOnly() {
	rows, err := res.GetRows()
	checkErr(err)

	useRows(rows)		

	res, err := res.NextResult()
	checkErr(err)
	if res == nil {
		panic("nil result from procedure")
	}
}

Example 9 - transactions using autorc

import (
	"github.com/ziutek/mymysql/autorc"
	_ "github.com/ziutek/mymysql/thrsafe" // You may also use the native engine
)

// [...]

db := autorc.New("tcp", "", "127.0.0.1:3306", user, pass, dbname)

var stmt1, stmt2 autorc.Stmt

func updateDb() {
	err := db.PrepareOnce(&stmt1, someSQL1)
	checkDbErr(err)
	err = db.PrepareOnce(&stmt2, someSQL2)
	checkDbErr(err)

	err = db.Begin(func(tr mysql.Transaction, args ...interface{}) error {
		// This function will be called again if returns a recoverable error
		s1 := tr.Do(stmt1.Raw)
		s2 := tr.Do(stmt2.Raw)
		if _, err := s1.Run(); err != nil {
			return err
		}
		if _, err := s2.Run(); err != nil {
			return err
		}
		// You have to commit or rollback before return
		return tr.Commit()
	})
	checkDbErr(err)
}

Additional examples are in examples directory.

Type mapping

In the case of classic text queries, all variables that are sent to the MySQL server are embedded in the text query. Thus you always convert them to a string and send them embedded in an SQL query:

rows, res, err := db.Query("select * from X where id > %d", id)

After text query you always receive a text result. Mysql text result corresponds to []byte type in mymysql. It isn't string type due to avoidance of unnecessary type conversions. You can always convert []byte to string yourself:

fmt.Print(string(rows[0][1].([]byte)))

or using Str helper method:

fmt.Print(rows[0].Str(1))

There are other helper methods for data conversion like Int or Uint:

fmt.Print(rows[0].Int(1))

All three above examples return value received in row 0 column 1. If you prefer to use the column names, you can use res.Map which maps result field names to corresponding indexes:

name := res.Map("name")
fmt.Print(rows[0].Str(name))

In case of prepared statements, the type mapping is slightly more complicated. For parameters sent from the client to the server, Go/mymysql types are mapped for MySQL protocol types as below:

         string  -->  MYSQL_TYPE_STRING
         []byte  -->  MYSQL_TYPE_VAR_STRING
    int8, uint8  -->  MYSQL_TYPE_TINY
  int16, uint16  -->  MYSQL_TYPE_SHORT
  int32, uint32  -->  MYSQL_TYPE_LONG
  int64, uint64  -->  MYSQL_TYPE_LONGLONG
      int, uint  -->  protocol integer type which match size of int
           bool  -->  MYSQL_TYPE_TINY
        float32  -->  MYSQL_TYPE_FLOAT
        float64  -->  MYSQL_TYPE_DOUBLE
      time.Time  -->  MYSQL_TYPE_DATETIME
mysql.Timestamp  -->  MYSQL_TYPE_TIMESTAMP
     mysql.Date  -->  MYSQL_TYPE_DATE
  time.Duration  -->  MYSQL_TYPE_TIME
     mysql.Blob  -->  MYSQL_TYPE_BLOB
            nil  -->  MYSQL_TYPE_NULL

The MySQL server maps/converts them to a particular MySQL storage type.

For received results MySQL storage types are mapped to Go/mymysql types as below:

                             TINYINT  -->  int8
                    UNSIGNED TINYINT  -->  uint8
                            SMALLINT  -->  int16
                   UNSIGNED SMALLINT  -->  uint16
                      MEDIUMINT, INT  -->  int32
    UNSIGNED MEDIUMINT, UNSIGNED INT  -->  uint32
                              BIGINT  -->  int64
                     UNSIGNED BIGINT  -->  uint64
                               FLOAT  -->  float32
                              DOUBLE  -->  float64
                             DECIMAL  -->  float64
                 TIMESTAMP, DATETIME  -->  time.Time
                                DATE  -->  mysql.Date
                                TIME  -->  time.Duration
                                YEAR  -->  int16
    CHAR, VARCHAR, BINARY, VARBINARY  -->  []byte
 TEXT, TINYTEXT, MEDIUMTEXT, LONGTEX  -->  []byte
BLOB, TINYBLOB, MEDIUMBLOB, LONGBLOB  -->  []byte
                                 BIT  -->  []byte
                           SET, ENUM  -->  []byte
                                NULL  -->  nil

Big packets

This package can send and receive MySQL data packets that are bigger than 16 MB. This means that you can receive response rows bigger than 16 MB and can execute prepared statements with parameter data bigger than 16 MB without using SendLongData method. If you want to use this feature you need to change the default mymysql setting using the Conn.SetMaxPktSize method and change max_allowed_packet value in your MySQL server configuration.

Thread safe engine

If you import "mymysql/thrsafe" engine instead of "mymysql/native" engine all methods are thread safe, unless the description of the method says something else.

If one thread is calling Query or Exec method, other threads will be blocked if they call Query, Start, Exec, Run or other method which send data to the server, until Query/Exec return in first thread.

If one thread is calling Start or Run method, other threads will be blocked if they call Query, Start, Exec, Run or other method which send data to the server, until all results and all rows will be readed from the connection in first thread.

In most of my web applications I use the autorecon interface with thrsafe engine. For any new connection, one goroutine is created. There is one persistent connection to MySQL server shared by all goroutines. Applications are usually running on dual-core machines with GOMAXPROCS=2. I use siege to test any application before put it into production. There is example output from siege:

# siege my.httpserver.pl -c25 -d0 -t 30s
** SIEGE 2.69
** Preparing 25 concurrent users for battle.
The server is now under siege...
Lifting the server siege..      done.
Transactions:                   3212 hits
Availability:                 100.00 %
Elapsed time:                  29.83 secs
Data transferred:               3.88 MB
Response time:                  0.22 secs
Transaction rate:             107.68 trans/sec
Throughput:	                    0.13 MB/sec
Concurrency:                   23.43
Successful transactions:        3218
Failed transactions:               0
Longest transaction:            9.28
Shortest transaction:           0.01

To do

  1. Complete documentation

Known bugs

  1. There is MySQL "bug" in the SUM function. If you use prepared statements SUM returns DECIMAL value, even if you sum integer column. mymysql returns decimals as float64 so cast result from sum to integer (or use Row.Int) causes panic.

Documentation

mysql native thrsafe autorc godrv

mymysql's People

Contributors

aeronotix avatar alml avatar codelingobot avatar danielheath avatar dsymonds avatar hugomfernandes avatar kevinburke avatar korbjt avatar kovetskiy avatar marcuswestin avatar martianzhang avatar michalderkacz avatar serge-v avatar sharuzzaman avatar tcard avatar testwill avatar xackery avatar zeebo avatar ziutek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mymysql's Issues

Unexpected EOF

I'm using Start() and then looping over the rows via ScanRow() for a query with about 250k rows in the results. The issue I'm having, is that after looping through ~3260 rows I always get an "unexpected EOF" error result from ScanRow().

Any ideas on a workaround or potential fix in this package?

Some notes:

  • mysql --version: mysql Ver 14.14 Distrib 5.1.41, for debian-linux-gnu (x86_64) using readline 6.1
  • mysqld is running on localhost, so unlikely to be network issues
  • go version: go version go1.0.2

Drop mysql, autorc, thrsafe; supply only godrv

It is a controversial issue :)

I'm sure you split things up into 4 different APIs for some good reason, but I don't clearly see why. Can you explain your reasoning?

My thought is: Go provides a very nice stdlib API for database access. The hooks for the driver code enable it to be threadsafe, and automatically reconnect on errors. So, I would propose that the threadsafe, auto-reconnecting functionality can (and should) be merged into the godrv driver code, and that mysql, autorc, and thrsafe packages be dropped.

autoreconnect(keepalive) in godrv

Hi Ziutek,

I want to use your mymysql package for my project. And I want to make
my application configurable about which database to use, sqlite3 or mysql,
based on the config file. So I need to use the database/sql interface
for a consistent api no matter which database I choose.

But there is a problem for me: There is no keepalilve in the database/sql
driver of mymysql, and for the reasons above, I don't want to use the
mymysql-specific api in the autorc package. So why not add autoconnect in mymysql/godrv?

Thanks!

'select sum(...)' results in 'no rows in result set'

Hi,

I'm not sure if I'm missing something important, but it seems that there's no way to perform "SELECT SUM(...)" queries without triggering an error. I'm using the godrv interface, and I haven't tested this behavior with other interfaces. Here is a test that fails (added at the end of driver_test.go):

var num int

// Ok
row := db.QueryRow("select 41 as test")
err = row.Scan(&num)
checkErr(t, err)

// Fails
row = db.QueryRow("select sum(41) as test")
err = row.Scan(&num)
checkErr(t, err)

Both queries return the same result using a MySQL client, the first test passes, but the second fails with the following error:

sql: no rows in result set

Connection pool?

Does mymysql support pooling connections? I didn't find it anywhere in the doc or the source, so I assume the answer is no. Is there any plan to add this?

mymysql doesn't work with Go tip

This may not be a problem when Go 1.1 comes out, but maybe you want to fix it anyway.

For the record, this is the bug I filed against Go:

https://code.google.com/p/go/issues/detail?id=4476

The github.com/ziutek/mymysql driver calls net.ResolveTCPAddr with an empty string for the network.

In Go 1.0, that worked.

In Go tip, that returns net.UnkownNetworkError("")

I just wasted time debugging this when I recompiled Camlistore, which happens to use ziutek/mymysql. I didn't get a nice UnkownNetworkError, either, since it had been eaten by other errors.

For Go 1 compatibility reasons, should we special-case "" in ResolveTCPAddr to mean "tcp"? I would like to.

wrong number of values for bind

I'm trying to read from the database using prepared statements. However I always get the error "wrong number of values for bind". The attribute param_count of the prepared statement is 0, although it should be 1.

I'm using the following statement:

SELECT HEX(DiverID), DiverName, DiverNick, BirthDay FROM Diver WHERE DiverName='?'

I also tried:

SELECT HEX(DiverID), DiverName, DiverNick, BirthDay FROM Diver WHERE DiverName=?

I'm using the following code to query the database:

    query = "SELECT HEX(DiverID), DiverName, DiverNick, BirthDay FROM Diver WHERE DiverName='?'"

    statement, statementError := Db.Prepare(query)
    if statementError != nil {
            log.Printf("Could not prepare SELECT statement: %s", statementError)
            return nil, statementError
    }

    log.Printf("%s\n", statement)

    statement("Markus")

When I try to run this code, I always get this error. I'm not really sure if this is a bug, or if I'm doing anything wrong...

Received #1461 error from MySQL server: "Can't create more than max_prepared_stmt_count statements (current value: 16382)"

I'm getting the above error in some code that amounts to (using the "database/sql" interface):

func main() { db := sql.Open("mymysql", ...) stmt, _ := db.Prepare("INSERT INTO a_table (a_column) VALUES (?)" for /* a lot of times */ { stmt.Exec(9) } }

Since the Prepare() statement is not in the loop, I wouldn't expect that I would run into a problem with the number of prepared statements, but apparently I am.

Understanding this library

Hi,

Having some trouble understanding what's the need for laddr and raddr in the Con type?

func (my *Conn) connect() (err error) {

Care to explain? Also, I can't seem to get tcp connections working using "localhost" and 127.0.0.1 is returning that the connection was refused (same behaviour when I use other languages), any ideas?

I'm quite new to Go so this could be the issue.

a error when go install which build in windows

hi,
i got the error when i build my project in windows

C:\Users\yejianfeng\Documents\360云盘\代码\webdemo>go install webdemo

github.com/ziutek/mymysql/native

C:\Users\yejianfeng\Documents\360锟斤拷锟斤拷\锟斤拷锟斤拷\webdemo\src\github.co
m\ziutek\mymysql\native\binding.go:4: can't find import: "github.com/ziutek/mymy
sql/mysql"

it is ok when i build it in linux.

my import code like this:
import (
"net/http"
"github.com/ziutek/mymysql/mysql"
_ "github.com/ziutek/mymysql/thrsafe"
"encoding/json"
)

could you kindly help me?

Unexpected or unknown result packet

Hello.

I'm write some code:

package main

import (
    "fmt"
    "database/sql"
    _ "github.com/ziutek/mymysql/godrv"
)

const (
    DB_PROTOCOL = "tcp"
    DB_ADDRESS = "127.0.0.1"
    DB_PORT = "3306"
    DB_NAME = "testbase"
    DB_USER = "root"
    DB_PASS = ""
)

func OpenDB() *sql.DB {
    db, err := sql.Open("mymysql", fmt.Sprintf("%s:%s:%s*%s/%s/%s", DB_PROTOCOL, DB_ADDRESS, DB_PORT, DB_NAME, DB_USER, DB_PASS))
    if err != nil { panic(err) }
    return db
}
/*
 * RequestsList
 */
type RequestsList struct {
    Id            int64      `json:"id"`
    Guid          string      `json:"guid"`
    Number        string      `json:"number"`
}

func main() {
    request_id := 1
    request_guid := "qwe-asd-zxc"
    request_number := "123"
    request_list := new(RequestsList)
    db := OpenDB()
    defer db.Close()
    row := db.QueryRow("SELECT * FROM `requests` WHERE `id` = ? AND `guid` = ? AND `number` = ?", request_id, request_guid, request_number)
    err := row.Scan(&request_list.Id, &request_list.Guid, &request_list.Number)
    if err != nil {
        fmt.Println("ERR:", err)
    } else {
        fmt.Println("Id:", request_list.Id)
        fmt.Println("Guid:", request_list.Guid)
        fmt.Println("Number:", request_list.Number)
    }
    return
}

Then try to execute it on notebook:

$ go run untitled.go 
Id: 1
Guid: qwe-asd-zxc
Number: 123

Then try to execute it on home server:

$ go run untitled.go 
ERR: unexpected or unknown result packet

Crashed in native/result.go

panic(UNK_RESULT_PKT_ERROR)

On notebook and home server i have identical version of Go and mymysql:

$ cd /opt/go
$ hg identify
dc5e410f0b4c weekly/weekly.2012-03-27
$ cd src/pkg/github.com/ziutek/mymysql
$ git rev-parse --verify HEAD
e107b1fc238e138fc4863d051dccd99311c429be
$ git log | head -n 8
commit e107b1fc238e138fc4863d051dccd99311c429be
Merge: 49cd60b 035f750
Author: Michał Derkacz <[email protected]>
Date:   Tue Jun 12 06:39:51 2012 -0700

    Merge pull request #25 from AeroNotix/master

    Grammatical edit of the readme file

On notebook:

$  cat /etc/issue
Welcome to openSUSE 12.1 "Asparagus"
$ mysql --version
mysql  Ver 14.14 Distrib 5.5.25, for Linux (x86_64) using readline 6.2

On home server:

$  cat /etc/issue
CentOS release 5.8 (Final)
$ mysql --version
mysql  Ver 14.14 Distrib 5.5.25a, for Linux (x86_64) using readline 5.1

I try to install another version of MySQL on home server:

$ mysql --version
mysql  Ver 14.12 Distrib 5.0.95, for redhat-linux-gnu (x86_64) using readline 5.1

But nothing has changed.

Can you help me?

godrv Exec() creates new prepared statements

Here's a base test case that fails on my machine. Error message:

--- FAIL: godrv.TestTooManyStatements (51.87 seconds)
driver_test.go:11: Error: Received #1461 error from MySQL server: "Can't create more than max_prepared_stmt_count statements (current value: 16382)"

It looks like this is godrv related -- i was unable to repro this in native_test.go with a similar test against the native interface.

I haven't dug into the root cause yet. If you have time, please take a look. Otherwise I may get to this tomorrow.

// Add to: driver_test.go
func TestTooManyStatements(t *testing.T) {
db, err := sql.Open("mymysql", "test/testuser/TestPasswd9")
checkErr(t, err)
_, err = db.Exec("drop table if exists M")
checkErr(t, err)
_, err = db.Exec("create table M (id int primary key, str varchar(20))")
checkErr(t, err)

defer db.Exec("drop table M")
defer db.Close()

query := "insert into M (id, str) values (?, ?)"
insert, err := db.Prepare(query)
checkErr(t, err)
defer insert.Close()

for i := 0; i < 20000 && err == nil; i++ {
    _, err = insert.Exec(i, "mystr")
    checkErr(t, err)

    if i % 100 == 0 {
        fmt.Printf("Inserted %d rows\n", i)
    }
}
}

queries to mysql 4.1.21 don't work

Any statements that do not return data work fine - any SELECTs or SHOWs result in ErrBadConn. Everything works fine on MySQL 5.0+.

I'm using github.com/ziutek/mymysql/godrv with database/sql

fallthrough compile issue with codecs.go on tip

Seeing the below error on tip. Seems a fallthrough is not required as it's the final case in the switch. Commented out it works fine.

# github.com/ziutek/mymysql/native
../ziutek/mymysql/native/codecs.go:285: cannot fallthrough final case in switch

mymysql driver doesn't recover from 'broken pipe'

I use mymysql as a driver for database/sql. I create one *sql.DB in my main method, via sql.Open("mymysql", address), and share it between multiple goroutines. Those goroutines are long-lived, and perform regular SELECTs, which look like

rows, err := db.Query("...")
if err != nil { ... }
for rows.Next() {
    ...
}

After some time, db.Query() returns error write tcp 1.2.3.4:5678: broken pipe. After that, all subsequent calls to db.Query() fail.

I believe that database/sql should detect such errors from the driver, and roll over to a new connection—see, for example, this issue. My problem makes me believe mymysql driver is not behaving correctly when encountering this error.

Can you confirm my usage is correct? Can you investigate why this is not behaving as expected?

Old passwords

Connecting as a user with the old password format results in an error of dubious helpfulness ("unexpected or unknown result packet").

Add a go1 branch

I recommend adding a go1 branch for the go tool to check out (e.g. not a tag). As long as no changes are made to that branch, it's pretty straightforward to push changes over to it when you're ready for them to be "released"

set -e
git tag $RELEASENAME
git push --tags
git checkout go1
git merge master
git push --all
git checkout master

Expected speed boost from using goroutines?

I've been experimenting with making a program run concurrently using goroutines, I've implemented my program as mentioned here https://gist.github.com/27e84d3dde014f4d63fe (with and without GOMAXPROCS)

I expected that the execution speed would improve (each modifier function makes a query to the database, and iterates over the rows in the result set, appending them to slices on the struct.) that seemed to be classical IO bound, and prime for concurrent execution.

When researching how best to parallelise my script, I started using goroutines as above (as against a weird channel based solution which made the code quite tough on the eyes) I stumbled upon the following:

Goroutines will yield on any kind of IO,syscalls,channel operations or
a call to runtime.Gosched()

This is exactly how so-called green threads work in Ruby, so I'm quite familiar with the concept...

I wanted to ask if this was something you needed to implement in mymysql, or whether you already had, or whether it's something you get for free by using the socket library.

Finally would be the query about whether you would expect to see an improvement from using goroutines in that kind of situation. Might it also be that I am reusing the same db object throughout all goroutines?

Thanks, not really sure if this is an issue, or a feature request or a cry for help. Feel free to close if it's way out of bounds, thanks.

MYSQL_TYPE_NEWDECIMAL and large numbers

Sorry to bother you again, but here's another case that triggers an error, this happens when using large numbers (I'm still using godrv) :

 var v int64
 sql = "select sum(4123232323232) as test"
 row := db.QueryRow(sql)
 err = row.Scan(&v)
 checkErr(t, err)

Which results in the following:

    driver_test.go:14: Error: sql: Scan error on column index 0: converting string "4.123232323232e+12" to a int64: strconv.ParseInt: parsing "4.123232323232e+12": invalid syntax

Using strconv.ParseFloat(string(data), 64), this error isn't triggered because it handles that notation. The problem seems to trigger only with MYSQL_TYPE_NEWDECIMAL types, as a "select 4123232323232" works.

Auto reconnect results in unknown prepared statement handler error

I have a test case where my go application can't execution any prepared statement. A prepared statement will result in an 'unknown prepared statement handler' error, if the application lost its database connection because of e.a. mysql shutdown or crash and mysql is up and running again before a prepared statement is being executed.

My understanding is that the problem is caused by calling the Connect method in the function below. Because when a new connection is established the prepared statements aren't resubmitted. Calling method reconnectIfNetErr would resubmit prepared statements, but return because a connection is already established by the Connect method.

autorecon.go

...
func (c *Conn) connectIfNotConnected() (err error) {
        if c.Raw.IsConnected() {
                return
        }   
        err = c.Raw.Connect()
        nn := 0
        c.reconnectIfNetErr(&nn, &err)
        return
}
...

Changing the Query kill to connection close in the unit test, will result in the same are as described in my test case above.

autorecon_test.go

...
func TestAutoConnectReconnect(t *testing.T) {
    ...
    // Kill the connection
    //c.Query("kill %d", c.Raw.ThreadId())
    // Disconnect
    c.Raw.Close()

    // Bind insert parameters
    ins.Raw.Bind(1, "jeden")
    // Insert into table
    // Will result in an error because the prepared statements are unknown
    _, _, err = ins.Exec()
    checkErr(t, err, nil)
    ...

At the moment I don't have a suggestion to solve this problem.

more End problems

If ExecFirst() returns a row, End() must be called - otherwise not. The semantics are not clear to me - is this desired?

test error in Go weekly.2012-02-14

Hi,
Hope you can update the code to work with weekly.2012-02-14

[weekly@640m mymysql]$ go test github.com/ziutek/mymysql/native
--- FAIL: TestQuery (0.15 seconds)
native_test.go:121: Bad result:
res=&{my:0x18740e00 binary:false field_count:1 fields:[0x1872fd80] fc_map:map[Str:0] message:[] affected_rows:0 insert_id:0 warning_count:0 status:34 eor_returned:true}
exp=&{my:0x18740e00 binary:false field_count:1 fields:[0x1872fc80] fc_map:map[Str:0] message:[] affected_rows:0 insert_id:0 warning_count:0 status:2 eor_returned:true}
--- FAIL: TestBigBlob (0.33 seconds)
native_test.go:43: Error: write tcp 127.0.0.1:3306: broken pipe
--- FAIL: TestSendLongData (0.18 seconds)
native_test.go:43: Error: Received #1105 error from MySQL server: "Parameter of prepared statement which is set through mysql_send_long_data() is longer than 'max_long_data_size' bytes"
FAIL
FAIL github.com/ziutek/mymysql/native 2.609s
[weekly@640m mymysql]$ go version
go version weekly.2012-02-14 +43cf9b39b647
[weekly@640m mymysql]$

Why all the common query use prepare?

I am a sphinx client ...
sphinx implement a mysql protocol .but not support PREPARE cmd
I set mysql general log on
get this

121226 18:03:51 47216 Connect [email protected] on K8_v2
47216 Query SET NAMES utf8
47216 Prepare SELECT SKey FROM FTSKey WHERE SKey = '123' ORDER BY Type ASC, PCount DESC, SCount DESC, VMTime DESC LIMIT 10
47216 Execute SELECT SKey FROM FTSKey WHERE SKey = '123' ORDER BY Type ASC, PCount DESC, SCount DESC, VMTime DESC LIMIT 10
47216 Close stmt

so all the common query use PREPARE cmd

not the QUERY cmd

in my option
if Query cmd without args, then use QUERY cmd (0x30)
if have args, USE PREPARE cmd?

Escaping in godrv

Hello!

First of all: Thanks for your work on the MySQL driver.

I'm using the godrv package. When executing insert or update commands, the fields get escaped and quoted. Enabling the query log in MySQL, I see output like this:

INSERT INTO users (tenant_id, view_id, name) VALUES ('1', '<nil>', 'Oliver')

where the ..._id columns are of type int(11) and view_id is nullable. Seems like nil values in Go get quoted as '<nil>', which fails e.g. with foreign key constraints.

It did work fine just days ago. Am I missing something?

If you need more information, just let me know.

(Using go1.0.3 here.)

multi statement query error

package main

import (
    "database/sql"
    _ "github.com/ziutek/mymysql/godrv"
    "log"
)

func main() {
    // Create a connection handler
    db, err := sql.Open("mymysql", "tcp:localhost:3306*test/root/111111")

    _, err = db.Exec("select 1; select 1;")
    if err != nil {
        log.Fatalln(err)
    }
}

$ go run mysql-test.go

2012/08/09 22:59:08 Received #1064 error from MySQL server: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select 1' at line 1"
exit status 1

go 1.0.2

MySql closes IDLE connections

When client opens connection and doesn't send queries during some timeout, mysql closes connection (
http://dev.mysql.com/doc/refman/5.0/en/gone-away.html ).
As result, on client side we get error when trying to send any query on closed connection. Consider the sample:

var db *autorc.Conn
var userSel *autorc.Stmt
...

//during program startup
db = autorc.New(...)
userSel, err = db.Prepare("select * from User where Id=?")
CheckError(err)

//some time T passed without queries
rows, res, err := userSel.Exec(id)
if(err!=nil){
log.Panicf("read user, Exec failed %+v", err)
}

When "silent time" T exceeds mysql wait_timeout, which is 8 hours by default, we get panic with message (on Windows) :
read user, Exec failed, WSASend an established connection was aborted by the software in your host machine

Expected behavior
With normal connections (not autoreconnectable) the error is what's expected.
With autorc connection I don't expect this error, as autoreconnection can handle it.

Additional details
Due to 8 hours default wait timeout the problem is hard to reproduce. Typically:

MySQL drops a connection after 8 hours
The software is used during the day, but isn’t used during the night, therefore the connection times out in the night
Therefore in the morning, the program installed the day before no longer works
We can change wait_timeout like this:
mysql> SET @@GLOBAL.wait_timeout=300

Panic using row.Bool when Query method is used

Using row.Bool when the Query method is used results in a panic. A rewrite to prepared statement works fine.

Looks like a row misses some field types when using Query.

Row data when using the Exec method on a prepared statement:
[%!s(uint32=21) %!s(uint32=9) %!s(uint32=1) %!s(uint32=19) bla1 bla2 bla3 bla4 %!s(int8=0)]

Row data when using the Query method:
[21 9 1 19 bla1 bla2 bla3 bla4 0]

Both a printed with fmt.Printf("%s", row).

Using native package.

Could not prepare statement

Could not prepare statement : Received #1461 error from MySQL server: "Can't create more than max_prepared_stmt_count statements (current value: 16382)"

How do I close a prepared stmt? and What if I dont want too, so that I can have my server reuse them, instead of preparing them for each request?

[Query] Best Performance from MyMysql

Hi,

Firstly thank you for writing such a good library. This is not a bug I am just seeking some advice on using the library. I have currently written my database layer using MyMysql for a big project and I am very happy with how everything is working but I wanted to check that I am using it correctly as I think I might be opening and closing connections every time I connect to the database and I was hoping to use connection pooling type functionality.

I have a getConnection class which is used by all methods and I then use defer to close the connection at the end of the method:

import (
    "github.com/ziutek/mymysql/mysql"
    "github.com/ziutek/mymysql/thrsafe"
    "strconv"
    "tribeguru/configuration"
)

func getConnection() (mysql.Conn, error) {
    db := thrsafe.New("tcp", "", configuration.Get("dbHost"), configuration.Get("dbUser"), configuration.Get("dbPass"), configuration.Get("dbName"))
    err := db.Connect()
    if err != nil {
        return nil, err
    }
    return db, nil
}

type Course struct {
    Id          int
    PersonId    int
    Name        string
    Description string
}

func getCourse(row mysql.Row) (*Course, error) {
    if row == nil {
        return nil, errors.New("No row passed")
    }
    course := &Course{
        Id:          row.Int(0),
        PersonId:    row.Int(1),
        Name:        row.Str(2),
        Description: row.Str(3),
    }
    return course, nil
}

func GetCourseById(id int) (*Course, error) {
    db, err := getConnection()
    if err != nil {
        return nil, err
    }
    defer db.Close()
    row, _, err := db.QueryFirst("SELECT Id, PersonId, Name, Description FROM Course WHERE Id=%d;", id)
    if err != nil {
        return nil, err
    }
    course, err := getCourse(row)
    return course, err
}

As you can see in the GetCourseById I defer db.Close() so it closes at the end of the method. Does the MyMysql library support connection pooling or should I use the auto reconnect library and never close the connection?

Unable to connect to account with no password

Sorry - maybe I just don't know how to do it...

The thing is that I am not able to login as any mysql user that has no password set.

When I put "" as the password, the Connect() gives me:
Received #1045 error from MySQL server: "Access denied for user 'go'@'localhost' (using password: YES)"

If I try nil as the password parameter - it doesn't even compile.

godrv has trouble reading mediumint

it appears godrv has issues when reading rows that contain mediumint. it only reads the first row and if you check rows.Err() it reports either a packet sequence error or a network error. this works fine if i use mymysql directly or i don't select the mediumint column.

native_test.go:121: Bad result:

I tried installing mymysql today (2012-04-25) and am seeing it fail
some of its tests.

My mysql server version is 5.5.20, I see from your readme that
you specifically support 5.0 and 5.1, so perhaps my problem is
a too-new database version.

This is on a Mac OS X 10.7.3 darwin_amd64 system:

$ hg summary
parent: 12872:920e9d1ffd1f go1 release tip
go1
branch: release-branch.go1
commit: (clean)
update: (current)

$ ls src/pkg/github.com/ pkg/darwin_amd64/github.com/
pkg/darwin_amd64/github.com/:

src/pkg/github.com/:
nsf

$ go get github.com/ziutek/mymysql/thrsafe
$ go get github.com/ziutek/mymysql/autorc
$ go get github.com/ziutek/mymysql/godrv

$ cd src/pkg/github.com/ziutek/mymysql/

$ ./all.bash test
ok github.com/ziutek/mymysql/mysql 0.418s
--- FAIL: TestQuery (0.18 seconds)
native_test.go:121: Bad result:
res=&{my:0xf840000e10 binary:false field_count:1 fields:[0xf8400533f0] fc_map:map[Str:0] message:[] affected_rows:0 insert_id:0 warning_count:0 status:34 eor_returned:true}
exp=&{my:0xf840000e10 binary:false field_count:1 fields:[0xf8400532a0] fc_map:map[Str:0] message:[] affected_rows:0 insert_id:0 warning_count:0 status:2 eor_returned:true}
&{Catalog:def Db:test Table:P OrgTable:p Name:i OrgName:ii DispLen:11 Flags:4097 Type:3 Scale:0}
&{Catalog:def Db:test Table:P OrgTable:p Name:s OrgName:ss DispLen:60 Flags:0 Type:253 Scale:0}
&{Catalog:def Db:test Table:P OrgTable:p Name:d OrgName:dd DispLen:19 Flags:128 Type:12 Scale:0}
--- FAIL: TestPrepared (0.01 seconds)
native_test.go:249: Bad result statement: res=&{0xf840000d20 1 select ii i, ss s, dd d from P where ii = ? and ss = ? [ ] false false [0xf840053850 0xf8400538c0 0xf840053930] map[d:2 i:0 s:1] 3 2 0 2} exp=&{ 0 [] false false [0xf8400535b0 0xf840053620 0xf840053690] map[d:2 i:0 s:1] 3 2 0 2}
FAIL
FAIL github.com/ziutek/mymysql/native 3.087s
ok github.com/ziutek/mymysql/thrsafe 0.013s
--- FAIL: TestAutoConnectReconnect (0.49 seconds)
autorecon_test.go:18: Error: Received #1317 error from MySQL server: "Query execution was interrupted"
FAIL
FAIL github.com/ziutek/mymysql/autorc 0.515s
ok github.com/ziutek/mymysql/godrv 0.312s

This is the contents of /etc/my.cnf:

$ cat /etc/my.cnf
[mysqld]

log=/usr/local/var/log/mysqld.log

max_allowed_packet=35M

Panic "unlock of unlocked mutex" using database/sql interface

The following stack trace happens when I do a very simple operation:

    db, err := sql.Open("mymysql", .....)
    rows, err := db.Query("select * from test.tbl1")
    for rows.Next() {
        i := myType{}
        err = rows.Scan(&i.Foo, &i.Bar...)

Here is the error, which you can see happens after row 2. There are only 2 rows:

2012/12/18 13:19:09 Retrieving row 1
2012/12/18 13:19:09 Retrieving row 2
2012/12/18 13:19:09 http: panic serving [::1]:58792: sync: unlock of unlocked mutex
/usr/local/go/src/pkg/net/http/server.go:589 (0x3a6c2)
    _func_004: buf.Write(debug.Stack())
/usr/local/go/src/pkg/runtime/proc.c:1443 (0xfd22)
    panic: reflect·call(d->fn, d->args, d->siz);
/usr/local/go/src/pkg/sync/mutex.go:76 (0x67cd4)
    (*Mutex).Unlock: panic("sync: unlock of unlocked mutex")
/Users/baron/Documents/go/src/github.com/VividCortex/mymysql/thrsafe/thrsafe.go:35 (0x95157)
    com/VividCortex/mymysql/thrsafe.(*Conn).unlock: c.mutex.Unlock()
/Users/baron/Documents/go/src/github.com/VividCortex/mymysql/thrsafe/thrsafe.go:149 (0x95985)
    com/VividCortex/mymysql/thrsafe.(*Result).ScanRow: res.conn.unlock()
/Users/baron/Documents/go/src/github.com/VividCortex/mymysql/mysql/utils.go:198 (0x9c473)
    com/VividCortex/mymysql/mysql.GetLastRow: err := r.ScanRow(row)
/Users/baron/Documents/go/src/github.com/VividCortex/mymysql/mysql/utils.go:214 (0x9c55f)
    com/VividCortex/mymysql/mysql.End: _, err := GetLastRow(r)
/Users/baron/Documents/go/src/github.com/VividCortex/mymysql/thrsafe/thrsafe.go:258 (0x963d8)
    com/VividCortex/mymysql/thrsafe.(*Result).End: return mysql.End(res)
/Users/baron/Documents/go/src/github.com/VividCortex/mymysql/godrv/driver.go:121 (0x22dcf)
    com/VividCortex/mymysql/godrv.rowsRes.Close: err := r.my.End()
/Users/baron/Documents/go/src/github.com/VividCortex/mymysql/godrv/driver.go:0 (0x2410b)
    com/VividCortex/mymysql/godrv.(*rowsRes).Close: ???
/usr/local/go/src/pkg/database/sql/sql.go:1008 (0x1ce2d)
    (*Rows).Close: err := rs.rowsi.Close()
/usr/local/go/src/pkg/database/sql/sql.go:922 (0x1c680)
    (*Rows).Next: rs.Close()
[omitting a couple of levels for privacy]
/usr/local/go/src/pkg/net/http/server.go:703 (0x2f533)
    HandlerFunc.ServeHTTP: f(w, r)
/usr/local/go/src/pkg/net/http/server.go:941 (0x30113)
    (*ServeMux).ServeHTTP: mux.handler(r).ServeHTTP(w, r)
/usr/local/go/src/pkg/net/http/server.go:669 (0x2f385)
    (*conn).serve: handler.ServeHTTP(w, w.req)
/usr/local/go/src/pkg/runtime/proc.c:271 (0xe214)
    goexit: runtime·goexit(void)

As you can see I've done this with our fork of the code, but it's recent and that should not be the issue as far as I can see.

panic: runtime error: call of nil func value

I have been using mymysql for about half a year, and it always work fine.
In about last week, it breeks with the error:"panic: runtime error: call of nil func value"

db := mysql.New("tcp", "", "127.0.0.1:3306", "root", "a1b2c3", "hostye")

I am using ubuntu 12.04(amd 64), and the go version is 1.0.2. mysql version:5.5.24,

go run main.go
panic: runtime error: call of nil func value
[signal 0xb code=0x1 addr=0x0 pc=0x0]

goroutine 1 [running]:
main.main()
/home/joe/dev/go/hostye/src/main.go:9 +0xb9
goroutine 2 [syscall]:
created by runtime.main
/home/joe/app/go/src/pkg/runtime/proc.c:221
exit status 2

Any help we be appreciated.

question about encode&decode

func DecodeU24(buf []byte) uint32 {
return (uint32(buf[2])<<8|uint32(buf[1]))<<8 | uint32(buf[0])
}

func EncodeU24(val uint32) []byte {
return []byte{byte(val), byte(val >> 8), byte(val >> 16)}
}

why the DecodeU24's impl is not:

func DecodeU24(buf []byte) uint32 {
return (uint32(buf[2])<<16|uint32(buf[1]))<<8 | uint32(buf[0])
}

Cannot reuse connection with multi-statement stored procedures

I have problems with stored procedures which contain multiple statements (of which at least one returns some data), or something similar. I can provide an example but I did not have time to refine it in order to find out the exact error. I hope it's simple enough to let you find out the bug and know if my solution makes sense.

I have a stored procedure like this:

CREATE PROCEDURE foo(...)
BEGIN
  INSERT INTO table (...) VALUES (...);
  SELECT LAST_INSERT_ID() AS 'lastId';
END

and this code:

conn := native.New("tcp", "", "x.x.x.x:3306", "user", "password")
conn.Connect()
conn.Use("db")
rows, res, err := conn.Query("CALL foo(...)")
fmt.Println(rows, res, err)
rows, res, err := conn.Query("CALL foo(...)")
fmt.Println(rows, res, err)

The output:

[[[50 49 56 55 51]]] &{0xf84004d000 false 1 [0xf8400002a0] map[lastId:0] [] 0 0 0 10 true} <nil>
[] <nil> reply is not completely read
[...]

There is no apparent way to solve this without closing and reopening the connection: all the following queries of the same connection will have "reply is not completely read" as error.

A tentative solution would add this loop after each Query:

for res.MoreResults() {
    // Eat remaining results.
    res, err = res.NextResult()
    fmt.Println(res, err)
}

It works BUT I had to patch native/mysql.go in func (my *Conn) getResponse() (res *Result) by adding an "else" clause to the if res.field_count != block, so to make:

  if res.field_count != 0 {
      // This query can return rows (this isn't OK result)
      my.unreaded_reply = true
+ } else {
+ my.unreaded_reply = false
  }

Without this, my.unreaded_reply is never set back to false after having been set to true (as it would happen only in GetRow but before reading the second result "MoreResults()" is still true so the "my.unreaded_reply = false" statement is never executed).

With my patch, and by doing the NextResult loop, it seems to work, but it seems a bit strange (as, in any case, the result I get is empty), so probably it's not the correct way to fix this issue.

Thanks!

thrsafe api report "unlock of unlocked mutex" when executeing multi statements

hi I am using the thrsafe api to execute multiple statements, and it panic and report "unlock of unlocked mutex" .
the SQL is "set @rtn= 0; CALL sp_test(1, @rtn); select @rtn as aaa;"
i intented to call a stored procedure and get the result .

Here is how i reproduced this issue

package main

import (
    "fmt"
    "github.com/ziutek/mymysql/mysql"
    "os"
)

import "github.com/ziutek/mymysql/thrsafe"

//import "github.com/ziutek/mymysql/native"

func printOK() {
    fmt.Println("OK")
}

func checkError(err error) {
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

func checkedResult(rows []mysql.Row, res mysql.Result, err error) ([]mysql.Row,
    mysql.Result) {
    checkError(err)
    return rows, res
}

func main() {
    user := "root"
    pass := "mysql"
    dbname := "test"
    addr := "127.0.0.1:3306"

    //  db := native.New("tcp", "", addr, user, pass, dbname)
    db := thrsafe.New("tcp", "", addr, user, pass, dbname)

    fmt.Printf("Connect to %s... ", addr)
    checkError(db.Connect())
    printOK()

    //  res, err := db.Start("set @rtn= 0; CALL sp_test(1, @rtn); select @rtn as aaa;")     //it panic!
    res, err := db.Start("set @rtn= 0; select @rtn as aaa;")                 // it panic!
    //  res, err := db.Start("select * from user; select count(*) from user;")    //it works!

    if err == nil {
        printOK()
    } else if e, ok := err.(*mysql.Error); ok {
        fmt.Println(e)
        return
    } else {
        checkError(err)
    }
    index := 0
    for {
        index++

        fmt.Printf("loop :%d res :%+v more:%+v only:%+v\n", index, res.Fields(), res.MoreResults(), res.StatusOnly())

        if !res.StatusOnly() {

            row, err := res.GetRows()
            if err != nil {

                fmt.Printf("GetRow error :%s \n", err)
            }
            if row == nil {

                fmt.Printf("why nil\n")
                break
            }
            fmt.Printf("row :%+v  \n", row)
        }
        if res.MoreResults() {
            res, err = res.NextResult()
            if err != nil {
                fmt.Printf("Get NextResult error err:%s\n", err)
                break
            }
            if res == nil {
                panic("3Hmm, there is no result. Why?!")
            }
        } else {
            fmt.Printf("good! no result, break\n")
            break
        }

    }
    fmt.Print("Close connection... ")
    checkError(db.Close())
    printOK()
}

when i run this code , it produce this msg

panic: sync: unlock of unlocked mutex

goroutine 1 [running]:
sync.(*Mutex).Unlock(0xf840057060, 0x36a1b3d8)
    /usr/local/go/src/pkg/sync/mutex.go:76 +0x7f
github.com/ziutek/mymysql/thrsafe.(*Conn).unlock(0xf840042740, 0xf840046100)
    /usr/local/go/src/pkg/github.com/ziutek/mymysql/thrsafe/thrsafe.go:36 +0x4f
github.com/ziutek/mymysql/thrsafe.(*Result).ScanRow(0xf840043820, 0xf8400466e0, 0x100000001, 0x7fb39b3bfca0, 0x10, ...)
    /usr/local/go/src/pkg/github.com/ziutek/mymysql/thrsafe/thrsafe.go:136 +0x160
github.com/ziutek/mymysql/mysql.GetRow(0xf84008e120, 0xf840043820, 0xf840043820, 0xf84008e120, 0xf840043820, ...)
    /usr/local/go/src/pkg/github.com/ziutek/mymysql/mysql/utils.go:33 +0x6d
github.com/ziutek/mymysql/thrsafe.(*Result).GetRow(0xf840043820, 0x0, 0x0, 0x1)
    /usr/local/go/src/pkg/github.com/ziutek/mymysql/thrsafe/thrsafe.go:142 +0x49
github.com/ziutek/mymysql/mysql.GetRows(0xf84008e120, 0xf840043820, 0xf8400466d0, 0x100000001, 0x0, ...)
    /usr/local/go/src/pkg/github.com/ziutek/mymysql/mysql/utils.go:64 +0x74
github.com/ziutek/mymysql/thrsafe.(*Result).GetRows(0xf840043820, 0x706f6f6c00000000, 0x7fb39b3bfea0, 0x400000004)
    /usr/local/go/src/pkg/github.com/ziutek/mymysql/thrsafe/thrsafe.go:220 +0x49
main.main()
    /home/white/Code/go/mysql/mysql.go:63 +0x508
....

when I changed the api to native api, it could get the correct result , But thrsafe api failed!

Rows not commiting to database

I am having problems inserting rows into a table. The row id is incremented but the row does not display when I query it. I have checked and auto commit is enabled on the server.

import (
    "github.com/ziutek/mymysql/mysql"
    _ "github.com/ziutek/mymysql/thrsafe"
)

type Course struct {
    Id          int
    PersonId    int
    Name        string
    Description string
}

type CourseRepository struct {

}

func (this *CourseRepository) GetConnection() (mysql.Conn, error) {
    db := mysql.New("tcp", "", "127.0.0.1:3306", "*****", "*****", "*****")
    err := db.Connect()
    if err != nil {
        return nil, err
    }
    return db, nil
}

func (this *CourseRepository) Insert(course *Course) (err error) {
    db, err := this.GetConnection()
    if err != nil {
        return err
    }
    //defer db.Close()
    stmt, err := db.Prepare("INSERT INTO Course (PersonId, Name, Description) VALUES (?,?,?)")
    if err != nil {
        return err
    }
    result, err := stmt.Run(course.PersonId, course.Name, course.Description)
    if err == nil {
        course.Id = int(result.InsertId())
    }
    return err
}

Mysql

DROP TABLE IF EXISTS `Course`;
CREATE TABLE `Course` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `Name` text,
  `Description` text,
  `PersonId` int(11) DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=97 DEFAULT CHARSET=latin1;

I am not sure if I have found a bug or if I am doing something wrong.

native_test.go:263 fails on mac os x

Using

  • go release-branch.go1
  • mymysql v0.2-170-g443635f
  • mysql Ver 14.14 Distrib 5.5.27, for osx10.7 (i386) using readline 5.1

on a Mac OS X system, I see the following error during the native test:

$ go test github.com/ziutek/mymysql/native &{Catalog:def Db:test Table:P OrgTable:p Name:i OrgName:ii DispLen:11 Flags:4097 Type:3 Scale:0} &{Catalog:def Db:test Table:P OrgTable:p Name:s OrgName:ss DispLen:60 Flags:0 Type:253 Scale:0} &{Catalog:def Db:test Table:P OrgTable:p Name:d OrgName:dd DispLen:19 Flags:128 Type:12 Scale:0} --- FAIL: TestPrepared (0.02 seconds) native_test.go:263: Bad result statement: res=&{0xf8400842d0 1 select ii i, ss s, dd d from P where ii = ? and ss = ? [<nil> <nil>] false false [0xf840065770 0xf8400657e0 0xf840065850] map[s:1 d:2 i:0] 3 2 0 2} exp=&{<nil> 0 [] false false [0xf840065460 0xf8400654d0 0xf840065540] map[s:1 d:2 i:0] 3 2 0 2} FAIL FAIL github.com/ziutek/mymysql/native 3.088s

I've got a packet capture of the client/server request/response, but unfortunately wireshark isn't advanced enough to let pull apart the actual mysql wire protocol.

I don't see a way to make a file attachment here, so I've made a gzip'ed copy of the pcap available on google docs:
https://docs.google.com/open?id=0B-XOm9UO5BkgaFdFd0FvOUZBU3c

Problem with character encoding

This is almost certainly me making a stupid mistake but I don't know where else to ask!

I am attempting to insert UTF-8 encoded data into a table. If I insert the data directly using the mysql command prompt, it works fine. If I use mymysql, L’ Échafaud becomes L’ Échafaud.

It was my understanding that mymysql uses UTF-8 by default. Just in case I added the explicit db.Register("set names utf8") but that hasn't helped either.

Is there something else I need to do in Go to insert UTF-8 encoded strings?

dbConn.Prepare(sql) error on valid sql statement

Working sql. Tested pasting this text on the shell.

INSERT
INTO users (email,
password,
status,
signup_date,
zipcode,
fname,
lname)
VALUES (
'[email protected]',
'asdf',
'unverified',
now(),
'111',
'asdf',
'asdf'
);
SELECT LAST_INSERT_ID();

Error by using ? where the quotes are like this

`INSERT
      INTO users (email,
    password,
    status,
    signup_date,
    zipcode,
    fname,
    lname)
      VALUES (
      ?,
      ?,
      'unverified',
      now(),
      ?,
      ?,
      ?
      );
      SELECT LAST_INSERT_ID();`

That will cause a:

Cannot create new user sql prepared statement:Received #1064 error from MySQL server: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select last_insert_id()' at line 1"

blob -- bad connection

when i create a table like this

var tbl_email string = CREATE TABLE IF NOT EXISTS email ( eid INT(10) NOT NULL AUTO_INCREMENT, md5 CHAR(64) NOT NULL, created DATETIME NULL, time_zone VARCHAR(256) NULL, sdk VARCHAR(64) NULL, software VARCHAR(256) NULL, cpu VARCHAR(256) NULL, device VARCHAR(256) NULL, exception VARCHAR(256) NULL, camera360 VARCHAR(256) NULL, summary MediumBlob NULL, detail VARCHAR(256) NULL, -- detail MediumBlob NULL, PRIMARY KEY (eid) )

the Go data struct as follows:
type Email struct {
Eid int PK
Md5 string
Created time.Time
TimeZone string
Sdk string
Software string
Cpu string
Device string
Exception string
Camera360 string
Summary []byte
Detail string //Detail []byte
}

when the Detail's sql type is MediumBlob , insert into the 'email' will failed with error: "Bad Connection", but it's not fail every time, fox example, insert 100 times, the operation will success in 50,60, 15,5 ..., the len(Detail) >=1Mb

Get UNK_RESULT_PKT_ERROR on Connect

The mymysql work well with other version,
but on this version(5.0.77), it cannot connect:

system:
Centos 5.5 32-bit

mysql server version:
mysql Ver 14.12 Distrib 5.0.77, for redhat-linux-gnu (i686) using readline 5.1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.