#At file:///home/frazer/bzr/mysql-5.1-telco-6.2/
3012 Frazer Clement 2009-10-06
Bug#45282 NDBAPI - Duplicate read of column results in Api failure
modified:
storage/ndb/src/ndbapi/NdbOperationExec.cpp
storage/ndb/test/include/HugoCalculator.hpp
storage/ndb/test/ndbapi/testNdbApi.cpp
storage/ndb/test/run-test/daily-basic-tests.txt
storage/ndb/test/src/HugoCalculator.cpp
=== modified file 'storage/ndb/src/ndbapi/NdbOperationExec.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationExec.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationExec.cpp 2009-10-06 10:39:02 +0000
@@ -350,7 +350,7 @@ Uint32
NdbOperation::repack_read(Uint32 len)
{
Uint32 i;
- Uint32 maxId = 0, check = 0;
+ Uint32 check = 0, prevId = 0;
Uint32 save = len;
Bitmask<MAXNROFATTRIBUTESINWORDS> mask;
NdbApiSignal *tSignal = theFirstATTRINFO;
@@ -362,14 +362,16 @@ NdbOperation::repack_read(Uint32 len)
{
AttributeHeader tmp(* ptr++);
Uint32 id = tmp.getAttributeId();
- if (id >= NDB_MAX_ATTRIBUTES_IN_TABLE)
+ if (((i > 0) && // No prevId for first attrId
+ (id <= prevId)) ||
+ (id >= NDB_MAX_ATTRIBUTES_IN_TABLE))
{
- // Dont support == fallback
+ // AttrIds not strictly ascending with no duplicates
+ // and no pseudo-columns == fallback
return save;
}
+ prevId = id;
mask.set(id);
- maxId = (id > maxId) ? id : maxId;
- check |= (id - maxId);
}
Uint32 cnt = 0;
@@ -382,20 +384,20 @@ NdbOperation::repack_read(Uint32 len)
{
AttributeHeader tmp(* ptr++);
Uint32 id = tmp.getAttributeId();
- if (id >= NDB_MAX_ATTRIBUTES_IN_TABLE)
+ if ((id <= prevId) ||
+ (id >= NDB_MAX_ATTRIBUTES_IN_TABLE))
{
- // Dont support == fallback
+ // AttrIds not strictly ascending with no duplicates
+ // and no pseudo-columns == fallback
return save;
}
+ prevId = id;
mask.set(id);
-
- maxId = (id > maxId) ? id : maxId;
- check |= (id - maxId);
}
tSignal = tSignal->next();
}
- const Uint32 newlen = 1 + (maxId >> 5);
+ const Uint32 newlen = 1 + (prevId >> 5);
const bool all = cols == save;
if (check == 0)
{
=== modified file 'storage/ndb/test/include/HugoCalculator.hpp'
--- a/storage/ndb/test/include/HugoCalculator.hpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/test/include/HugoCalculator.hpp 2009-10-06 10:39:02 +0000
@@ -37,6 +37,9 @@ public:
int len, Uint32* real_len) const;
int verifyRowValues(NDBT_ResultRow* const pRow) const;
+ int verifyRecAttr(int record, int updates, const NdbRecAttr* recAttr);
+ int verifyColValue(int record, int attrib, int updates,
+ const char* valPtr, Uint32 valLen);
int getIdValue(NDBT_ResultRow* const pRow) const;
int getUpdatesValue(NDBT_ResultRow* const pRow) const;
int isIdCol(int colId) { return m_idCol == colId; };
=== modified file 'storage/ndb/test/ndbapi/testNdbApi.cpp'
--- a/storage/ndb/test/ndbapi/testNdbApi.cpp 2009-09-22 13:04:32 +0000
+++ b/storage/ndb/test/ndbapi/testNdbApi.cpp 2009-10-06 10:39:02 +0000
@@ -3121,6 +3121,157 @@ int runBulkPkReads(NDBT_Context* ctx, ND
return NDBT_OK;
}
+int runReadColumnDuplicates(NDBT_Context* ctx, NDBT_Step* step){
+
+ int result = NDBT_OK;
+ const NdbDictionary::Table* pTab = ctx->getTab();
+ HugoCalculator hc(*pTab);
+ Uint32 numRecords = ctx->getNumRecords();
+
+ 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;
+ }
+
+ HugoOperations hugoOps(*pTab);
+
+ for (int m = 1; m < 100; m++){
+ Uint32 record = (100 - m) % numRecords;
+ NdbConnection* pCon = pNdb->startTransaction();
+ if (pCon == NULL){
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
+ if (pOp == NULL){
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ if (pOp->readTuple() != 0){
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ int numCols= pTab->getNoOfColumns();
+
+ for(int a = 0; a < numCols; a++){
+ if (pTab->getColumn(a)->getPrimaryKey() == true){
+ if(hugoOps.equalForAttr(pOp, a, record) != 0){
+ ERR(pCon->getNdbError());
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+ }
+ }
+
+ int dupColNum = m % numCols;
+ int numReads = m + 1;
+
+ NdbRecAttr* first = NULL;
+ ndbout << "Reading record "
+ << record << " Column "
+ << dupColNum << " " << numReads
+ << " times" << endl;
+ while (numReads--)
+ {
+ NdbRecAttr* recAttr = pOp->getValue(dupColNum);
+ if (recAttr == NULL) {
+ const NdbError err = pCon->getNdbError();
+ ERR(err);
+ result = NDBT_FAILED;
+ pNdb->closeTransaction(pCon);
+ break;
+ }
+ first = (first == NULL) ? recAttr : first;
+ };
+
+ if (result == NDBT_FAILED)
+ break;
+
+ if (pCon->execute(Commit) != 0){
+ const NdbError err = pCon->getNdbError();
+ ERR(err);
+ result = NDBT_FAILED;
+ pNdb->closeTransaction(pCon);
+ break;
+ }
+
+ if (pCon->getNdbError().code != 0)
+ {
+ NdbError err = pCon->getNdbError();
+ if (err.code == 880)
+ {
+ /* Tried to read too much error - this column
+ * is probably too large.
+ * Skip to next iteration
+ */
+ ndbout << "Reading too much in one op, skipping..." << endl;
+ pNdb->closeTransaction(pCon);
+ continue;
+ }
+ ndbout << "Error at execute time : " << err.code
+ << ":" << err.message << endl;
+ pNdb->closeTransaction(pCon);
+ result = NDBT_FAILED;
+ break;
+ }
+
+ /* Let's check the results */
+
+
+ const NdbRecAttr* curr = first;
+
+ for (int c= 0; c < (m+1); c++)
+ {
+ if (hc.verifyRecAttr(record,
+ 0,
+ curr))
+ {
+ ndbout << "Mismatch on record "
+ << record << " column "
+ << dupColNum << " read number "
+ << c+1 << endl;
+ result = NDBT_FAILED;
+ break;
+ }
+
+ ndbout << "/";
+
+ curr = curr->next();
+ }
+
+ ndbout << endl;
+
+ pNdb->closeTransaction(pCon);
+
+ if (result == NDBT_FAILED)
+ break;
+
+ if (curr != NULL)
+ {
+ ndbout << "Error - extra RecAttr(s) found" << endl;
+ result = NDBT_FAILED;
+ break;
+ }
+
+ }// m
+
+ delete pNdb;
+
+ return result;
+}
+
NDBT_TESTSUITE(testNdbApi);
@@ -3290,6 +3441,12 @@ TESTCASE("ApiFailReqBehaviour",
STEP(testApiFailReq);
FINALIZER(runClearTable);
}
+TESTCASE("ReadColumnDuplicates",
+ "Check NdbApi behaves ok when reading same column multiple times") {
+ INITIALIZER(runLoadTable);
+ STEP(runReadColumnDuplicates);
+ FINALIZER(runClearTable);
+}
NDBT_TESTSUITE_END(testNdbApi);
int main(int argc, const char** argv){
=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt 2009-10-05 10:38:50 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2009-10-06 10:39:02 +0000
@@ -1362,3 +1362,7 @@ max-time: 300
cmd: testNdbApi
args: -n ApiFailReqBehaviour T1
+max-time: 300
+cmd: testNdbApi
+args: -n ReadColumnDuplicates
+
=== modified file 'storage/ndb/test/src/HugoCalculator.cpp'
--- a/storage/ndb/test/src/HugoCalculator.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/test/src/HugoCalculator.cpp 2009-10-06 10:39:02 +0000
@@ -304,6 +304,105 @@ HugoCalculator::verifyRowValues(NDBT_Res
return result;
}
+
+int
+HugoCalculator::verifyRecAttr(int record,
+ int updates,
+ const NdbRecAttr* recAttr)
+{
+ const char* valPtr = NULL;
+ int attrib = recAttr->getColumn()->getAttrId();
+ Uint32 valLen = recAttr->get_size_in_bytes();
+ if (!recAttr->isNULL())
+ valPtr= (const char*) recAttr->aRef();
+
+ return verifyColValue(record,
+ attrib,
+ updates,
+ valPtr,
+ valLen);
+}
+
+int
+HugoCalculator::verifyColValue(int record,
+ int attrib,
+ int updates,
+ const char* valPtr,
+ Uint32 valLen)
+{
+ int result = 0;
+
+ if (attrib == m_updatesCol)
+ {
+ int val= *((const int*) valPtr);
+ if (val != updates)
+ {
+ g_err << "|- Updates column (" << attrib << ")" << endl;
+ g_err << "|- Expected " << updates << " but found " << val << endl;
+ result = -1;
+ }
+ }
+ else if (attrib == m_idCol)
+ {
+ int val= *((const int*) valPtr);
+ if (val != record)
+ {
+ g_err << "|- Identity column (" << attrib << ")" << endl;
+ g_err << "|- Expected " << record << " but found " << val << endl;
+ result = -1;
+ }
+ }
+ else
+ {
+ /* 'Normal' data column */
+ const NdbDictionary::Column* attr = m_tab.getColumn(attrib);
+ Uint32 len = attr->getSizeInBytes(), real_len;
+ char buf[NDB_MAX_TUPLE_SIZE];
+ const char* res = calcValue(record, attrib, updates, buf, len, &real_len);
+ if (res == NULL){
+ if (valPtr != NULL){
+ g_err << "|- NULL ERROR: expected a NULL but the column was not null" << endl;
+ g_err << "|- Column length is " << valLen << " bytes" << endl;
+ g_err << "|- Column data follows :" << endl;
+ for (Uint32 j = 0; j < valLen; j ++)
+ {
+ g_err << j << ":" << hex << (Uint32)(Uint8)valPtr[j] << endl;
+ }
+ result = -1;
+ }
+ } else{
+ if (real_len != valLen)
+ {
+ g_err << "|- Invalid data found in attribute " << attrib << ": \""
+ << "Length of expected=" << real_len << endl
+ << "Length of passed="
+ << valLen << endl;
+ result= -1;
+ }
+ else if (memcmp(res, valPtr, real_len) != 0)
+ {
+ g_err << "|- Expected data mismatch on column "
+ << attr->getName() << " length " << real_len
+ << " bytes " << endl;
+ g_err << "|- Bytewise comparison follows :" << endl;
+ for (Uint32 j = 0; j < real_len; j++)
+ {
+ g_err << j << ":" << hex << (Uint32)(Uint8)buf[j] << "[" << hex << (Uint32)(Uint8)valPtr[j] << "]";
+ if (buf[j] != valPtr[j])
+ {
+ g_err << "==>Match failed!";
+ }
+ g_err << endl;
+ }
+ g_err << endl;
+ result = -1;
+ }
+ }
+ }
+
+ return result;
+}
+
int
HugoCalculator::getIdValue(NDBT_ResultRow* const pRow) const {
return pRow->attributeStore(m_idCol)->u_32_value();
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-6.2 branch (frazer:3012) Bug#45282 | Frazer Clement | 6 Oct |