Fix `panic` when executing a prepare statement with over `65,528` parameters (#12614) (#12629)

* fix type conversion in query.go for the bitMap size



* enhance the TestHighNumberOfParams test



* fix test comment



---------

Signed-off-by: Florent Poinsard <florent.poinsard@outlook.fr>
This commit is contained in:
Florent Poinsard 2023-03-16 14:37:08 +02:00 коммит произвёл GitHub
Родитель ab1d0fe888
Коммит e3d889be05
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 48 добавлений и 1 удалений

Просмотреть файл

@ -573,7 +573,7 @@ func (c *Conn) parseComStmtExecute(prepareData map[uint32]*PrepareData, data []b
}
if prepare.ParamsCount > 0 {
bitMap, pos, ok = readBytes(payload, pos, int((prepare.ParamsCount+7)/8))
bitMap, pos, ok = readBytes(payload, pos, (int(prepare.ParamsCount)+7)/8)
if !ok {
return stmtID, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "reading NULL-bitmap failed")
}

Просмотреть файл

@ -17,8 +17,14 @@ limitations under the License.
package misc
import (
"database/sql"
"fmt"
"strconv"
"strings"
"testing"
_ "github.com/go-sql-driver/mysql"
"github.com/stretchr/testify/require"
"vitess.io/vitess/go/test/endtoend/cluster"
@ -113,3 +119,44 @@ func TestCast(t *testing.T) {
mcmp.AssertMatches("select cast('3.2' as double)", `[[FLOAT64(3.2)]]`)
mcmp.AssertMatches("select cast('3.2' as unsigned)", `[[UINT64(3)]]`)
}
// This test ensures that we support PREPARE statement with 65530 parameters.
// It opens a MySQL connection using the go-mysql driver and execute a select query
// it then checks the result contains the proper rows and that it's not failing.
func TestHighNumberOfParams(t *testing.T) {
mcmp, closer := start(t)
defer closer()
mcmp.Exec("insert into t1(id1) values (0), (1), (2), (3), (4)")
paramCount := 65530
// create the value and argument slices used to build the prepare stmt
var vals []any
var params []string
for i := 0; i < paramCount; i++ {
vals = append(vals, strconv.Itoa(i))
params = append(params, "?")
}
// connect to the vitess cluster
db, err := sql.Open("mysql", fmt.Sprintf("@tcp(%s:%v)/%s", vtParams.Host, vtParams.Port, vtParams.DbName))
require.NoError(t, err)
// run the query
r, err := db.Query(fmt.Sprintf("SELECT /*vt+ QUERY_TIMEOUT_MS=10000 */ id1 FROM t1 WHERE id1 in (%s) ORDER BY id1 ASC", strings.Join(params, ", ")), vals...)
require.NoError(t, err)
// check the results we got, we should get 5 rows with each: 0, 1, 2, 3, 4
// count is the row number we are currently visiting, also correspond to the
// column value we expect.
count := 0
for r.Next() {
j := -1
err := r.Scan(&j)
require.NoError(t, err)
require.Equal(t, j, count)
count++
}
require.Equal(t, 5, count)
}