Skip to content

Commit d1a8b86

Browse files
methaneBrigitte Lamarche
authored and
Brigitte Lamarche
committed
Fix prepared statement (go-sql-driver#734)
* 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. * Change minimum size of LONG_DATA to 64byte * Add test which reproduce issue 730 * TestPreparedManyCols test only numParams = 65535 case * s/as possible//
1 parent f853432 commit d1a8b86

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

Diff for: driver_test.go

+14-3
Original file line numberDiff line numberDiff line change
@@ -1669,24 +1669,35 @@ func TestStmtMultiRows(t *testing.T) {
16691669
// Regression test for
16701670
// * more than 32 NULL parameters (issue 209)
16711671
// * more parameters than fit into the buffer (issue 201)
1672+
// * parameters * 64 > max_allowed_packet (issue 734)
16721673
func TestPreparedManyCols(t *testing.T) {
1673-
const numParams = defaultBufSize
1674+
numParams := 65535
16741675
runTests(t, dsn, func(dbt *DBTest) {
16751676
query := "SELECT ?" + strings.Repeat(",?", numParams-1)
16761677
stmt, err := dbt.db.Prepare(query)
16771678
if err != nil {
16781679
dbt.Fatal(err)
16791680
}
16801681
defer stmt.Close()
1682+
16811683
// create more parameters than fit into the buffer
16821684
// which will take nil-values
16831685
params := make([]interface{}, numParams)
16841686
rows, err := stmt.Query(params...)
16851687
if err != nil {
1686-
stmt.Close()
16871688
dbt.Fatal(err)
16881689
}
1689-
defer rows.Close()
1690+
rows.Close()
1691+
1692+
// Create 0byte string which we can't send via STMT_LONG_DATA.
1693+
for i := 0; i < numParams; i++ {
1694+
params[i] = ""
1695+
}
1696+
rows, err = stmt.Query(params...)
1697+
if err != nil {
1698+
dbt.Fatal(err)
1699+
}
1700+
rows.Close()
16901701
})
16911702
}
16921703

Diff for: packets.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,12 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
927927
const minPktLen = 4 + 1 + 4 + 1 + 4
928928
mc := stmt.mc
929929

930+
// Determine threshould dynamically to avoid packet size shortage.
931+
longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1)
932+
if longDataSize < 64 {
933+
longDataSize = 64
934+
}
935+
930936
// Reset packet-sequence
931937
mc.sequence = 0
932938
mc.compressionSequence = 0
@@ -1055,7 +1061,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
10551061
paramTypes[i+i] = byte(fieldTypeString)
10561062
paramTypes[i+i+1] = 0x00
10571063

1058-
if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
1064+
if len(v) < longDataSize {
10591065
paramValues = appendLengthEncodedInteger(paramValues,
10601066
uint64(len(v)),
10611067
)
@@ -1077,7 +1083,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
10771083
paramTypes[i+i] = byte(fieldTypeString)
10781084
paramTypes[i+i+1] = 0x00
10791085

1080-
if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
1086+
if len(v) < longDataSize {
10811087
paramValues = appendLengthEncodedInteger(paramValues,
10821088
uint64(len(v)),
10831089
)

0 commit comments

Comments
 (0)