From 40352b0098406d39399fb596b3c12fddfc59801a Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 9 Jan 2018 03:12:04 +0900 Subject: [PATCH 1/5] Fix prepared statement When there are many args and maxAllowedPacket is not enough, writeExecutePacket() attempted to use STMT_LONG_DATA even for 0byte string. But writeCommandLongData() doesn't support 0byte data. So it caused to send malfold packet. This commit loosen threshold for using STMT_LONG_DATA. --- packets.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packets.go b/packets.go index f63d25072..ec687d1f8 100644 --- a/packets.go +++ b/packets.go @@ -912,6 +912,11 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { const minPktLen = 4 + 1 + 4 + 1 + 4 mc := stmt.mc + longDataSize := mc.maxAllowedPacket / stmt.paramCount + if longDataSize < 16 { + longDataSize = 16 + } + // Reset packet-sequence mc.sequence = 0 @@ -1039,7 +1044,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 - if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 { + if len(v) < longDataSize { paramValues = appendLengthEncodedInteger(paramValues, uint64(len(v)), ) @@ -1061,7 +1066,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 - if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 { + if len(v) < longDataSize { paramValues = appendLengthEncodedInteger(paramValues, uint64(len(v)), ) From 2954ddce7fa96d2107cc9c94f7d3b957243fc116 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 9 Jan 2018 03:47:01 +0900 Subject: [PATCH 2/5] Change minimum size of LONG_DATA to 64byte --- packets.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packets.go b/packets.go index ec687d1f8..83b929250 100644 --- a/packets.go +++ b/packets.go @@ -912,9 +912,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { const minPktLen = 4 + 1 + 4 + 1 + 4 mc := stmt.mc - longDataSize := mc.maxAllowedPacket / stmt.paramCount - if longDataSize < 16 { - longDataSize = 16 + // Determine threshould dynamically to avoid packet size shortage as possible. + longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) + if longDataSize < 64 { + longDataSize = 64 } // Reset packet-sequence From 475ca2642c13f64d16eec5ddfcdf974f7e991261 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Wed, 10 Jan 2018 21:18:55 +0900 Subject: [PATCH 3/5] Add test which reproduce issue 730 --- driver_test.go | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/driver_test.go b/driver_test.go index 224a24c53..9e678ee15 100644 --- a/driver_test.go +++ b/driver_test.go @@ -1669,24 +1669,40 @@ func TestStmtMultiRows(t *testing.T) { // Regression test for // * more than 32 NULL parameters (issue 209) // * more parameters than fit into the buffer (issue 201) +// * parameters * 64 > max_allowed_packet (issue 734) func TestPreparedManyCols(t *testing.T) { - const numParams = defaultBufSize + numParams := []int{32, int(defaultBufSize), 65535} runTests(t, dsn, func(dbt *DBTest) { - query := "SELECT ?" + strings.Repeat(",?", numParams-1) - stmt, err := dbt.db.Prepare(query) - if err != nil { - dbt.Fatal(err) - } - defer stmt.Close() - // create more parameters than fit into the buffer - // which will take nil-values - params := make([]interface{}, numParams) - rows, err := stmt.Query(params...) - if err != nil { + for _, np := range numParams { + query := "SELECT ?" + strings.Repeat(",?", np-1) + stmt, err := dbt.db.Prepare(query) + if err != nil { + dbt.Fatal(err) + } + + // create more parameters than fit into the buffer + // which will take nil-values + params := make([]interface{}, np) + rows, err := stmt.Query(params...) + if err != nil { + stmt.Close() + dbt.Fatal(err) + } + rows.Close() + + // Create 0byte string which we can't send via STMT_LONG_DATA. + for i := 0; i < np; i++ { + params[i] = "" + } + rows, err = stmt.Query(params...) + if err != nil { + stmt.Close() + dbt.Fatal(err) + } + rows.Close() + stmt.Close() - dbt.Fatal(err) } - defer rows.Close() }) } From 2661e9061669de03febdd9decc22c2b1ad309604 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Wed, 10 Jan 2018 21:33:54 +0900 Subject: [PATCH 4/5] TestPreparedManyCols test only numParams = 65535 case --- driver_test.go | 51 +++++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/driver_test.go b/driver_test.go index 9e678ee15..7877aa979 100644 --- a/driver_test.go +++ b/driver_test.go @@ -1671,38 +1671,33 @@ func TestStmtMultiRows(t *testing.T) { // * more parameters than fit into the buffer (issue 201) // * parameters * 64 > max_allowed_packet (issue 734) func TestPreparedManyCols(t *testing.T) { - numParams := []int{32, int(defaultBufSize), 65535} + numParams := 65535 runTests(t, dsn, func(dbt *DBTest) { - for _, np := range numParams { - query := "SELECT ?" + strings.Repeat(",?", np-1) - stmt, err := dbt.db.Prepare(query) - if err != nil { - dbt.Fatal(err) - } - - // create more parameters than fit into the buffer - // which will take nil-values - params := make([]interface{}, np) - rows, err := stmt.Query(params...) - if err != nil { - stmt.Close() - dbt.Fatal(err) - } - rows.Close() + query := "SELECT ?" + strings.Repeat(",?", numParams-1) + stmt, err := dbt.db.Prepare(query) + if err != nil { + dbt.Fatal(err) + } + defer stmt.Close() - // Create 0byte string which we can't send via STMT_LONG_DATA. - for i := 0; i < np; i++ { - params[i] = "" - } - rows, err = stmt.Query(params...) - if err != nil { - stmt.Close() - dbt.Fatal(err) - } - rows.Close() + // create more parameters than fit into the buffer + // which will take nil-values + params := make([]interface{}, numParams) + rows, err := stmt.Query(params...) + if err != nil { + dbt.Fatal(err) + } + rows.Close() - stmt.Close() + // Create 0byte string which we can't send via STMT_LONG_DATA. + for i := 0; i < numParams; i++ { + params[i] = "" + } + rows, err = stmt.Query(params...) + if err != nil { + dbt.Fatal(err) } + rows.Close() }) } From d08f145b67bb8a34ec3d50074effb97865060368 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Sun, 14 Jan 2018 01:02:52 +0900 Subject: [PATCH 5/5] s/as possible// --- packets.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packets.go b/packets.go index 83b929250..afd131424 100644 --- a/packets.go +++ b/packets.go @@ -912,7 +912,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { const minPktLen = 4 + 1 + 4 + 1 + 4 mc := stmt.mc - // Determine threshould dynamically to avoid packet size shortage as possible. + // Determine threshould dynamically to avoid packet size shortage. longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) if longDataSize < 64 { longDataSize = 64