diff --git a/executor/issuetest/executor_issue_test.go b/executor/issuetest/executor_issue_test.go index 6c132ef088f87..b025bf1116710 100644 --- a/executor/issuetest/executor_issue_test.go +++ b/executor/issuetest/executor_issue_test.go @@ -682,7 +682,7 @@ func TestIssue22231(t *testing.T) { tk.MustExec("create table t_issue_22231(a datetime)") tk.MustExec("insert into t_issue_22231 values('2020--05-20 01:22:12')") tk.MustQuery("select * from t_issue_22231 where a >= '2020-05-13 00:00:00 00:00:00' and a <= '2020-05-28 23:59:59 00:00:00'").Check(testkit.Rows("2020-05-20 01:22:12")) - tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect datetime value: '2020-05-13 00:00:00 00:00:00'", "Warning 1292 Truncated incorrect datetime value: '2020-05-28 23:59:59 00:00:00'")) + tk.MustQuery("show warnings").MultiCheckContain([]string{"Truncated incorrect datetime value: '2020-05-13 00:00:00 00:00:00'", "Truncated incorrect datetime value: '2020-05-28 23:59:59 00:00:00'"}) tk.MustQuery("select cast('2020-10-22 10:31-10:12' as datetime)").Check(testkit.Rows("2020-10-22 10:31:10")) tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect datetime value: '2020-10-22 10:31-10:12'")) diff --git a/expression/integration_serial_test/integration_serial_test.go b/expression/integration_serial_test/integration_serial_test.go index 6aeb23c64f919..64510e7742ee9 100644 --- a/expression/integration_serial_test/integration_serial_test.go +++ b/expression/integration_serial_test/integration_serial_test.go @@ -2300,7 +2300,7 @@ func TestTimeBuiltin(t *testing.T) { tk.MustExec(`update t set a = dayOfMonth("0000-00-00")`) tk.MustExec("set sql_mode = 'NO_ZERO_DATE';") tk.MustExec("insert into t value(dayOfMonth('0000-00-00'))") - tk.MustQuery("show warnings").Check(testkit.RowsWithSep("|", "Warning|1292|Incorrect datetime value: '0000-00-00 00:00:00.000000'")) + tk.MustQuery("show warnings").CheckContain("Incorrect datetime value: '0000-00-00 00:00:00.000000'") tk.MustExec(`update t set a = dayOfMonth("0000-00-00")`) tk.MustExec("set sql_mode = 'NO_ZERO_DATE,STRICT_TRANS_TABLES';") _, err = tk.Exec("insert into t value(dayOfMonth('0000-00-00'))") @@ -2395,7 +2395,7 @@ func TestTimeBuiltin(t *testing.T) { tk.MustExec(`update t set a = monthname("0000-00-00")`) tk.MustExec("set sql_mode = 'NO_ZERO_DATE'") tk.MustExec("insert into t value(monthname('0000-00-00'))") - tk.MustQuery("show warnings").Check(testkit.RowsWithSep("|", "Warning|1292|Incorrect datetime value: '0000-00-00 00:00:00.000000'")) + tk.MustQuery("show warnings").CheckContain("Incorrect datetime value: '0000-00-00 00:00:00.000000'") tk.MustExec(`update t set a = monthname("0000-00-00")`) tk.MustExec("set sql_mode = ''") tk.MustExec("insert into t value(monthname('0000-00-00'))") @@ -2406,7 +2406,7 @@ func TestTimeBuiltin(t *testing.T) { require.NoError(t, err) result = tk.MustQuery(`select monthname("2017-12-01"), monthname("0000-00-00"), monthname("0000-01-00"), monthname("0000-01-00 00:00:00")`) result.Check(testkit.Rows("December January January")) - tk.MustQuery("show warnings").Check(testkit.RowsWithSep("|", "Warning|1292|Incorrect datetime value: '0000-00-00 00:00:00.000000'")) + tk.MustQuery("show warnings").CheckContain("Incorrect datetime value: '0000-00-00 00:00:00.000000'") // for dayname tk.MustExec(`drop table if exists t`) diff --git a/expression/integration_test/integration_test.go b/expression/integration_test/integration_test.go index e59e03af081dc..f20f33097a494 100644 --- a/expression/integration_test/integration_test.go +++ b/expression/integration_test/integration_test.go @@ -1711,7 +1711,7 @@ func TestArithmeticBuiltin(t *testing.T) { tk.MustExec("drop table if exists t;") tk.MustExec("CREATE TABLE t (v int);") tk.MustExec("INSERT IGNORE INTO t VALUE(12 MOD 0);") - tk.MustQuery("show warnings;").Check(testkit.Rows("Warning 1365 Division by 0")) + tk.MustQuery("show warnings;").CheckContain("Division by 0") tk.MustQuery("select v from t;").Check(testkit.Rows("")) tk.MustQuery("select 0.000 % 0.11234500000000000000;").Check(testkit.Rows("0.00000000000000000000")) @@ -7172,7 +7172,7 @@ func TestIssue29708(t *testing.T) { }) tk.MustExec("INSERT IGNORE INTO t1 VALUES (REPEAT(0125,200000000));") - tk.MustQuery("show warnings;").Check(testkit.Rows("Warning 1301 Result of repeat() was larger than max_allowed_packet (67108864) - truncated")) + tk.MustQuery("show warnings;").CheckContain("Result of repeat() was larger than max_allowed_packet (67108864) - truncated") tk.MustQuery("select a from t1 order by a;").Check([][]interface{}{ {nil}, {"a"}, diff --git a/parser/format/format.go b/parser/format/format.go index a4ac72532519d..31d760d98b70f 100644 --- a/parser/format/format.go +++ b/parser/format/format.go @@ -377,7 +377,7 @@ func (ctx *RestoreCtx) WriteKeyWord(keyWord string) { case ctx.Flags.HasKeyWordLowercaseFlag(): keyWord = strings.ToLower(keyWord) } - fmt.Fprint(ctx.In, keyWord) + ctx.In.WriteString(keyWord) } // WriteWithSpecialComments writes a string with a special comment wrapped. @@ -412,7 +412,9 @@ func (ctx *RestoreCtx) WriteString(str string) { str = strings.Replace(str, `"`, `""`, -1) quotes = `"` } - fmt.Fprint(ctx.In, quotes, str, quotes) + ctx.In.WriteString(quotes) + ctx.In.WriteString(str) + ctx.In.WriteString(quotes) } // WriteName writes the name into writer diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index 77bd80146a044..db94217d8e110 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -4940,7 +4940,7 @@ func TestIssue37760(t *testing.T) { tk.MustExec("insert into t values (2), (4), (6)") tk.MustExec("set @@tidb_opt_range_max_size=1") tk.MustQuery("select * from t where a").Check(testkit.Rows("2", "4", "6")) - tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 Memory capacity of 1 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen")) + tk.MustQuery("show warnings").CheckContain("Memory capacity of 1 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen") } // TestExplainAnalyzeDMLCommit covers the issue #37373. diff --git a/planner/core/plan_cache_param.go b/planner/core/plan_cache_param.go index 1e2d808bcf231..abd8ce679f9c6 100644 --- a/planner/core/plan_cache_param.go +++ b/planner/core/plan_cache_param.go @@ -72,8 +72,8 @@ func (pr *paramReplacer) Enter(in ast.Node) (out ast.Node, skipChildren bool) { } case *driver.ValueExpr: pr.params = append(pr.params, n) - param := ast.NewParamMarkerExpr(len(pr.params) - 1) // offset is used as order in non-prepared plan cache. - param.(*driver.ParamMarkerExpr).Datum = *n.Datum.Clone() // init the ParamMakerExpr's Datum + param := ast.NewParamMarkerExpr(len(pr.params) - 1) // offset is used as order in non-prepared plan cache. + n.Datum.Copy(¶m.(*driver.ParamMarkerExpr).Datum) // init the ParamMakerExpr's Datum return param, true } return in, false diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index 3af6cb3c1b8b5..bc75ffd1d0e3d 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -103,6 +103,41 @@ func TestIssue40296(t *testing.T) { tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) // unary operator '-' is not supported now. } +func TestNonPreparedPlanCacheDMLHints(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec(`use test`) + tk.MustExec(`create table t (a int)`) + tk.MustExec(`set @@tidb_enable_non_prepared_plan_cache=1`) + + tk.MustExec(`insert into t values (1)`) + tk.MustExec(`insert into t values (1)`) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) + tk.MustExec(`update t set a=1`) + tk.MustExec(`update t set a=1`) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) + tk.MustExec(`delete from t where a=1`) + tk.MustExec(`delete from t where a=1`) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) + + tk.MustExec(`insert /*+ ignore_plan_cache() */ into t values (1)`) + tk.MustExec(`insert /*+ ignore_plan_cache() */ into t values (1)`) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) + tk.MustExec(`update /*+ ignore_plan_cache() */ t set a=1`) + tk.MustExec(`update /*+ ignore_plan_cache() */ t set a=1`) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) + tk.MustExec(`delete /*+ ignore_plan_cache() */ from t where a=1`) + tk.MustExec(`delete /*+ ignore_plan_cache() */ from t where a=1`) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) + + tk.MustExec(`insert into t values (1)`) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) + tk.MustExec(`update t set a=1`) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) + tk.MustExec(`delete from t where a=1`) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) +} + func TestNonPreparedPlanCachePlanString(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) diff --git a/planner/core/plan_cache_utils.go b/planner/core/plan_cache_utils.go index 31d2a3fd7191b..ea5d816664370 100644 --- a/planner/core/plan_cache_utils.go +++ b/planner/core/plan_cache_utils.go @@ -186,6 +186,7 @@ func GeneratePlanCacheStmtWithAST(ctx context.Context, sctx sessionctx.Context, // Put the parameters that may affect the plan in planCacheValue. // However, due to some compatibility reasons, we will temporarily keep some system variable-related values in planCacheKey. // At the same time, because these variables have a small impact on plan, we will move them to PlanCacheValue later if necessary. +// TODO: maintain a sync.pool for this structure. type planCacheKey struct { database string connID uint64 @@ -214,14 +215,10 @@ type planCacheKey struct { // Hash implements Key interface. func (key *planCacheKey) Hash() []byte { if len(key.hash) == 0 { - var ( - dbBytes = hack.Slice(key.database) - bufferSize = len(dbBytes) + 8*6 + 3*8 - ) if key.hash == nil { - key.hash = make([]byte, 0, bufferSize) + key.hash = make([]byte, 0, len(key.stmtText)*2) } - key.hash = append(key.hash, dbBytes...) + key.hash = append(key.hash, hack.Slice(key.database)...) key.hash = codec.EncodeInt(key.hash, int64(key.connID)) key.hash = append(key.hash, hack.Slice(key.stmtText)...) key.hash = codec.EncodeInt(key.hash, key.schemaVersion) @@ -496,6 +493,12 @@ func (checker *matchOptsExtractor) Enter(in ast.Node) (out ast.Node, skipChildre } tStats := getStatsTable(checker.sctx, t.Meta(), t.Meta().ID) checker.statsVersionHash += tableStatsVersionForPlanCache(tStats) // use '+' as the hash function for simplicity + case *ast.InsertStmt: + if node.Select != nil { + node.Select.Accept(checker) + } + // skip node.Table for performance. + return in, true } return in, false } diff --git a/planner/core/plan_cacheable_checker.go b/planner/core/plan_cacheable_checker.go index 61bd1d884b7ac..228d0678a11a7 100644 --- a/planner/core/plan_cacheable_checker.go +++ b/planner/core/plan_cacheable_checker.go @@ -225,6 +225,9 @@ func NonPreparedPlanCacheableWithCtx(sctx sessionctx.Context, node ast.Node, is return ok, reason } case *ast.UpdateStmt: + if len(x.TableHints) > 0 { + return false, "not support update statement with table hints" + } if x.MultipleTable { return false, "not support multiple tables update statements" } @@ -233,6 +236,9 @@ func NonPreparedPlanCacheableWithCtx(sctx sessionctx.Context, node ast.Node, is return ok, reason } case *ast.InsertStmt: + if len(x.TableHints) > 0 { + return false, "not support insert statement with table hints" + } if x.Select == nil { // `insert into t values (...)` nRows := len(x.Lists) nCols := 0 @@ -261,6 +267,9 @@ func NonPreparedPlanCacheableWithCtx(sctx sessionctx.Context, node ast.Node, is } } case *ast.DeleteStmt: + if len(x.TableHints) > 0 { + return false, "not support insert statement with table hints" + } if x.IsMultiTable { return false, "not support multiple tables delete statements" }