Skip to content

Commit

Permalink
executor: fix prepared protocol charset (#58872) (#58906)
Browse files Browse the repository at this point in the history
close #58870
  • Loading branch information
ti-chi-bot authored Jan 15, 2025
1 parent 3029ea6 commit 1219706
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
21 changes: 14 additions & 7 deletions pkg/executor/prepared.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ type PrepareExec struct {
// If it's generated from executing "prepare stmt from '...'", the process is parse -> plan -> executor
// If it's generated from the prepare protocol, the process is session.PrepareStmt -> NewPrepareExec
// They both generate a PrepareExec struct, but the second case needs to reset the statement context while the first already do that.
// Also, the second case need charset_client param since SQL is directly passed from clients.
// While the text-prepare already transformed charset by parser.
needReset bool
}

Expand All @@ -84,23 +86,28 @@ func (e *PrepareExec) Next(ctx context.Context, _ *chunk.Chunk) error {
return nil
}
}
charset, collation := vars.GetCharsetInfo()
var (
stmts []ast.StmtNode
err error
)
var params []parser.ParseParam
if e.needReset {
params = vars.GetParseParams()
} else {
var paramsArr [2]parser.ParseParam
charset, collation := vars.GetCharsetInfo()
paramsArr[0] = parser.CharsetConnection(charset)
paramsArr[1] = parser.CollationConnection(collation)
params = paramsArr[:]
}
if sqlParser, ok := e.Ctx().(sqlexec.SQLParser); ok {
// FIXME: ok... yet another parse API, may need some api interface clean.
stmts, _, err = sqlParser.ParseSQL(ctx, e.sqlText,
parser.CharsetConnection(charset),
parser.CollationConnection(collation))
stmts, _, err = sqlParser.ParseSQL(ctx, e.sqlText, params...)
} else {
p := parser.New()
p.SetParserConfig(vars.BuildParserConfig())
var warns []error
stmts, warns, err = p.ParseSQL(e.sqlText,
parser.CharsetConnection(charset),
parser.CollationConnection(collation))
stmts, warns, err = p.ParseSQL(e.sqlText, params...)
for _, warn := range warns {
e.Ctx().GetSessionVars().StmtCtx.AppendWarning(util.SyntaxWarn(warn))
}
Expand Down
24 changes: 24 additions & 0 deletions pkg/executor/prepared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package executor_test

import (
"context"
"fmt"
"strconv"
"strings"
Expand Down Expand Up @@ -1273,3 +1274,26 @@ func TestMaxPreparedStmtCount(t *testing.T) {
err := tk.ExecToErr("prepare stmt3 from 'select ? as num from dual'")
require.True(t, terror.ErrorEqual(err, variable.ErrMaxPreparedStmtCountReached))
}

func TestIssue58870(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)

tk.MustExec("use test")
tk.MustExec("set names GBK")
tk.MustExec(`CREATE TABLE tsecurity (
security_id int(11) NOT NULL DEFAULT 0,
mkt_id smallint(6) NOT NULL DEFAULT 0,
security_code varchar(64) CHARACTER SET gbk COLLATE gbk_bin NOT NULL DEFAULT ' ',
security_name varchar(128) CHARACTER SET gbk COLLATE gbk_bin NOT NULL DEFAULT ' ',
PRIMARY KEY (security_id) USING BTREE
) ENGINE = InnoDB CHARACTER SET = gbk COLLATE = gbk_bin ROW_FORMAT = Compact;`)
tk.MustExec("INSERT INTO tsecurity (security_id, security_code, mkt_id, security_name) VALUES (1, '1', 1 ,'\xB2\xE2')")
tk.MustExec("PREPARE a FROM 'INSERT INTO tsecurity (security_id, security_code, mkt_id, security_name) VALUES (2, 2, 2 ,\"\xB2\xE2\")'")
tk.MustExec("EXECUTE a")
stmt, _, _, err := tk.Session().PrepareStmt("INSERT INTO tsecurity (security_id, security_code, mkt_id, security_name) VALUES (3, 3, 3 ,\"\xB2\xE2\")")
require.Nil(t, err)
rs, err := tk.Session().ExecutePreparedStmt(context.TODO(), stmt, nil)
require.Nil(t, err)
require.Nil(t, rs)
}

0 comments on commit 1219706

Please sign in to comment.