From e3d889be05e446eec86b30bd44edffcde7fad5fe Mon Sep 17 00:00:00 2001 From: Florent Poinsard <35779988+frouioui@users.noreply.github.com> Date: Thu, 16 Mar 2023 14:37:08 +0200 Subject: [PATCH] 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 --- go/mysql/query.go | 2 +- .../endtoend/vtgate/queries/misc/misc_test.go | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/go/mysql/query.go b/go/mysql/query.go index 0107e7606b..f8adb91f60 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -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") } diff --git a/go/test/endtoend/vtgate/queries/misc/misc_test.go b/go/test/endtoend/vtgate/queries/misc/misc_test.go index ac9cf7473b..2f77d20b78 100644 --- a/go/test/endtoend/vtgate/queries/misc/misc_test.go +++ b/go/test/endtoend/vtgate/queries/misc/misc_test.go @@ -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) +}