From: Jorgen Loland Date: February 14 2011 2:51pm Subject: bzr commit into mysql-trunk branch (jorgen.loland:3641) Bug#11762751 Bug#11764529 List-Archive: http://lists.mysql.com/commits/131195 X-Bug: 11762751,11764529 Message-Id: <20110214145151.80C0B7A3@atum21.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5699830878365128063==" --===============5699830878365128063== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/jl208045/mysql/mysql-trunk-55385/ based on revid:luis.soares@stripped 3641 Jorgen Loland 2011-02-14 BUG#11762751: UPDATE STATEMENT THROWS AN ERROR, BUT STILL UPDATES THE TABLE ENTRIES (formerly 55385) BUG#11764529: MULTI UPDATE+INNODB REPORTS ER_KEY_NOT_FOUND IF A TABLE IS UPDATED TWICE (formerly 57373) If multiple-table update updates a row through two aliases and the first update physically moves the row, the second update will fail to locate the row. This results in an error. Two update operations may physically move a row: 1) Update of a column in a clustered primary key 2) Update of a column used to calculate which partition the row belongs to BUG#11764529 is about case 1) above, BUG#11762751 was about case 2). The fix for these bugs is to return with an error if multiple-table update is about to: a) Update a table through multiple aliases, and b) Perform an update that may physically more the row in at least one of these aliases @ mysql-test/r/multi_update.result Add test for bug#57373 @ mysql-test/r/multi_update_innodb.result Add test for BUG#57373 @ mysql-test/r/partition.result Add test for bug#55385 @ mysql-test/t/multi_update.test Add test for bug#57373 @ mysql-test/t/multi_update_innodb.test Add test for BUG#57373 @ mysql-test/t/partition.test Add test for bug#55385 @ sql/handler.cc Translate handler error HA_ERR_RECORD_DELETED to server error @ sql/share/errmsg-utf8.txt New error message for multi-table update where the same table is updated multiple times. @ sql/sql_update.cc Add function unsafe_key_update() added: mysql-test/r/multi_update_innodb.result mysql-test/t/multi_update_innodb.test modified: mysql-test/r/multi_update.result mysql-test/r/partition.result mysql-test/t/multi_update.test mysql-test/t/partition.test sql/handler.cc sql/share/errmsg-utf8.txt sql/sql_update.cc === modified file 'mysql-test/r/multi_update.result' --- a/mysql-test/r/multi_update.result 2010-12-14 11:15:13 +0000 +++ b/mysql-test/r/multi_update.result 2011-02-14 14:51:47 +0000 @@ -680,4 +680,21 @@ Warnings: Warning 1292 Truncated incorrect datetime value: '1' DROP FUNCTION f1; DROP TABLE t1; +# +# BUG#57373: Multi update+InnoDB reports ER_KEY_NOT_FOUND if a +# table is updated twice +# +CREATE TABLE t1( +pk INT, +a INT, +PRIMARY KEY (pk) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (0,0); +UPDATE t1 AS A, t1 AS B SET A.pk = 1, B.a = 2; + +# Should be (1,2) +SELECT * FROM t1; +pk a +1 2 +DROP TABLE t1; end of tests === added file 'mysql-test/r/multi_update_innodb.result' --- a/mysql-test/r/multi_update_innodb.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/r/multi_update_innodb.result 2011-02-14 14:51:47 +0000 @@ -0,0 +1,25 @@ +# +# BUG#57373: Multi update+InnoDB reports ER_KEY_NOT_FOUND if a +# table is updated twice +# +CREATE TABLE t1( +pk INT, +a INT, +PRIMARY KEY (pk) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES (0,0); +UPDATE t1 AS A, t1 AS B SET A.pk = 1, B.a = 2; +ERROR HY000: Primary key/partition key update is not allowed since the table is updated both as 'A' and 'B'. +SELECT * FROM t1; +pk a +0 0 +CREATE VIEW v1 AS SELECT * FROM t1; +UPDATE v1 AS A, t1 AS B SET A.pk = 1, B.a = 2; +ERROR HY000: Primary key/partition key update is not allowed since the table is updated both as 'A' and 'B'. + +# Should be (0,0) +SELECT * FROM t1; +pk a +0 0 +DROP VIEW v1; +DROP TABLE t1; === modified file 'mysql-test/r/partition.result' --- a/mysql-test/r/partition.result 2011-01-10 16:37:47 +0000 +++ b/mysql-test/r/partition.result 2011-02-14 14:51:47 +0000 @@ -2263,3 +2263,51 @@ INSERT INTO t1 VALUES(0); DROP TABLE t1; SET GLOBAL myisam_use_mmap=default; End of 5.1 tests +# +# BUG#55385: UPDATE statement throws an error, but still updates +# the table entries +CREATE TABLE t1_part ( +col1 int, +col2 int +) PARTITION BY LINEAR HASH(col1) PARTITIONS 3; +INSERT INTO t1_part VALUES (1, 1) , (10, 10); +CREATE VIEW v1 AS SELECT * FROM t1_part; + +# Should be (1,1),(10,10) +SELECT * FROM t1_part; +col1 col2 +1 1 +10 10 + +# Case 1 +# Update is refused because partitioning key is updated +UPDATE t1_part AS A NATURAL JOIN t1_part B SET A.col1 = 2, B.col2 = 3; +ERROR HY000: Primary key/partition key update is not allowed since the table is updated both as 'A' and 'B'. +UPDATE t1_part AS A NATURAL JOIN t1_part B SET A.col2 = 2, B.col1 = 3; +ERROR HY000: Primary key/partition key update is not allowed since the table is updated both as 'A' and 'B'. + +# Case 2 +# Like 1, but partition accessed through a view +UPDATE t1_part AS A NATURAL JOIN v1 as B SET A.col2 = 2 , B.col1 = 3; +ERROR HY000: Primary key/partition key update is not allowed since the table is updated both as 'A' and 'B'. +UPDATE v1 AS A NATURAL JOIN t1_part as B SET A.col2 = 2 , B.col1 = 3; +ERROR HY000: Primary key/partition key update is not allowed since the table is updated both as 'A' and 'B'. + +# Should be (1,1),(10,10) +SELECT * FROM t1_part; +col1 col2 +1 1 +10 10 + +# Case 3 +# Update is accepted because partitioning key is not updated +UPDATE t1_part AS A NATURAL JOIN t1_part B SET A.col2 = 2 , B.col2 = 3; + +# Should be (1,3),(10,3) +SELECT * FROM t1_part; +col1 col2 +1 3 +10 3 + +DROP VIEW v1; +DROP TABLE t1_part; === modified file 'mysql-test/t/multi_update.test' --- a/mysql-test/t/multi_update.test 2010-12-14 11:15:13 +0000 +++ b/mysql-test/t/multi_update.test 2011-02-14 14:51:47 +0000 @@ -683,4 +683,24 @@ UPDATE (SELECT 1 FROM t1 WHERE f1 = (SEL DROP FUNCTION f1; DROP TABLE t1; +--echo # +--echo # BUG#57373: Multi update+InnoDB reports ER_KEY_NOT_FOUND if a +--echo # table is updated twice +--echo # + +# Results differ between storage engines. +# See multi_update_innodb.test for the InnoDB variant of this test +CREATE TABLE t1( + pk INT, + a INT, + PRIMARY KEY (pk) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (0,0); +UPDATE t1 AS A, t1 AS B SET A.pk = 1, B.a = 2; +--echo +--echo # Should be (1,2) +SELECT * FROM t1; +DROP TABLE t1; + --echo end of tests === added file 'mysql-test/t/multi_update_innodb.test' --- a/mysql-test/t/multi_update_innodb.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/t/multi_update_innodb.test 2011-02-14 14:51:47 +0000 @@ -0,0 +1,31 @@ +--source include/have_innodb.inc + +--echo # +--echo # BUG#57373: Multi update+InnoDB reports ER_KEY_NOT_FOUND if a +--echo # table is updated twice +--echo # + +# Results differ between storage engines. +# See multi_update.test for the MyISAM variant of this test +CREATE TABLE t1( + pk INT, + a INT, + PRIMARY KEY (pk) +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES (0,0); +--error ER_MULTI_UPDATE_KEY_CONFLICT +UPDATE t1 AS A, t1 AS B SET A.pk = 1, B.a = 2; +SELECT * FROM t1; + +CREATE VIEW v1 AS SELECT * FROM t1; +--error ER_MULTI_UPDATE_KEY_CONFLICT +UPDATE v1 AS A, t1 AS B SET A.pk = 1, B.a = 2; + +--echo +--echo # Should be (0,0) +SELECT * FROM t1; + +DROP VIEW v1; +DROP TABLE t1; + === modified file 'mysql-test/t/partition.test' --- a/mysql-test/t/partition.test 2011-01-10 16:37:47 +0000 +++ b/mysql-test/t/partition.test 2011-02-14 14:51:47 +0000 @@ -2266,3 +2266,53 @@ DROP TABLE t1; SET GLOBAL myisam_use_mmap=default; --echo End of 5.1 tests + +--echo # +--echo # BUG#55385: UPDATE statement throws an error, but still updates +--echo # the table entries + +CREATE TABLE t1_part ( + col1 int, + col2 int +) PARTITION BY LINEAR HASH(col1) PARTITIONS 3; + +INSERT INTO t1_part VALUES (1, 1) , (10, 10); +CREATE VIEW v1 AS SELECT * FROM t1_part; + +--echo +--echo # Should be (1,1),(10,10) +SELECT * FROM t1_part; + +--echo +--echo # Case 1 +--echo # Update is refused because partitioning key is updated +--error ER_MULTI_UPDATE_KEY_CONFLICT +UPDATE t1_part AS A NATURAL JOIN t1_part B SET A.col1 = 2, B.col2 = 3; +--error ER_MULTI_UPDATE_KEY_CONFLICT +UPDATE t1_part AS A NATURAL JOIN t1_part B SET A.col2 = 2, B.col1 = 3; + +--echo +--echo # Case 2 +--echo # Like 1, but partition accessed through a view +--error ER_MULTI_UPDATE_KEY_CONFLICT +UPDATE t1_part AS A NATURAL JOIN v1 as B SET A.col2 = 2 , B.col1 = 3; +--error ER_MULTI_UPDATE_KEY_CONFLICT +UPDATE v1 AS A NATURAL JOIN t1_part as B SET A.col2 = 2 , B.col1 = 3; + +--echo +--echo # Should be (1,1),(10,10) +SELECT * FROM t1_part; + +--echo +--echo # Case 3 +--echo # Update is accepted because partitioning key is not updated +UPDATE t1_part AS A NATURAL JOIN t1_part B SET A.col2 = 2 , B.col2 = 3; + +--echo +--echo # Should be (1,3),(10,3) +SELECT * FROM t1_part; + +--echo +# Cleanup +DROP VIEW v1; +DROP TABLE t1_part; === modified file 'sql/handler.cc' --- a/sql/handler.cc 2011-02-08 15:54:12 +0000 +++ b/sql/handler.cc 2011-02-14 14:51:47 +0000 @@ -2879,6 +2879,7 @@ void handler::print_error(int error, myf break; case HA_ERR_KEY_NOT_FOUND: case HA_ERR_NO_ACTIVE_RECORD: + case HA_ERR_RECORD_DELETED: case HA_ERR_END_OF_FILE: textno=ER_KEY_NOT_FOUND; break; === modified file 'sql/share/errmsg-utf8.txt' --- a/sql/share/errmsg-utf8.txt 2011-02-08 17:48:20 +0000 +++ b/sql/share/errmsg-utf8.txt 2011-02-14 14:51:47 +0000 @@ -6454,3 +6454,6 @@ ER_STMT_CACHE_FULL eng "Multi-row statements required more than 'max_binlog_stmt_cache_size' bytes of storage; increase this mysqld variable and try again" ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX eng "Option binlog_stmt_cache_size (%lu) is greater than max_binlog_stmt_cache_size (%lu); setting binlog_stmt_cache_size equal to max_binlog_stmt_cache_size." + +ER_MULTI_UPDATE_KEY_CONFLICT + eng "Primary key/partition key update is not allowed since the table is updated both as '%-.192s' and '%-.192s'." === modified file 'sql/sql_update.cc' --- a/sql/sql_update.cc 2010-12-29 00:38:59 +0000 +++ b/sql/sql_update.cc 2011-02-14 14:51:47 +0000 @@ -999,6 +999,88 @@ static table_map get_table_map(Listnext_leaf) + { + if (tl->table->map & tables_for_update) + { + for (TABLE_LIST* tl2= tl->next_leaf; tl2 ; tl2= tl2->next_leaf) + { + /* + Look at "next" tables only since all previous tables have + already been checked + */ + TABLE *table1= tl->table; + TABLE *table2= tl2->table; + if (table2->map & tables_for_update && table1->s == table2->s) + { + // A table is updated through two aliases +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (table1->part_info && + (partition_key_modified(table1, table1->write_set) || + partition_key_modified(table2, table2->write_set))) + { + // Partitioned key is updated + my_error(ER_MULTI_UPDATE_KEY_CONFLICT, MYF(0), + tl->belong_to_view ? tl->belong_to_view->alias + : tl->alias, + tl2->belong_to_view ? tl2->belong_to_view->alias + : tl2->alias); + return true; + } +#endif + if ((table1->file->primary_key_is_clustered() && + table1->s->primary_key != MAX_KEY) && + (bitmap_is_set(table1->write_set, table1->s->primary_key) || + bitmap_is_set(table2->write_set, table2->s->primary_key))) + { + // Clustered primary key is updated + my_error(ER_MULTI_UPDATE_KEY_CONFLICT, MYF(0), + tl->belong_to_view ? tl->belong_to_view->alias + : tl->alias, + tl2->belong_to_view ? tl2->belong_to_view->alias + : tl2->alias); + return true; + } + } + } + } + } + return false; +} + /* make update specific preparation and checks after opening tables @@ -1078,10 +1160,14 @@ int mysql_multi_update_prepare(THD *thd) thd->table_map_for_update= tables_for_update= get_table_map(fields); + leaves= lex->select_lex.leaf_tables; + + if (unsafe_key_update(leaves, tables_for_update)) + DBUG_RETURN(true); + /* Setup timestamp handling and locking mode */ - leaves= lex->select_lex.leaf_tables; for (tl= leaves; tl; tl= tl->next_leaf) { TABLE *table= tl->table; --===============5699830878365128063== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/jorgen.loland@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: jorgen.loland@stripped\ # w13okic3h9u46pb1 # target_branch: file:///export/home/jl208045/mysql/mysql-trunk-55385/ # testament_sha1: 50269e25686dbc093aeb7687bbe8e34322859c5a # timestamp: 2011-02-14 15:51:51 +0100 # base_revision_id: luis.soares@stripped\ # ixbz7jj4teaw6vtx # # Begin bundle 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 tLS/i7kinChIK2FMEIA= --===============5699830878365128063==--