Skip to content

Commit 30eba16

Browse files
committed
parser: support pre-split global index add special comment support for pre_split index option (#58408)
ref #57551, ref #57552
1 parent dafffb0 commit 30eba16

5 files changed

Lines changed: 98 additions & 18 deletions

File tree

pkg/ddl/index_presplit.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ import (
3737
"go.uber.org/zap"
3838
)
3939

40-
// TODO(tangenta): support global index.
41-
// Wrap the job.Query to with special comments.
4240
func preSplitIndexRegions(
4341
ctx context.Context,
4442
sctx sessionctx.Context,
@@ -112,6 +110,11 @@ func getSplitIdxKeysFromValueList(
112110
return getSplitIdxPhysicalKeysFromValueList(sctx, tblInfo, idxInfo, tblInfo.ID, byRows, destKeys)
113111
}
114112

113+
if idxInfo.Global {
114+
destKeys = make([][]byte, 0, len(byRows)+1)
115+
return getSplitIdxPhysicalKeysFromValueList(sctx, tblInfo, idxInfo, tblInfo.ID, byRows, destKeys)
116+
}
117+
115118
destKeys = make([][]byte, 0, (len(byRows)+1)*len(pi.Definitions))
116119
for _, p := range pi.Definitions {
117120
destKeys, err = getSplitIdxPhysicalKeysFromValueList(sctx, tblInfo, idxInfo, p.ID, byRows, destKeys)
@@ -296,6 +299,20 @@ func evalSplitDatumFromArgs(
296299
return &splitArgs{byRows: indexValues}, nil
297300
}
298301

302+
if len(opt.Lower) == 0 && len(opt.Upper) == 0 && opt.Num > 0 {
303+
lowerVals := make([]types.Datum, 0, len(idxInfo.Columns))
304+
upperVals := make([]types.Datum, 0, len(idxInfo.Columns))
305+
for i := 0; i < len(idxInfo.Columns); i++ {
306+
lowerVals = append(lowerVals, types.MinNotNullDatum())
307+
upperVals = append(upperVals, types.MaxValueDatum())
308+
}
309+
return &splitArgs{
310+
betweenLower: lowerVals,
311+
betweenUpper: upperVals,
312+
regionsCnt: int(opt.Num),
313+
}, nil
314+
}
315+
299316
// Split index regions by lower, upper value.
300317
checkLowerUpperValue := func(valuesItem []string, name string) ([]types.Datum, error) {
301318
if len(valuesItem) == 0 {

pkg/parser/ast/ddl.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -791,16 +791,22 @@ func (n *IndexOption) Restore(ctx *format.RestoreCtx) error {
791791
if hasPrevOption {
792792
ctx.WritePlain(" ")
793793
}
794-
ctx.WriteKeyWord("PRE_SPLIT_REGIONS")
795-
ctx.WritePlain(" = ")
796-
if n.SplitOpt.Num != 0 && len(n.SplitOpt.Lower) == 0 {
797-
ctx.WritePlainf("%d", n.SplitOpt.Num)
798-
} else {
799-
ctx.WritePlain("(")
800-
if err := n.SplitOpt.Restore(ctx); err != nil {
801-
return errors.Annotate(err, "An error occurred while splicing IndexOption SplitOpt")
794+
err := ctx.WriteWithSpecialComments(tidb.FeatureIDPresplit, func() error {
795+
ctx.WriteKeyWord("PRE_SPLIT_REGIONS")
796+
ctx.WritePlain(" = ")
797+
if n.SplitOpt.Num != 0 && len(n.SplitOpt.Lower) == 0 {
798+
ctx.WritePlainf("%d", n.SplitOpt.Num)
799+
} else {
800+
ctx.WritePlain("(")
801+
if err := n.SplitOpt.Restore(ctx); err != nil {
802+
return errors.Annotate(err, "An error occurred while splicing IndexOption SplitOpt")
803+
}
804+
ctx.WritePlain(")")
802805
}
803-
ctx.WritePlain(")")
806+
return nil
807+
})
808+
if err != nil {
809+
return err
804810
}
805811
}
806812
return nil

pkg/parser/ast/ddl_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,3 +918,31 @@ func TestTableOptionTTLRestoreWithTTLEnableOffFlag(t *testing.T) {
918918
runNodeRestoreTestWithFlagsStmtChange(t, testCases, "%s", extractNodeFunc, ca.flags)
919919
}
920920
}
921+
922+
func TestPresplitIndexSpecialComments(t *testing.T) {
923+
specialCmtFlag := format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment
924+
cases := []struct {
925+
sourceSQL string
926+
flags format.RestoreFlags
927+
expectSQL string
928+
}{
929+
{"ALTER TABLE t ADD INDEX (a) PRE_SPLIT_REGIONS = 4", specialCmtFlag, "ALTER TABLE `t` ADD INDEX(`a`) /*T![pre_split] PRE_SPLIT_REGIONS = 4 */"},
930+
{"ALTER TABLE t ADD INDEX (a) PRE_SPLIT_REGIONS 4", specialCmtFlag, "ALTER TABLE `t` ADD INDEX(`a`) /*T![pre_split] PRE_SPLIT_REGIONS = 4 */"},
931+
{"ALTER TABLE t ADD PRIMARY KEY (a) CLUSTERED PRE_SPLIT_REGIONS = 4", specialCmtFlag, "ALTER TABLE `t` ADD PRIMARY KEY(`a`) /*T![clustered_index] CLUSTERED */ /*T![pre_split] PRE_SPLIT_REGIONS = 4 */"},
932+
{"ALTER TABLE t ADD PRIMARY KEY (a) PRE_SPLIT_REGIONS = 4 NONCLUSTERED", specialCmtFlag, "ALTER TABLE `t` ADD PRIMARY KEY(`a`) /*T![clustered_index] NONCLUSTERED */ /*T![pre_split] PRE_SPLIT_REGIONS = 4 */"},
933+
{"ALTER TABLE t ADD INDEX (a) PRE_SPLIT_REGIONS = (between (1, 'a') and (2, 'b') regions 4);", specialCmtFlag, "ALTER TABLE `t` ADD INDEX(`a`) /*T![pre_split] PRE_SPLIT_REGIONS = (BETWEEN (1,_UTF8MB4'a') AND (2,_UTF8MB4'b') REGIONS 4) */"},
934+
{"ALTER TABLE t ADD INDEX idx(a) pre_split_regions = 100, ADD INDEX idx2(b) pre_split_regions = (by(1),(2),(3))", specialCmtFlag, "ALTER TABLE `t` ADD INDEX `idx`(`a`) /*T![pre_split] PRE_SPLIT_REGIONS = 100 */, ADD INDEX `idx2`(`b`) /*T![pre_split] PRE_SPLIT_REGIONS = (BY (1),(2),(3)) */"},
935+
{"ALTER TABLE t ADD INDEX (a) comment 'a' PRE_SPLIT_REGIONS = (between (1, 'a') and (2, 'b') regions 4);", specialCmtFlag, "ALTER TABLE `t` ADD INDEX(`a`) COMMENT 'a' /*T![pre_split] PRE_SPLIT_REGIONS = (BETWEEN (1,_UTF8MB4'a') AND (2,_UTF8MB4'b') REGIONS 4) */"},
936+
}
937+
938+
extractNodeFunc := func(node Node) Node {
939+
return node
940+
}
941+
942+
for _, ca := range cases {
943+
testCases := []NodeRestoreTestCase{
944+
{ca.sourceSQL, ca.expectSQL},
945+
}
946+
runNodeRestoreTestWithFlags(t, testCases, "%s", extractNodeFunc, ca.flags)
947+
}
948+
}

pkg/parser/tidb/features.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ const (
3232
FeatureIDTTL = "ttl"
3333
// FeatureIDResourceGroup is the `resource group` feature.
3434
FeatureIDResourceGroup = "resource_group"
35+
// FeatureIDPresplit is the pre-split feature.
36+
FeatureIDPresplit = "pre_split"
3537
)
3638

3739
var featureIDs = map[string]struct{}{
@@ -42,6 +44,7 @@ var featureIDs = map[string]struct{}{
4244
FeatureIDForceAutoInc: {},
4345
FeatureIDPlacement: {},
4446
FeatureIDTTL: {},
47+
FeatureIDPresplit: {},
4548
}
4649

4750
// CanParseFeature is used to check if a feature can be parsed.

tests/realtikvtest/addindextest3/functional_test.go

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ func TestAddIndexPresplitIndexRegions(t *testing.T) {
5555
splitKeyHex = nil
5656
}
5757
}
58+
var idxID int64
59+
nextIdxID := func() int64 {
60+
idxID++
61+
return idxID
62+
}
63+
resetIdxID := func() {
64+
idxID = 0
65+
}
5866

5967
tk.MustExec("create table t (a int primary key, b int);")
6068
for i := 0; i < 10; i++ {
@@ -65,39 +73,57 @@ func TestAddIndexPresplitIndexRegions(t *testing.T) {
6573
require.Len(t, retRows, 1)
6674
tk.MustExec("set @@global.tidb_ddl_enable_fast_reorg = off;")
6775
tk.MustExec("set @@global.tidb_enable_dist_task = off;")
76+
tk.MustExec("alter table t add index idx(b) pre_split_regions = 4;")
77+
checkSplitKeys(nextIdxID(), 3, true)
78+
tk.MustExec("drop index idx on t;")
6879
tk.MustExec("alter table t add index idx(b) pre_split_regions = (by (10000), (20000), (30000));")
69-
checkSplitKeys(1, 3, true)
80+
checkSplitKeys(nextIdxID(), 3, true)
81+
tk.MustExec("drop index idx on t;")
82+
tk.MustExec("alter table t add index idx(b) /*T![pre_split] pre_split_regions = (by (10000), (20000), (30000)) */;")
83+
checkSplitKeys(nextIdxID(), 3, true)
7084
tk.MustExec("drop index idx on t;")
7185
tk.MustExec("alter table t add index idx(b) pre_split_regions = (between (0) and (10 * 10000) regions 3);")
72-
checkSplitKeys(2, 2, true)
86+
checkSplitKeys(nextIdxID(), 2, true)
7387
tk.MustExec("drop index idx on t;")
7488
tk.MustExec("set @@global.tidb_ddl_enable_fast_reorg = on;")
7589

7690
tk.MustExec("alter table t add index idx(b) pre_split_regions = (by (10000), (20000), (30000));")
77-
checkSplitKeys(3, 0, false)
78-
checkSplitKeys(tablecodec.TempIndexPrefix|3, 3, true)
91+
nextID := nextIdxID()
92+
checkSplitKeys(nextID, 0, false)
93+
checkSplitKeys(tablecodec.TempIndexPrefix|nextID, 3, true)
7994

8095
tk.MustExec("set @@global.tidb_ddl_enable_fast_reorg = off;")
8196

8297
// Test partition tables.
98+
resetIdxID()
8399
tk.MustExec("drop table t;")
84100
tk.MustExec("create table t (a int primary key, b int) partition by hash(a) partitions 4;")
85101
for i := 0; i < 10; i++ {
86102
insertSQL := fmt.Sprintf("insert into t values (%[1]d, %[1]d);", 10000*i)
87103
tk.MustExec(insertSQL)
88104
}
89105
tk.MustExec("alter table t add index idx(b) pre_split_regions = (by (10000), (20000), (30000));")
90-
checkSplitKeys(1, 3*4, true)
106+
checkSplitKeys(nextIdxID(), 3*4, true)
91107
tk.MustExec("drop index idx on t;")
92108
tk.MustExec("alter table t add index idx(b) pre_split_regions = (between (0) and (10 * 10000) regions 3);")
93-
checkSplitKeys(2, 2*4, true)
109+
checkSplitKeys(nextIdxID(), 2*4, true)
94110
tk.MustExec("drop index idx on t;")
95111
tk.MustExec("set @@global.tidb_ddl_enable_fast_reorg = on;")
96112
tk.MustExec("alter table t add index idx(b) pre_split_regions = (by (10000), (20000), (30000));")
97-
checkSplitKeys(3, 0, false)
113+
checkSplitKeys(nextIdxID(), 0, false)
98114
checkSplitKeys(tablecodec.TempIndexPrefix|3, 12, true)
99115
tk.MustExec("drop index idx on t;")
100116
tk.MustExec("set @@global.tidb_ddl_enable_fast_reorg = off;")
117+
118+
resetIdxID()
119+
tk.MustExec("drop table t;")
120+
tk.MustExec("set @@global.tidb_ddl_enable_fast_reorg = on;")
121+
tk.MustExec("set @@global.tidb_enable_dist_task = off;")
122+
tk.MustExec("create table t (a int, b int) partition by range (b)" +
123+
" (partition p0 values less than (10), " +
124+
" partition p1 values less than (maxvalue));")
125+
tk.MustExec("alter table t add unique index p_a (a) global pre_split_regions = (by (5), (15));")
126+
checkSplitKeys(tablecodec.TempIndexPrefix|nextIdxID(), 2, true)
101127
}
102128

103129
func TestAddIndexPresplitFunctional(t *testing.T) {

0 commit comments

Comments
 (0)