From: Date: July 4 2008 2:37pm Subject: bzr commit into mysql-5.1-telco-6.2 tree (frazer:2633) Bug#37672 List-Archive: http://lists.mysql.com/commits/49012 X-Bug: 37672 Message-Id: <200807041237.m64CbY10012091@forth.ndb.mysql.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1109202045==" --===============1109202045== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/frazer/bzr/mysql-5.1-telco-6.2/ ------------------------------------------------------------ revno: 2633 revision-id: frazer@stripped parent: jonas@stripped committer: Frazer Clement branch nick: mysql-5.1-telco-6.2 timestamp: Fri 2008-07-04 13:37:19 +0100 message: Bug#37672 NDBAPI : NdbRecord option OO_ANYVALUE causes interpreted delete to abort. Setting the ANYVALUE operation option for an NdbRecord interpreted delete results in transaction abort. Error 888 is given. 2 problems : 1) For delete, NdbRecord code was placing ANYVALUE update ATTRINFO in the 'final Update' part of the TCKEYREQ rather than the 'initial Read' part. 2) For interpreted delete, TUP was ignoring log ATTRINFO words generated by read part of interpreted delete, resulting in SUMA sending events without correct ANYVALUE. modified: storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp sp1f-dbtupexecquery.cpp-20040414082419-mq6uenb66nxl6kcdp3v27evwjkcs2ttz storage/ndb/src/ndbapi/NdbOperationExec.cpp sp1f-ndboperationexec.cpp-20040414082425-spfhlvqpx5hh2u7nyud2l5ordg7u43eb storage/ndb/test/ndbapi/test_event.cpp sp1f-test_event.cpp-20040414082438-mn2bippetrmdotxdqygnmo7y2fhcioia storage/ndb/test/run-test/daily-basic-tests.txt sp1f-dailybasictests.txt-20040623115449-liur6p3tedydxdte6rr35pqap26frov6 per-file comments: storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp Modify TUP interpreter to include log words generated as a side-effect of interpretation. storage/ndb/src/ndbapi/NdbOperationExec.cpp Modify NdbRecord TCKEYREQ generating code to put ANYVALUE ATTRINFO in initial read section for delete requests. storage/ndb/test/ndbapi/test_event.cpp Add testcase to check that AnyValue is correctly propagated to events for PK insert, update, write (update), delete with and without interpreted code. storage/ndb/test/run-test/daily-basic-tests.txt Add new testcase to daily-basic. --===============1109202045== MIME-Version: 1.0 Content-Type: text/text/x-diff; charset="us-ascii"; name="patch-2633.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline === modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp' --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2008-03-25 16:49:01 +0000 +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2008-07-04 12:37:19 +0000 @@ -1845,7 +1845,11 @@ Uint32 RattroutCounter= 0; Uint32 RinstructionCounter= 5; - Uint32 RlogSize= 0; + + /* All information to be logged/propagated to replicas + * is generated from here on so reset the log word count + */ + Uint32 RlogSize= req_struct->log_size= 0; if (((RtotalLen + 5) == RattrinbufLen) && (RattrinbufLen >= 5) && (RattrinbufLen < ZATTR_BUFFER_SIZE)) { @@ -1951,7 +1955,12 @@ return -1; } } - req_struct->log_size= RlogSize; + /* Add log words explicitly generated here to existing log size + * - readAttributes can generate log for ANYVALUE column + * It adds the words directly to req_struct->log_size + * This is used for ANYVALUE and interpreted delete. + */ + req_struct->log_size+= RlogSize; req_struct->read_length= RattroutCounter; sendReadAttrinfo(signal, req_struct, RattroutCounter, regOperPtr); if (RlogSize > 0) { === modified file 'storage/ndb/src/ndbapi/NdbOperationExec.cpp' --- a/storage/ndb/src/ndbapi/NdbOperationExec.cpp 2008-06-03 10:00:31 +0000 +++ b/storage/ndb/src/ndbapi/NdbOperationExec.cpp 2008-07-04 12:37:19 +0000 @@ -795,6 +795,28 @@ } } + if (m_use_any_value && + (tOpType == DeleteRequest)) + { + /* Special hack for delete and ANYVALUE pseudo-column + * We want to be able set the ANYVALUE pseudo-column as + * part of a delete, but deletes don't allow updates + * So we perform a 'read' of the column, passing a value. + * Code in TUP which handles this 'read' will set the + * value when the read is processed. + */ + res= insertATTRINFOHdr_NdbRecord(aTC_ConnectPtr, aTransId, + AttributeHeader::ANY_VALUE, 4, + &attrInfoPtr, &remain); + if(res) + return res; + res= insertATTRINFOData_NdbRecord(aTC_ConnectPtr, aTransId, + (const char *)(&m_any_value), 4, + &attrInfoPtr, &remain); + if(res) + return res; + } + /* Interpreted program main signal words */ if (code) { @@ -977,10 +999,9 @@ if ((tOpType == InsertRequest) || (tOpType == WriteRequest) || - (tOpType == UpdateRequest) || - (tOpType == DeleteRequest)) + (tOpType == UpdateRequest)) { - /* Handle any setAnyValue(). */ + /* Handle setAnyValue() for all cases except delete */ if (m_use_any_value) { res= insertATTRINFOHdr_NdbRecord(aTC_ConnectPtr, aTransId, === modified file 'storage/ndb/test/ndbapi/test_event.cpp' --- a/storage/ndb/test/ndbapi/test_event.cpp 2008-06-18 15:05:56 +0000 +++ b/storage/ndb/test/ndbapi/test_event.cpp 2008-07-04 12:37:19 +0000 @@ -25,14 +25,13 @@ #define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb() -static int createEvent(Ndb *pNdb, +static int createEvent(Ndb *pNdb, const NdbDictionary::Table &tab, - NDBT_Context* ctx) + bool merge_events, + bool report) { char eventName[1024]; sprintf(eventName,"%s_EVENT",tab.getName()); - bool merge_events = ctx->getProperty("MergeEvents"); - bool report = ctx->getProperty("ReportSubscribe"); NdbDictionary::Dictionary *myDict = pNdb->getDictionary(); @@ -89,6 +88,16 @@ return NDBT_OK; } +static int createEvent(Ndb *pNdb, + const NdbDictionary::Table &tab, + NDBT_Context* ctx) +{ + bool merge_events = ctx->getProperty("MergeEvents"); + bool report = ctx->getProperty("ReportSubscribe"); + + return createEvent(pNdb, tab, merge_events, report); +} + static int dropEvent(Ndb *pNdb, const NdbDictionary::Table &tab) { char eventName[1024]; @@ -2690,6 +2699,346 @@ return NDBT_OK; } +const NdbDictionary::Table* createBoringTable(const char* name, Ndb* pNdb) +{ + NdbDictionary::Table tab; + + tab.setName(name); + + NdbDictionary::Column pk; + pk.setName("Key"); + pk.setType(NdbDictionary::Column::Unsigned); + pk.setLength(1); + pk.setNullable(false); + pk.setPrimaryKey(true); + tab.addColumn(pk); + + NdbDictionary::Column attr; + attr.setName("Attr"); + attr.setType(NdbDictionary::Column::Unsigned); + attr.setLength(1); + attr.setNullable(true); + attr.setPrimaryKey(false); + tab.addColumn(attr); + + pNdb->getDictionary()->dropTable(tab.getName()); + if(pNdb->getDictionary()->createTable(tab) == 0) + { + ndbout << (NDBT_Table&)tab << endl; + return pNdb->getDictionary()->getTable(tab.getName()); + } + + ndbout << "Table create failed, err : " << + pNdb->getDictionary()->getNdbError().code << endl; + + return NULL; +} + +/* Types of operation which can be tagged via 'setAnyValue */ +enum OpTypes {Insert, Update, Write, Delete, EndOfOpTypes}; + +/** + * executeOps + * Generate a number of PK operations of the supplied type + * using the passed operation options and setting the + * anyValue tag + */ +int +executeOps(Ndb* pNdb, + const NdbDictionary::Table* tab, + OpTypes op, + Uint32 rowCount, + Uint32 keyOffset, + Uint32 anyValueOffset, + NdbOperation::OperationOptions opts) +{ + NdbTransaction* trans= pNdb->startTransaction(); + const NdbRecord* record= tab->getDefaultRecord(); + + char RowBuf[16]; + Uint32* keyPtr= (Uint32*) NdbDictionary::getValuePtr(record, + RowBuf, + 0); + Uint32* attrPtr= (Uint32*) NdbDictionary::getValuePtr(record, + RowBuf, + 1); + + for (Uint32 i=keyOffset; i < (keyOffset + rowCount); i++) + { + *keyPtr= *attrPtr= i; + opts.optionsPresent |= NdbOperation::OperationOptions::OO_ANYVALUE; + opts.anyValue= anyValueOffset + i; + bool allowInterpreted= + (op == Update) || + (op == Delete); + + if (!allowInterpreted) + opts.optionsPresent &= + ~ (Uint64) NdbOperation::OperationOptions::OO_INTERPRETED; + + switch (op) { + case Insert : + if (trans->insertTuple(record, + RowBuf, + NULL, + &opts, + sizeof(opts)) == NULL) + { + g_err << "Can't create operation : " << + trans->getNdbError().code << endl; + return NDBT_FAILED; + } + break; + case Update : + if (trans->updateTuple(record, + RowBuf, + record, + RowBuf, + NULL, + &opts, + sizeof(opts)) == NULL) + { + g_err << "Can't create operation : " << + trans->getNdbError().code << endl; + return NDBT_FAILED; + } + break; + case Write : + if (trans->writeTuple(record, + RowBuf, + record, + RowBuf, + NULL, + &opts, + sizeof(opts)) == NULL) + { + g_err << "Can't create operation : " << + trans->getNdbError().code << endl; + return NDBT_FAILED; + } + break; + case Delete : + if (trans->deleteTuple(record, + RowBuf, + record, + NULL, + NULL, + &opts, + sizeof(opts)) == NULL) + { + g_err << "Can't create operation : " << + trans->getNdbError().code << endl; + return NDBT_FAILED; + } + break; + default: + g_err << "Bad operation type : " << op << endl; + return NDBT_FAILED; + } + } + + trans->execute(Commit); + + if (trans->getNdbError().code != 0) + { + g_err << "Error executing operations :" << + trans->getNdbError().code << endl; + return NDBT_FAILED; + } + + trans->close(); + + return NDBT_OK; +} + +int +checkAnyValueInEvent(Ndb* pNdb, + NdbRecAttr* preKey, + NdbRecAttr* postKey, + NdbRecAttr* preAttr, + NdbRecAttr* postAttr, + Uint32 num, + Uint32 anyValueOffset, + bool checkPre) +{ + Uint32 received= 0; + + while (received < num) + { + int pollRc; + + if ((pollRc= pNdb->pollEvents(10000)) < 0) + { + g_err << "Error while polling for events : " << + pNdb->getNdbError().code; + return NDBT_FAILED; + } + + if (pollRc == 0) + { + printf("No event, waiting...\n"); + continue; + } + + NdbEventOperation* event; + while((event= pNdb->nextEvent()) != NULL) + { +// printf("Event is %p of type %u\n", +// event, event->getEventType()); +// printf("Got event, prekey is %u predata is %u \n", +// preKey->u_32_value(), +// preAttr->u_32_value()); +// printf(" postkey is %u postdata is %u anyvalue is %u\n", +// postKey->u_32_value(), +// postAttr->u_32_value(), +// event->getAnyValue()); + + received ++; + Uint32 keyVal= (checkPre? + preKey->u_32_value() : + postKey->u_32_value()); + + if (event->getAnyValue() != + (anyValueOffset + keyVal)) + { + g_err << "Error : Got event, key is " << + keyVal << " anyValue is " << + event->getAnyValue() << + " expected " << (anyValueOffset + keyVal) + << endl; + return NDBT_FAILED; + } + } + } + + return NDBT_OK; +} + + + +int +runBug37672(NDBT_Context* ctx, NDBT_Step* step) +{ + /* InterpretedDelete and setAnyValue failed */ + /* Let's create a boring, known table for this since + * we don't yet have Hugo tools for NdbRecord + */ + BaseString name; + name.assfmt("TAB_TESTEVENT%d", rand() & 65535); + Ndb* pNdb= GETNDB(step); + + const NdbDictionary::Table* tab= createBoringTable(name.c_str(), pNdb); + + if (tab == NULL) + return NDBT_FAILED; + + /* Create an event to listen to events on the table */ + char eventName[1024]; + sprintf(eventName,"%s_EVENT", tab->getName()); + + if (createEvent(pNdb, *tab, false, true) != 0) + return NDBT_FAILED; + + /* Now create the event operation to retrieve the events */ + NdbEventOperation* eventOp; + eventOp= pNdb->createEventOperation(eventName); + + if (eventOp == NULL) + { + g_err << "Failed to create event operation :" << + pNdb->getNdbError().code << endl; + return NDBT_FAILED; + } + + NdbRecAttr* eventKeyData= eventOp->getValue("Key"); + NdbRecAttr* eventOldKeyData= eventOp->getPreValue("Key"); + NdbRecAttr* eventAttrData= eventOp->getValue("Attr"); + NdbRecAttr* eventOldAttrData= eventOp->getPreValue("Attr"); + + if ((eventKeyData == NULL) || (eventAttrData == NULL)) + { + g_err << "Failed to get NdbRecAttrs for events" << endl; + return NDBT_FAILED; + }; + + if (eventOp->execute() != 0) + { + g_err << "Failed to execute event operation :" << + eventOp->getNdbError().code << endl; + return NDBT_FAILED; + } + + /* Perform some operations on the table, and check + * that we get the correct AnyValues propagated + * through + */ + NdbOperation::OperationOptions opts; + opts.optionsPresent= 0; + + NdbInterpretedCode nonsenseProgram; + + nonsenseProgram.load_const_u32(0, 0); + nonsenseProgram.interpret_exit_ok(); + + nonsenseProgram.finalise(); + + const Uint32 rowCount= 1500; + Uint32 keyOffset= 0; + Uint32 anyValueOffset= 100; + + printf ("Testing AnyValue with no interpreted program\n"); + for (int variants= 0; variants < 2; variants ++) + { + for (int op= Insert; op < EndOfOpTypes; op++) + { + printf(" Testing opType %d (ko=%d, ao=%d)...", + op, keyOffset, anyValueOffset); + + if (executeOps(pNdb, + tab, + (OpTypes)op, + rowCount, + keyOffset, + anyValueOffset, + opts)) + return NDBT_FAILED; + + if (checkAnyValueInEvent(pNdb, + eventOldKeyData, eventKeyData, + eventOldAttrData, eventAttrData, + rowCount, + anyValueOffset, + false // always use postKey data + ) != NDBT_OK) + return NDBT_FAILED; + printf("ok\n"); + }; + + printf("Testing AnyValue with interpreted program\n"); + opts.optionsPresent|= NdbOperation::OperationOptions::OO_INTERPRETED; + opts.interpretedCode= &nonsenseProgram; + } + + if (dropEventOperations(pNdb) != 0) + { + g_err << "Dropping event operations failed : " << + pNdb->getNdbError().code << endl; + return NDBT_FAILED; + } + + if (dropEvent(pNdb, tab->getName()) != 0) + { + g_err << "Dropping event failed : " << + pNdb->getDictionary()->getNdbError().code << endl; + return NDBT_FAILED; + } + + pNdb->getDictionary()->dropTable(tab->getName()); + + return NDBT_OK; +} + + NDBT_TESTSUITE(test_event); TESTCASE("BasicEventOperation", "Verify that we can listen to Events" @@ -2881,6 +3230,10 @@ { INITIALIZER(runBug37442); } +TESTCASE("Bug37672", "NdbRecord option OO_ANYVALUE causes interpreted delete to abort.") +{ + INITIALIZER(runBug37672); +} NDBT_TESTSUITE_END(test_event); 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 2008-06-27 08:38:07 +0000 +++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2008-07-04 12:37:19 +0000 @@ -1149,3 +1149,9 @@ args: -l 100 -n Bug37158 # EOF 2008-06-03 + +max-time: 500 +cmd: test_event +args -n bug37672 T1 + +#EOF 2008-07-04 --===============1109202045==--