-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Fix BIT column in unique key bug
#1483
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
30adcb5
72a7b6e
bf160d5
854449d
e6a4b0c
c7e13a6
62a0038
a181283
ed167cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,6 +58,8 @@ func buildColumnsPreparedValues(columns *ColumnList) []string { | |
| token = fmt.Sprintf("ELT(?, %s)", column.EnumValues) | ||
| } else if column.Type == JSONColumnType { | ||
| token = "convert(? using utf8mb4)" | ||
| } else if column.Type == BitColumnType { | ||
| token = "cast(? as unsigned)" | ||
| } else { | ||
|
Comment on lines
+61
to
63
|
||
| token = "?" | ||
| } | ||
|
|
@@ -340,6 +342,7 @@ func BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, tableName string | |
| if includeRangeStartValues { | ||
| startRangeComparisonSign = GreaterThanOrEqualsComparisonSign | ||
| } | ||
|
|
||
| rangeStartComparison, rangeExplodedArgs, err := BuildRangePreparedComparison(uniqueKeyColumns, rangeStartArgs, startRangeComparisonSign) | ||
| if err != nil { | ||
| return "", explodedArgs, err | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,6 +24,7 @@ const ( | |||||||||||||||||||||||
| JSONColumnType | ||||||||||||||||||||||||
| FloatColumnType | ||||||||||||||||||||||||
| BinaryColumnType | ||||||||||||||||||||||||
| BitColumnType | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const maxMediumintUnsigned int32 = 16777215 | ||||||||||||||||||||||||
|
|
@@ -95,6 +96,15 @@ func (this *Column) convertArg(arg interface{}) interface{} { | |||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // We convert BIT col to uint64 to force correct value comparison. | ||||||||||||||||||||||||
| if this.Type == BitColumnType { | ||||||||||||||||||||||||
| var n uint64 | ||||||||||||||||||||||||
| for _, b := range arg2Bytes { | ||||||||||||||||||||||||
| n = (n << 8) | uint64(b) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| arg = n | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return arg | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -342,6 +352,12 @@ func (this *ColumnValues) AbstractValues() []interface{} { | |||||||||||||||||||||||
| return this.abstractValues | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| func (this *ColumnValues) NormalizeValues(columns ColumnList) { | ||||||||||||||||||||||||
| for i, col := range columns.Columns() { | ||||||||||||||||||||||||
| this.abstractValues[i] = col.convertArg(this.abstractValues[i]) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
Comment on lines
+356
to
+358
|
||||||||||||||||||||||||
| for i, col := range columns.Columns() { | |
| this.abstractValues[i] = col.convertArg(this.abstractValues[i]) | |
| } | |
| cols := columns.Columns() | |
| limit := len(cols) | |
| if len(this.abstractValues) < limit { | |
| limit = len(this.abstractValues) | |
| } | |
| for i := 0; i < limit; i++ { | |
| this.abstractValues[i] = cols[i].convertArg(this.abstractValues[i]) | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| drop table if exists gh_ost_test; | ||
| create table gh_ost_test ( | ||
| `id` bigint not null, | ||
| `bit_col` bit not null, | ||
| primary key (`id`, `bit_col`) | ||
| ) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; | ||
| insert into gh_ost_test values (1, b'1'); | ||
| insert into gh_ost_test values (2, b'1'); | ||
| insert into gh_ost_test values (3, b'1'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BIT normalization is applied for min/max range reads, but the resume-from-checkpoint path populates
MigrationIterationRangeMinValues/MaxValuesfrom_ghkviaReadLastCheckpoint()and those values are never normalized. Since the checkpoint table uses the original column types (includingBIT), scanned values will still be[]uint8, which can reintroduce the incorrect range-comparison behavior (infinite loop / missing rows) after resume. Consider normalizing the checkpoint-derivedIterationRangeMin/Max(e.g., insideReadLastCheckpoint()before returning, or immediately after assigning them during resume).