Skip to content

Commit 0fe1190

Browse files
authored
Fix generated column in unique key error (#1461)
* reproduce error in generate-columns-unique * only check non-virtual columns from unique key
1 parent 19cf183 commit 0fe1190

File tree

6 files changed

+32
-10
lines changed

6 files changed

+32
-10
lines changed

go/logic/inspect.go

+4
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ func (this *Inspector) applyColumnTypes(databaseName, tableName string, columnsL
628628
columnName := m.GetString("COLUMN_NAME")
629629
columnType := m.GetString("COLUMN_TYPE")
630630
columnOctetLength := m.GetUint("CHARACTER_OCTET_LENGTH")
631+
extra := m.GetString("EXTRA")
631632
for _, columnsList := range columnsLists {
632633
column := columnsList.GetColumn(columnName)
633634
if column == nil {
@@ -660,6 +661,9 @@ func (this *Inspector) applyColumnTypes(databaseName, tableName string, columnsL
660661
column.Type = sql.BinaryColumnType
661662
column.BinaryOctetLength = columnOctetLength
662663
}
664+
if strings.Contains(extra, " GENERATED") {
665+
column.IsVirtual = true
666+
}
663667
if charset := m.GetString("CHARACTER_SET_NAME"); charset != "" {
664668
column.Charset = charset
665669
}

go/sql/builder.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,12 @@ func NewDMLUpdateQueryBuilder(databaseName, tableName string, tableColumns, shar
546546
if uniqueKeyColumns.Len() == 0 {
547547
return nil, fmt.Errorf("no unique key columns found in NewDMLUpdateQueryBuilder")
548548
}
549+
// If unique key contains virtual columns, those column won't be in sharedColumns
550+
// which only contains non-virtual columns
551+
nonVirtualUniqueKeyColumns := uniqueKeyColumns.FilterBy(func(column Column) bool { return !column.IsVirtual })
552+
if !nonVirtualUniqueKeyColumns.IsSubsetOf(sharedColumns) {
553+
return nil, fmt.Errorf("unique key columns is not a subset of shared columns in NewDMLUpdateQueryBuilder")
554+
}
549555
databaseName = EscapeName(databaseName)
550556
tableName = EscapeName(tableName)
551557
setClause, err := BuildSetPreparedClause(mappedSharedColumns)
@@ -580,11 +586,6 @@ func NewDMLUpdateQueryBuilder(databaseName, tableName string, tableColumns, shar
580586
// BuildQuery builds the arguments array for a DML event UPDATE query.
581587
// It returns the query string, the shared arguments array, and the unique key arguments array.
582588
func (b *DMLUpdateQueryBuilder) BuildQuery(valueArgs, whereArgs []interface{}) (string, []interface{}, []interface{}, error) {
583-
// TODO: move this check back to `NewDMLUpdateQueryBuilder()`, needs fix on generated columns.
584-
if !b.uniqueKeyColumns.IsSubsetOf(b.sharedColumns) {
585-
return "", nil, nil, fmt.Errorf("unique key columns is not a subset of shared columns in DMLUpdateQueryBuilder")
586-
}
587-
588589
sharedArgs := make([]interface{}, 0, b.sharedColumns.Len())
589590
for _, column := range b.sharedColumns.Columns() {
590591
tableOrdinal := b.tableColumns.Ordinals[column.Name]

go/sql/builder_test.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -688,9 +688,7 @@ func TestBuildDMLUpdateQuery(t *testing.T) {
688688
{
689689
sharedColumns := NewColumnList([]string{"id", "name", "position", "age"})
690690
uniqueKeyColumns := NewColumnList([]string{"age", "surprise"})
691-
builder, err := NewDMLUpdateQueryBuilder(databaseName, tableName, tableColumns, sharedColumns, sharedColumns, uniqueKeyColumns)
692-
require.NoError(t, err)
693-
_, _, _, err = builder.BuildQuery(valueArgs, whereArgs)
691+
_, err := NewDMLUpdateQueryBuilder(databaseName, tableName, tableColumns, sharedColumns, sharedColumns, uniqueKeyColumns)
694692
require.Error(t, err)
695693
}
696694
{

go/sql/types.go

+11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type CharacterSetConversion struct {
4040
type Column struct {
4141
Name string
4242
IsUnsigned bool
43+
IsVirtual bool
4344
Charset string
4445
Type ColumnType
4546
EnumValues string
@@ -244,6 +245,16 @@ func (this *ColumnList) IsSubsetOf(other *ColumnList) bool {
244245
return true
245246
}
246247

248+
func (this *ColumnList) FilterBy(f func(Column) bool) *ColumnList {
249+
filteredCols := make([]Column, 0, len(this.columns))
250+
for _, column := range this.columns {
251+
if f(column) {
252+
filteredCols = append(filteredCols, column)
253+
}
254+
}
255+
return &ColumnList{Ordinals: this.Ordinals, columns: filteredCols}
256+
}
257+
247258
func (this *ColumnList) Len() int {
248259
return len(this.columns)
249260
}

localtests/generated-columns-unique/create.sql

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ create table gh_ost_test (
33
id int auto_increment,
44
`idb` varchar(36) CHARACTER SET utf8mb4 GENERATED ALWAYS AS (json_unquote(json_extract(`jsonobj`,_utf8mb4'$._id'))) STORED NOT NULL,
55
`jsonobj` json NOT NULL,
6+
updated datetime DEFAULT NULL,
67
PRIMARY KEY (`id`,`idb`)
78
) auto_increment=1;
89

@@ -25,6 +26,11 @@ begin
2526
insert into gh_ost_test (id, jsonobj) values (null, '{"_id":13}');
2627
insert into gh_ost_test (id, jsonobj) values (null, '{"_id":17}');
2728
insert into gh_ost_test (id, jsonobj) values (null, '{"_id":19}');
28-
insert into gh_ost_test (id, jsonobj) values (null, '{"_id":23}');
29-
insert into gh_ost_test (id, jsonobj) values (null, '{"_id":27}');
29+
30+
update gh_ost_test set updated=NOW() where idb=5;
31+
update gh_ost_test set updated=NOW() where idb=7;
32+
update gh_ost_test set updated=NOW() where idb=11;
33+
update gh_ost_test set updated=NOW() where idb=13;
34+
update gh_ost_test set updated=NOW() where idb=17;
35+
update gh_ost_test set updated=NOW() where idb=19;
3036
end ;;

localtests/generated-columns/create.sql

+2
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,6 @@ begin
2727
insert into gh_ost_test (id, a, b) values (null, 2,0);
2828
insert into gh_ost_test (id, a, b) values (null, 2,1);
2929
insert into gh_ost_test (id, a, b) values (null, 2,2);
30+
update gh_ost_test set b=b+1 where id < 5;
31+
update gh_ost_test set b=b-1 where id >= 5;
3032
end ;;

0 commit comments

Comments
 (0)