Skip to content

Commit 920eb53

Browse files
authored
executor: fix prepared protocol charset (#58872) (#58931)
close #58870
1 parent 65f8417 commit 920eb53

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

pkg/executor/prepared.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ type PrepareExec struct {
6262
// If it's generated from executing "prepare stmt from '...'", the process is parse -> plan -> executor
6363
// If it's generated from the prepare protocol, the process is session.PrepareStmt -> NewPrepareExec
6464
// They both generate a PrepareExec struct, but the second case needs to reset the statement context while the first already do that.
65+
// Also, the second case need charset_client param since SQL is directly passed from clients.
66+
// While the text-prepare already transformed charset by parser.
6567
needReset bool
6668
}
6769

@@ -87,23 +89,28 @@ func (e *PrepareExec) Next(ctx context.Context, _ *chunk.Chunk) error {
8789
return nil
8890
}
8991
}
90-
charset, collation := vars.GetCharsetInfo()
9192
var (
9293
stmts []ast.StmtNode
9394
err error
9495
)
96+
var params []parser.ParseParam
97+
if e.needReset {
98+
params = vars.GetParseParams()
99+
} else {
100+
var paramsArr [2]parser.ParseParam
101+
charset, collation := vars.GetCharsetInfo()
102+
paramsArr[0] = parser.CharsetConnection(charset)
103+
paramsArr[1] = parser.CollationConnection(collation)
104+
params = paramsArr[:]
105+
}
95106
if sqlParser, ok := e.Ctx().(sqlexec.SQLParser); ok {
96107
// FIXME: ok... yet another parse API, may need some api interface clean.
97-
stmts, _, err = sqlParser.ParseSQL(ctx, e.sqlText,
98-
parser.CharsetConnection(charset),
99-
parser.CollationConnection(collation))
108+
stmts, _, err = sqlParser.ParseSQL(ctx, e.sqlText, params...)
100109
} else {
101110
p := parser.New()
102111
p.SetParserConfig(vars.BuildParserConfig())
103112
var warns []error
104-
stmts, warns, err = p.ParseSQL(e.sqlText,
105-
parser.CharsetConnection(charset),
106-
parser.CollationConnection(collation))
113+
stmts, warns, err = p.ParseSQL(e.sqlText, params...)
107114
for _, warn := range warns {
108115
e.Ctx().GetSessionVars().StmtCtx.AppendWarning(util.SyntaxWarn(warn))
109116
}

pkg/executor/prepared_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,3 +1172,26 @@ func TestPrepareProtocolWorkWithForeignKey(t *testing.T) {
11721172
// As schema version increased, the plan cache should be invalidated.
11731173
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
11741174
}
1175+
1176+
func TestIssue58870(t *testing.T) {
1177+
store := testkit.CreateMockStore(t)
1178+
tk := testkit.NewTestKit(t, store)
1179+
1180+
tk.MustExec("use test")
1181+
tk.MustExec("set names GBK")
1182+
tk.MustExec(`CREATE TABLE tsecurity (
1183+
security_id int(11) NOT NULL DEFAULT 0,
1184+
mkt_id smallint(6) NOT NULL DEFAULT 0,
1185+
security_code varchar(64) CHARACTER SET gbk COLLATE gbk_bin NOT NULL DEFAULT ' ',
1186+
security_name varchar(128) CHARACTER SET gbk COLLATE gbk_bin NOT NULL DEFAULT ' ',
1187+
PRIMARY KEY (security_id) USING BTREE
1188+
) ENGINE = InnoDB CHARACTER SET = gbk COLLATE = gbk_bin ROW_FORMAT = Compact;`)
1189+
tk.MustExec("INSERT INTO tsecurity (security_id, security_code, mkt_id, security_name) VALUES (1, '1', 1 ,'\xB2\xE2')")
1190+
tk.MustExec("PREPARE a FROM 'INSERT INTO tsecurity (security_id, security_code, mkt_id, security_name) VALUES (2, 2, 2 ,\"\xB2\xE2\")'")
1191+
tk.MustExec("EXECUTE a")
1192+
stmt, _, _, err := tk.Session().PrepareStmt("INSERT INTO tsecurity (security_id, security_code, mkt_id, security_name) VALUES (3, 3, 3 ,\"\xB2\xE2\")")
1193+
require.Nil(t, err)
1194+
rs, err := tk.Session().ExecutePreparedStmt(context.TODO(), stmt, nil)
1195+
require.Nil(t, err)
1196+
require.Nil(t, rs)
1197+
}

0 commit comments

Comments
 (0)