Commit 8b17d33d authored by unknown's avatar unknown

Bug#17400 (CRBR: Delete and update of table w/o PK fails on slave):

Fixing bug where UPDATE failed on slave and some cleanup of ndb_unpack_record().


mysql-test/r/rpl_bit_npk.result:
  Result change
mysql-test/t/disabled.def:
  Disabling tests
mysql-test/t/rpl_bit_npk.test:
  Making test storage-engine independent
mysql-test/t/rpl_ndb_innodb2ndb-slave.opt:
  Storage engine name change
mysql-test/t/rpl_ndb_myisam2ndb-slave.opt:
  Storage engine name change
sql/ha_ndbcluster.cc:
  Using move_field_offset() to move field pointer.
  Using my_ptrdiff_t instead of uint for pointer difference.
  Removing ineffective cast.
  Calling member function directly, bypassing the virtual mechanism
  for Field_bit.
sql/log_event.cc:
  Starting and stopping range scan and index read inside find_and_fetch row
  instead of in calling function. There are storage engines that require the
  search to be restarted for every changed row.
parent 94c6f6dc
...@@ -56,86 +56,90 @@ INSERT INTO test.t1 VALUES (8,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4 ...@@ -56,86 +56,90 @@ INSERT INTO test.t1 VALUES (8,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4
UNLOCK TABLES; UNLOCK TABLES;
UPDATE test.t1 set x034 = 50 where bit3 = b'000000'; UPDATE test.t1 set x034 = 50 where bit3 = b'000000';
UPDATE test.t1 set VNotSupp = 33 where bit1 = b'0'; UPDATE test.t1 set VNotSupp = 33 where bit1 = b'0';
SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034 FROM test.t1; SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034
FROM test.t1
ORDER BY oSupp, sSuppD, GSuppDf, VNotSupp, x034;
oSupp sSuppD GSuppDf VNotSupp x034 oSupp sSuppD GSuppDf VNotSupp x034
5 5 3 NULL 1 5 5 3 NULL 1
5 5 3 2 1 5 5 3 2 1
5 5 3 33 1
5 5 3 2 50 5 5 3 2 50
5 5 3 33 1 5 5 3 33 1
5 5 3 33 1 5 5 3 33 1
5 5 3 33 1 5 5 3 33 1
5 5 3 33 1 5 5 3 33 1
SELECT hex(bit1) from test.t1; 5 5 3 33 1
SELECT hex(bit1) from test.t1 ORDER BY bit1;
hex(bit1) hex(bit1)
3F
3F
0
2A
0 0
0 0
0 0
0 0
SELECT hex(bit2) from test.t1;
hex(bit2)
3E
0 0
2A 2A
3F 3F
3F
SELECT hex(bit2) from test.t1 ORDER BY bit2;
hex(bit2)
0
1 1
1 1
1 1
1 1
SELECT hex(bit3) from test.t1; 2A
3E
3F
SELECT hex(bit3) from test.t1 ORDER BY bit3;
hex(bit3) hex(bit3)
35
24
15
0 0
1 1
1 1
1 1
1 1
SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034 FROM test.t1; 15
24
35
SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034
FROM test.t1
ORDER BY oSupp, sSuppD, GSuppDf, VNotSupp, x034;
oSupp sSuppD GSuppDf VNotSupp x034 oSupp sSuppD GSuppDf VNotSupp x034
5 5 3 NULL 1 5 5 3 NULL 1
5 5 3 2 1 5 5 3 2 1
5 5 3 33 1
5 5 3 2 50 5 5 3 2 50
5 5 3 33 1 5 5 3 33 1
5 5 3 33 1 5 5 3 33 1
5 5 3 33 1 5 5 3 33 1
5 5 3 33 1 5 5 3 33 1
SELECT hex(bit1) from test.t1; 5 5 3 33 1
SELECT hex(bit1) from test.t1 ORDER BY bit1;
hex(bit1) hex(bit1)
3F
3F
0
2A
0 0
0 0
0 0
0 0
SELECT hex(bit2) from test.t1;
hex(bit2)
3E
0 0
2A 2A
3F 3F
3F
SELECT hex(bit2) from test.t1 ORDER BY bit2;
hex(bit2)
0
1 1
1 1
1 1
1 1
SELECT hex(bit3) from test.t1; 2A
3E
3F
SELECT hex(bit3) from test.t1 ORDER BY bit3;
hex(bit3) hex(bit3)
35
24
15
0 0
1 1
1 1
1 1
1 1
15
24
35
CREATE TABLE test.t2 (a INT, b BIT(1)); CREATE TABLE test.t2 (a INT, b BIT(1));
INSERT INTO test.t2 VALUES (1, b'0'); INSERT INTO test.t2 VALUES (1, b'0');
INSERT INTO test.t2 VALUES (1, b'1'); INSERT INTO test.t2 VALUES (1, b'1');
...@@ -144,19 +148,19 @@ CREATE TABLE test.t3 (a INT, b INT); ...@@ -144,19 +148,19 @@ CREATE TABLE test.t3 (a INT, b INT);
INSERT INTO test.t3 VALUES (1, NULL); INSERT INTO test.t3 VALUES (1, NULL);
INSERT INTO test.t3 VALUES (1, 0); INSERT INTO test.t3 VALUES (1, 0);
UPDATE test.t3 SET a = 2 WHERE b = 0; UPDATE test.t3 SET a = 2 WHERE b = 0;
SELECT a, hex(b) FROM test.t2; SELECT a, hex(b) FROM test.t2 ORDER BY a,b;
a hex(b) a hex(b)
1 0 1 0
2 1 2 1
SELECT * FROM test.t3; SELECT * FROM test.t3 ORDER BY a,b;
a b a b
1 NULL 1 NULL
2 0 2 0
SELECT a, hex(b) FROM test.t2; SELECT a, hex(b) FROM test.t2 ORDER BY a,b;
a hex(b) a hex(b)
1 0 1 0
2 1 2 1
SELECT * FROM test.t3; SELECT * FROM test.t3 ORDER BY a,b;
a b a b
1 NULL 1 NULL
2 0 2 0
......
...@@ -27,9 +27,9 @@ rpl_ndb_auto_inc : BUG#17086 2006-02-16 jmiller CR: auto_increment_incre ...@@ -27,9 +27,9 @@ rpl_ndb_auto_inc : BUG#17086 2006-02-16 jmiller CR: auto_increment_incre
rpl_ndb_commit_afterflush : BUG#19328 2006-05-04 tomas Slave timeout with COM_REGISTER_SLAVE error causing stop rpl_ndb_commit_afterflush : BUG#19328 2006-05-04 tomas Slave timeout with COM_REGISTER_SLAVE error causing stop
rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD
rpl_ndb_ddl : BUG#18946 result file needs update + test needs to checked rpl_ndb_ddl : BUG#18946 result file needs update + test needs to checked
rpl_ndb_innodb2ndb : BUG#17400 2006-04-19 tomas Cluster Replication: delete & update of rows in table without pk fails on slave. rpl_ndb_innodb2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
rpl_ndb_log : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create table and insert (on different table) not determ rpl_ndb_log : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create table and insert (on different table) not determ
rpl_ndb_myisam2ndb : BUG#17400 2006-04-19 tomas Cluster Replication: delete & update of rows in table without pk fails on slave. rpl_ndb_myisam2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
rpl_switch_stm_row_mixed : BUG#18590 2006-03-28 brian rpl_switch_stm_row_mixed : BUG#18590 2006-03-28 brian
rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly
rpl_row_func003 : BUG#19074 2006-13-04 andrei test failed rpl_row_func003 : BUG#19074 2006-13-04 andrei test failed
......
...@@ -70,18 +70,22 @@ UNLOCK TABLES; ...@@ -70,18 +70,22 @@ UNLOCK TABLES;
UPDATE test.t1 set x034 = 50 where bit3 = b'000000'; UPDATE test.t1 set x034 = 50 where bit3 = b'000000';
UPDATE test.t1 set VNotSupp = 33 where bit1 = b'0'; UPDATE test.t1 set VNotSupp = 33 where bit1 = b'0';
SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034 FROM test.t1; SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034
SELECT hex(bit1) from test.t1; FROM test.t1
SELECT hex(bit2) from test.t1; ORDER BY oSupp, sSuppD, GSuppDf, VNotSupp, x034;
SELECT hex(bit3) from test.t1; SELECT hex(bit1) from test.t1 ORDER BY bit1;
SELECT hex(bit2) from test.t1 ORDER BY bit2;
SELECT hex(bit3) from test.t1 ORDER BY bit3;
save_master_pos; save_master_pos;
connection slave; connection slave;
sync_with_master; sync_with_master;
SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034 FROM test.t1; SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034
SELECT hex(bit1) from test.t1; FROM test.t1
SELECT hex(bit2) from test.t1; ORDER BY oSupp, sSuppD, GSuppDf, VNotSupp, x034;
SELECT hex(bit3) from test.t1; SELECT hex(bit1) from test.t1 ORDER BY bit1;
SELECT hex(bit2) from test.t1 ORDER BY bit2;
SELECT hex(bit3) from test.t1 ORDER BY bit3;
connection master; connection master;
CREATE TABLE test.t2 (a INT, b BIT(1)); CREATE TABLE test.t2 (a INT, b BIT(1));
...@@ -94,14 +98,14 @@ INSERT INTO test.t3 VALUES (1, NULL); ...@@ -94,14 +98,14 @@ INSERT INTO test.t3 VALUES (1, NULL);
INSERT INTO test.t3 VALUES (1, 0); INSERT INTO test.t3 VALUES (1, 0);
UPDATE test.t3 SET a = 2 WHERE b = 0; UPDATE test.t3 SET a = 2 WHERE b = 0;
SELECT a, hex(b) FROM test.t2; SELECT a, hex(b) FROM test.t2 ORDER BY a,b;
SELECT * FROM test.t3; SELECT * FROM test.t3 ORDER BY a,b;
save_master_pos; save_master_pos;
connection slave; connection slave;
sync_with_master; sync_with_master;
SELECT a, hex(b) FROM test.t2; SELECT a, hex(b) FROM test.t2 ORDER BY a,b;
SELECT * FROM test.t3; SELECT * FROM test.t3 ORDER BY a,b;
connection master; connection master;
DROP TABLE IF EXISTS test.t1; DROP TABLE IF EXISTS test.t1;
......
--binlog-format=row --default-storage-engine=ndb --binlog-format=row --default-storage-engine=ndbcluster
--default-storage-engine=ndb --binlog-format=row --default-storage-engine=ndbcluster --binlog-format=row
...@@ -2875,7 +2875,7 @@ void ndb_unpack_record(TABLE *table, NdbValue *value, ...@@ -2875,7 +2875,7 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
MY_BITMAP *defined, byte *buf) MY_BITMAP *defined, byte *buf)
{ {
Field **p_field= table->field, *field= *p_field; Field **p_field= table->field, *field= *p_field;
uint row_offset= (uint) (buf - table->record[0]); my_ptrdiff_t row_offset= buf - table->record[0];
DBUG_ENTER("ndb_unpack_record"); DBUG_ENTER("ndb_unpack_record");
// Set null flag(s) // Set null flag(s)
...@@ -2906,24 +2906,34 @@ void ndb_unpack_record(TABLE *table, NdbValue *value, ...@@ -2906,24 +2906,34 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
} }
else if (field->type() == MYSQL_TYPE_BIT) else if (field->type() == MYSQL_TYPE_BIT)
{ {
byte *save_field_ptr= field->ptr; Field_bit *field_bit= static_cast<Field_bit*>(field);
field->ptr= save_field_ptr + row_offset;
/*
Move internal field pointer to point to 'buf'. Calling
the correct member function directly since we know the
type of the object.
*/
field_bit->Field_bit::move_field_offset(row_offset);
if (field->pack_length() < 5) if (field->pack_length() < 5)
{ {
DBUG_PRINT("info", ("bit field H'%.8X", DBUG_PRINT("info", ("bit field H'%.8X",
(*value).rec->u_32_value())); (*value).rec->u_32_value()));
((Field_bit*) field)->store((longlong) field_bit->Field_bit::store((longlong) (*value).rec->u_32_value(),
(*value).rec->u_32_value(), FALSE); FALSE);
} }
else else
{ {
DBUG_PRINT("info", ("bit field H'%.8X%.8X", DBUG_PRINT("info", ("bit field H'%.8X%.8X",
*(Uint32*) (*value).rec->aRef(), *(Uint32*) (*value).rec->aRef(),
*((Uint32*) (*value).rec->aRef()+1))); *((Uint32*) (*value).rec->aRef()+1)));
((Field_bit*) field)->store((longlong) field_bit->Field_bit::store((longlong) (*value).rec->u_64_value(),
(*value).rec->u_64_value(),TRUE); TRUE);
} }
field->ptr= save_field_ptr; /*
Move back internal field pointer to point to original
value (usually record[0]).
*/
field_bit->Field_bit::move_field_offset(-row_offset);
DBUG_PRINT("info",("[%u] SET", DBUG_PRINT("info",("[%u] SET",
(*value).rec->getColumn()->getColumnNo())); (*value).rec->getColumn()->getColumnNo()));
DBUG_DUMP("info", (const char*) field->ptr, field->field_length); DBUG_DUMP("info", (const char*) field->ptr, field->field_length);
......
...@@ -6416,11 +6416,16 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6416,11 +6416,16 @@ static int find_and_fetch_row(TABLE *table, byte *key)
if (table->s->keys > 0) if (table->s->keys > 0)
{ {
int error; int error;
/* We have a key: search the table using the index */
if (!table->file->inited)
if ((error= table->file->ha_index_init(0, FALSE)))
return error;
/* /*
We need to set the null bytes to ensure that the filler bit We need to set the null bytes to ensure that the filler bit are
are all set when returning. There are storage engines that all set when returning. There are storage engines that just set
just set the necessary bits on the bytes and don't set the the necessary bits on the bytes and don't set the filler bits
filler bits correctly. correctly.
*/ */
my_ptrdiff_t const pos= my_ptrdiff_t const pos=
table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0; table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0;
...@@ -6430,6 +6435,7 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6430,6 +6435,7 @@ static int find_and_fetch_row(TABLE *table, byte *key)
HA_READ_KEY_EXACT))) HA_READ_KEY_EXACT)))
{ {
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
table->file->ha_index_end();
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -6448,7 +6454,10 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6448,7 +6454,10 @@ static int find_and_fetch_row(TABLE *table, byte *key)
chose the row to change only using a PK or an UNNI. chose the row to change only using a PK or an UNNI.
*/ */
if (table->key_info->flags & HA_NOSAME) if (table->key_info->flags & HA_NOSAME)
{
table->file->ha_index_end();
DBUG_RETURN(0); DBUG_RETURN(0);
}
while (record_compare(table)) while (record_compare(table))
{ {
...@@ -6465,15 +6474,26 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6465,15 +6474,26 @@ static int find_and_fetch_row(TABLE *table, byte *key)
if ((error= table->file->index_next(table->record[1]))) if ((error= table->file->index_next(table->record[1])))
{ {
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
table->file->ha_index_end();
DBUG_RETURN(error); DBUG_RETURN(error);
} }
} }
/*
Have to restart the scan to be able to fetch the next row.
*/
table->file->ha_index_end();
} }
else else
{ {
/* Continue until we find the right record or have made a full loop */
int restart_count= 0; // Number of times scanning has restarted from top int restart_count= 0; // Number of times scanning has restarted from top
int error= 0; int error;
/* We don't have a key: search the table using rnd_next() */
if ((error= table->file->ha_rnd_init(1)))
return error;
/* Continue until we find the right record or have made a full loop */
do do
{ {
/* /*
...@@ -6499,11 +6519,17 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6499,11 +6519,17 @@ static int find_and_fetch_row(TABLE *table, byte *key)
default: default:
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
table->file->ha_rnd_end();
DBUG_RETURN(error); DBUG_RETURN(error);
} }
} }
while (restart_count < 2 && record_compare(table)); while (restart_count < 2 && record_compare(table));
/*
Have to restart the scan to be able to fetch the next row.
*/
table->file->ha_rnd_end();
DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0); DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -6626,20 +6652,6 @@ int Delete_rows_log_event::do_exec_row(TABLE *table) ...@@ -6626,20 +6652,6 @@ int Delete_rows_log_event::do_exec_row(TABLE *table)
{ {
DBUG_ASSERT(table != NULL); DBUG_ASSERT(table != NULL);
if (table->s->keys > 0)
{
/* We have a key: search the table using the index */
if (!table->file->inited)
if (int error= table->file->ha_index_init(0, FALSE))
return error;
}
else
{
/* We doesn't have a key: search the table using rnd_next() */
if (int error= table->file->ha_rnd_init(1))
return error;
}
int error= find_and_fetch_row(table, m_key); int error= find_and_fetch_row(table, m_key);
if (error) if (error)
return error; return error;
...@@ -6651,11 +6663,6 @@ int Delete_rows_log_event::do_exec_row(TABLE *table) ...@@ -6651,11 +6663,6 @@ int Delete_rows_log_event::do_exec_row(TABLE *table)
*/ */
error= table->file->ha_delete_row(table->record[0]); error= table->file->ha_delete_row(table->record[0]);
/*
Have to restart the scan to be able to fetch the next row.
*/
table->file->ha_index_or_rnd_end();
return error; return error;
} }
...@@ -6736,17 +6743,6 @@ int Update_rows_log_event::do_before_row_operations(TABLE *table) ...@@ -6736,17 +6743,6 @@ int Update_rows_log_event::do_before_row_operations(TABLE *table)
if (!m_memory) if (!m_memory)
return HA_ERR_OUT_OF_MEM; return HA_ERR_OUT_OF_MEM;
if (table->s->keys > 0)
{
/* We have a key: search the table using the index */
if (!table->file->inited)
error= table->file->ha_index_init(0, FALSE);
}
else
{
/* We doesn't have a key: search the table using rnd_next() */
error= table->file->ha_rnd_init(1);
}
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
return error; return error;
......
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