Skip to content

Commit f34f99c

Browse files
authored
Merge branch 'master' into no-rename-partition-col
2 parents 837c4f3 + f9af75f commit f34f99c

26 files changed

+799
-22
lines changed

config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,9 @@ type Config struct {
261261
// EnableGlobalKill indicates whether to enable global kill.
262262
TrxSummary TrxSummary `toml:"transaction-summary" json:"transaction-summary"`
263263
EnableGlobalKill bool `toml:"enable-global-kill" json:"enable-global-kill"`
264+
// InitializeSQLFile is a file that will be executed after first bootstrap only.
265+
// It can be used to set GLOBAL system variable values
266+
InitializeSQLFile string `toml:"initialize-sql-file" json:"initialize-sql-file"`
264267

265268
// The following items are deprecated. We need to keep them here temporarily
266269
// to support the upgrade process. They can be removed in future.

ddl/fktest/foreign_key_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"bytes"
1919
"context"
2020
"fmt"
21+
"sync"
2122
"testing"
2223
"time"
2324

@@ -1700,3 +1701,112 @@ func TestForeignKeyWithCacheTable(t *testing.T) {
17001701
tk.MustExec("alter table t2 nocache;")
17011702
tk.MustExec("drop table t1,t2;")
17021703
}
1704+
1705+
func TestForeignKeyAndConcurrentDDL(t *testing.T) {
1706+
store := testkit.CreateMockStore(t)
1707+
tk := testkit.NewTestKit(t, store)
1708+
tk.MustExec("set @@foreign_key_checks=1;")
1709+
tk.MustExec("use test")
1710+
// Test foreign key refer cache table.
1711+
tk.MustExec("create table t1 (a int, b int, c int, index(a), index(b), index(c));")
1712+
tk.MustExec("create table t2 (a int, b int, c int, index(a), index(b), index(c));")
1713+
tk2 := testkit.NewTestKit(t, store)
1714+
tk2.MustExec("set @@foreign_key_checks=1;")
1715+
tk2.MustExec("use test")
1716+
passCases := []struct {
1717+
prepare []string
1718+
ddl1 string
1719+
ddl2 string
1720+
}{
1721+
{
1722+
ddl1: "alter table t2 add constraint fk_1 foreign key (a) references t1(a)",
1723+
ddl2: "alter table t2 add constraint fk_2 foreign key (b) references t1(b)",
1724+
},
1725+
{
1726+
ddl1: "alter table t2 drop foreign key fk_1",
1727+
ddl2: "alter table t2 drop foreign key fk_2",
1728+
},
1729+
{
1730+
prepare: []string{
1731+
"alter table t2 drop index a",
1732+
},
1733+
ddl1: "alter table t2 add index(a)",
1734+
ddl2: "alter table t2 add constraint fk_1 foreign key (a) references t1(a)",
1735+
},
1736+
{
1737+
ddl1: "alter table t2 drop index c",
1738+
ddl2: "alter table t2 add constraint fk_2 foreign key (b) references t1(b)",
1739+
},
1740+
}
1741+
for _, ca := range passCases {
1742+
var wg sync.WaitGroup
1743+
wg.Add(2)
1744+
go func() {
1745+
defer wg.Done()
1746+
tk.MustExec(ca.ddl1)
1747+
}()
1748+
go func() {
1749+
defer wg.Done()
1750+
tk2.MustExec(ca.ddl2)
1751+
}()
1752+
wg.Wait()
1753+
}
1754+
errorCases := []struct {
1755+
prepare []string
1756+
ddl1 string
1757+
err1 string
1758+
ddl2 string
1759+
err2 string
1760+
}{
1761+
{
1762+
ddl1: "alter table t2 add constraint fk foreign key (a) references t1(a)",
1763+
err1: "[ddl:1826]Duplicate foreign key constraint name 'fk'",
1764+
ddl2: "alter table t2 add constraint fk foreign key (b) references t1(b)",
1765+
err2: "[ddl:1826]Duplicate foreign key constraint name 'fk'",
1766+
},
1767+
{
1768+
prepare: []string{
1769+
"alter table t2 add constraint fk_1 foreign key (a) references t1(a)",
1770+
},
1771+
ddl1: "alter table t2 drop foreign key fk_1",
1772+
err1: "[schema:1091]Can't DROP 'fk_1'; check that column/key exists",
1773+
ddl2: "alter table t2 drop foreign key fk_1",
1774+
err2: "[schema:1091]Can't DROP 'fk_1'; check that column/key exists",
1775+
},
1776+
{
1777+
ddl1: "alter table t2 drop index a",
1778+
err1: "[ddl:1553]Cannot drop index 'a': needed in a foreign key constraint",
1779+
ddl2: "alter table t2 add constraint fk_1 foreign key (a) references t1(a)",
1780+
err2: "[ddl:-1]Failed to add the foreign key constraint. Missing index for 'fk_1' foreign key columns in the table 't2'",
1781+
},
1782+
}
1783+
tk.MustExec("drop table t1,t2")
1784+
tk.MustExec("create table t1 (a int, b int, c int, index(a), index(b), index(c));")
1785+
tk.MustExec("create table t2 (a int, b int, c int, index(a), index(b), index(c));")
1786+
for i, ca := range errorCases {
1787+
for _, sql := range ca.prepare {
1788+
tk.MustExec(sql)
1789+
}
1790+
var wg sync.WaitGroup
1791+
var err1, err2 error
1792+
wg.Add(2)
1793+
go func() {
1794+
defer wg.Done()
1795+
err1 = tk.ExecToErr(ca.ddl1)
1796+
}()
1797+
go func() {
1798+
defer wg.Done()
1799+
err2 = tk2.ExecToErr(ca.ddl2)
1800+
}()
1801+
wg.Wait()
1802+
if (err1 == nil && err2 == nil) || (err1 != nil && err2 != nil) {
1803+
require.Failf(t, "both ddl1 and ddl2 execute success, but expect 1 error", fmt.Sprintf("idx: %v, err1: %v, err2: %v", i, err1, err2))
1804+
}
1805+
if err1 != nil {
1806+
require.Equal(t, ca.err1, err1.Error())
1807+
}
1808+
if err2 != nil {
1809+
require.Equal(t, ca.err2, err2.Error())
1810+
}
1811+
}
1812+
}

ddl/metadatalocktest/mdl_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,47 @@ func TestMDLBasicBatchPointGet(t *testing.T) {
257257
require.Less(t, ts1, ts2)
258258
}
259259

260+
func TestMDLAddForeignKey(t *testing.T) {
261+
store, dom := testkit.CreateMockStoreAndDomain(t)
262+
sv := server.CreateMockServer(t, store)
263+
264+
sv.SetDomain(dom)
265+
dom.InfoSyncer().SetSessionManager(sv)
266+
defer sv.Close()
267+
268+
conn1 := server.CreateMockConn(t, sv)
269+
tk := testkit.NewTestKitWithSession(t, store, conn1.Context().Session)
270+
conn2 := server.CreateMockConn(t, sv)
271+
tkDDL := testkit.NewTestKitWithSession(t, store, conn2.Context().Session)
272+
tk.MustExec("use test")
273+
tk.MustExec("set global tidb_enable_metadata_lock=1")
274+
tk.MustExec("create table t1(id int key);")
275+
tk.MustExec("create table t2(id int key);")
276+
277+
tk.MustExec("begin")
278+
tk.MustExec("insert into t2 values(1);")
279+
280+
var wg sync.WaitGroup
281+
var ddlErr error
282+
wg.Add(1)
283+
var ts2 time.Time
284+
go func() {
285+
defer wg.Done()
286+
ddlErr = tkDDL.ExecToErr("alter table test.t2 add foreign key (id) references t1(id)")
287+
ts2 = time.Now()
288+
}()
289+
290+
time.Sleep(2 * time.Second)
291+
292+
ts1 := time.Now()
293+
tk.MustExec("commit")
294+
295+
wg.Wait()
296+
require.Error(t, ddlErr)
297+
require.Equal(t, "[ddl:1452]Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk_1` FOREIGN KEY (`id`) REFERENCES `t1` (`id`))", ddlErr.Error())
298+
require.Less(t, ts1, ts2)
299+
}
300+
260301
func TestMDLRRUpdateSchema(t *testing.T) {
261302
store, dom := testkit.CreateMockStoreAndDomain(t)
262303
sv := server.CreateMockServer(t, store)

executor/adapter.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"bytes"
1919
"context"
2020
"fmt"
21+
"math"
2122
"runtime/trace"
2223
"strconv"
2324
"strings"
@@ -295,8 +296,12 @@ func (a *ExecStmt) PointGet(ctx context.Context) (*recordSet, error) {
295296
}
296297
a.Ctx.GetSessionVars().StmtCtx.Priority = kv.PriorityHigh
297298

299+
var pointExecutor *PointGetExecutor
300+
useMaxTS := startTs == math.MaxUint64
301+
298302
// try to reuse point get executor
299-
if a.PsStmt.Executor != nil {
303+
// We should only use the cached the executor when the startTS is MaxUint64
304+
if a.PsStmt.Executor != nil && useMaxTS {
300305
exec, ok := a.PsStmt.Executor.(*PointGetExecutor)
301306
if !ok {
302307
logutil.Logger(ctx).Error("invalid executor type, not PointGetExecutor for point get path")
@@ -306,17 +311,21 @@ func (a *ExecStmt) PointGet(ctx context.Context) (*recordSet, error) {
306311
pointGetPlan := a.PsStmt.PreparedAst.CachedPlan.(*plannercore.PointGetPlan)
307312
exec.Init(pointGetPlan)
308313
a.PsStmt.Executor = exec
314+
pointExecutor = exec
309315
}
310316
}
311-
if a.PsStmt.Executor == nil {
317+
318+
if pointExecutor == nil {
312319
b := newExecutorBuilder(a.Ctx, a.InfoSchema, a.Ti)
313-
newExecutor := b.build(a.Plan)
320+
pointExecutor = b.build(a.Plan).(*PointGetExecutor)
314321
if b.err != nil {
315322
return nil, b.err
316323
}
317-
a.PsStmt.Executor = newExecutor
324+
325+
if useMaxTS {
326+
a.PsStmt.Executor = pointExecutor
327+
}
318328
}
319-
pointExecutor := a.PsStmt.Executor.(*PointGetExecutor)
320329

321330
if err = pointExecutor.Open(ctx); err != nil {
322331
terror.Call(pointExecutor.Close)

executor/compiler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ func (c *Compiler) Compile(ctx context.Context, stmtNode ast.StmtNode) (_ *ExecS
157157
}
158158
}
159159
}
160+
161+
if err = sessiontxn.OptimizeWithPlanAndThenWarmUp(c.Ctx, stmt.Plan); err != nil {
162+
return nil, err
163+
}
164+
160165
if c.Ctx.GetSessionVars().IsPlanReplayerCaptureEnabled() && !c.Ctx.GetSessionVars().InRestrictedSQL {
161166
startTS, err := sessiontxn.GetTxnManager(c.Ctx).GetStmtReadTS()
162167
if err != nil {

executor/fktest/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ go_test(
1515
"//infoschema",
1616
"//kv",
1717
"//meta/autoid",
18+
"//parser",
1819
"//parser/ast",
1920
"//parser/auth",
2021
"//parser/format",

executor/fktest/foreign_key_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ import (
2121
"strconv"
2222
"strings"
2323
"sync"
24+
"sync/atomic"
2425
"testing"
2526
"time"
2627

2728
"github.com/pingcap/tidb/config"
2829
"github.com/pingcap/tidb/executor"
2930
"github.com/pingcap/tidb/infoschema"
3031
"github.com/pingcap/tidb/kv"
32+
"github.com/pingcap/tidb/parser"
3133
"github.com/pingcap/tidb/parser/ast"
3234
"github.com/pingcap/tidb/parser/auth"
3335
"github.com/pingcap/tidb/parser/format"
@@ -2643,3 +2645,91 @@ func TestForeignKeyOnReplaceInto(t *testing.T) {
26432645
tk.MustExec("replace into t1 values (1, 'new-boss', null)")
26442646
tk.MustQuery("select id from t1 order by id").Check(testkit.Rows("1"))
26452647
}
2648+
2649+
func TestForeignKeyLargeTxnErr(t *testing.T) {
2650+
store := testkit.CreateMockStore(t)
2651+
tk := testkit.NewTestKit(t, store)
2652+
tk.MustExec("set @@foreign_key_checks=1")
2653+
tk.MustExec("use test")
2654+
tk.MustExec("create table t1 (id int auto_increment key, pid int, name varchar(200), index(pid));")
2655+
tk.MustExec("insert into t1 (name) values ('abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890');")
2656+
for i := 0; i < 8; i++ {
2657+
tk.MustExec("insert into t1 (name) select name from t1;")
2658+
}
2659+
tk.MustQuery("select count(*) from t1").Check(testkit.Rows("256"))
2660+
tk.MustExec("update t1 set pid=1 where id>1")
2661+
tk.MustExec("alter table t1 add foreign key (pid) references t1 (id) on update cascade")
2662+
originLimit := atomic.LoadUint64(&kv.TxnTotalSizeLimit)
2663+
defer func() {
2664+
atomic.StoreUint64(&kv.TxnTotalSizeLimit, originLimit)
2665+
}()
2666+
// Set the limitation to a small value, make it easier to reach the limitation.
2667+
atomic.StoreUint64(&kv.TxnTotalSizeLimit, 10240)
2668+
tk.MustQuery("select sum(id) from t1").Check(testkit.Rows("32896"))
2669+
// foreign key cascade behaviour will cause ErrTxnTooLarge.
2670+
tk.MustGetDBError("update t1 set id=id+100000 where id=1", kv.ErrTxnTooLarge)
2671+
tk.MustQuery("select sum(id) from t1").Check(testkit.Rows("32896"))
2672+
tk.MustGetDBError("update t1 set id=id+100000 where id=1", kv.ErrTxnTooLarge)
2673+
tk.MustQuery("select id,pid from t1 where id<3 order by id").Check(testkit.Rows("1 <nil>", "2 1"))
2674+
tk.MustExec("set @@foreign_key_checks=0")
2675+
tk.MustExec("update t1 set id=id+100000 where id=1")
2676+
tk.MustQuery("select id,pid from t1 where id<3 or pid is null order by id").Check(testkit.Rows("2 1", "100001 <nil>"))
2677+
}
2678+
2679+
func TestForeignKeyAndLockView(t *testing.T) {
2680+
store := testkit.CreateMockStore(t)
2681+
tk := testkit.NewTestKit(t, store)
2682+
tk.MustExec("use test")
2683+
tk.MustExec("create table t1 (id int key)")
2684+
tk.MustExec("create table t2 (id int key, foreign key (id) references t1(id) ON DELETE CASCADE ON UPDATE CASCADE)")
2685+
tk.MustExec("insert into t1 values (1)")
2686+
tk.MustExec("insert into t2 values (1)")
2687+
tk.MustExec("begin pessimistic")
2688+
tk.MustExec("set @@foreign_key_checks=0")
2689+
tk.MustExec("update t2 set id=2")
2690+
2691+
tk2 := testkit.NewTestKit(t, store)
2692+
tk2.MustExec("set @@foreign_key_checks=1")
2693+
tk2.MustExec("use test")
2694+
var wg sync.WaitGroup
2695+
wg.Add(1)
2696+
go func() {
2697+
defer wg.Done()
2698+
tk2.MustExec("begin pessimistic")
2699+
tk2.MustExec("update t1 set id=2 where id=1")
2700+
tk2.MustExec("commit")
2701+
}()
2702+
time.Sleep(time.Millisecond * 200)
2703+
_, digest := parser.NormalizeDigest("update t1 set id=2 where id=1")
2704+
tk.MustQuery("select CURRENT_SQL_DIGEST from information_schema.tidb_trx where state='LockWaiting' and db='test'").Check(testkit.Rows(digest.String()))
2705+
tk.MustGetErrMsg("update t1 set id=2", "[executor:1213]Deadlock found when trying to get lock; try restarting transaction")
2706+
wg.Wait()
2707+
}
2708+
2709+
func TestForeignKeyAndMemoryTracker(t *testing.T) {
2710+
store := testkit.CreateMockStore(t)
2711+
tk := testkit.NewTestKit(t, store)
2712+
tk.MustExec("set @@foreign_key_checks=1")
2713+
tk.MustExec("use test")
2714+
tk.MustExec("create table t1 (id int auto_increment key, pid int, name varchar(200), index(pid));")
2715+
tk.MustExec("insert into t1 (name) values ('abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz');")
2716+
for i := 0; i < 8; i++ {
2717+
tk.MustExec("insert into t1 (name) select name from t1;")
2718+
}
2719+
tk.MustQuery("select count(*) from t1").Check(testkit.Rows("256"))
2720+
tk.MustExec("update t1 set pid=1 where id>1")
2721+
tk.MustExec("alter table t1 add foreign key (pid) references t1 (id) on update cascade")
2722+
tk.MustQuery("select sum(id) from t1").Check(testkit.Rows("32896"))
2723+
defer tk.MustExec("SET GLOBAL tidb_mem_oom_action = DEFAULT")
2724+
tk.MustExec("SET GLOBAL tidb_mem_oom_action='CANCEL'")
2725+
tk.MustExec("set @@tidb_mem_quota_query=40960;")
2726+
// foreign key cascade behaviour will exceed memory quota.
2727+
err := tk.ExecToErr("update t1 set id=id+100000 where id=1")
2728+
require.Error(t, err)
2729+
require.Contains(t, err.Error(), "Out Of Memory Quota!")
2730+
tk.MustQuery("select id,pid from t1 where id = 1").Check(testkit.Rows("1 <nil>"))
2731+
tk.MustExec("set @@foreign_key_checks=0")
2732+
// After disable foreign_key_checks, following DML will execute successful.
2733+
tk.MustExec("update t1 set id=id+100000 where id=1")
2734+
tk.MustQuery("select id,pid from t1 where id<3 or pid is null order by id").Check(testkit.Rows("2 1", "100001 <nil>"))
2735+
}

executor/point_get_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,3 +825,20 @@ func TestPointGetIssue25167(t *testing.T) {
825825
tk.MustExec("insert into t values (1)")
826826
tk.MustQuery("select * from t as of timestamp @a where a = 1").Check(testkit.Rows())
827827
}
828+
829+
func TestPointGetIssue40194(t *testing.T) {
830+
store := testkit.CreateMockStore(t)
831+
tk := testkit.NewTestKit(t, store)
832+
tk.MustExec("use test")
833+
tk.MustExec("create table t1(id int primary key, v int)")
834+
tk.MustExec("insert into t1 values(1, 10)")
835+
tk.MustExec("prepare s from 'select * from t1 where id=1'")
836+
tk.MustExec("set @@tidb_enable_plan_replayer_capture=1")
837+
tk.MustQuery("execute s").Check(testkit.Rows("1 10"))
838+
tk.MustQuery("execute s").Check(testkit.Rows("1 10"))
839+
840+
tk2 := testkit.NewTestKit(t, store)
841+
tk2.MustExec("use test")
842+
tk2.MustExec("update t1 set v=v+1")
843+
tk.MustQuery("execute s").Check(testkit.Rows("1 11"))
844+
}

planner/core/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ go_test(
171171
"flat_plan_test.go",
172172
"fragment_test.go",
173173
"indexmerge_intersection_test.go",
174+
"indexmerge_path_test.go",
174175
"indexmerge_test.go",
175176
"integration_partition_test.go",
176177
"integration_test.go",

planner/core/find_best_task.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,12 @@ func (ds *DataSource) addSelection4PlanCache(task *rootTask, stats *property.Sta
14191419
// convertToIndexScan converts the DataSource to index scan with idx.
14201420
func (ds *DataSource) convertToIndexScan(prop *property.PhysicalProperty,
14211421
candidate *candidatePath, _ *physicalOptimizeOp) (task task, err error) {
1422+
if candidate.path.Index.MVIndex {
1423+
// MVIndex is special since different index rows may return the same _row_id and this can break some assumptions of IndexReader.
1424+
// Currently only support using IndexMerge to access MVIndex instead of IndexReader.
1425+
// TODO: make IndexReader support accessing MVIndex directly.
1426+
return invalidTask, nil
1427+
}
14221428
if !candidate.path.IsSingleScan {
14231429
// If it's parent requires single read task, return max cost.
14241430
if prop.TaskTp == property.CopSingleReadTaskType {

0 commit comments

Comments
 (0)