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

Can not swap values by a multi-tables update #19137

Closed
zyguan opened this issue Aug 11, 2020 · 15 comments · Fixed by #20493
Closed

Can not swap values by a multi-tables update #19137

zyguan opened this issue Aug 11, 2020 · 15 comments · Fixed by #20493
Assignees
Labels
severity/major sig/execution SIG execution type/bug The issue is confirmed as a bug. type/compatibility
Milestone

Comments

@zyguan
Copy link
Contributor

zyguan commented Aug 11, 2020

Bug Report

Please answer these questions before submitting your issue. Thanks!

1. Minimal reproduce step (Required)

drop table if exists t1, t2;
create table t1 (c_str varchar(40));
create table t2 (c_str varchar(40));
insert into t1 values ('Alice');
insert into t2 values ('Bob');
select t1.c_str, t2.c_str from t1, t2 where t1.c_str <= t2.c_str;
update t1, t2 set t1.c_str = t2.c_str, t2.c_str = t1.c_str where t1.c_str <= t2.c_str;
select t1.c_str, t2.c_str from t1, t2 where t1.c_str <= t2.c_str;

2. What did you expect to see? (Required)

The values of t1.c_str and t2.c_str should be swapped in the above case, that is, the last selection should return an empty set.

3. What did you see instead (Required)

mysql> select t1.c_str, t2.c_str from t1, t2 where t1.c_str <= t2.c_str;
+-------+-------+
| c_str | c_str |
+-------+-------+
| Alice | Bob   |
+-------+-------+
1 row in set (0.06 sec)

mysql> update t1, t2 set t1.c_str = t2.c_str, t2.c_str = t1.c_str where t1.c_str <= t2.c_str;
Query OK, 1 row affected (0.06 sec)
Rows matched: 2  Changed: 1  Warnings: 0

mysql> select t1.c_str, t2.c_str from t1, t2 where t1.c_str <= t2.c_str;
+-------+-------+
| c_str | c_str |
+-------+-------+
| Bob   | Bob   |
+-------+-------+
1 row in set (0.05 sec)

4. What is your TiDB version? (Required)

master @ 8978773
release-4.0 @ 3948c7b

@zyguan zyguan added the type/bug The issue is confirmed as a bug. label Aug 11, 2020
@zyguan
Copy link
Contributor Author

zyguan commented Aug 11, 2020

/assign @zz-jason

@cfzjywxk
Copy link
Contributor

The MySQL behavior is explained in link, TiDB implementation is different from MySQL.

@cfzjywxk
Copy link
Contributor

MySQL behaviors are different for single and multiple tables, the TiDB behavior is more reasonable, I think we can document about this.

@ghost
Copy link

ghost commented Aug 13, 2020

I believe the SQL standards do talk about what the correct behavior is here. I am not sure if MySQL is necessarily correct, but if TiDB differs, it should be defendable if it is at least standard.

@fzhedu
Copy link
Contributor

fzhedu commented Aug 13, 2020

I verify this in mysql version 8.0.19, it actually swaps two values from different tables. Should TiDB have the same behavior? @SunRunAway @cfzjywxk @nullnotnil

mysql> drop table if exists t1, t2;
Query OK, 0 rows affected, 2 warnings (0.00 sec)

mysql> create table t1 (c_str varchar(40));
Query OK, 0 rows affected (0.01 sec)

mysql> create table t2 (c_str varchar(40));
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1 values ('Alice');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t2 values ('Bob');
Query OK, 1 row affected (0.00 sec)

mysql> select t1.c_str, t2.c_str from t1, t2 where t1.c_str <= t2.c_str;
+-------+-------+
| c_str | c_str |
+-------+-------+
| Alice | Bob   |
+-------+-------+
1 row in set (0.00 sec)

mysql> update t1, t2 set t1.c_str = t2.c_str, t2.c_str = t1.c_str where t1.c_str <= t2.c_str;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2  Changed: 2  Warnings: 0

