Skip to content

Commit 83c7c3d

Browse files
sharedSchema: add more colum info checks for using shared schema (#3875) (#3877)
* This is an automated cherry-pick of #3875 Signed-off-by: ti-chi-bot <[email protected]> * update --------- Signed-off-by: ti-chi-bot <[email protected]> Co-authored-by: hongyunyan <[email protected]>
1 parent a2b2031 commit 83c7c3d

File tree

9 files changed

+370
-13
lines changed

9 files changed

+370
-13
lines changed

pkg/common/table_info_helper.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"crypto/sha256"
1818
"encoding/binary"
1919
"encoding/json"
20+
"reflect"
2021
"strings"
2122
"sync"
2223

@@ -90,6 +91,15 @@ func hashTableInfo(tableInfo *model.TableInfo) Digest {
9091
}
9192
binary.BigEndian.PutUint64(buf, uint64(boolToInt(columnType.IsArray())))
9293
sha256Hasher.Write(buf)
94+
95+
binary.BigEndian.PutUint64(buf, uint64(boolToInt(col.DefaultIsExpr)))
96+
sha256Hasher.Write(buf)
97+
binary.BigEndian.PutUint64(buf, uint64(boolToInt(col.GeneratedStored)))
98+
sha256Hasher.Write(buf)
99+
binary.BigEndian.PutUint64(buf, uint64(boolToInt(col.Hidden)))
100+
sha256Hasher.Write(buf)
101+
binary.BigEndian.PutUint64(buf, col.Version)
102+
sha256Hasher.Write(buf)
93103
}
94104
// idx info
95105
sha256Hasher.Write([]byte("idxInfo"))
@@ -173,7 +183,27 @@ func (s *columnSchema) sameColumnsAndIndices(columns []*model.ColumnInfo, indice
173183
if col.ID != columns[i].ID {
174184
return false
175185
}
176-
if col.GetDefaultValue() != columns[i].GetDefaultValue() {
186+
if !reflect.DeepEqual(col.GetDefaultValue(), columns[i].GetDefaultValue()) {
187+
return false
188+
}
189+
190+
if !reflect.DeepEqual(col.GetOriginDefaultValue(), columns[i].GetOriginDefaultValue()) {
191+
return false
192+
}
193+
194+
if col.DefaultIsExpr != columns[i].DefaultIsExpr {
195+
return false
196+
}
197+
if col.GeneratedStored != columns[i].GeneratedStored {
198+
return false
199+
}
200+
if col.Hidden != columns[i].Hidden {
201+
return false
202+
}
203+
if col.GeneratedExprString != columns[i].GeneratedExprString {
204+
return false
205+
}
206+
if col.Version != columns[i].Version {
177207
return false
178208
}
179209
}

pkg/common/table_info_helper_test.go

Lines changed: 138 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -504,15 +504,16 @@ func TestGetOrSetColumnSchema_SharedSchema(t *testing.T) {
504504
},
505505
}
506506

507-
// Get shared column schema storage
508-
storage := GetSharedColumnSchemaStorage()
507+
storage := &SharedColumnSchemaStorage{
508+
m: make(map[Digest][]ColumnSchemaWithCount),
509+
}
509510

510511
// Get column schema for both tables
511512
columnSchema1 := storage.GetOrSetColumnSchema(tableInfo1)
512513
columnSchema2 := storage.GetOrSetColumnSchema(tableInfo2)
513514

514515
// Verify that both tables share the same columnSchema object
515-
require.Equal(t, columnSchema1, columnSchema2, "Tables with same schema should share the same columnSchema object")
516+
require.Same(t, columnSchema1, columnSchema2, "Tables with same schema should share the same columnSchema object")
516517

517518
// Verify that the digest is the same
518519
require.Equal(t, columnSchema1.Digest, columnSchema2.Digest, "Digest should be the same for tables with same schema")
@@ -572,10 +573,143 @@ func TestGetOrSetColumnSchema_SharedSchema(t *testing.T) {
572573
columnSchema3 := storage.GetOrSetColumnSchema(tableInfo3)
573574

574575
// Verify that different schema creates a different columnSchema object
575-
require.NotEqual(t, columnSchema1, columnSchema3, "Tables with different schema should have different columnSchema objects")
576+
require.NotSame(t, columnSchema1, columnSchema3, "Tables with different schema should have different columnSchema objects")
576577
require.NotEqual(t, columnSchema1.Digest, columnSchema3.Digest, "Digest should be different for tables with different schema")
577578
}
578579

