From 6247f62f6ca0224ee91f8d734264c92ebbe0e875 Mon Sep 17 00:00:00 2001 From: Haibin Xie Date: Mon, 4 Nov 2019 15:02:19 +0800 Subject: [PATCH] bindinfo: correctly handle quotes for bindings sql --- bindinfo/bind_test.go | 2 +- bindinfo/handle.go | 39 ++++++++++++++++++------------------ expression/builtin_string.go | 7 ++++++- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/bindinfo/bind_test.go b/bindinfo/bind_test.go index d4a0316109641..ea90d8e3c0607 100644 --- a/bindinfo/bind_test.go +++ b/bindinfo/bind_test.go @@ -138,7 +138,7 @@ func (s *testSuite) TestBindParse(c *C) { c.Check(bind.UpdateTime, NotNil) // Test fields with quotes or slashes. - sql = `CREATE GLOBAL BINDING FOR select * from t where i BETWEEN "a" and "b" USING select * from t use index(index_t) where i BETWEEN "a\nb\rc\td\0e" and "x"` + sql = `CREATE GLOBAL BINDING FOR select * from t where i BETWEEN "a" and "b" USING select * from t use index(index_t) where i BETWEEN "a\nb\rc\td\0e" and 'x'` tk.MustExec(sql) tk.MustExec(`DROP global binding for select * from t use index(idx) where i BETWEEN "a\nb\rc\td\0e" and "x"`) } diff --git a/bindinfo/handle.go b/bindinfo/handle.go index 203be6de8457d..8f110ca39c23e 100644 --- a/bindinfo/handle.go +++ b/bindinfo/handle.go @@ -25,6 +25,7 @@ import ( "github.com/pingcap/parser/ast" "github.com/pingcap/parser/mysql" "github.com/pingcap/parser/terror" + "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/infoschema" "github.com/pingcap/tidb/metrics" "github.com/pingcap/tidb/sessionctx" @@ -430,39 +431,39 @@ func (c cache) getBindRecord(hash, normdOrigSQL, db string) *BindRecord { func (h *BindHandle) deleteBindInfoSQL(normdOrigSQL, db string) string { return fmt.Sprintf( - "DELETE FROM mysql.bind_info WHERE original_sql='%s' AND default_db='%s'", - normdOrigSQL, - db, + `DELETE FROM mysql.bind_info WHERE original_sql=%s AND default_db=%s`, + expression.Quote(normdOrigSQL), + expression.Quote(db), ) } func (h *BindHandle) insertBindInfoSQL(orignalSQL string, db string, info Binding) string { - return fmt.Sprintf(`INSERT INTO mysql.bind_info VALUES ('%s', '%s', '%s', '%s', '%s', '%s','%s', '%s')`, - orignalSQL, - info.BindSQL, - db, - info.Status, - info.CreateTime, - info.UpdateTime, - info.Charset, - info.Collation, + return fmt.Sprintf(`INSERT INTO mysql.bind_info VALUES (%s, %s, %s, %s, %s, %s, %s, %s)`, + expression.Quote(orignalSQL), + expression.Quote(info.BindSQL), + expression.Quote(db), + expression.Quote(info.Status), + expression.Quote(info.CreateTime.String()), + expression.Quote(info.UpdateTime.String()), + expression.Quote(info.Charset), + expression.Quote(info.Collation), ) } func (h *BindHandle) logicalDeleteBindInfoSQL(record *BindRecord, updateTs types.Time) string { - sql := fmt.Sprintf(`UPDATE mysql.bind_info SET status='%s',update_time='%s' WHERE original_sql='%s' and default_db='%s'`, - deleted, - updateTs, - record.OriginalSQL, - record.Db) + sql := fmt.Sprintf(`UPDATE mysql.bind_info SET status=%s,update_time=%s WHERE original_sql=%s and default_db=%s`, + expression.Quote(deleted), + expression.Quote(updateTs.String()), + expression.Quote(record.OriginalSQL), + expression.Quote(record.Db)) if len(record.Bindings) == 0 { return sql } bindings := make([]string, 0, len(record.Bindings)) for _, bind := range record.Bindings { - bindings = append(bindings, fmt.Sprintf(`'%s'`, bind.BindSQL)) + bindings = append(bindings, fmt.Sprintf(`%s`, expression.Quote(bind.BindSQL))) } - return sql + fmt.Sprintf(" and bind_sql in (%s)", strings.Join(bindings, ",")) + return sql + fmt.Sprintf(` and bind_sql in (%s)`, strings.Join(bindings, ",")) } // GenHintsFromSQL is used to generate hints from SQL. diff --git a/expression/builtin_string.go b/expression/builtin_string.go index 7288ae1afbf0e..c6aafd30f4eb6 100644 --- a/expression/builtin_string.go +++ b/expression/builtin_string.go @@ -2702,6 +2702,11 @@ func (b *builtinQuoteSig) evalString(row chunk.Row) (string, bool, error) { return "NULL", false, err } + return Quote(str), false, nil +} + +// Quote produce a result that can be used as a properly escaped data value in an SQL statement. +func Quote(str string) string { runes := []rune(str) buffer := bytes.NewBufferString("") buffer.WriteRune('\'') @@ -2722,7 +2727,7 @@ func (b *builtinQuoteSig) evalString(row chunk.Row) (string, bool, error) { } buffer.WriteRune('\'') - return buffer.String(), false, nil + return buffer.String() } type binFunctionClass struct {