mysql> select t1.c_str, t2.c_str from t1, t2 where t1.c_str <= t2.c_str;
Empty set (0.00 sec)

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.19    |
+-----------+
1 row in set (0.00 sec)

@fzhedu
Copy link
Contributor

fzhedu commented Aug 19, 2020

Yes, this is a standard behaviour in MySQL, but not only in MySQL, but most relational databases.

responsed from Mysql comminuty
https://bugs.mysql.com/bug.php?id=100527&thanks=2&notify=67
@cfzjywxk @nullnotnil @SunRunAway
So we should recovery the behavior.

@SunRunAway
Copy link
Contributor

I tried on SQLite3

sqlite> create table t(a int, b int);
sqlite> insert into t values(1, 2);
sqlite> select * from t;
1|2
sqlite> update t set a=b, b=a;
sqlite> select * from t;
2|1

@fzhedu
Copy link
Contributor

fzhedu commented Aug 24, 2020

PG

test=# create table t (a int, b int);
CREATE TABLE
test=# insert into t values (1,3);
INSERT 0 1
test=# select * from t;
 1 | 3

test=# update t set a=b, b=a;
UPDATE 1
test=# select * from t;
 3 | 1

PG does not supprot update more than one tables in one statement:

test=# update t1, t2 set t1.a=t2.a, t2.a=t1.a;
ERROR:  syntax error at or near ","
LINE 1: update t1, t2 set t1.a=t2.a, t2.a=t1.a;

@zyguan
Copy link
Contributor Author

zyguan commented Aug 24, 2020

Oracle http://sqlfiddle.com/#!4/794de/1/0

@fzhedu
Copy link
Contributor

fzhedu commented Aug 24, 2020

compared Mysql to Oracle, PG and sqlLite, only mysql does not support swaping two columns. We can verify this on http://sqlfiddle.com/#!4/794de/1/0

@imtbkcat imtbkcat modified the milestones: v4.0.5, v4.0.6 Sep 8, 2020
@AilinKid AilinKid modified the milestones: v4.0.6, 4.0.7 Sep 8, 2020
@ghost
Copy link

ghost commented Sep 11, 2020

https://bugs.mysql.com/bug.php?id=100527&thanks=2&notify=67
@cfzjywxk @nullnotnil @SunRunAway
So we should recovery the behavior.

I think it is better to have the standard behavior here.

If it turns out users depend on the (incorrect) MySQL behavior, we can add an option to permit this behavior. But to keep the options to a minimum: change it first, add the option if it becomes required.

@lzmhhh123 lzmhhh123 removed this from the v4.0.7 milestone Sep 21, 2020
@SunRunAway
Copy link
Contributor

SunRunAway commented Oct 13, 2020

I think it is better to have the standard behavior here.
change it first, add the option if it becomes required.

Agree. Let's resolve this issue as @nullnotnil said. That is, TiDB swaps two values from one table if the query is update t set t.a=t.b, t.b=t.a;

cc @cfzjywxk, @lzmhhh123, @fzhedu

@lzmhhh123
Copy link
Contributor

/cc @dyzsr

@dyzsr
Copy link
Contributor

dyzsr commented Oct 13, 2020

/assign

@ti-srebot
Copy link
Contributor

Please edit this comment or add a new comment to complete the following information

Not a bug

  1. Remove the 'type/bug' label
  2. Add notes to indicate why it is not a bug

Duplicate bug

  1. Add the 'type/duplicate' label
  2. Add the link to the original bug

Bug

Note: Make Sure that 'component', and 'severity' labels are added
Example for how to fill out the template: #20100

1. Root Cause Analysis (RCA) (optional)

2. Symptom (optional)

3. All Trigger Conditions (optional)

4. Workaround (optional)

5. Affected versions

6. Fixed versions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
severity/major sig/execution SIG execution type/bug The issue is confirmed as a bug. type/compatibility
Projects
None yet