2727 Frazer Clement 2008-11-08
Bug#39867 MySQL Cluster : Failures during Blob part operations not always detected
Add new testcase to Daily Basic
modified:
storage/ndb/test/run-test/daily-basic-tests.txt
2726 Frazer Clement 2008-11-08
Bug#40241 : NDBAPI : NdbScanOperation::getBlobHandle() fails with incorrect col
names/nums
Scan operation getBlobHandle() methods have insufficient checks for bad
column names + numbers
New testcase to verify behaviour.
modified:
storage/ndb/src/ndbapi/NdbOperationDefine.cpp
storage/ndb/src/ndbapi/NdbOperationSearch.cpp
storage/ndb/src/ndbapi/NdbScanOperation.cpp
storage/ndb/test/ndbapi/testNdbApi.cpp
storage/ndb/test/run-test/daily-basic-tests.txt
2725 Frazer Clement 2008-11-08
Bug#39839 some all clusterlog stastics data do not report with node id
Events with no sender's block reference should still indicate the
node number from which they originated.
modified:
storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
2724 Frazer Clement 2008-11-08
Bug#39867 MySQL Cluster : Failures during Blob part operations not always
detected
2 parts :
1) The Ndb SQL handler (ha_ndbcluster) reported the error from the NdbBlob
object
rather than from the NdbTransaction object. This results in inconsistent
error
messages in some cases
2) The NDB kernel bypassed the TC block when reporting primary key 'simple
read'
failure in some scenarios. This resulted in the API node not detecting
operation failures in some scenarios, and eventual transaction timeouts.
Fixes :
Change NDB kernel to send LQHKEYREF to TC for early simple read failure.
Direct send
of TCKEYREF to API remains for 'dirty' read.
Change ha_ndbcluster to obtain error information from the NdbTransaction
object rather than the Blob object.
Tests :
Re-enable simple read testing in testOperations and testTransactions.
Extend testing to include Simple Reads in testNdbApi.
Add Blob read transporter overload testcase to MTR test_blob testcase.
modified:
mysql-test/suite/ndb/r/ndb_blob.result
mysql-test/suite/ndb/t/ndb_blob.test
sql/ha_ndbcluster.cc
storage/ndb/src/common/debugger/signaldata/SignalNames.cpp
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/test/ndbapi/testNdbApi.cpp
storage/ndb/test/ndbapi/testOperations.cpp
storage/ndb/test/ndbapi/testTransactions.cpp
2723 Frazer Clement 2008-11-08
Bug# 40242 NDBAPI : All NDBAPI objects should provide accessors for their
'parents'
This patch adds :
- getNdbOperation() method to NdbBlob to get const operation*
- getNdbTransaction() method to NdbScanOperation and NdbOperation to get
NdbTransaction*
- const variant of getNdbErrorLine() to NdbOperation to allow error handling
with
a const*.
modified:
storage/ndb/include/ndbapi/NdbBlob.hpp
storage/ndb/include/ndbapi/NdbOperation.hpp
storage/ndb/include/ndbapi/NdbScanOperation.hpp
storage/ndb/src/ndbapi/NdbBlob.cpp
storage/ndb/src/ndbapi/NdbOperation.cpp
2722 Magnus Svensson 2008-11-07
Bug#39180 Segfault in Logger::Log causes ndbd to hang indefinately - part2
- Fix one more warning for "too many format specifiers"
modified:
storage/ndb/src/mgmsrv/Services.cpp
=== modified file 'mysql-test/suite/ndb/r/ndb_blob.result'
--- a/mysql-test/suite/ndb/r/ndb_blob.result 2008-06-03 10:00:31 +0000
+++ b/mysql-test/suite/ndb/r/ndb_blob.result 2008-11-08 20:45:48 +0000
@@ -636,3 +636,16 @@ select (giga = repeat(@stuff, 2000)) fro
(giga = repeat(@stuff, 2000))
1
drop table t1;
+create table t1 (
+id int,
+data longblob,
+primary key(id))
+engine=ndb;
+set @blurb= repeat('B', 1000000);
+set @blurbHash= sha1(@blurb);
+set autocommit = 1;
+insert into t1 values (1, @blurb);
+create table result_space (k int primary key, result int) engine=myisam;
+set autocommit = 0;
+drop table result_space;
+drop table t1;
=== modified file 'mysql-test/suite/ndb/t/ndb_blob.test'
--- a/mysql-test/suite/ndb/t/ndb_blob.test 2008-06-03 10:00:31 +0000
+++ b/mysql-test/suite/ndb/t/ndb_blob.test 2008-11-08 20:45:48 +0000
@@ -589,3 +589,114 @@ select sha1(giga) from t1;
select (giga = repeat(@stuff, 2000)) from t1 where a=0;
drop table t1;
+
+# bug# 39867 : Blob part operation error handling
+# We attempt to generate a transporter overload
+# and check that an error is generated, rather than
+# rubbish being silently returned.
+# Since transporter overload is not easy to reliably
+# reproduce, this testcase passes when all SELECTS
+# return either the correct result, or fail with
+# MySQL error 1297, and warnings about transporter
+# overload from Ndb. (1218)
+# The testcase will fail if there is no error, and
+# incorrect data/NULL, or if there is an error other
+# than 1297 due to 1218.
+#
+
+create table t1 (
+ id int,
+ data longblob,
+ primary key(id))
+ engine=ndb;
+
+set @blurb= repeat('B', 1000000); # ~1MB of stuff
+set @blurbHash= sha1(@blurb);
+
+set autocommit = 1;
+
+let $mysqltest_loopcounter= 500;
+let $success_count=0;
+let $fail_count=0;
+
+
+insert into t1 values (1, @blurb);
+
+create table result_space (k int primary key, result int) engine=myisam;
+
+--disable_result_log
+--disable_query_log
+
+while ($mysqltest_loopcounter)
+{
+ # Allow success or unmapped error type (1297).
+ --error 0,1297
+ insert into result_space select 1, (sha1(data) = @blurbHash) from t1 where id=1;
+
+ let $orig_errno= $mysql_errno;
+
+ # Statement execution success path
+ if (!$orig_errno)
+ {
+ # Test that the SHA1 of the data read was as expected
+ # (e.g. comparison returned true)
+ let $is_right_answer=`SELECT result from result_space where k=1`;
+
+ if (!$is_right_answer)
+ {
+ --enable_result_log
+ echo SELECT succeeded but gave bad result.
+ SHOW WARNINGS;
+ die "Bad data returned";
+ }
+ #echo Success gave correct result;
+ inc $success_count;
+ }
+
+ # Statement execution failure path
+ if ($orig_errno)
+ {
+ inc $fail_count;
+ #echo FAIL;
+
+ # For the error we are interested in (1218), MySQLD returns a generic error
+ # code (1297). We use the warning info to check the Ndb error.
+ # Note that sometimes the end of the warning states 'from NDB', sometimes
+ # 'from NDBCLUSTER'. Probably it should be made consistent.
+ #
+ let $warning_message= query_get_value("SHOW WARNINGS", Message, 1);
+ let $is_correct_message= `SELECT "$warning_message" LIKE "Got temporary error 1218
'Send Buffers overloaded in NDB kernel' from NDB%"`;
+
+ if (!$is_correct_message)
+ {
+ --enable_result_log
+ echo SELECT failed with incorrect error ($mysql_errno);
+ SHOW WARNINGS;
+ die "Incorrect error from statement";
+ }
+ #echo Failed as expected;
+ }
+
+ delete from result_space;
+
+ #echo $mysqltest_loopcounter;
+
+ dec $mysqltest_loopcounter;
+
+ if ($fail_count = 20)
+ {
+ # That's enough punishment
+ #echo Exiting loop early at iteration $mysqltest_loopcounter;
+ let $mysqltest_loopcounter= 0;
+ }
+}
+
+--enable_result_log
+--enable_query_log
+
+# Interesting, but can't output as it's different every time
+# echo Successes $success_count;
+# echo Failures $fail_count;
+set autocommit = 0;
+drop table result_space;
+drop table t1;
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2008-10-29 13:09:15 +0000
+++ b/sql/ha_ndbcluster.cc 2008-11-08 20:45:48 +0000
@@ -655,6 +655,33 @@ ha_ndbcluster::copy_row_to_buffer(Thd_nd
return row;
}
+/**
+ * findBlobError
+ * This method attempts to find an error in the hierarchy of runtime
+ * NDBAPI objects from Blob up to transaction.
+ * It will return -1 if no error is found, 0 if an error is found.
+ */
+int findBlobError(NdbError& error, NdbBlob* pBlob)
+{
+ error= pBlob->getNdbError();
+ if (error.code != 0)
+ return 0;
+
+ const NdbOperation* pOp= pBlob->getNdbOperation();
+ error= pOp->getNdbError();
+ if (error.code != 0)
+ return 0;
+
+ NdbTransaction* pTrans= pOp->getNdbTransaction();
+ error= pTrans->getNdbError();
+ if (error.code != 0)
+ return 0;
+
+ /* No error on any of the objects */
+ return -1;
+}
+
+
int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg)
{
ha_ndbcluster *ha= (ha_ndbcluster *)arg;
@@ -733,7 +760,19 @@ int g_get_ndb_blobs_value(NdbBlob *ndb_b
uchar *buf= ha->m_blobs_buffer + offset;
uint32 len= ha->m_blobs_buffer_size - offset;
if (ndb_blob->readData(buf, len) != 0)
- ERR_RETURN(ndb_blob->getNdbError());
+ {
+ NdbError err;
+ if (findBlobError(err, ndb_blob) == 0)
+ {
+ ERR_RETURN(err);
+ }
+ else
+ {
+ /* Should always have some error code set */
+ assert(err.code != 0);
+ ERR_RETURN(err);
+ }
+ }
DBUG_PRINT("info", ("[%u] offset: %u buf: 0x%lx len=%u",
i, offset, (long) buf, len));
DBUG_ASSERT(len == len64);
=== modified file 'storage/ndb/include/ndbapi/NdbBlob.hpp'
--- a/storage/ndb/include/ndbapi/NdbBlob.hpp 2008-02-19 10:41:22 +0000
+++ b/storage/ndb/include/ndbapi/NdbBlob.hpp 2008-11-08 20:40:15 +0000
@@ -263,6 +263,13 @@ public:
*/
const NdbError& getNdbError() const;
/**
+ * Get a pointer to the operation which this Blob Handle
+ * was initially created as part of.
+ * Note that this could be a scan operation.
+ * Note that the pointer returned is a const pointer.
+ */
+ const NdbOperation* getNdbOperation() const;
+ /**
* Return info about all blobs in this operation.
*
* Get first blob in list.
=== modified file 'storage/ndb/include/ndbapi/NdbOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbOperation.hpp 2008-08-07 06:24:52 +0000
+++ b/storage/ndb/include/ndbapi/NdbOperation.hpp 2008-11-08 20:40:15 +0000
@@ -837,6 +837,7 @@ public:
* @return method number where the error occured.
*/
int getNdbErrorLine();
+ int getNdbErrorLine() const;
/**
* Get table name of this operation.
@@ -885,6 +886,11 @@ public:
*/
AbortOption getAbortOption() const;
int setAbortOption(AbortOption);
+
+ /**
+ * Get NdbTransaction object pointer for this operation
+ */
+ virtual NdbTransaction* getNdbTransaction() const;
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
@@ -1037,7 +1043,6 @@ protected:
public:
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
- NdbTransaction* getNdbTransaction();
const NdbOperation* next() const;
const NdbRecAttr* getFirstRecAttr() const;
#endif
@@ -1473,6 +1478,13 @@ NdbOperation::getNdbErrorLine()
return theErrorLine;
}
+inline
+int
+NdbOperation::getNdbErrorLine() const
+{
+ return theErrorLine;
+}
+
/******************************************************************************
void next(NdbOperation* aNdbOperation);
=== modified file 'storage/ndb/include/ndbapi/NdbScanOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbScanOperation.hpp 2008-08-11 12:44:24 +0000
+++ b/storage/ndb/include/ndbapi/NdbScanOperation.hpp 2008-11-08 20:40:15 +0000
@@ -377,6 +377,11 @@ public:
const NdbOperation::OperationOptions *opts = 0,
Uint32 sizeOfOptions = 0);
+ /**
+ * Get NdbTransaction object for this scan operation
+ */
+ NdbTransaction* getNdbTransaction() const;
+
protected:
NdbScanOperation(Ndb* aNdb,
NdbOperation::Type aType = NdbOperation::TableScan);
@@ -651,4 +656,14 @@ NdbScanOperation::deleteCurrentTuple(Ndb
opts, sizeOfOptions);
}
+inline
+NdbTransaction*
+NdbScanOperation::getNdbTransaction() const
+{
+ /* return the user visible transaction object ptr, not the
+ * scan's 'internal' / buddy transaction object
+ */
+ return m_transConnection;
+};
+
#endif
=== modified file 'storage/ndb/src/common/debugger/signaldata/SignalNames.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp 2007-10-23 09:38:20 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp 2008-11-08 20:45:48 +0000
@@ -646,5 +646,7 @@ const GsnName SignalNames [] = {
,{ GSN_PREPARE_COPY_FRAG_CONF, "PREPARE_COPY_FRAG_CONF" }
,{ GSN_UPGRADE_PROTOCOL_ORD, "UPGRADE_PROTOCOL_ORD" }
+
+ ,{ GSN_TC_HBREP, "TC_HBREP" }
};
const unsigned short NO_OF_SIGNAL_NAMES = sizeof(SignalNames)/sizeof(GsnName);
=== modified file 'storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp'
--- a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp 2008-08-27 19:56:41 +0000
+++ b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp 2008-11-08 20:46:53 +0000
@@ -212,6 +212,15 @@ void Cmvmi::execEVENT_REP(Signal* signal
if (nodeId == 0)
{
nodeId= refToNode(signal->getSendersBlockRef());
+
+ if (nodeId == 0)
+ {
+ /* Event reporter supplied no node id,
+ * assume it was local
+ */
+ nodeId= getOwnNodeId();
+ }
+
eventReport->setNodeId(nodeId);
}
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2008-11-07 08:01:33 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2008-11-08 20:45:48 +0000
@@ -2284,9 +2284,10 @@ void Dblqh::noFreeRecordLab(Signal* sign
releaseTcrec(signal, tcConnectptr);
}
- if (LqhKeyReq::getSimpleFlag(reqInfo) &&
+ if (LqhKeyReq::getDirtyFlag(reqInfo) &&
LqhKeyReq::getOperation(reqInfo) == ZREAD){
jam();
+ /* Dirty read sends TCKEYREF direct to client, and nothing to TC */
ndbrequire(LqhKeyReq::getApplicationAddressFlag(reqInfo));
const Uint32 apiRef = lqhKeyReq->variableData[0];
const Uint32 apiOpRec = lqhKeyReq->variableData[1];
@@ -2300,6 +2301,9 @@ void Dblqh::noFreeRecordLab(Signal* sign
sendTCKEYREF(signal, apiRef, signal->getSendersBlockRef(), 0);
} else {
jam();
+ /* All ops apart from dirty read send LQHKEYREF to TC
+ * (This includes simple read)
+ */
const Uint32 clientPtr = lqhKeyReq->clientConnectPtr;
Uint32 TcOprec = clientPtr;
=== modified file 'storage/ndb/src/ndbapi/NdbBlob.cpp'
--- a/storage/ndb/src/ndbapi/NdbBlob.cpp 2008-06-03 10:00:31 +0000
+++ b/storage/ndb/src/ndbapi/NdbBlob.cpp 2008-11-08 20:40:15 +0000
@@ -3070,3 +3070,8 @@ NdbBlob::blobsNextBlob()
return theNext;
}
+const NdbOperation*
+NdbBlob::getNdbOperation() const
+{
+ return theNdbOp;
+};
=== modified file 'storage/ndb/src/ndbapi/NdbOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperation.cpp 2008-04-17 06:59:16 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperation.cpp 2008-11-08 20:40:15 +0000
@@ -517,7 +517,7 @@ NdbOperation::getTable() const
}
NdbTransaction*
-NdbOperation::getNdbTransaction()
+NdbOperation::getNdbTransaction() const
{
return theNdbCon;
}
=== modified file 'storage/ndb/src/ndbapi/NdbOperationDefine.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationDefine.cpp 2008-06-03 10:00:31 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationDefine.cpp 2008-11-08 21:06:51 +0000
@@ -475,7 +475,9 @@ NdbOperation::setValue( const NdbColumnI
{
DBUG_ENTER("NdbOperation::setValue");
DBUG_PRINT("enter", ("col: %s op:%d val: 0x%lx",
- tAttrInfo->m_name.c_str(), theOperationType,
+ (tAttrInfo == NULL) ? "NULL":
+ tAttrInfo->m_name.c_str(),
+ theOperationType,
(long) aValuePassed));
int tReturnCode;
=== modified file 'storage/ndb/src/ndbapi/NdbOperationSearch.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationSearch.cpp 2008-06-03 10:00:31 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationSearch.cpp 2008-11-08 21:06:51 +0000
@@ -58,7 +58,9 @@ NdbOperation::equal_impl(const NdbColumn
{
DBUG_ENTER("NdbOperation::equal_impl");
DBUG_PRINT("enter", ("col: %s op: %d val: 0x%lx",
- tAttrInfo->m_name.c_str(), theOperationType,
+ (tAttrInfo == NULL) ? "NULL" :
+ tAttrInfo->m_name.c_str(),
+ theOperationType,
(long) aValuePassed));
const char* aValue = aValuePassed;
=== modified file 'storage/ndb/src/ndbapi/NdbScanOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp 2008-11-06 16:34:02 +0000
+++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp 2008-11-08 21:06:51 +0000
@@ -2365,31 +2365,49 @@ NdbScanOperation::takeOverScanOpNdbRecor
NdbBlob*
NdbScanOperation::getBlobHandle(const char* anAttrName)
{
- /* We need the row KeyInfo for Blobs
- * Old Api scans have saved flags at this point
- */
- if (m_scanUsingOldApi)
- m_savedScanFlagsOldApi|= SF_KeyInfo;
+ const NdbColumnImpl* col= m_currentTable->getColumn(anAttrName);
+
+ if (col != NULL)
+ {
+ /* We need the row KeyInfo for Blobs
+ * Old Api scans have saved flags at this point
+ */
+ if (m_scanUsingOldApi)
+ m_savedScanFlagsOldApi|= SF_KeyInfo;
+ else
+ m_keyInfo= 1;
+
+ return NdbOperation::getBlobHandle(m_transConnection, col);
+ }
else
- m_keyInfo= 1;
-
- return NdbOperation::getBlobHandle(m_transConnection,
- m_currentTable->getColumn(anAttrName));
+ {
+ setErrorCode(4004);
+ return NULL;
+ }
}
NdbBlob*
NdbScanOperation::getBlobHandle(Uint32 anAttrId)
{
- /* We need the row KeyInfo for Blobs
- * Old Api scans have saved flags at this point
- */
- if (m_scanUsingOldApi)
- m_savedScanFlagsOldApi|= SF_KeyInfo;
+ const NdbColumnImpl* col= m_currentTable->getColumn(anAttrId);
+
+ if (col != NULL)
+ {
+ /* We need the row KeyInfo for Blobs
+ * Old Api scans have saved flags at this point
+ */
+ if (m_scanUsingOldApi)
+ m_savedScanFlagsOldApi|= SF_KeyInfo;
+ else
+ m_keyInfo= 1;
+
+ return NdbOperation::getBlobHandle(m_transConnection, col);
+ }
else
- m_keyInfo= 1;
-
- return NdbOperation::getBlobHandle(m_transConnection,
- m_currentTable->getColumn(anAttrId));
+ {
+ setErrorCode(4004);
+ return NULL;
+ }
}
NdbRecAttr*
=== modified file 'storage/ndb/test/ndbapi/testNdbApi.cpp'
--- a/storage/ndb/test/ndbapi/testNdbApi.cpp 2008-06-03 12:37:17 +0000
+++ b/storage/ndb/test/ndbapi/testNdbApi.cpp 2008-11-08 21:06:51 +0000
@@ -26,10 +26,8 @@
#define MAX_NDB_OBJECTS 32678
#define CHECK(b) if (!(b)) { \
- ndbout << "ERR: "<< step->getName() \
- << " failed on line " << __LINE__ << endl; \
- result = NDBT_FAILED; \
- continue; }
+ ndbout << "ERR: failed on line " << __LINE__ << endl; \
+ return -1; }
#define CHECKE(b) if (!(b)) { \
errors++; \
@@ -628,6 +626,175 @@ int runGetNdbOperationNoTab(NDBT_Context
return NDBT_OK;
}
+int runBadColNameHandling(NDBT_Context* ctx, NDBT_Step* step){
+ int result = NDBT_OK;
+ const NdbDictionary::Table* pTab = ctx->getTab();
+
+
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
+ if (pNdb == NULL){
+ ndbout << "pNdb == NULL" << endl;
+ return NDBT_FAILED;
+ }
+ if (pNdb->init()){
+ ERR(pNdb->getNdbError());
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ const int CASES= 5;
+ int i;
+
+ for (i= 0; i < CASES; i++)
+ {
+ ndbout << "Case " << i << endl;
+ NdbConnection* pCon = pNdb->startTransaction();
+ if (pCon == NULL){
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ /* Cases 0-3 use PK ops, 4 + use scans */
+ NdbOperation* pOp = (i < 4 ? pCon->getNdbOperation(pTab->getName()):
+ pCon->getNdbScanOperation(pTab->getName()));
+ if (pOp == NULL){
+ ERR(pCon->getNdbError());
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ bool failed= false;
+ int expectedError= 0;
+ HugoOperations hugoOps(*pTab);
+
+ switch(i) {
+ case 0:
+ if (pOp->readTuple() != 0){
+ ERR(pCon->getNdbError());
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ // getValue should fail, we check that we get correct errors
+ // in expected places.
+ expectedError= 4004;
+ failed= (pOp->getValue("MOST_IMPROBABLE2") == NULL);
+ break;
+
+ case 1:
+ if (pOp->readTuple() != 0){
+ ERR(pCon->getNdbError());
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ // equal should fail, we check that we get correct errors
+ // in expected places.
+ expectedError= 4004;
+ failed= (pOp->equal("MOST_IMPROBABLE2", 0) != 0);
+ break;
+
+ case 2:
+ if (pOp->writeTuple() != 0){
+ ERR(pCon->getNdbError());
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ // set equality on pk columns
+ for(int a = 0; a<pTab->getNoOfColumns(); a++){
+ if (pTab->getColumn(a)->getPrimaryKey() == true){
+ if(hugoOps.equalForAttr(pOp, a, 1) != 0){
+ const NdbError err = pCon->getNdbError();
+ ERR(err);
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+ }
+ }
+
+ // setValue should fail, we check that we get correct errors
+ // in expected places.
+ expectedError= 4004;
+ failed= (pOp->setValue("MOST_IMPROBABLE2", 0) != 0);
+ break;
+
+ case 3:
+ if (pOp->readTuple() != 0){
+ ERR(pCon->getNdbError());
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ // getBlobHandle should fail, we check that we get correct errors
+ // in expected places.
+ expectedError= 4004;
+ failed= (pOp->getBlobHandle("MOST_IMPROBABLE2") == NULL);
+ break;
+
+ case 4:
+ {
+ NdbScanOperation* sop= (NdbScanOperation*) pOp;
+ if (sop->readTuples() != 0){
+ ERR(pCon->getNdbError());
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ // getBlobHandle should fail, we check that we get correct errors
+ // in expected places.
+ expectedError= 4004;
+ ndbout << "About to call getBlobHandle" << endl;
+ failed= (sop->getBlobHandle("MOST_IMPROBABLE2") == NULL);
+
+ sop->close();
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (failed)
+ {
+ const NdbError opErr= pOp->getNdbError();
+ const NdbError transErr = pCon->getNdbError();
+ ERR(opErr);
+ ERR(transErr);
+ if (opErr.code != transErr.code) {
+ ndbout << "Error reporting mismatch, expected "
+ << expectedError << endl;
+ result = NDBT_FAILED;
+ }
+ if (opErr.code != expectedError){
+ ndbout << "No or bad error detected, expected "
+ << expectedError << endl;
+ result = NDBT_FAILED;
+ }
+ } else {
+ ndbout << "Case " << i << " did not fail" << endl;
+ result = NDBT_FAILED;
+ }
+
+ pNdb->closeTransaction(pCon);
+
+ if (result == NDBT_FAILED)
+ break;
+ } // for
+
+ delete pNdb;
+
+ return result;
+}
+
int runMissingOperation(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
const NdbDictionary::Table* pTab = ctx->getTab();
@@ -1326,6 +1493,7 @@ op_row(NdbTransaction* pTrans, HugoOpera
case 3:
case 4:
case 5:
+ case 12:
pOp = pTrans->getNdbOperation(pTab->getName());
break;
case 9:
@@ -1365,10 +1533,13 @@ op_row(NdbTransaction* pTrans, HugoOpera
case 11:
pOp->deleteTuple();
break;
+ case 12:
+ CHECK(!pOp->simpleRead());
+ break;
default:
abort();
}
-
+
for(int a = 0; a<pTab->getNoOfColumns(); a++){
if (pTab->getColumn(a)->getPrimaryKey() == true){
if(hugoOps.equalForAttr(pOp, a, row) != 0){
@@ -1384,8 +1555,9 @@ op_row(NdbTransaction* pTrans, HugoOpera
case 6:
case 7:
case 8:
+ case 12:
for(int a = 0; a<pTab->getNoOfColumns(); a++){
- pOp->getValue(a);
+ CHECK(pOp->getValue(a));
}
break;
case 3:
@@ -1427,6 +1599,8 @@ static void print(int op)
case 9: str = "noop "; break;
case 10: str = "uk update "; break;
case 11: str = "uk delete "; break;
+ case 12: str = "pk read-si"; break;
+
default:
abort();
}
@@ -1457,9 +1631,10 @@ runTestIgnoreError(NDBT_Context* ctx, ND
printf("case: <op1> <op2> c/nc ao/ie\n");
Uint32 tno = 0;
- for (Uint32 op1 = 0; op1 < 12; op1++)
+ for (Uint32 op1 = 0; op1 < 13; op1++)
{
- for (Uint32 op2 = op1; op2 < 12; op2++)
+ // NOTE : I get a node crash if the following loop starts from 0!
+ for (Uint32 op2 = op1; op2 < 13; op2++)
{
int ret;
NdbTransaction* pTrans = 0;
@@ -1486,25 +1661,25 @@ runTestIgnoreError(NDBT_Context* ctx, ND
hugoTrans.loadTable(pNdb, 1);
- pTrans = pNdb->startTransaction();
- op_row(pTrans, hugoOps, pTab, op1, 0);
+ CHECK(pTrans = pNdb->startTransaction());
+ CHECK(!op_row(pTrans, hugoOps, pTab, op1, 0));
ret = pTrans->execute(et, ao);
pTrans->close();
printf("%d ", ret);
hugoTrans.clearTable(pNdb);
hugoTrans.loadTable(pNdb, 1);
- pTrans = pNdb->startTransaction();
- op_row(pTrans, hugoOps, pTab, op1, 1);
+ CHECK(pTrans = pNdb->startTransaction());
+ CHECK(!op_row(pTrans, hugoOps, pTab, op1, 1));
ret = pTrans->execute(et, ao);
pTrans->close();
printf("%d ", ret);
hugoTrans.clearTable(pNdb);
hugoTrans.loadTable(pNdb, 1);
- pTrans = pNdb->startTransaction();
- op_row(pTrans, hugoOps, pTab, op1, 0);
- op_row(pTrans, hugoOps, pTab, op2, 1);
+ CHECK(pTrans = pNdb->startTransaction());
+ CHECK(!op_row(pTrans, hugoOps, pTab, op1, 0));
+ CHECK(!op_row(pTrans, hugoOps, pTab, op2, 1));
ret = pTrans->execute(et, ao);
pTrans->close();
printf("%d\n", ret);
@@ -1728,6 +1903,85 @@ done:
return result;
}
+int
+simpleReadAbortOnError(NDBT_Context* ctx, NDBT_Step* step)
+{
+ /* Simple read has some error handling issues
+ * Setting the operation to be AbortOnError can expose these
+ */
+ Ndb* pNdb = GETNDB(step);
+ const NdbDictionary::Table* pTab= ctx->getTab();
+ HugoOperations hugoOps(*pTab);
+ NdbRestarter restarter;
+
+ hugoOps.startTransaction(pNdb);
+ CHECK(!hugoOps.pkWriteRecord(pNdb,0));
+ CHECK(!hugoOps.execute_Commit(pNdb, AbortOnError));
+
+ NdbTransaction* trans;
+
+ CHECK(trans= pNdb->startTransaction());
+
+ /* Insert error 5047 which causes next LQHKEYREQ to fail due
+ * to 'transporter overload'
+ * Error insert is self-clearing
+ */
+ restarter.insertErrorInAllNodes(5047);
+
+ /* Create SimpleRead on row 0, which exists (though we'll get
+ * 'transporter overload for this'
+ */
+ NdbOperation* op;
+ CHECK(op= trans->getNdbOperation(pTab));
+
+ CHECK(!op->simpleRead());
+
+ for(int a = 0; a<pTab->getNoOfColumns(); a++){
+ if (pTab->getColumn(a)->getPrimaryKey() == true){
+ if(hugoOps.equalForAttr(op, a, 0) != 0){
+ restarter.insertErrorInAllNodes(0);
+ return NDBT_FAILED;
+ }
+ }
+ }
+ for(int a = 0; a<pTab->getNoOfColumns(); a++){
+ CHECK(op->getValue(a));
+ }
+
+ CHECK(!op->setAbortOption(NdbOperation::AbortOnError));
+
+ /* Create normal read on row 0 which will succeed */
+ NdbOperation* op2;
+ CHECK(op2= trans->getNdbOperation(pTab));
+
+ CHECK(!op2->readTuple());
+
+ for(int a = 0; a<pTab->getNoOfColumns(); a++){
+ if (pTab->getColumn(a)->getPrimaryKey() == true){
+ if(hugoOps.equalForAttr(op2, a, 0) != 0){
+ restarter.insertErrorInAllNodes(0);
+ return NDBT_FAILED;
+ }
+ }
+ }
+ for(int a = 0; a<pTab->getNoOfColumns(); a++){
+ CHECK(op2->getValue(a));
+ }
+
+ CHECK(!op2->setAbortOption(NdbOperation::AbortOnError));
+
+
+ CHECK(trans->execute(NoCommit) == -1);
+
+ CHECK(trans->getNdbError().code == 1218); // Transporter Overload
+
+ restarter.insertErrorInAllNodes(0);
+
+ return NDBT_OK;
+
+}
+
+
NDBT_TESTSUITE(testNdbApi);
TESTCASE("MaxNdb",
"Create Ndb objects until no more can be created\n"){
@@ -1769,6 +2023,10 @@ TESTCASE("GetOperationNoTab",
"Call getNdbOperation on a table that does not exist\n"){
INITIALIZER(runGetNdbOperationNoTab);
}
+TESTCASE("BadColNameHandling",
+ "Call methods with an invalid column name and check error handling\n"){
+ INITIALIZER(runBadColNameHandling);
+}
TESTCASE("MissingOperation",
"Missing operation request(insertTuple) should give an error code\n"){
INITIALIZER(runMissingOperation);
@@ -1840,6 +2098,10 @@ TESTCASE("Bug37158",
""){
INITIALIZER(runBug37158);
}
+TESTCASE("SimpleReadAbortOnError",
+ "Test behaviour of Simple reads with Abort On Error"){
+ INITIALIZER(simpleReadAbortOnError);
+}
NDBT_TESTSUITE_END(testNdbApi);
int main(int argc, const char** argv){
=== modified file 'storage/ndb/test/ndbapi/testOperations.cpp'
--- a/storage/ndb/test/ndbapi/testOperations.cpp 2007-08-01 03:07:58 +0000
+++ b/storage/ndb/test/ndbapi/testOperations.cpp 2008-11-08 20:45:48 +0000
@@ -59,6 +59,20 @@ OperationTestCase matrix[] = {
{ "FReadUpdate", false, "READ", 626, 0, "UPDATE", 626, 0, 626, 0 },
{ "FReadDelete", false, "READ", 626, 0, "DELETE", 626, 0, 626, 0 },
+ { "FSimpleReadRead", false, "S-READ", 626, 0, "READ", 626, 0, 626, 0 },
+ { "FSimpleReadReadEx",
+ false, "S-READ", 626, 0, "READ-EX", 626, 0, 626, 0 },
+ { "FSimpleReadSimpleRead",
+ false, "S-READ", 626, 0, "S-READ", 626, 0, 626, 0 },
+ { "FSimpleReadDirtyRead",
+ false, "S-READ", 626, 0, "D-READ", 626, 0, 626, 0 },
+ { "FSimpleReadInsert",
+ false, "S-READ", 626, 0, "INSERT", 0, 1, 0, 1 },
+ { "FSimpleReadUpdate",
+ false, "S-READ", 626, 0, "UPDATE", 626, 0, 626, 0 },
+ { "FSimpleReadDelete",
+ false, "S-READ", 626, 0, "DELETE", 626, 0, 626, 0 },
+
{ "ReadExRead", true, "READ-EX", 0, 0, "READ", 0, 0, 0, 0 },
{ "ReadExReadEx", true, "READ-EX", 0, 0, "READ-EX", 0, 0, 0, 0 },
{ "ReadExSimpleRead", true, "READ-EX", 0, 0, "S-READ", 0, 0, 0, 0 },
@@ -118,7 +132,7 @@ runOp(HugoOperations & hugoOps,
} else if(strcmp(op, "READ-EX") == 0){
C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive), 0);
} else if(strcmp(op, "S-READ") == 0){
- C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read), 0);
+ C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_SimpleRead), 0);
} else if(strcmp(op, "D-READ") == 0){
C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_CommittedRead), 0);
} else if(strcmp(op, "INSERT") == 0){
=== modified file 'storage/ndb/test/ndbapi/testTransactions.cpp'
--- a/storage/ndb/test/ndbapi/testTransactions.cpp 2006-12-23 19:20:40 +0000
+++ b/storage/ndb/test/ndbapi/testTransactions.cpp 2008-11-08 20:45:48 +0000
@@ -109,6 +109,23 @@ OperationTestCase matrix[] = {
{ "ScanExScanDe", true, "SCAN-EX",1, "SCAN-DE", 266, X, 0, 1 },
#endif
+ { "SimpleReadRead", true, "S-READ", 1, "READ", 0, 1, 0, 1 },
+ { "SimpleReadReadEx", true, "S-READ", 1, "READ-EX", 0, 1, 0, 1 }, // no lock held
+ { "SimpleReadSimpleRead",
+ true, "S-READ", 1, "S-READ", 0, 1, 0, 1 },
+ { "SimpleReadDirtyRead",
+ true, "S-READ", 1, "D-READ", 0, 1, 0, 1 },
+ { "SimpleReadInsert", true, "S-READ", 1, "INSERT", 630, X, 0, 1 }, // no lock held
+ { "SimpleReadUpdate", true, "S-READ", 1, "UPDATE", 0, 2, 0, 2 }, // no lock held
+ { "SimpleReadDelete", true, "S-READ", 1, "DELETE", 0, X, 626, X }, // no lock held
+ { "SimpleReadScan", true, "S-READ", 1, "SCAN", 0, 1, 0, 1 },
+ { "SimpleReadScanHl", true, "S-READ", 1, "SCAN-HL", 0, 1, 0, 1 },
+ { "SimpleReadScanEx", true, "S-READ", 1, "SCAN-EX", 0, 1, 0, 1 }, // no lock held
+#if 0
+ { "SimpleReadScanUp", true, "S-READ", 1, "SCAN-UP", 0, 1, 0, 2 }, // no lock held
+ { "SimpleReadScanDe", true, "S-READ", 1, "SCAN-DE", 0, X, 626, X }, // no lock held
+#endif
+
{ "ReadExRead", true, "READ-EX",1, "READ", 266, X, 0, 1 },
{ "ReadExReadEx", true, "READ-EX",1, "READ-EX", 266, X, 0, 1 },
{ "ReadExSimpleRead", true, "READ-EX",1, "S-READ", 266, X, 0, 1 },
@@ -169,6 +186,9 @@ OperationTestCase matrix[] = {
{ "DeleteScanDe", true, "DELETE", X, "SCAN-DE", 266, X, 626, X }
#endif
+
+
+
};
#define CHECK(a, b) { int x = a; int y = b; if (x != y) { \
@@ -193,7 +213,7 @@ runOp(HugoOperations & hugoOps,
} else if(strcmp(op, "READ-EX") == 0){
C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0);
} else if(strcmp(op, "S-READ") == 0){
- C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0);
+ C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_SimpleRead) == 0);
} else if(strcmp(op, "D-READ") == 0){
C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_CommittedRead) == 0);
} else if(strcmp(op, "INSERT") == 0){
=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt 2008-08-11 10:41:11 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2008-11-08 21:08:06 +0000
@@ -765,6 +765,14 @@ cmd: testNdbApi
args: -n Bug28443
max-time: 500
+cmd: testNdbApi
+args: -n BadColNameHandling T6
+
+max-time: 500
+cmd: testNdbApi
+args: -n SimpleReadAbortOnError T1 T6 T15
+
+max-time: 500
cmd: testInterpreter
args: T1
@@ -1167,3 +1175,4 @@ cmd: test_event
args -r 5000 -n Bug30780 T1
#EOF 2008-08-11
+
| Thread |
|---|
| • bzr push into mysql-5.1 branch (frazer:2722 to 2727) Bug#39867 | Frazer Clement | 8 Nov |