4493 Frazer Clement 2011-09-01
Bug#62321 NdbApi: Blobs obscure other operations error codes
Modify NdbTransaction::execute() to avoid trampling first operation
error in NdbError object returned by NdbTransaction::getNdbError().
modified:
mysql-test/suite/ndb_rpl/r/ndb_rpl_conflict.result
mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict.test
storage/ndb/src/ndbapi/NdbTransaction.cpp
storage/ndb/test/ndbapi/testBlobs.cpp
storage/ndb/test/run-test/daily-basic-tests.txt
4492 Maitrayi Sabaratnam 2011-09-01
BUG#11766870 60097: NDB_CONFIG TO DUMP CONFIG VERSION FOR DATA NODES - additional fixes
modified:
storage/ndb/src/mgmsrv/MgmtSrvr.cpp
storage/ndb/src/mgmsrv/Services.cpp
storage/ndb/tools/ndb_config.cpp
=== modified file 'mysql-test/suite/ndb_rpl/r/ndb_rpl_conflict.result'
--- a/mysql-test/suite/ndb_rpl/r/ndb_rpl_conflict.result 2011-05-13 07:40:50 +0000
+++ b/mysql-test/suite/ndb_rpl/r/ndb_rpl_conflict.result 2011-09-01 15:12:11 +0000
@@ -66,6 +66,169 @@ select * from t1_max_delete_win;
a b X
delete from t1_old;
delete from t1_max;
+drop table t1_old, t1_max, t1_max_delete_win;
+delete from t1_old$EX;
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+delete from t1_old$EX;
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+create table t1_old (a int primary key, b longtext, X int unsigned) engine = ndb;
+create table t1_max (a int primary key, b longtext, X int unsigned) engine = ndb;
+create table t1_max_delete_win (a int primary key, b longtext, X int unsigned) engine = ndb;
+"Test 3"
+insert into t1_old values (1, repeat('Initial X=1',1000), 1);
+insert into t1_max values (1, repeat('Initial X=1',1000), 1);
+insert into t1_max_delete_win values (1, repeat('Initial X=1',1000), 1);
+update t1_old set X = 2, b=repeat('Slave X=2',1001);
+update t1_max set X = 2, b=repeat('Slave X=2',1001);
+update t1_max_delete_win set X = 2, b=repeat('Slave X=2',1001);
+update t1_old set X = 3, b=repeat('Master X=3',1002);
+update t1_max set X = 3, b=repeat('Master X=3',1002);
+update t1_max_delete_win set X = 3, b=repeat('Master X=3',1002);
+"Expect t1_old to contain slave row, and t1_max* to contain master row"
+select a, left(b, 20), length(b), X from t1_old;
+a left(b, 20) length(b) X
+1 Slave X=2Slave X=2Sl 9009 2
+select a, left(b, 20), length(b), X from t1_max;
+a left(b, 20) length(b) X
+1 Master X=3Master X=3 10020 3
+select a, left(b, 20), length(b), X from t1_max_delete_win;
+a left(b, 20) length(b) X
+1 Master X=3Master X=3 10020 3
+Expect t1_old to have 1 entry, and t1_max* to have no entries
+select server_id, master_server_id, count, a from t1_old$EX order by count;
+server_id master_server_id count a
+2 1 1 1
+select server_id, master_server_id, count, a from t1_max$EX order by count;
+server_id master_server_id count a
+select server_id, master_server_id, count, a from t1_max_delete_win$EX order by count;
+server_id master_server_id count a
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+delete from t1_old$EX;
+update t1_old set X = 3, b=repeat('Master X=3', 1002);
+"Test 4"
+update t1_old set X = 4, b=repeat('Slave X=4',2000);
+update t1_max set X = 4, b=repeat('Slave X=4',2000);
+update t1_max_delete_win set X = 4, b=repeat('Slave X=4',2000);
+delete from t1_old;
+delete from t1_max;
+delete from t1_max_delete_win;
+"Expect t1_old and t1_max to contain slave row, and t1_max_delete_win to be empty(as master)"
+select a, left(b, 20), length(b), X from t1_old;
+a left(b, 20) length(b) X
+1 Slave X=4Slave X=4Sl 18000 4
+select a, left(b, 20), length(b), X from t1_max;
+a left(b, 20) length(b) X
+1 Slave X=4Slave X=4Sl 18000 4
+select a, left(b, 20), length(b), X from t1_max_delete_win;
+a left(b, 20) length(b) X
+Expect t1_old and t1_max to contain 1 entry, and t1_max_delete_win to be empty
+select server_id, master_server_id, count, a from t1_old$EX order by count;
+server_id master_server_id count a
+2 1 2 1
+select server_id, master_server_id, count, a from t1_max$EX order by count;
+server_id master_server_id count a
+2 1 1 1
+select server_id, master_server_id, count, a from t1_max_delete_win$EX order by count;
+server_id master_server_id count a
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+delete from t1_old$EX;
+delete from t1_old;
+delete from t1_max;
+delete from t1_max_delete_win;
+delete from t1_old;
+delete from t1_max;
+delete from t1_max_delete_win;
+"Test 5"
+Test that Updates affecting Blobs are rejected
+correctly on the slave
+drop table t1_max;
+create table t1_max (a int primary key, b int, c longtext, d longtext, X int unsigned) engine = ndb;
+insert into t1_max values (1, 1, repeat("B", 10000), repeat("E", 10001), 1);
+insert into t1_max values (2, 2, repeat("A", 10002), repeat("T", 10003), 1);
+update t1_max set X=20;
+Initial values on Slave
+select a,b,SHA1(c),length(c), SHA1(d), length(d), X from t1_max order by a;
+a b SHA1(c) length(c) SHA1(d) length(d) X
+1 1 4a222e18b539cdefbf0960eaa7f4362a4976e1e0 10000 9641d473ab1bd921263190eee074397084933e2d 10001 20
+2 2 f833241322c062495632923d74314a6a5c23034d 10002 2dad269dfa115f6c7e53e91a73251e597aab8fe9 10003 20
+Originate update which will be rejected
+update t1_max set c=repeat("Z", 10006), d=repeat("I", 10005), X=2 where a=1;
+Check slave has rejected due to lower version
+select a,b,SHA1(c),length(c), SHA1(d), length(d), X from t1_max order by a;
+a b SHA1(c) length(c) SHA1(d) length(d) X
+1 1 4a222e18b539cdefbf0960eaa7f4362a4976e1e0 10000 9641d473ab1bd921263190eee074397084933e2d 10001 20
+2 2 f833241322c062495632923d74314a6a5c23034d 10002 2dad269dfa115f6c7e53e91a73251e597aab8fe9 10003 20
+Originate delete which will be rejected (due to NDB-OLD) algorith
+delete from t1_max where a=1;
+Check slave has rejected due to before image mismatch
+select a,b,SHA1(c),length(c), SHA1(d), length(d), X from t1_max order by a;
+a b SHA1(c) length(c) SHA1(d) length(d) X
+1 1 4a222e18b539cdefbf0960eaa7f4362a4976e1e0 10000 9641d473ab1bd921263190eee074397084933e2d 10001 20
+2 2 f833241322c062495632923d74314a6a5c23034d 10002 2dad269dfa115f6c7e53e91a73251e597aab8fe9 10003 20
+Originate insert which will be rejected (as row exists)
+insert into t1_max values (1, 1, repeat("R", 10004), repeat("A", 10007), 1);
+Check slave has rejected due to row existing already
+select a,b,SHA1(c),length(c), SHA1(d), length(d), X from t1_max order by a;
+a b SHA1(c) length(c) SHA1(d) length(d) X
+1 1 4a222e18b539cdefbf0960eaa7f4362a4976e1e0 10000 9641d473ab1bd921263190eee074397084933e2d 10001 20
+2 2 f833241322c062495632923d74314a6a5c23034d 10002 2dad269dfa115f6c7e53e91a73251e597aab8fe9 10003 20
+Expect t1_max to have 3 entries
+select server_id, master_server_id, count, a from t1_old$EX order by count;
+server_id master_server_id count a
+select server_id, master_server_id, count, a from t1_max$EX order by count;
+server_id master_server_id count a
+2 1 1 1
+2 1 2 1
+2 1 3 1
+select server_id, master_server_id, count, a from t1_max_delete_win$EX order by count;
+server_id master_server_id count a
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+delete from t1_old$EX;
+Test 6
+Check that non-Blob related operations in a batch with a Blob
+operation are still subject to conflict detection.
+
+insert into mysql.ndb_replication values ("test", "t2_max", 0, 7, "NDB$MAX(X)");
+create table `t2_max$EX`
+ (server_id int unsigned,
+master_server_id int unsigned,
+master_epoch bigint unsigned,
+count int unsigned,
+a int not null,
+primary key(server_id, master_server_id, master_epoch, count)) engine ndb;
+create table t2_max (a int primary key, b int, X bigint unsigned) engine=ndb;
+insert into t2_max values (1,1,10), (2,2,10), (3,3,10), (4,4,10), (5,5,10);
+Now issue a transaction with a successful Blob op, and unsuccessful
+non-Blob op. Check that the Blob op succeeds, and the unsuccessful
+non-Blob op is handled as expected.
+begin;
+update t2_max set b=b+1, X=1 where a=3;
+update t1_max set c=repeat("R", 10008), d=repeat("A", 10009), X = 21 where a=1;
+commit;
+Contents on Slave
+Expect Blob data applied to t1_max, no update applied to t2_max
+select a,b,left(c,1), length(c), left(d,1), length(d), X from t1_max where a=1;
+a b left(c,1) length(c) left(d,1) length(d) X
+1 1 R 10008 A 10009 21
+select * from t2_max order by a;
+a b X
+1 1 10
+2 2 10
+3 3 10
+4 4 10
+5 5 10
+Expect No conflict in t1_max, 1 conflict in t2_max
+select server_id, master_server_id, count, a from t1_max$EX order by count;
+server_id master_server_id count a
+select server_id, master_server_id, count, a from t2_max$EX order by count;
+server_id master_server_id count a
+2 1 1 3
+drop table t2_max, t2_max$EX;
"Cleanup"
drop table mysql.ndb_replication;
drop table t1_old, `t1_old$EX`, t1_max, `t1_max$EX`, t1_max_delete_win, `t1_max_delete_win$EX`;
=== modified file 'mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict.test'
--- a/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict.test 2011-05-13 07:40:50 +0000
+++ b/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict.test 2011-09-01 15:12:11 +0000
@@ -105,6 +105,209 @@ select * from t1_max_delete_win;
delete from t1_old;
delete from t1_max;
+--connection master
+
+# Now test with Blobs
+drop table t1_old, t1_max, t1_max_delete_win;
+delete from t1_old$EX;
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+
+--sync_slave_with_master
+--connection slave
+# Delete on slave, as $EX table ops don't replicate
+delete from t1_old$EX;
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+
+--connection master
+
+create table t1_old (a int primary key, b longtext, X int unsigned) engine = ndb;
+create table t1_max (a int primary key, b longtext, X int unsigned) engine = ndb;
+create table t1_max_delete_win (a int primary key, b longtext, X int unsigned) engine = ndb;
+
+--sync_slave_with_master
+
+###############
+--echo "Test 3"
+
+--connection master
+insert into t1_old values (1, repeat('Initial X=1',1000), 1);
+insert into t1_max values (1, repeat('Initial X=1',1000), 1);
+insert into t1_max_delete_win values (1, repeat('Initial X=1',1000), 1);
+--sync_slave_with_master
+
+--connection slave
+update t1_old set X = 2, b=repeat('Slave X=2',1001);
+update t1_max set X = 2, b=repeat('Slave X=2',1001);
+update t1_max_delete_win set X = 2, b=repeat('Slave X=2',1001);
+
+--connection master
+update t1_old set X = 3, b=repeat('Master X=3',1002);
+update t1_max set X = 3, b=repeat('Master X=3',1002);
+update t1_max_delete_win set X = 3, b=repeat('Master X=3',1002);
+--sync_slave_with_master
+
+--connection slave
+--echo "Expect t1_old to contain slave row, and t1_max* to contain master row"
+select a, left(b, 20), length(b), X from t1_old;
+select a, left(b, 20), length(b), X from t1_max;
+select a, left(b, 20), length(b), X from t1_max_delete_win;
+
+--echo Expect t1_old to have 1 entry, and t1_max* to have no entries
+select server_id, master_server_id, count, a from t1_old$EX order by count;
+select server_id, master_server_id, count, a from t1_max$EX order by count;
+select server_id, master_server_id, count, a from t1_max_delete_win$EX order by count;
+
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+delete from t1_old$EX;
+
+# syncronize
+update t1_old set X = 3, b=repeat('Master X=3', 1002);
+
+###############
+--echo "Test 4"
+
+--connection slave
+update t1_old set X = 4, b=repeat('Slave X=4',2000);
+update t1_max set X = 4, b=repeat('Slave X=4',2000);
+update t1_max_delete_win set X = 4, b=repeat('Slave X=4',2000);
+
+--connection master
+delete from t1_old;
+delete from t1_max;
+delete from t1_max_delete_win;
+--sync_slave_with_master
+
+--connection slave
+--echo "Expect t1_old and t1_max to contain slave row, and t1_max_delete_win to be empty(as master)"
+select a, left(b, 20), length(b), X from t1_old;
+select a, left(b, 20), length(b), X from t1_max;
+select a, left(b, 20), length(b), X from t1_max_delete_win;
+
+--echo Expect t1_old and t1_max to contain 1 entry, and t1_max_delete_win to be empty
+select server_id, master_server_id, count, a from t1_old$EX order by count;
+select server_id, master_server_id, count, a from t1_max$EX order by count;
+select server_id, master_server_id, count, a from t1_max_delete_win$EX order by count;
+
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+delete from t1_old$EX;
+
+delete from t1_old;
+delete from t1_max;
+delete from t1_max_delete_win;
+
+--connection master
+delete from t1_old;
+delete from t1_max;
+delete from t1_max_delete_win;
+
+#################
+--echo "Test 5"
+
+--echo Test that Updates affecting Blobs are rejected
+--echo correctly on the slave
+drop table t1_max;
+create table t1_max (a int primary key, b int, c longtext, d longtext, X int unsigned) engine = ndb;
+
+insert into t1_max values (1, 1, repeat("B", 10000), repeat("E", 10001), 1);
+insert into t1_max values (2, 2, repeat("A", 10002), repeat("T", 10003), 1);
+
+--sync_slave_with_master
+--connection slave
+
+# Bump up tuple versions
+update t1_max set X=20;
+
+--echo Initial values on Slave
+select a,b,SHA1(c),length(c), SHA1(d), length(d), X from t1_max order by a;
+
+--connection master
+--echo Originate update which will be rejected
+update t1_max set c=repeat("Z", 10006), d=repeat("I", 10005), X=2 where a=1;
+
+--sync_slave_with_master
+--connection slave
+--echo Check slave has rejected due to lower version
+select a,b,SHA1(c),length(c), SHA1(d), length(d), X from t1_max order by a;
+
+--connection master
+--echo Originate delete which will be rejected (due to NDB-OLD) algorith
+delete from t1_max where a=1;
+
+--sync_slave_with_master
+--connection slave
+--echo Check slave has rejected due to before image mismatch
+select a,b,SHA1(c),length(c), SHA1(d), length(d), X from t1_max order by a;
+
+--connection master
+--echo Originate insert which will be rejected (as row exists)
+insert into t1_max values (1, 1, repeat("R", 10004), repeat("A", 10007), 1);
+
+--sync_slave_with_master
+--connection slave
+--echo Check slave has rejected due to row existing already
+select a,b,SHA1(c),length(c), SHA1(d), length(d), X from t1_max order by a;
+
+--echo Expect t1_max to have 3 entries
+select server_id, master_server_id, count, a from t1_old$EX order by count;
+select server_id, master_server_id, count, a from t1_max$EX order by count;
+select server_id, master_server_id, count, a from t1_max_delete_win$EX order by count;
+
+delete from t1_max$EX;
+delete from t1_max_delete_win$EX;
+delete from t1_old$EX;
+
+--connection master
+
+#######
+--echo Test 6
+--echo Check that non-Blob related operations in a batch with a Blob
+--echo operation are still subject to conflict detection.
+--echo
+insert into mysql.ndb_replication values ("test", "t2_max", 0, 7, "NDB$MAX(X)");
+
+create table `t2_max$EX`
+ (server_id int unsigned,
+ master_server_id int unsigned,
+ master_epoch bigint unsigned,
+ count int unsigned,
+ a int not null,
+ primary key(server_id, master_server_id, master_epoch, count)) engine ndb;
+
+create table t2_max (a int primary key, b int, X bigint unsigned) engine=ndb;
+
+insert into t2_max values (1,1,10), (2,2,10), (3,3,10), (4,4,10), (5,5,10);
+
+--sync_slave_with_master
+
+--connection master
+--echo Now issue a transaction with a successful Blob op, and unsuccessful
+--echo non-Blob op. Check that the Blob op succeeds, and the unsuccessful
+--echo non-Blob op is handled as expected.
+
+begin;
+update t2_max set b=b+1, X=1 where a=3; # conflicts
+update t1_max set c=repeat("R", 10008), d=repeat("A", 10009), X = 21 where a=1; # ok
+commit;
+
+--sync_slave_with_master
+
+--connection slave
+--echo Contents on Slave
+--echo Expect Blob data applied to t1_max, no update applied to t2_max
+select a,b,left(c,1), length(c), left(d,1), length(d), X from t1_max where a=1;
+select * from t2_max order by a;
+
+--echo Expect No conflict in t1_max, 1 conflict in t2_max$EX
+select server_id, master_server_id, count, a from t1_max$EX order by count;
+select server_id, master_server_id, count, a from t2_max$EX order by count;
+
+--connection master
+drop table t2_max, t2_max$EX;
+
###############
--echo "Cleanup"
=== modified file 'storage/ndb/src/ndbapi/NdbTransaction.cpp'
--- a/storage/ndb/src/ndbapi/NdbTransaction.cpp 2011-07-04 13:40:57 +0000
+++ b/storage/ndb/src/ndbapi/NdbTransaction.cpp 2011-09-01 15:12:11 +0000
@@ -290,7 +290,8 @@ NdbTransaction::execute(ExecType aTypeOf
NdbOperation::AbortOption abortOption,
int forceSend)
{
- NdbError savedError= theError;
+ NdbError existingTransError = theError;
+ NdbError firstTransError;
DBUG_ENTER("NdbTransaction::execute");
DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
aTypeOfExec, abortOption));
@@ -374,8 +375,8 @@ NdbTransaction::execute(ExecType aTypeOf
if (tBlob->preExecute(tExecType, batch) == -1)
{
ret = -1;
- if(savedError.code==0)
- savedError= theError;
+ if (firstTransError.code==0)
+ firstTransError= theError;
}
tBlob = tBlob->theNext;
}
@@ -413,8 +414,8 @@ NdbTransaction::execute(ExecType aTypeOf
if (tBlob->preCommit() == -1)
{
ret = -1;
- if(savedError.code==0)
- savedError= theError;
+ if (firstTransError.code==0)
+ firstTransError= theError;
}
tBlob = tBlob->theNext;
}
@@ -440,8 +441,6 @@ NdbTransaction::execute(ExecType aTypeOf
NdbOperation::DefaultAbortOption,
forceSend) == -1)
{
- if(savedError.code==0)
- savedError= theError;
/**
* We abort the execute here. But we still need to put the split-off
* operation list back into the transaction object, or we will get a
@@ -463,9 +462,13 @@ NdbTransaction::execute(ExecType aTypeOf
theCompletedLastOp = tCompletedLastOp;
}
+ /* executeNoBlobs will have set transaction error */
DBUG_RETURN(-1);
}
+ /* Capture any trans error left by the execute() in case it gets trampled */
+ if (firstTransError.code==0)
+ firstTransError= theError;
#ifdef ndb_api_crash_on_complex_blob_abort
assert(theFirstOpInList == NULL && theLastOpInList == NULL);
@@ -483,8 +486,8 @@ NdbTransaction::execute(ExecType aTypeOf
if (tBlob->postExecute(tExecType) == -1)
{
ret = -1;
- if(savedError.code==0)
- savedError= theError;
+ if (firstTransError.code==0)
+ firstTransError= theError;
}
tBlob = tBlob->theNext;
}
@@ -520,8 +523,37 @@ NdbTransaction::execute(ExecType aTypeOf
}
#endif
- if(savedError.code!=0 && theError.code==4350) // Trans already aborted
- theError= savedError;
+ /* Sometimes the original error is trampled by 'Trans already aborted',
+ * detect this case and attempt to restore the original error
+ */
+ if (theError.code == 4350) // Trans already aborted
+ {
+ DBUG_PRINT("info", ("Trans already aborted, existingTransError.code %u, "
+ "firstTransError.code %u",
+ existingTransError.code,
+ firstTransError.code));
+ if (existingTransError.code != 0)
+ {
+ theError = existingTransError;
+ }
+ else if (firstTransError.code != 0)
+ {
+ theError = firstTransError;
+ }
+ }
+
+ /* Generally return the first error which we encountered as
+ * the Trans error. Caller can traverse the op list to
+ * get the full picture
+ */
+ if (firstTransError.code != 0)
+ {
+ DBUG_PRINT("info", ("Setting error to first error. firstTransError.code = %u, "
+ "theError.code = %u",
+ firstTransError.code,
+ theError.code));
+ theError = firstTransError;
+ }
DBUG_RETURN(ret);
}
=== modified file 'storage/ndb/test/ndbapi/testBlobs.cpp'
--- a/storage/ndb/test/ndbapi/testBlobs.cpp 2011-06-30 15:59:25 +0000
+++ b/storage/ndb/test/ndbapi/testBlobs.cpp 2011-09-01 15:12:11 +0000
@@ -184,6 +184,7 @@ printusage()
<< " -bug 27370 Potential inconsistent blob reads for ReadCommitted reads" << endl
<< " -bug 36756 Handling execute(.., abortOption) and Blobs " << endl
<< " -bug 45768 execute(Commit) after failing blob batch " << endl
+ << " -bug 62321 Blob obscures ignored error codes in batch" << endl
;
}
@@ -3860,6 +3861,124 @@ static int bugtest_48040()
}
+static int bugtest_62321()
+{
+ /* Having a Blob operation in a batch with other operations
+ * causes the other operation's ignored error not to be
+ * set as the transaction error code after execution.
+ * This is used (e.g in MySQLD) to check for conflicts
+ */
+ DBG("bugtest_62321 : Error code from other ops in batch obscured");
+
+ /*
+ 1) Setup table : 1 row exists, another doesnt
+ 2) Start transaction
+ 3) Define failing before op
+ 4) Define Blob op with/without post-exec part
+ 5) Define failing after op
+ 6) Execute
+ 7) Check results
+ */
+ calcTups(true);
+
+ /* Setup table */
+ Tup& tupExists = g_tups[0];
+ Tup& notExists = g_tups[1];
+ {
+ CHK((g_con= g_ndb->startTransaction()) != 0);
+ CHK((g_opr= g_con->getNdbOperation(g_opt.m_tname)) != 0);
+ CHK(g_opr->insertTuple() == 0);
+ CHK(g_opr->equal("PK1", tupExists.m_pk1) == 0);
+ if (g_opt.m_pk2chr.m_len != 0)
+ {
+ CHK(g_opr->equal("PK2", tupExists.m_pk2) == 0);
+ CHK(g_opr->equal("PK3", tupExists.m_pk3) == 0);
+ }
+ setUDpartId(tupExists, g_opr);
+ CHK(getBlobHandles(g_opr) == 0);
+
+ CHK(setBlobValue(tupExists) == 0);
+
+ CHK(g_con->execute(Commit) == 0);
+ g_con->close();
+ }
+
+ for (int scenario = 0; scenario < 4; scenario++)
+ {
+ DBG(" Scenario : " << scenario);
+ CHK((g_con= g_ndb->startTransaction()) != 0);
+ NdbOperation* failOp = NULL;
+ if ((scenario & 0x1) == 0)
+ {
+ DBG(" Fail op before");
+ /* Define failing op in batch before Blob op */
+ failOp= g_con->getNdbOperation(g_opt.m_tname);
+ CHK(failOp != 0);
+ CHK(failOp->readTuple() == 0);
+ CHK(failOp->equal("PK1", notExists.m_pk1) == 0);
+ if (g_opt.m_pk2chr.m_len != 0)
+ {
+ CHK(failOp->equal("PK2", notExists.m_pk2) == 0);
+ CHK(failOp->equal("PK3", notExists.m_pk3) == 0);
+ }
+ setUDpartId(notExists, failOp);
+ CHK(failOp->getValue("PK1") != 0);
+ CHK(failOp->setAbortOption(NdbOperation::AO_IgnoreError) == 0);
+ }
+
+ /* Now define successful Blob op */
+ CHK((g_opr= g_con->getNdbOperation(g_opt.m_tname)) != 0);
+ CHK(g_opr->readTuple() == 0);
+ CHK(g_opr->equal("PK1", tupExists.m_pk1) == 0);
+ if (g_opt.m_pk2chr.m_len != 0)
+ {
+ CHK(g_opr->equal("PK2", tupExists.m_pk2) == 0);
+ CHK(g_opr->equal("PK3", tupExists.m_pk3) == 0);
+ }
+ setUDpartId(tupExists, g_opr);
+ CHK(getBlobHandles(g_opr) == 0);
+
+ CHK(getBlobValue(tupExists) == 0);
+
+
+ /* Define failing batch op after Blob op if not defined before */
+ if (failOp == 0)
+ {
+ DBG(" Fail op after");
+ failOp= g_con->getNdbOperation(g_opt.m_tname);
+ CHK(failOp != 0);
+ CHK(failOp->readTuple() == 0);
+ CHK(failOp->equal("PK1", notExists.m_pk1) == 0);
+ if (g_opt.m_pk2chr.m_len != 0)
+ {
+ CHK(failOp->equal("PK2", notExists.m_pk2) == 0);
+ CHK(failOp->equal("PK3", notExists.m_pk3) == 0);
+ }
+ setUDpartId(notExists, failOp);
+ CHK(failOp->getValue("PK1") != 0);
+ CHK(failOp->setAbortOption(NdbOperation::AO_IgnoreError) == 0);
+ }
+
+ /* Now execute and check rc etc */
+ NdbTransaction::ExecType et = (scenario & 0x2) ?
+ NdbTransaction::NoCommit:
+ NdbTransaction::Commit;
+
+ DBG(" Executing with execType = " << ((et == NdbTransaction::NoCommit)?
+ "NoCommit":"Commit"));
+ int rc = g_con->execute(NdbTransaction::NoCommit);
+
+ CHK(rc == 0);
+ CHK(g_con->getNdbError().code == 626);
+ CHK(failOp->getNdbError().code == 626);
+ CHK(g_opr->getNdbError().code == 0);
+ DBG(" Error code on transaction as expected");
+
+ g_con->close();
+ }
+
+ return 0;
+}
// main
@@ -4824,7 +4943,8 @@ static struct {
{ 36756, bugtest_36756 },
{ 45768, bugtest_45768 },
{ 48040, bugtest_48040 },
- { 28116, bugtest_28116 }
+ { 28116, bugtest_28116 },
+ { 62321, bugtest_62321 }
};
NDB_COMMAND(testOdbcDriver, "testBlobs", "testBlobs", "testBlobs", 65535)
=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt 2011-06-28 08:47:18 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2011-09-01 15:12:11 +0000
@@ -1740,3 +1740,8 @@ max-time: 300
cmd: testIndexStat
args:
+max-time: 300
+cmd: testBlobs
+args: -bug 62321 -skip p
+
+
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.1-telco-7.0 branch (frazer.clement:4492 to 4493)Bug#62321 | Frazer Clement | 1 Sep |