Skip to content

Commit 2cc627a

Browse files
methanejulienschmidt
authored andcommitted
Fix prepared statement (#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 4a0c3d7 commit 2cc627a

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
@@ -916,6 +916,12 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
916916
const minPktLen = 4 + 1 + 4 + 1 + 4
917917
mc := stmt.mc
918918

919+
// Determine threshould dynamically to avoid packet size shortage.
920+
longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1)
921+
if longDataSize < 64 {
922+
longDataSize = 64
923+
}
924+
919925
// Reset packet-sequence
920926
mc.sequence = 0
921927

@@ -1043,7 +1049,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
10431049
paramTypes[i+i] = byte(fieldTypeString)
10441050
paramTypes[i+i+1] = 0x00
10451051

1046-
if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
1052+
if len(v) < longDataSize {
10471053
paramValues = appendLengthEncodedInteger(paramValues,
10481054
uint64(len(v)),
10491055
)
@@ -1065,7 +1071,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
10651071
paramTypes[i+i] = byte(fieldTypeString)
10661072
paramTypes[i+i+1] = 0x00
10671073

1068-
if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
1074+
if len(v) < longDataSize {
10691075
paramValues = appendLengthEncodedInteger(paramValues,
10701076
uint64(len(v)),
10711077
)

0 commit comments

Comments
 (0)