=== modified file 'storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp' --- storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp 2009-03-17 15:45:05 +0000 +++ storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp 2009-03-27 16:24:56 +0000 @@ -4934,7 +4934,6 @@ NdbDictInterface::execLIST_TABLES_CONF(N } else { - Uint32 fid = signal->getFragmentId(); if (m_fragmentId != signal->getFragmentId()) { abort(); @@ -5700,6 +5699,11 @@ NdbDictionaryImpl::initialiseColumnData( recCol->flags|= NdbRecord::IsNullable; recCol->nullbit_byte_offset= recSpec->nullbit_byte_offset; recCol->nullbit_bit_in_byte= recSpec->nullbit_bit_in_byte; + + const Uint32 nullbit_byte= recSpec->nullbit_byte_offset + + (recSpec->nullbit_bit_in_byte >> 3); + if (nullbit_byte >= rec->m_row_size) + rec->m_row_size= nullbit_byte + 1; } if (col->m_arrayType==NDB_ARRAYTYPE_SHORT_VAR) { === modified file 'storage/ndb/test/ndbapi/testNdbApi.cpp' --- storage/ndb/test/ndbapi/testNdbApi.cpp 2009-03-18 07:14:50 +0000 +++ storage/ndb/test/ndbapi/testNdbApi.cpp 2009-03-27 15:51:58 +0000 @@ -47,7 +47,6 @@ int runTestMaxNdb(NDBT_Context* ctx, NDB while (l < loops && result == NDBT_OK){ ndbout_c("loop %d", l + 1); int errors = 0; - int maxErrors = 5; Vector ndbVector; int i = 0; @@ -1611,7 +1610,6 @@ static void print(int op) int runTestIgnoreError(NDBT_Context* ctx, NDBT_Step* step) { - int result = NDBT_OK; Uint32 loops = ctx->getNumRecords(); const NdbDictionary::Table* pTab = ctx->getTab(); @@ -1653,10 +1651,12 @@ runTestIgnoreError(NDBT_Context* ctx, ND switch(et){ case Commit: printf("c "); break; case NoCommit: printf("nc "); break; + default: printf("bad exectype : %d\n", et); return NDBT_FAILED; } switch(ao){ case AbortOnError: printf("aoe "); break; case AO_IgnoreError: printf("ie "); break; + default: printf("bad abortoption : %d\n", ao); return NDBT_FAILED; } printf(": "); @@ -1707,8 +1707,6 @@ do_cnt(Ndb_cluster_connection* con) int runCheckNdbObjectList(NDBT_Context* ctx, NDBT_Step* step) { - const NdbDictionary::Table* pTab = ctx->getTab(); - Ndb_cluster_connection* con = &ctx->m_cluster_connection; Uint32 cnt1 = do_cnt(con); @@ -1829,7 +1827,7 @@ runBug28443(NDBT_Context* ctx, NDBT_Step restarter.insertErrorInAllNodes(9003); - for (Uint32 i = 0; igetNumLoops(); i++) + for (int i = 0; igetNumLoops(); i++) { HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.loadTable(GETNDB(step), records, 2048) != 0) @@ -1856,7 +1854,7 @@ runBug37158(NDBT_Context* ctx, NDBT_Step int result = NDBT_OK; Ndb* pNdb = GETNDB(step); - for (Uint32 i = 0; igetNumLoops(); i++) + for (int i = 0; igetNumLoops(); i++) { HugoOperations hugoOps(*ctx->getTab()); hugoOps.startTransaction(pNdb); @@ -2576,6 +2574,68 @@ testNdbRecordCICharPKUpdate(NDBT_Context } +int +testNdbRecordRowLength(NDBT_Context* ctx, NDBT_Step* step) +{ + /* Bug#43891 ignored null bits at the end of an row + * when calculating the row length, leading to various + * problems + */ + Ndb* pNdb = GETNDB(step); + const NdbDictionary::Table* pTab= ctx->getTab(); + int numCols= pTab->getNoOfColumns(); + const NdbRecord* defaultRecord= pTab->getDefaultRecord(); + + /* Create an NdbRecord structure with all the Null + * bits at the end - to test that they are included + * correctly in row length calculations. + */ + NdbDictionary::RecordSpecification rsArray[ NDB_MAX_ATTRIBUTES_IN_TABLE ]; + + bool hasNullable= false; + Uint32 highestUsed= 9000; + for (int attrId=0; attrId< numCols; attrId++) + { + NdbDictionary::RecordSpecification& rs= rsArray[attrId]; + + rs.column= pTab->getColumn(attrId); + CHECK(NdbDictionary::getOffset(defaultRecord, + attrId, + rs.offset)); + CHECK(NdbDictionary::getNullBitOffset(defaultRecord, + attrId, + rs.nullbit_byte_offset, + rs.nullbit_bit_in_byte)); + if (rs.column->getNullable()) + { + /* Shift null bit(s) to bytes beyond the end of the record */ + hasNullable= true; + rs.nullbit_byte_offset= highestUsed++; + rs.nullbit_bit_in_byte= 0; + } + } + + if (hasNullable) + { + printf("Testing"); + const NdbRecord* myRecord= pNdb->getDictionary()->createRecord(pTab, + rsArray, + numCols, + sizeof(NdbDictionary::RecordSpecification)); + CHECK(myRecord != 0); + Uint32 rowLength= NdbDictionary::getRecordRowLength(myRecord); + if (rowLength != highestUsed) + { + ndbout << "Failure, expected row length " << highestUsed + << " got row length " << rowLength + << endl; + return NDBT_FAILED; + } + } + + return NDBT_OK; +} + NDBT_TESTSUITE(testNdbApi); TESTCASE("MaxNdb", @@ -2709,6 +2769,10 @@ TESTCASE("NdbRecordCICharPKUpdate", "Verify that a case-insensitive char pk column can be updated"){ INITIALIZER(testNdbRecordCICharPKUpdate); } +TESTCASE("NdbRecordRowLength", + "Verify that the record row length calculation is correct") { + INITIALIZER(testNdbRecordRowLength); +} NDBT_TESTSUITE_END(testNdbApi); int main(int argc, const char** argv){