580+
func TestGetOrSetColumnSchema_SameColumnsAndIndices_ChecksAdditionalColumnAttrs(t *testing.T) {
581+
tests := []struct {
582+
name string
583+
mutate func(col *model.ColumnInfo) error
584+
expectDigestSame bool
585+
}{
586+
{
587+
name: "origin default value",
588+
mutate: func(col *model.ColumnInfo) error {
589+
return col.SetOriginDefaultValue(int64(2))
590+
},
591+
expectDigestSame: true,
592+
},
593+
{
594+
name: "default is expr",
595+
mutate: func(col *model.ColumnInfo) error {
596+
col.DefaultIsExpr = true
597+
return nil
598+
},
599+
expectDigestSame: false,
600+
},
601+
{
602+
name: "generated stored",
603+
mutate: func(col *model.ColumnInfo) error {
604+
col.GeneratedStored = true
605+
return nil
606+
},
607+
expectDigestSame: false,
608+
},
609+
{
610+
name: "hidden column",
611+
mutate: func(col *model.ColumnInfo) error {
612+
col.Hidden = true
613+
return nil
614+
},
615+
expectDigestSame: false,
616+
},
617+
{
618+
name: "generated expr string",
619+
mutate: func(col *model.ColumnInfo) error {
620+
col.GeneratedExprString = "id + 2"
621+
return nil
622+
},
623+
expectDigestSame: true,
624+
},
625+
{
626+
name: "column info version",
627+
mutate: func(col *model.ColumnInfo) error {
628+
col.Version = model.ColumnInfoVersion0
629+
return nil
630+
},
631+
expectDigestSame: false,
632+
},
633+
}
634+
635+
newStorage := func() *SharedColumnSchemaStorage {
636+
return &SharedColumnSchemaStorage{m: make(map[Digest][]ColumnSchemaWithCount)}
637+
}
638+
639+
buildTable := func(idCol, otherCol *model.ColumnInfo) *model.TableInfo {
640+
return &model.TableInfo{
641+
ID: 1,
642+
Name: ast.NewCIStr("t"),
643+
PKIsHandle: true,
644+
Columns: []*model.ColumnInfo{
645+
idCol,
646+
otherCol,
647+
},
648+
Indices: []*model.IndexInfo{
649+
{
650+
ID: 1,
651+
Name: ast.NewCIStr("PRIMARY"),
652+
Primary: true,
653+
Unique: true,
654+
State: model.StatePublic,
655+
Columns: []*model.IndexColumn{
656+
{
657+
Name: ast.NewCIStr("id"),
658+
Offset: 0,
659+
},
660+
},
661+
},
662+
},
663+
}
664+
}
665+
666+
buildBaseTable := func() (*model.TableInfo, error) {
667+
idCol := newColumnInfo(1, "id", mysql.TypeLong, mysql.PriKeyFlag|mysql.NotNullFlag)
668+
idCol.Offset = 0
669+
otherCol := newColumnInfo(2, "c", mysql.TypeLong, mysql.NotNullFlag|mysql.GeneratedColumnFlag)
670+
otherCol.Offset = 1
671+
if err := otherCol.SetDefaultValue(int64(1)); err != nil {
672+
return nil, err
673+
}
674+
if err := otherCol.SetOriginDefaultValue(int64(1)); err != nil {
675+
return nil, err
676+
}
677+
otherCol.DefaultIsExpr = false
678+
otherCol.GeneratedExprString = "id + 1"
679+
otherCol.GeneratedStored = false
680+
otherCol.Hidden = false
681+
otherCol.Version = model.CurrLatestColumnInfoVersion
682+
return buildTable(idCol, otherCol), nil
683+
}
684+
685+
for _, tt := range tests {
686+
t.Run(tt.name, func(t *testing.T) {
687+
storage := newStorage()
688+
689+
baseTable, err := buildBaseTable()
690+
require.NoError(t, err)
691+
baseSchema := storage.GetOrSetColumnSchema(baseTable)
692+
693+
variantTable, err := buildBaseTable()
694+
require.NoError(t, err)
695+
err = tt.mutate(variantTable.Columns[1])
696+
require.NoError(t, err)
697+
variantSchema := storage.GetOrSetColumnSchema(variantTable)
698+
699+
if tt.expectDigestSame {
700+
require.Equal(t, baseSchema.Digest, variantSchema.Digest)
701+
require.NotSame(t, baseSchema, variantSchema)
702+
require.Len(t, storage.m[baseSchema.Digest], 2)
703+
} else {
704+
require.NotEqual(t, baseSchema.Digest, variantSchema.Digest)
705+
require.NotSame(t, baseSchema, variantSchema)
706+
require.Len(t, storage.m[baseSchema.Digest], 1)
707+
require.Len(t, storage.m[variantSchema.Digest], 1)
708+
}
709+
})
710+
}
711+
}
712+
579713
func TestIsEligible(t *testing.T) {
580714
t.Parallel()
581715

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# diff Configuration.
2+
3+
check-thread-count = 4
4+
5+
export-fix-sql = true
6+
7+
check-struct-only = false
8+
9+
[task]
10+
output-dir = "/tmp/tidb_cdc_test/correctness_for_shared_column_schema/sync_diff/output"
11+
12+
source-instances = ["mysql1"]
13+
14+
target-instance = "tidb0"
15+
16+
target-check-tables = ["test_?00.t1"]
17+
18+
[data-sources]
19+
[data-sources.mysql1]
20+
host = "127.0.0.1"
21+
port = 4000
22+
user = "root"
23+
password = ""
24+
25+
[data-sources.tidb0]
26+
host = "127.0.0.1"
27+
port = 3306
28+
user = "root"
29+
password = ""
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
DROP DATABASE IF EXISTS test_100;
2+
CREATE DATABASE test_100;
3+
USE test_100;
4+
CREATE TABLE t1 (a INT, b INT, site_code VARCHAR(64) NOT NULL DEFAULT '', PRIMARY KEY (a, site_code));
5+
INSERT INTO t1 VALUES (1, 2, '100'), (2, 3, '100'), (12, 13, '100');
6+
7+
DROP DATABASE IF EXISTS test_200;
8+
CREATE DATABASE test_200;
9+
USE test_200;
10+
CREATE TABLE t1 (a INT, b INT, site_code VARCHAR(64) NOT NULL DEFAULT '', PRIMARY KEY (a, site_code));
11+
INSERT INTO t1 VALUES (1, 2, '200'), (2, 3, '200'), (12, 13, '200');
12+
13+
DROP DATABASE IF EXISTS test_300;
14+
CREATE DATABASE test_300;
15+
USE test_300;
16+
CREATE TABLE t1 (a INT, b INT, site_code VARCHAR(64) NOT NULL DEFAULT '', PRIMARY KEY (a, site_code));
17+
INSERT INTO t1 VALUES (1, 2, '300'), (2, 3, '300'), (12, 13, '300');
18+
19+
DROP DATABASE IF EXISTS test_400;
20+
CREATE DATABASE test_400;
21+
USE test_400;
22+
CREATE TABLE t1 (a INT, b INT, site_code VARCHAR(64) NOT NULL DEFAULT '', PRIMARY KEY (a, site_code));
23+
INSERT INTO t1 VALUES (1, 2, '400'), (2, 3, '400'), (12, 13, '400');
24+
25+
DROP DATABASE IF EXISTS test_500;
26+
CREATE DATABASE test_500;
27+
USE test_500;
28+
CREATE TABLE t1 (a INT, b INT, site_code VARCHAR(64) NOT NULL DEFAULT '', PRIMARY KEY (a, site_code));
29+
INSERT INTO t1 VALUES (1, 2, '500'), (2, 3, '500'), (12, 13, '500');
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
USE test_100;
2+
INSERT INTO t1 (a, b) VALUES (20, 21);
3+
UPDATE t1 SET b = b + 10 WHERE a = 1 AND site_code = '100';
4+
DELETE FROM t1 WHERE a = 2 AND site_code = '100';
5+
UPDATE t1 SET b = b + 1 WHERE a = 12 AND site_code = '100';
6+
7+
USE test_200;
8+
INSERT INTO t1 (a, b) VALUES (20, 21);
9+
UPDATE t1 SET b = b + 10 WHERE a = 1 AND site_code = '200';
10+
DELETE FROM t1 WHERE a = 2 AND site_code = '200';
11+
UPDATE t1 SET b = b + 1 WHERE a = 12 AND site_code = '200';
12+
13+
USE test_300;
14+
INSERT INTO t1 (a, b) VALUES (20, 21);
15+
UPDATE t1 SET b = b + 10 WHERE a = 1 AND site_code = '300';
16+
DELETE FROM t1 WHERE a = 2 AND site_code = '300';
17+
UPDATE t1 SET b = b + 1 WHERE a = 12 AND site_code = '300';
18+
19+
USE test_400;
20+
INSERT INTO t1 (a, b) VALUES (20, 21);
21+
UPDATE t1 SET b = b + 10 WHERE a = 1 AND site_code = '400';
22+
DELETE FROM t1 WHERE a = 2 AND site_code = '400';
23+
UPDATE t1 SET b = b + 1 WHERE a = 12 AND site_code = '400';
24+
25+
USE test_500;
26+
INSERT INTO t1 (a, b) VALUES (20, 21);
27+
UPDATE t1 SET b = b + 10 WHERE a = 1 AND site_code = '500';
28+
DELETE FROM t1 WHERE a = 2 AND site_code = '500';
29+
UPDATE t1 SET b = b + 1 WHERE a = 12 AND site_code = '500';
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
DROP DATABASE IF EXISTS test_100;
2+
CREATE DATABASE test_100;
3+
USE test_100;
4+
CREATE TABLE t1 (a INT, b INT);
5+
INSERT INTO t1 VALUES (1, 2), (2, 3);
6+
ALTER TABLE t1 ADD COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '100';
7+
INSERT INTO t1 VALUES (12, 13, '100');
8+
ALTER TABLE t1 MODIFY COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '';
9+
ALTER TABLE t1 ADD PRIMARY KEY (a, site_code);
10+
11+
DROP DATABASE IF EXISTS test_200;
12+
CREATE DATABASE test_200;
13+
USE test_200;
14+
CREATE TABLE t1 (a INT, b INT);
15+
INSERT INTO t1 VALUES (1, 2), (2, 3);
16+
ALTER TABLE t1 ADD COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '200';
17+
INSERT INTO t1 VALUES (12, 13, '200');
18+
ALTER TABLE t1 MODIFY COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '';
19+
ALTER TABLE t1 ADD PRIMARY KEY (a, site_code);
20+
21+
DROP DATABASE IF EXISTS test_300;
22+
CREATE DATABASE test_300;
23+
USE test_300;
24+
CREATE TABLE t1 (a INT, b INT);
25+
INSERT INTO t1 VALUES (1, 2), (2, 3);
26+
ALTER TABLE t1 ADD COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '300';
27+
INSERT INTO t1 VALUES (12, 13, '300');
28+
ALTER TABLE t1 MODIFY COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '';
29+
ALTER TABLE t1 ADD PRIMARY KEY (a, site_code);
30+
31+
DROP DATABASE IF EXISTS test_400;
32+
CREATE DATABASE test_400;
33+
USE test_400;
34+
CREATE TABLE t1 (a INT, b INT);
35+
INSERT INTO t1 VALUES (1, 2), (2, 3);
36+
ALTER TABLE t1 ADD COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '400';
37+
INSERT INTO t1 VALUES (12, 13, '400');
38+
ALTER TABLE t1 MODIFY COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '';
39+
ALTER TABLE t1 ADD PRIMARY KEY (a, site_code);
40+
41+
DROP DATABASE IF EXISTS test_500;
42+
CREATE DATABASE test_500;
43+
USE test_500;
44+
CREATE TABLE t1 (a INT, b INT);
45+
INSERT INTO t1 VALUES (1, 2), (2, 3);
46+
ALTER TABLE t1 ADD COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '500';
47+
INSERT INTO t1 VALUES (12, 13, '500');
48+
ALTER TABLE t1 MODIFY COLUMN site_code VARCHAR(64) NOT NULL DEFAULT '';
49+
ALTER TABLE t1 ADD PRIMARY KEY (a, site_code);

0 commit comments

Comments
 (0)