Skip to content
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

Expression filter: UPDATE filter always return "TRUE" when there are INSERT/DELETE filters for the same table #7831

Closed
kennytm opened this issue Dec 7, 2022 · 1 comment · Fixed by #7851

Comments

@kennytm
Copy link
Contributor

kennytm commented Dec 7, 2022

What did you do?

  1. create and populate the table...
create table db.tbl (p bigint primary key, v int);
insert into db.tbl values (1, 1), (3, 3);
  1. prepare a DM task with the following filters
expression-filter:
  e11:
    schema: db
    table: tbl
    insert-value-expr: v = 1
  e12:
    schema: db
    table: tbl
    update-old-value-expr: v = 1
    update-new-value-expr: v = 1

mysql-instances:
- expression-filters: ["e11", "e12"]
  ....
  1. Perform an UPDATE
update db.tbl set v = 2 where v = 3;

What did you expect to see?

The UPDATE statement should be synchronized since it hits none of the filters

select * from db.tbl;
p v
1 1
3 2

What did you see instead?

The UPDATE statement is skipped

p v
1 1
3 3

(The log indicates the expression "1" is evaluated inside SkipDMLByExpression)

Versions of the cluster

v6.4.0

current status of DM cluster (execute query-status <task-name> in dmctl)

No response

@kennytm
Copy link
Contributor Author

kennytm commented Dec 7, 2022

if _, ok := g.hasUpdateFilter[tableID]; ok {
for _, c := range g.configs[tableID] {
if c.UpdateOldValueExpr != "" {
expr, err := getSimpleExprOfTable(g.tidbCtx, c.UpdateOldValueExpr, ti, g.logCtx.L())
if err != nil {
// TODO: terror
return nil, nil, err
}
g.updateOldExprs[tableID] = append(g.updateOldExprs[tableID], expr)
} else {
g.updateOldExprs[tableID] = append(g.updateOldExprs[tableID], expression.NewOne())
}
if c.UpdateNewValueExpr != "" {
expr, err := getSimpleExprOfTable(g.tidbCtx, c.UpdateNewValueExpr, ti, g.logCtx.L())
if err != nil {
// TODO: terror
return nil, nil, err
}
g.updateNewExprs[tableID] = append(g.updateNewExprs[tableID], expr)
} else {
g.updateNewExprs[tableID] = append(g.updateNewExprs[tableID], expression.NewOne())
}
}
}

When a table db.tbl contains both UPDATE and non-UPDATE filters, we will find g.hasUpdateFilter[tableID] == true but some of the g.configs[tableID] contains rules that both c.UpdateOldValueExpr and c.UpdateNewValueExpr are empty.

The current algorithm will push "1", "1" onto the result which caused everything to be skipped.

The correct way is to not push anything when both c.UpdateOldValueExpr and c.UpdateNewValueExpr are empty, just like the correct implementation for GetInsertExprs and GetDeleteExprs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants