-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
executor: fix panic and update error data when table has column in write only state #8792
executor: fix panic and update error data when table has column in write only state #8792
Conversation
/run-all-tests |
84ae70a
to
0cdf468
Compare
/rebuild |
/run-all-tests |
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.
Do we need to append value to newData after
Line 305 in bd69b15
value = oldData[col.Offset] |
@jackysp newData will already have the value of writeOnly column. tidb/planner/core/logical_plan_builder.go Line 1916 in bd69b15
|
How about |
e40f54a
to
7ce2a24
Compare
/run-all-tests |
/run-unit-test |
executor/write.go
Outdated
@@ -143,7 +143,7 @@ func updateRecord(ctx sessionctx.Context, h int64, oldData, newData []types.Datu | |||
return false, false, 0, errors.Trace(err) | |||
} | |||
// the `affectedRows` is increased when adding new record. | |||
newHandle, err = t.AddRecord(ctx, newData, skipHandleCheck) | |||
newHandle, err = t.AddRecord(ctx, newData[:len(t.Cols())], skipHandleCheck) |
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.
Add some comments to explain.
@jackysp PTAL |
59d5c39
to
0f5cc8d
Compare
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.
LGTM
/run-all-tests |
/run-unit-test |
203e2cd
to
a115126
Compare
@jackysp How about adding a new interface |
235ae1d
to
e95dca1
Compare
/run-all-tests |
/run-common-test |
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.
LGTM
LGTM |
@@ -425,7 +425,7 @@ func (t *tableCommon) AddRecord(ctx sessionctx.Context, r []types.Datum, opts .. | |||
} | |||
var hasRecordID bool | |||
cols := t.Cols() | |||
if len(r) > len(cols) { | |||
if len(r) > len(cols) && !opt.IsUpdate { |
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.
Add some comments about opt.IsUpdate
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.
reset LGTM
/run-all-tests |
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.
LGTM
/run-unit-test |
/run-common-test |
1 similar comment
/run-common-test |
What problem does this PR solve?
When table have a column in write only state, there are some problem.
For the following example, surpose table have 3 columns:
a int key,b int,c int not null
, but c column is in write only state. column a is primary key, also handle key.because insert only write public column, but update will also write column on write only state. then, in a transaction, insert first, then update will panic because update try to look up the value of write-only column from dirty table when union scan, because insert doesn't write the value of write-only column to dirty table, so update panic by index out of range.
when do update, if handle is changed, update will remove recored first, then call table.AddRecord, update will input newData with write-only column value to
table.AddRecord
, buttable.AddRecord
will think the last value is_tidb_rowid
, actualy the last value of newData is the value of write-only column. Then will cause update wrong record or overwrite the other row record. see code here: https://github.com/pingcap/tidb/pull/5984/files#diff-f92a6a9ee57cf92f8d63bd55d2edc05bR356Because online change scheme will have atmostly 2 state in cluster. Add column c, state change is: none -> delete only -> write only -> write reorganization -> public. Suppose TiDB-A is in public state , TiDB-B is in write reorganization.
first, execute in TiDB-A:
insert into t (a,b,c) value (1,1,1);
then, execute in TiDB-B:
update t set a=2 where a=1;
finally, the result of
select a,b,c from t
should be2,1,1
, but in fact, the result is2,1,0
, the value of column c is overwritten when TiDB-B executes update.What is changed and how it works?
For problem 1: insert should also write value of write-only column to dirty table, to avoid update panic.
For problem 2 and 3, change
table.AddRecord
interface, add a flag to indicate this is call for insert or update. if for update,newData
, should not get from default value.Check List
Tests
Code changes
Side effects
Related changes
This change is![Reviewable](https://camo.githubusercontent.com/1541c4039185914e83657d3683ec25920c672c6c5c7ab4240ee7bff601adec0b/68747470733a2f2f72657669657761626c652e696f2f7265766965775f627574746f6e2e737667)