Commit f3c3c9c3 authored by unknown's avatar unknown

Bug #16494: Updates that set a column to NULL fail sometimes

 When building the UPDATE query to send to the remote server, the
 federated storage engine built the query incorrectly if it was updating
 a field to be NULL.

 Thanks to Bjšrn Steinbrink for an initial patch for the problem.


mysql-test/r/federated.result:
  Add new results
mysql-test/t/federated.test:
  Add new regression test
sql/ha_federated.cc:
  Fix logic of how fields are added to SET and WHERE clauses of an
  UPDATE statement. Fields that were NULL were being handled incorrectly.
  Also reorganizes the code a little bit so the update of the two
  clauses is consistent.
parent c3cb4690
...@@ -1601,6 +1601,22 @@ fld_cid fld_name fld_parentid fld_delt ...@@ -1601,6 +1601,22 @@ fld_cid fld_name fld_parentid fld_delt
5 Torkel 0 0 5 Torkel 0 0
DROP TABLE federated.t1; DROP TABLE federated.t1;
DROP TABLE federated.bug_17377_table; DROP TABLE federated.bug_17377_table;
create table t1 (id int not null auto_increment primary key, val int);
create table t1
(id int not null auto_increment primary key, val int) engine=federated
connection='mysql://root@127.0.0.1:9308/test/t1';
insert into t1 values (1,0),(2,0);
update t1 set val = NULL where id = 1;
select * from t1;
id val
1 NULL
2 0
select * from t1;
id val
1 NULL
2 0
drop table t1;
drop table t1;
DROP TABLE IF EXISTS federated.t1; DROP TABLE IF EXISTS federated.t1;
DROP DATABASE IF EXISTS federated; DROP DATABASE IF EXISTS federated;
DROP TABLE IF EXISTS federated.t1; DROP TABLE IF EXISTS federated.t1;
......
...@@ -1309,5 +1309,22 @@ DROP TABLE federated.t1; ...@@ -1309,5 +1309,22 @@ DROP TABLE federated.t1;
connection slave; connection slave;
DROP TABLE federated.bug_17377_table; DROP TABLE federated.bug_17377_table;
#
# Bug #16494: Updates that set a column to NULL fail sometimes
#
connection slave;
create table t1 (id int not null auto_increment primary key, val int);
connection master;
eval create table t1
(id int not null auto_increment primary key, val int) engine=federated
connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
insert into t1 values (1,0),(2,0);
update t1 set val = NULL where id = 1;
select * from t1;
connection slave;
select * from t1;
drop table t1;
connection master;
drop table t1;
source include/federated_cleanup.inc; source include/federated_cleanup.inc;
...@@ -1857,8 +1857,8 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) ...@@ -1857,8 +1857,8 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
In this loop, we want to match column names to values being inserted In this loop, we want to match column names to values being inserted
(while building INSERT statement). (while building INSERT statement).
Iterate through table->field (new data) and share->old_filed (old_data) Iterate through table->field (new data) and share->old_field (old_data)
using the same index to created an SQL UPDATE statement, new data is using the same index to create an SQL UPDATE statement. New data is
used to create SET field=value and old data is used to create WHERE used to create SET field=value and old data is used to create WHERE
field=oldvalue field=oldvalue
*/ */
...@@ -1870,30 +1870,28 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) ...@@ -1870,30 +1870,28 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
update_string.append(FEDERATED_EQ); update_string.append(FEDERATED_EQ);
if ((*field)->is_null()) if ((*field)->is_null())
new_field_value.append(FEDERATED_NULL); update_string.append(FEDERATED_NULL);
else else
{ {
/* otherwise = */ /* otherwise = */
(*field)->val_str(&new_field_value); (*field)->val_str(&new_field_value);
(*field)->quote_data(&new_field_value); (*field)->quote_data(&new_field_value);
update_string.append(new_field_value);
if (!field_in_record_is_null(table, *field, (char*) old_data)) new_field_value.length(0);
where_string.append(FEDERATED_EQ);
} }
if (field_in_record_is_null(table, *field, (char*) old_data)) if (field_in_record_is_null(table, *field, (char*) old_data))
where_string.append(FEDERATED_ISNULL); where_string.append(FEDERATED_ISNULL);
else else
{ {
where_string.append(FEDERATED_EQ);
(*field)->val_str(&old_field_value, (*field)->val_str(&old_field_value,
(char*) (old_data + (*field)->offset())); (char*) (old_data + (*field)->offset()));
(*field)->quote_data(&old_field_value); (*field)->quote_data(&old_field_value);
where_string.append(old_field_value); where_string.append(old_field_value);
old_field_value.length(0);
} }
update_string.append(new_field_value);
new_field_value.length(0);
/* /*
Only append conjunctions if we have another field in which Only append conjunctions if we have another field in which
to iterate to iterate
...@@ -1903,7 +1901,6 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) ...@@ -1903,7 +1901,6 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
update_string.append(FEDERATED_COMMA); update_string.append(FEDERATED_COMMA);
where_string.append(FEDERATED_AND); where_string.append(FEDERATED_AND);
} }
old_field_value.length(0);
} }
update_string.append(FEDERATED_WHERE); update_string.append(FEDERATED_WHERE);
update_string.append(where_string); update_string.append(where_string);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment